2 * Routines for sFlow dissection
3 * Copyright 2003, Jeff Rizzo <riz@boogers.sf.ca.us>
5 * $Id: packet-sflow.c,v 1.1 2003/06/13 22:31:11 guy Exp $
7 * Ethereal - Network traffic analyzer
8 * By Gerald Combs <gerald@ethereal.com>
9 * Copyright 1998 Gerald Combs
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU General Public License
13 * as published by the Free Software Foundation; either version 2
14 * of the License, or (at your option) any later version.
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
26 /* This file (mostly) implements a dissector for sFlow (RFC3176),
27 * from the version 4 spec at http://www.sflow.org/SFLOW-DATAGRAM.txt .
30 * Fix the highlighting of the datastream when bits are selected
31 * split things out into packet-sflow.h ?
32 * make routines more consistent as to whether they return
33 * 'offset' or bytes consumed ('len')
34 * implement sampled_ipv4 and sampled_ipv6 packet data types
35 * implement extended_gateway
36 * implement extended_user
37 * implement extended_url
38 * implement non-generic counters sampling
39 * implement the draft version 5 spec
52 #ifdef NEED_SNPRINTF_H
53 # include "snprintf.h"
56 #include <epan/packet.h>
57 /*#include "packet-sflow.h"*/
59 #define UDP_PORT_SFLOW 6343
61 #define ADDRESS_IPV4 1
62 #define ADDRESS_IPV6 2
65 #define COUNTERSSAMPLE 2
67 static const value_string sflow_sampletype[] = {
68 { FLOWSAMPLE, "Flow sample" },
69 { COUNTERSSAMPLE, "Counters sample" },
73 /* interface counter types */
74 #define SFLOW_COUNTERS_GENERIC 1
75 #define SFLOW_COUNTERS_ETHERNET 2
76 #define SFLOW_COUNTERS_TOKENRING 3
77 #define SFLOW_COUNTERS_FDDI 4
78 #define SFLOW_COUNTERS_VG 5
79 #define SFLOW_COUNTERS_WAN 6
80 #define SFLOW_COUNTERS_VLAN 7
82 static const value_string sflow_counterstype [] = {
83 { SFLOW_COUNTERS_GENERIC, "Generic counters" },
84 { SFLOW_COUNTERS_ETHERNET, "Ethernet counters" },
85 { SFLOW_COUNTERS_FDDI, "FDDI counters" },
86 { SFLOW_COUNTERS_VG, "100baseVG counters" },
87 { SFLOW_COUNTERS_WAN, "WAN counters" },
88 { SFLOW_COUNTERS_VLAN, "VLAN counters" },
92 #define MAX_HEADER_SIZE 256
94 #define SFLOW_PACKET_DATA_TYPE_HEADER 1
95 #define SFLOW_PACKET_DATA_TYPE_IPV4 2
96 #define SFLOW_PACKET_DATA_TYPE_IPV6 3
98 static const value_string sflow_packet_information_type [] = {
99 { SFLOW_PACKET_DATA_TYPE_HEADER, "Packet headers are sampled" },
100 { SFLOW_PACKET_DATA_TYPE_IPV4, "IP Version 4 data" },
101 { SFLOW_PACKET_DATA_TYPE_IPV6, "IP Version 6 data" },
105 #define SFLOW_HEADER_ETHERNET 1
106 #define SFLOW_HEADER_TOKENBUS 2
107 #define SFLOW_HEADER_TOKENRING 3
108 #define SFLOW_HEADER_FDDI 4
109 #define SFLOW_HEADER_FRAME_RELAY 5
110 #define SFLOW_HEADER_X25 6
111 #define SFLOW_HEADER_PPP 7
112 #define SFLOW_HEADER_SMDS 8
113 #define SFLOW_HEADER_AAL5 9
114 #define SFLOW_HEADER_AAL5_IP 10
115 #define SFLOW_HEADER_IPv4 11
116 #define SFLOW_HEADER_IPv6 12
117 #define SFLOW_HEADER_MPLS 13
119 static const value_string sflow_header_protocol[] = {
120 { SFLOW_HEADER_ETHERNET, "Ethernet" },
121 { SFLOW_HEADER_TOKENBUS, "Token Bus" },
122 { SFLOW_HEADER_TOKENRING, "Token Ring" },
123 { SFLOW_HEADER_FDDI, "FDDI" },
124 { SFLOW_HEADER_FRAME_RELAY, "Frame Relay" },
125 { SFLOW_HEADER_X25, "X.25" },
126 { SFLOW_HEADER_PPP, "PPP" },
127 { SFLOW_HEADER_SMDS, "SMDS" },
128 { SFLOW_HEADER_AAL5, "ATM AAL5" },
129 { SFLOW_HEADER_AAL5_IP, "ATM AAL5-IP (e.g., Cisco AAL5 mux)" },
130 { SFLOW_HEADER_IPv4, "IPv4" },
131 { SFLOW_HEADER_IPv6, "IPv6" },
132 { SFLOW_HEADER_MPLS, "MPLS" },
136 /* extended data types */
137 #define SFLOW_EXTENDED_SWITCH 1
138 #define SFLOW_EXTENDED_ROUTER 2
139 #define SFLOW_EXTENDED_GATEWAY 3
140 #define SFLOW_EXTENDED_USER 4
141 #define SFLOW_EXTENDED_URL 5
143 static const value_string sflow_extended_data_types[] = {
144 { SFLOW_EXTENDED_SWITCH, "Extended switch information" },
145 { SFLOW_EXTENDED_ROUTER, "Extended router information" },
146 { SFLOW_EXTENDED_GATEWAY, "Extended gateway information" },
147 { SFLOW_EXTENDED_USER, "Extended user information" },
148 { SFLOW_EXTENDED_URL, "Extended URL information" },
153 /* flow sample header */
154 struct sflow_flow_sample_header {
155 guint32 sequence_number;
157 guint32 sampling_rate;
164 /* counters sample header */
165 struct sflow_counters_sample_header {
166 guint32 sequence_number;
168 guint32 sampling_interval;
169 guint32 counters_type;
172 /* generic interface counters */
180 guint32 ifInUcastPkts;
181 guint32 ifInMulticastPkts;
182 guint32 ifInBroadcastPkts;
183 guint32 ifInDiscards;
185 guint32 ifInUnknownProtos;
187 guint32 ifOutUcastPkts;
188 guint32 ifOutMulticastPkts;
189 guint32 ifOutBroadcastPkts;
190 guint32 ifOutDiscards;
192 guint32 ifPromiscuousMode;
195 /* ethernet counters. These will be preceded by generic counters. */
196 struct ethernet_counters {
197 guint32 dot3StatsAlignmentErrors;
198 guint32 dot3StatsFCSErrors;
199 guint32 dot3StatsSingleCollisionFrames;
200 guint32 dot3StatsMultipleCollisionFrames;
201 guint32 dot3StatsSQETestErrors;
202 guint32 dot3StatsDeferredTransmissions;
203 guint32 dot3StatsLateCollisions;
204 guint32 dot3StatsExcessiveCollisions;
205 guint32 dot3StatsInternalMacTransmitErrors;
206 guint32 dot3StatsCarrierSenseErrors;
207 guint32 dot3StatsFrameTooLongs;
208 guint32 dot3StatsInternalMacReceiveErrors;
209 guint32 dot3StatsSymbolErrors;
212 /* Token Ring counters */
213 struct token_ring_counters {
214 guint32 dot5StatsLineErrors;
215 guint32 dot5StatsBurstErrors;
216 guint32 dot5StatsACErrors;
217 guint32 dot5StatsAbortTransErrors;
218 guint32 dot5StatsInternalErrors;
219 guint32 dot5StatsLostFrameErrors;
220 guint32 dot5StatsReceiveCongestions;
221 guint32 dot5StatsFrameCopiedErrors;
222 guint32 dot5StatsTokenErrors;
223 guint32 dot5StatsSoftErrors;
224 guint32 dot5StatsHardErrors;
225 guint32 dot5StatsSignalLoss;
226 guint32 dot5StatsTransmitBeacons;
227 guint32 dot5StatsRecoverys;
228 guint32 dot5StatsLobeWires;
229 guint32 dot5StatsRemoves;
230 guint32 dot5StatsSingles;
231 guint32 dot5StatsFreqErrors;
234 /* 100BaseVG counters */
237 guint32 dot12InHighPriorityFrames;
238 guint64 dot12InHighPriorityOctets;
239 guint32 dot12InNormPriorityFrames;
240 guint64 dot12InNormPriorityOctets;
241 guint32 dot12InIPMErrors;
242 guint32 dot12InOversizeFrameErrors;
243 guint32 dot12InDataErrors;
244 guint32 dot12InNullAddressedFrames;
245 guint32 dot12OutHighPriorityFrames;
246 guint64 dot12OutHighPriorityOctets;
247 guint32 dot12TransitionIntoTrainings;
248 guint64 dot12HCInHighPriorityOctets;
249 guint64 dot12HCInNormPriorityOctets;
250 guint64 dot12HCOutHighPriorityOctets;
255 struct vlan_counters {
259 guint32 multicastPkts;
260 guint32 broadcastPkts;
264 /* Initialize the protocol and registered fields */
265 static int proto_sflow = -1;
266 static int hf_sflow_version = -1;
267 /*static int hf_sflow_agent_address_type = -1; */
268 static int hf_sflow_agent_address_v4 = -1;
269 static int hf_sflow_agent_address_v6 = -1;
270 static int hf_sflow_seqnum = -1;
271 static int hf_sflow_sysuptime = -1;
272 static int hf_sflow_numsamples = -1;
273 static int hf_sflow_header_protocol = -1;
274 static int hf_sflow_sampletype = -1;
275 static int hf_sflow_header = -1;
276 static int hf_sflow_packet_information_type = -1;
277 static int hf_sflow_vlan_in = -1; /* incoming 802.1q VLAN ID */
278 static int hf_sflow_vlan_out = -1; /* outgoing 802.1q VLAN ID */
279 static int hf_sflow_pri_in = -1; /* incominging 802.1p priority */
280 static int hf_sflow_pri_out = -1; /* outgoing 802.1p priority */
281 static int hf_sflow_nexthop_v4 = -1; /* nexthop address */
282 static int hf_sflow_nexthop_v6 = -1; /* nexthop address */
283 static int hf_sflow_ifindex = -1;
284 static int hf_sflow_iftype = -1;
285 static int hf_sflow_ifspeed = -1;
286 static int hf_sflow_ifdirection = -1;
287 static int hf_sflow_ifstatus = -1;
288 static int hf_sflow_ifinoct = -1;
289 static int hf_sflow_ifinpkt = -1;
290 static int hf_sflow_ifinmcast = -1;
291 static int hf_sflow_ifinbcast = -1;
292 static int hf_sflow_ifinerr = -1;
293 static int hf_sflow_ifindisc = -1;
294 static int hf_sflow_ifinunk = -1;
295 static int hf_sflow_ifoutoct = -1;
296 static int hf_sflow_ifoutpkt = -1;
297 static int hf_sflow_ifoutmcast = -1;
298 static int hf_sflow_ifoutbcast = -1;
299 static int hf_sflow_ifoutdisc = -1;
300 static int hf_sflow_ifouterr = -1;
301 static int hf_sflow_ifpromisc = -1;
303 /* Initialize the subtree pointers */
304 static gint ett_sflow = -1;
305 static gint ett_sflow_sample = -1;
306 static gint ett_sflow_extended_data = -1;
307 static gint ett_sflow_sampled_header = -1;
309 /* dissectors for other protocols */
310 static dissector_handle_t eth_handle;
311 static dissector_handle_t tr_handle;
312 static dissector_handle_t fddi_handle;
313 static dissector_handle_t fr_handle;
314 static dissector_handle_t x25_handle;
315 static dissector_handle_t ppp_handle;
316 static dissector_handle_t smds_handle;
317 static dissector_handle_t aal5_handle;
318 static dissector_handle_t ipv4_handle;
319 static dissector_handle_t ipv6_handle;
320 static dissector_handle_t mpls_handle;
322 /* dissect a sampled header - layer 2 protocols */
324 dissect_sflow_sampled_header(tvbuff_t *tvb, packet_info *pinfo,
325 proto_tree *tree, volatile gint offset)
327 guint32 header_proto, frame_length;
328 volatile guint32 header_length;
330 proto_tree *sflow_header_tree;
332 /* stuff for saving column state before calling other dissectors.
333 * Thanks to Guy Harris for the tip. */
334 gboolean save_writable;
335 volatile address save_dl_src;
336 volatile address save_dl_dst;
337 volatile address save_net_src;
338 volatile address save_net_dst;
339 volatile address save_src;
340 volatile address save_dst;
342 header_proto = tvb_get_ntohl(tvb,offset);
343 proto_tree_add_item(tree, hf_sflow_header_protocol, tvb, offset,
346 frame_length = tvb_get_ntohl(tvb,offset);
347 proto_tree_add_text(tree, tvb, offset, 4, "Frame Length: %d bytes",
350 header_length = tvb_get_ntohl(tvb,offset);
353 if (header_length % 4) /* XDR requires 4-byte alignment */
354 header_length += 4 - (header_length % 4);
357 ti = proto_tree_add_item(tree, hf_sflow_header, tvb, offset,
358 header_length, FALSE);
359 sflow_header_tree = proto_item_add_subtree(ti, ett_sflow_sampled_header);
361 /* hand the header off to the appropriate dissector. It's probably
362 * a short frame, so ignore any exceptions. */
363 next_tvb = tvb_new_subset(tvb, offset, header_length, frame_length);
365 /* save some state */
366 save_writable = col_get_writable(pinfo->cinfo);
367 col_set_writable(pinfo->cinfo, FALSE);
368 save_dl_src = pinfo->dl_src;
369 save_dl_dst = pinfo->dl_dst;
370 save_net_src = pinfo->net_src;
371 save_net_dst = pinfo->net_dst;
372 save_src = pinfo->src;
373 save_dst = pinfo->dst;
376 switch (header_proto) {
377 case SFLOW_HEADER_ETHERNET:
378 call_dissector(eth_handle, next_tvb, pinfo, sflow_header_tree);
380 case SFLOW_HEADER_TOKENRING:
381 call_dissector(tr_handle, next_tvb, pinfo, sflow_header_tree);
383 case SFLOW_HEADER_FDDI:
384 call_dissector(fddi_handle, next_tvb, pinfo, sflow_header_tree);
386 case SFLOW_HEADER_FRAME_RELAY:
387 call_dissector(fr_handle, next_tvb, pinfo, sflow_header_tree);
389 case SFLOW_HEADER_X25:
390 call_dissector(x25_handle, next_tvb, pinfo, sflow_header_tree);
392 case SFLOW_HEADER_PPP:
393 call_dissector(ppp_handle, next_tvb, pinfo, sflow_header_tree);
395 case SFLOW_HEADER_SMDS:
396 call_dissector(smds_handle, next_tvb, pinfo, sflow_header_tree);
398 case SFLOW_HEADER_AAL5:
399 case SFLOW_HEADER_AAL5_IP:
400 /* I'll be surprised if this works! I have no AAL5 captures
401 * to test with, and I'm not sure how the encapsulation goes */
402 call_dissector(aal5_handle, next_tvb, pinfo, sflow_header_tree);
404 case SFLOW_HEADER_IPv4:
405 call_dissector(ipv4_handle, next_tvb, pinfo, sflow_header_tree);
407 case SFLOW_HEADER_IPv6:
408 call_dissector(ipv6_handle, next_tvb, pinfo, sflow_header_tree);
410 case SFLOW_HEADER_MPLS:
411 call_dissector(mpls_handle, next_tvb, pinfo, sflow_header_tree);
414 /* some of the protocols, I have no clue where to begin. */
418 CATCH2(BoundsError, ReportedBoundsError) {
423 /* restore saved state */
424 col_set_writable(pinfo->cinfo, save_writable);
425 pinfo->dl_src = save_dl_src;
426 pinfo->dl_dst = save_dl_dst;
427 pinfo->net_src = save_net_src;
428 pinfo->net_dst = save_net_dst;
429 pinfo->src = save_src;
430 pinfo->dst = save_dst;
432 offset += header_length;
436 /* extended switch data, after the packet data */
438 dissect_sflow_extended_switch(tvbuff_t *tvb, proto_tree *tree, gint offset)
442 proto_tree_add_item(tree, hf_sflow_vlan_in, tvb, offset + len, 4, FALSE);
444 proto_tree_add_item(tree, hf_sflow_vlan_out, tvb, offset + len, 4, FALSE);
446 proto_tree_add_item(tree, hf_sflow_pri_in, tvb, offset + len, 4, FALSE);
448 proto_tree_add_item(tree, hf_sflow_pri_out, tvb, offset + len, 4, FALSE);
454 /* extended router data, after the packet data */
456 dissect_sflow_extended_router(tvbuff_t *tvb, proto_tree *tree, gint offset)
459 guint32 address_type, mask_bits;
461 address_type = tvb_get_ntohl(tvb, offset);
462 switch (address_type) {
464 proto_tree_add_ipv4(tree, hf_sflow_nexthop_v4, tvb, offset + len,
469 proto_tree_add_ipv6(tree, hf_sflow_nexthop_v6, tvb, offset + len,
474 proto_tree_add_text(tree, tvb, offset + len, 4,
475 "Unknown address type (%d)", address_type);
476 len += 4; /* not perfect, but what else to do? */
477 return len; /* again, this is wrong. but... ? */
481 mask_bits = tvb_get_ntohl(tvb, offset + len);
482 proto_tree_add_text(tree, tvb, offset + len, 4,
483 "Source address prefix is %d bits long", mask_bits);
485 mask_bits = tvb_get_ntohl(tvb, offset + len);
486 proto_tree_add_text(tree, tvb, offset + len, 4,
487 "Destination address prefix is %d bits long",
493 /* dissect a flow sample */
495 dissect_sflow_flow_sample(tvbuff_t *tvb, packet_info *pinfo,
496 proto_tree *tree, gint offset, proto_item *parent)
498 struct sflow_flow_sample_header flow_header;
499 proto_tree *sflow_sample_tree;
501 guint32 packet_type, extended_data, ext_type, i;
503 /* grab the flow header. This will remain in network byte
504 order, so must convert each item before use */
505 tvb_memcpy(tvb,(guint8 *)&flow_header,offset,sizeof(flow_header));
506 proto_tree_add_text(tree, tvb, offset, 4,
507 "Sequence number: %u",
508 g_ntohl(flow_header.sequence_number));
509 proto_item_append_text(parent, ", seq %u",
510 g_ntohl(flow_header.sequence_number));
511 proto_tree_add_text(tree, tvb, offset+4, 4,
512 "Source ID class: %u index: %u",
513 g_ntohl(flow_header.source_id) >> 24,
514 g_ntohl(flow_header.source_id) & 0x00ffffff);
515 proto_tree_add_text(tree, tvb, offset+8, 4,
516 "Sampling rate: 1 out of %u packets",
517 g_ntohl(flow_header.sampling_rate));
518 proto_tree_add_text(tree, tvb, offset+12, 4,
519 "Sample pool: %u total packets",
520 g_ntohl(flow_header.sample_pool));
521 proto_tree_add_text(tree, tvb, offset+16, 4,
522 "Dropped packets: %u",
523 g_ntohl(flow_header.drops));
524 proto_tree_add_text(tree, tvb, offset+20, 4,
525 "Input Interface: ifIndex %u",
526 g_ntohl(flow_header.input));
527 if (g_ntohl(flow_header.output) >> 31)
528 proto_tree_add_text(tree, tvb, offset+24, 4,
529 "multiple outputs: %u interfaces",
530 g_ntohl(flow_header.output) & 0x00ffffff);
532 proto_tree_add_text(tree, tvb, offset+24, 4,
533 "Output interface: ifIndex %u",
534 g_ntohl(flow_header.output) & 0x00ffffff);
535 offset += sizeof(flow_header);
537 /* what kind of flow sample is it? */
538 packet_type = tvb_get_ntohl(tvb, offset);
540 switch (packet_type) {
541 case SFLOW_PACKET_DATA_TYPE_HEADER:
542 offset = dissect_sflow_sampled_header(tvb, pinfo, tree, offset);
544 case SFLOW_PACKET_DATA_TYPE_IPV4:
545 case SFLOW_PACKET_DATA_TYPE_IPV6:
548 /* still need to dissect extended data */
549 extended_data = tvb_get_ntohl(tvb,offset);
552 for (i=0; i < extended_data; i++) {
553 /* figure out what kind of extended data it is */
554 ext_type = tvb_get_ntohl(tvb,offset);
556 /* create a subtree. Might want to move this to
557 * the end, so more info can be correct.
559 ti = proto_tree_add_text(tree, tvb, offset, 4, "%s",
561 sflow_extended_data_types,
562 "Unknown extended information"));
564 sflow_sample_tree = proto_item_add_subtree(ti, ett_sflow_sample);
567 case SFLOW_EXTENDED_SWITCH:
568 offset += dissect_sflow_extended_switch(tvb, sflow_sample_tree,
571 case SFLOW_EXTENDED_ROUTER:
572 offset += dissect_sflow_extended_router(tvb, sflow_sample_tree,
575 case SFLOW_EXTENDED_GATEWAY:
577 case SFLOW_EXTENDED_USER:
579 case SFLOW_EXTENDED_URL:
589 /* dissect a counters sample */
591 dissect_sflow_counters_sample(tvbuff_t *tvb, proto_tree *tree,
592 gint offset, proto_item *parent)
594 struct sflow_counters_sample_header counters_header;
595 struct if_counters ifc;
596 struct ethernet_counters ethc;
597 struct token_ring_counters tokc;
598 struct vg_counters vgc;
599 struct vlan_counters vlanc;
601 /* grab the flow header. This will remain in network byte
602 order, so must convert each item before use */
603 tvb_memcpy(tvb,(guint8 *)&counters_header,offset,sizeof(counters_header));
604 proto_tree_add_text(tree, tvb, offset, 4,
605 "Sequence number: %u",
606 g_ntohl(counters_header.sequence_number));
607 proto_item_append_text(parent, ", seq %u",
608 g_ntohl(counters_header.sequence_number));
609 proto_tree_add_text(tree, tvb, offset + 4, 4,
610 "Source ID class: %u index: %u",
611 g_ntohl(counters_header.source_id) >> 24,
612 g_ntohl(counters_header.source_id) & 0x00ffffff);
613 proto_tree_add_text(tree, tvb, offset + 8, 4,
614 "Sampling Interval: %u",
615 g_ntohl(counters_header.sampling_interval));
616 proto_tree_add_text(tree, tvb, offset + 12, 4, "Counters type: %s",
617 val_to_str(g_ntohl(counters_header.counters_type),
618 sflow_counterstype, "Unknown type"));
620 offset += sizeof(counters_header);
622 /* most counters types have the "generic" counters first */
623 switch (g_ntohl(counters_header.counters_type)) {
624 case SFLOW_COUNTERS_GENERIC:
625 case SFLOW_COUNTERS_ETHERNET:
626 case SFLOW_COUNTERS_TOKENRING:
627 case SFLOW_COUNTERS_FDDI:
628 case SFLOW_COUNTERS_VG:
629 case SFLOW_COUNTERS_WAN:
630 tvb_memcpy(tvb,(guint8 *)&ifc, offset, sizeof(ifc));
631 proto_item_append_text(parent, ", ifIndex %u",
632 g_ntohl(ifc.ifIndex));
633 proto_tree_add_item(tree, hf_sflow_ifindex, tvb, offset, 4, FALSE);
635 proto_tree_add_item(tree, hf_sflow_iftype, tvb, offset, 4, FALSE);
637 proto_tree_add_item(tree, hf_sflow_ifspeed, tvb, offset, 8, FALSE);
639 proto_tree_add_item(tree, hf_sflow_ifdirection, tvb, offset,
642 proto_tree_add_item(tree, hf_sflow_ifstatus, tvb, offset, 4, FALSE);
644 proto_tree_add_item(tree, hf_sflow_ifinoct, tvb, offset, 8, FALSE);
646 proto_tree_add_item(tree, hf_sflow_ifinpkt, tvb, offset, 4, FALSE);
648 proto_tree_add_item(tree, hf_sflow_ifinmcast, tvb, offset,
651 proto_tree_add_item(tree, hf_sflow_ifinbcast, tvb, offset,
654 proto_tree_add_item(tree, hf_sflow_ifindisc, tvb, offset,
657 proto_tree_add_item(tree, hf_sflow_ifinerr, tvb, offset,
660 proto_tree_add_item(tree, hf_sflow_ifinunk, tvb, offset,
663 proto_tree_add_item(tree, hf_sflow_ifoutoct, tvb, offset, 8, FALSE);
665 proto_tree_add_item(tree, hf_sflow_ifoutpkt, tvb, offset, 4, FALSE);
667 proto_tree_add_item(tree, hf_sflow_ifoutmcast, tvb, offset,
670 proto_tree_add_item(tree, hf_sflow_ifoutbcast, tvb, offset,
673 proto_tree_add_item(tree, hf_sflow_ifoutdisc, tvb, offset,
676 proto_tree_add_item(tree, hf_sflow_ifouterr, tvb, offset,
679 proto_tree_add_item(tree, hf_sflow_ifpromisc, tvb, offset,
685 /* Some counter types have other info to gather */
686 switch (g_ntohl(counters_header.counters_type)) {
687 case SFLOW_COUNTERS_ETHERNET:
688 tvb_memcpy(tvb,(guint8 *)ðc, offset, sizeof(ethc));
689 offset += sizeof(ethc);
691 case SFLOW_COUNTERS_TOKENRING:
692 tvb_memcpy(tvb,(guint8 *)&tokc, offset, sizeof(tokc));
693 offset += sizeof(tokc);
695 case SFLOW_COUNTERS_VG:
696 tvb_memcpy(tvb,(guint8 *)&vgc, offset, sizeof(vgc));
697 offset += sizeof(vgc);
699 case SFLOW_COUNTERS_VLAN:
700 tvb_memcpy(tvb,(guint8 *)&vlanc, offset, sizeof(vlanc));
701 offset += sizeof(vlanc);
709 /* Code to dissect the sflow samples */
711 dissect_sflow_samples(tvbuff_t *tvb, packet_info *pinfo,
712 proto_tree *tree, gint offset)
714 proto_tree *sflow_sample_tree;
715 proto_item *ti; /* tree item */
718 /* decide what kind of sample it is. */
719 sample_type = tvb_get_ntohl(tvb,offset);
721 ti = proto_tree_add_text(tree, tvb, offset, 4, "%s",
722 val_to_str(sample_type, sflow_sampletype,
723 "Unknown sample type"));
724 sflow_sample_tree = proto_item_add_subtree(ti, ett_sflow_sample);
726 proto_tree_add_item(sflow_sample_tree, hf_sflow_sampletype, tvb,
730 switch (sample_type) {
732 return dissect_sflow_flow_sample(tvb, pinfo, sflow_sample_tree,
736 return dissect_sflow_counters_sample(tvb, sflow_sample_tree,
745 /* Code to actually dissect the packets */
747 dissect_sflow(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
750 /* Set up structures needed to add the protocol subtree and manage it */
752 proto_tree *sflow_tree;
753 guint32 version, seqnum;
754 guint32 agent_address_type;
760 volatile guint offset=0;
763 /* Make entries in Protocol column and Info column on summary display */
764 if (check_col(pinfo->cinfo, COL_PROTOCOL))
765 col_set_str(pinfo->cinfo, COL_PROTOCOL, "sflow");
768 /* create display subtree for the protocol */
769 ti = proto_tree_add_item(tree, proto_sflow, tvb, 0, -1, FALSE);
771 sflow_tree = proto_item_add_subtree(ti, ett_sflow);
773 version = tvb_get_ntohl(tvb, offset);
774 if (check_col(pinfo->cinfo, COL_INFO))
775 col_add_fstr(pinfo->cinfo, COL_INFO, "sFlow V%u",
777 proto_tree_add_item(sflow_tree,
778 hf_sflow_version, tvb, offset, 4, FALSE);
781 agent_address_type = tvb_get_ntohl(tvb, offset);
783 switch (agent_address_type) {
785 tvb_memcpy(tvb, agent_address.v4, offset, 4);
786 if (check_col(pinfo->cinfo, COL_INFO))
787 col_append_fstr(pinfo->cinfo, COL_INFO, ", agent %s",
788 ip_to_str(agent_address.v4));
789 proto_tree_add_item(sflow_tree,
790 hf_sflow_agent_address_v4, tvb, offset,
795 tvb_memcpy(tvb, agent_address.v6, offset, 16);
796 if (check_col(pinfo->cinfo, COL_INFO))
797 col_append_fstr(pinfo->cinfo, COL_INFO, ", agent %s",
798 ip6_to_str((struct e_in6_addr *)agent_address.v6));
799 proto_tree_add_item(sflow_tree,
800 hf_sflow_agent_address_v6, tvb, offset,
805 /* unknown address. this will cause a malformed packet. */
809 seqnum = tvb_get_ntohl(tvb, offset);
810 proto_tree_add_item(sflow_tree, hf_sflow_seqnum, tvb,
813 proto_tree_add_item(sflow_tree, hf_sflow_sysuptime, tvb,
816 numsamples = tvb_get_ntohl(tvb,offset);
817 if (check_col(pinfo->cinfo, COL_INFO))
818 col_append_fstr(pinfo->cinfo, COL_INFO, ", seq %u, %u samples",
820 proto_tree_add_item(sflow_tree, hf_sflow_numsamples, tvb,
824 /* Ok, we're now at the end of the sflow datagram header;
825 * everything from here out should be samples. Loop over
826 * the expected number of samples, and pass them to the appropriate
829 for (i=0; i < numsamples; i++) {
830 offset = dissect_sflow_samples(tvb, pinfo, sflow_tree, offset);
836 /* Register the protocol with Ethereal */
838 /* this format is require because a script is used to build the C function
839 that calls all the protocol registration.
843 proto_register_sflow(void)
846 /* Setup list of header fields See Section 1.6.1 for details*/
847 static hf_register_info hf[] = {
849 { "datagram version", "sflow.version",
850 FT_UINT32, BASE_DEC, NULL, 0x0,
851 "sFlow datagram version", HFILL }
853 { &hf_sflow_agent_address_v4,
854 { "agent address", "sflow.agent",
855 FT_IPv4, BASE_NONE, NULL, 0x0,
856 "sFlow Agent IP address", HFILL }
858 { &hf_sflow_agent_address_v6,
859 { "agent address", "sflow.agent.v6",
860 FT_IPv6, BASE_NONE, NULL, 0x0,
861 "sFlow Agent IPv6 address", HFILL }
864 { "Sequence number", "sflow.sequence_number",
865 FT_UINT32, BASE_DEC, NULL, 0x0,
866 "sFlow datagram sequence number", HFILL }
868 { &hf_sflow_sysuptime,
869 { "SysUptime", "sflow.sysuptime",
870 FT_UINT32, BASE_DEC, NULL, 0x0,
871 "System Uptime", HFILL }
873 { &hf_sflow_numsamples,
874 { "NumSamples", "sflow.numsamples",
875 FT_UINT32, BASE_DEC, NULL, 0x0,
876 "Number of samples in sFlow datagram", HFILL }
878 { &hf_sflow_sampletype,
879 { "sFlow sample type", "sflow.sampletype",
880 FT_UINT32, BASE_DEC, VALS(sflow_sampletype), 0x0,
881 "Type of sFlow sample", HFILL }
883 { &hf_sflow_header_protocol,
884 { "Header protocol", "sflow.header_protocol",
885 FT_UINT32, BASE_DEC, VALS(sflow_header_protocol), 0x0,
886 "Protocol of sampled header", HFILL }
889 { "Header of sampled packet", "sflow.header",
890 FT_BYTES, BASE_HEX, NULL, 0x0,
891 "Data from sampled header", HFILL }
893 { &hf_sflow_packet_information_type,
894 { "Sample type", "sflow.packet_information_type",
895 FT_UINT32, BASE_DEC, VALS(sflow_packet_information_type), 0x0,
896 "Type of sampled information", HFILL }
899 { "Incoming 802.1q VLAN", "sflow.vlan.in",
900 FT_UINT32, BASE_DEC, NULL, 0x0,
901 "Incoming VLAN ID", HFILL }
903 { &hf_sflow_vlan_out,
904 { "Outgoing 802.1q VLAN", "sflow.vlan.out",
905 FT_UINT32, BASE_DEC, NULL, 0x0,
906 "Outgoing VLAN ID", HFILL }
909 { "Incoming 802.1p priority", "sflow.pri.in",
910 FT_UINT32, BASE_DEC, NULL, 0x0,
911 "Incoming 802.1p priority", HFILL }
914 { "Outgoing 802.1p priority", "sflow.pri.out",
915 FT_UINT32, BASE_DEC, NULL, 0x0,
916 "Outgoing 802.1p priority", HFILL }
918 { &hf_sflow_nexthop_v4,
919 { "Next Hop", "sflow.nexthop",
920 FT_IPv4, BASE_DEC, NULL, 0x0,
921 "Next Hop address", HFILL }
923 { &hf_sflow_nexthop_v6,
924 { "Next Hop", "sflow.nexthop",
925 FT_IPv6, BASE_HEX, NULL, 0x0,
926 "Next Hop address", HFILL }
929 { "Interface index", "sflow.ifindex",
930 FT_UINT32, BASE_DEC, NULL, 0x0,
931 "Interface Index", HFILL }
934 { "Interface Type", "sflow.iftype",
935 FT_UINT32, BASE_DEC, NULL, 0x0,
936 "Interface Type", HFILL }
939 { "Interface Speed", "sflow.ifspeed",
940 FT_UINT64, BASE_DEC, NULL, 0x0,
941 "Interface Speed", HFILL }
943 { &hf_sflow_ifdirection,
944 { "Interface Direction", "sflow.ifdirection",
945 FT_UINT32, BASE_DEC, NULL, 0x0,
946 "Interface Direction", HFILL }
948 { &hf_sflow_ifstatus,
949 { "Interface Status", "sflow.ifstatus",
950 FT_UINT32, BASE_DEC, NULL, 0x0,
951 "Interface Status", HFILL }
954 { "Input Octets", "sflow.ifinoct",
955 FT_UINT64, BASE_DEC, NULL, 0x0,
956 "Interface Input Octets", HFILL }
959 { "Input Packets", "sflow.ifinpkt",
960 FT_UINT32, BASE_DEC, NULL, 0x0,
961 "Interface Input Packets", HFILL }
963 { &hf_sflow_ifinmcast,
964 { "Input Multicast Packets", "sflow.ifinmcast",
965 FT_UINT32, BASE_DEC, NULL, 0x0,
966 "Interface Input Multicast Packets", HFILL }
968 { &hf_sflow_ifinbcast,
969 { "Input Broadcast Packets", "sflow.ifinbcast",
970 FT_UINT32, BASE_DEC, NULL, 0x0,
971 "Interface Input Broadcast Packets", HFILL }
973 { &hf_sflow_ifindisc,
974 { "Input Discarded Packets", "sflow.ifindisc",
975 FT_UINT32, BASE_DEC, NULL, 0x0,
976 "Interface Input Discarded Packets", HFILL }
979 { "Input Errors", "sflow.ifinerr",
980 FT_UINT32, BASE_DEC, NULL, 0x0,
981 "Interface Input Errors", HFILL }
984 { "Input Unknown Protocol Packets", "sflow.ifinunk",
985 FT_UINT32, BASE_DEC, NULL, 0x0,
986 "Interface Input Unknown Protocol Packets", HFILL }
988 { &hf_sflow_ifoutoct,
989 { "Output Octets", "sflow.ifoutoct",
990 FT_UINT64, BASE_DEC, NULL, 0x0,
991 "Outterface Output Octets", HFILL }
993 { &hf_sflow_ifoutpkt,
994 { "Output Packets", "sflow.ifoutpkt",
995 FT_UINT32, BASE_DEC, NULL, 0x0,
996 "Interface Output Packets", HFILL }
998 { &hf_sflow_ifoutmcast,
999 { "Output Multicast Packets", "sflow.ifoutmcast",
1000 FT_UINT32, BASE_DEC, NULL, 0x0,
1001 "Interface Output Multicast Packets", HFILL }
1003 { &hf_sflow_ifoutbcast,
1004 { "Output Broadcast Packets", "sflow.ifoutbcast",
1005 FT_UINT32, BASE_DEC, NULL, 0x0,
1006 "Interface Output Broadcast Packets", HFILL }
1008 { &hf_sflow_ifoutdisc,
1009 { "Output Discarded Packets", "sflow.ifoutdisc",
1010 FT_UINT32, BASE_DEC, NULL, 0x0,
1011 "Interface Output Discarded Packets", HFILL }
1013 { &hf_sflow_ifouterr,
1014 { "Output Errors", "sflow.ifouterr",
1015 FT_UINT32, BASE_DEC, NULL, 0x0,
1016 "Interface Output Errors", HFILL }
1018 { &hf_sflow_ifpromisc,
1019 { "Promiscuous Mode", "sflow.ifpromisc",
1020 FT_UINT32, BASE_DEC, NULL, 0x0,
1021 "Interface Promiscuous Mode", HFILL }
1025 /* Setup protocol subtree array */
1026 static gint *ett[] = {
1029 &ett_sflow_extended_data,
1030 &ett_sflow_sampled_header,
1033 /* Register the protocol name and description */
1034 proto_sflow = proto_register_protocol("InMon sFlow",
1037 /* Required function calls to register the header fields and subtrees used */
1038 proto_register_field_array(proto_sflow, hf, array_length(hf));
1039 proto_register_subtree_array(ett, array_length(ett));
1043 /* If this dissector uses sub-dissector registration add a registration routine.
1044 This format is required because a script is used to find these routines and
1045 create the code that calls these routines.
1048 proto_reg_handoff_sflow(void)
1050 dissector_handle_t sflow_handle;
1052 eth_handle = find_dissector("eth");
1053 tr_handle = find_dissector("tr");
1054 fddi_handle = find_dissector("fddi");
1055 fr_handle = find_dissector("fr");
1056 x25_handle = find_dissector("x25");
1057 ppp_handle = find_dissector("ppp");
1058 smds_handle = find_dissector("smds");
1059 aal5_handle = find_dissector("atm");
1060 ipv4_handle = find_dissector("ip");
1061 ipv6_handle = find_dissector("ipv6");
1062 mpls_handle = find_dissector("mpls");
1064 sflow_handle = create_dissector_handle(dissect_sflow,
1066 dissector_add("udp.port", UDP_PORT_SFLOW, sflow_handle);