2 * Routines for sFlow dissection
3 * Copyright 2003, Jeff Rizzo <riz@boogers.sf.ca.us>
5 * $Id: packet-sflow.c,v 1.2 2003/06/14 23:50:43 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:
549 /* still need to dissect extended data */
550 extended_data = tvb_get_ntohl(tvb,offset);
553 for (i=0; i < extended_data; i++) {
554 /* figure out what kind of extended data it is */
555 ext_type = tvb_get_ntohl(tvb,offset);
557 /* create a subtree. Might want to move this to
558 * the end, so more info can be correct.
560 ti = proto_tree_add_text(tree, tvb, offset, 4, "%s",
562 sflow_extended_data_types,
563 "Unknown extended information"));
565 sflow_sample_tree = proto_item_add_subtree(ti, ett_sflow_sample);
568 case SFLOW_EXTENDED_SWITCH:
569 offset += dissect_sflow_extended_switch(tvb, sflow_sample_tree,
572 case SFLOW_EXTENDED_ROUTER:
573 offset += dissect_sflow_extended_router(tvb, sflow_sample_tree,
576 case SFLOW_EXTENDED_GATEWAY:
578 case SFLOW_EXTENDED_USER:
580 case SFLOW_EXTENDED_URL:
590 /* dissect a counters sample */
592 dissect_sflow_counters_sample(tvbuff_t *tvb, proto_tree *tree,
593 gint offset, proto_item *parent)
595 struct sflow_counters_sample_header counters_header;
596 struct if_counters ifc;
597 struct ethernet_counters ethc;
598 struct token_ring_counters tokc;
599 struct vg_counters vgc;
600 struct vlan_counters vlanc;
602 /* grab the flow header. This will remain in network byte
603 order, so must convert each item before use */
604 tvb_memcpy(tvb,(guint8 *)&counters_header,offset,sizeof(counters_header));
605 proto_tree_add_text(tree, tvb, offset, 4,
606 "Sequence number: %u",
607 g_ntohl(counters_header.sequence_number));
608 proto_item_append_text(parent, ", seq %u",
609 g_ntohl(counters_header.sequence_number));
610 proto_tree_add_text(tree, tvb, offset + 4, 4,
611 "Source ID class: %u index: %u",
612 g_ntohl(counters_header.source_id) >> 24,
613 g_ntohl(counters_header.source_id) & 0x00ffffff);
614 proto_tree_add_text(tree, tvb, offset + 8, 4,
615 "Sampling Interval: %u",
616 g_ntohl(counters_header.sampling_interval));
617 proto_tree_add_text(tree, tvb, offset + 12, 4, "Counters type: %s",
618 val_to_str(g_ntohl(counters_header.counters_type),
619 sflow_counterstype, "Unknown type"));
621 offset += sizeof(counters_header);
623 /* most counters types have the "generic" counters first */
624 switch (g_ntohl(counters_header.counters_type)) {
625 case SFLOW_COUNTERS_GENERIC:
626 case SFLOW_COUNTERS_ETHERNET:
627 case SFLOW_COUNTERS_TOKENRING:
628 case SFLOW_COUNTERS_FDDI:
629 case SFLOW_COUNTERS_VG:
630 case SFLOW_COUNTERS_WAN:
631 tvb_memcpy(tvb,(guint8 *)&ifc, offset, sizeof(ifc));
632 proto_item_append_text(parent, ", ifIndex %u",
633 g_ntohl(ifc.ifIndex));
634 proto_tree_add_item(tree, hf_sflow_ifindex, tvb, offset, 4, FALSE);
636 proto_tree_add_item(tree, hf_sflow_iftype, tvb, offset, 4, FALSE);
638 proto_tree_add_item(tree, hf_sflow_ifspeed, tvb, offset, 8, FALSE);
640 proto_tree_add_item(tree, hf_sflow_ifdirection, tvb, offset,
643 proto_tree_add_item(tree, hf_sflow_ifstatus, tvb, offset, 4, FALSE);
645 proto_tree_add_item(tree, hf_sflow_ifinoct, tvb, offset, 8, FALSE);
647 proto_tree_add_item(tree, hf_sflow_ifinpkt, tvb, offset, 4, FALSE);
649 proto_tree_add_item(tree, hf_sflow_ifinmcast, tvb, offset,
652 proto_tree_add_item(tree, hf_sflow_ifinbcast, tvb, offset,
655 proto_tree_add_item(tree, hf_sflow_ifindisc, tvb, offset,
658 proto_tree_add_item(tree, hf_sflow_ifinerr, tvb, offset,
661 proto_tree_add_item(tree, hf_sflow_ifinunk, tvb, offset,
664 proto_tree_add_item(tree, hf_sflow_ifoutoct, tvb, offset, 8, FALSE);
666 proto_tree_add_item(tree, hf_sflow_ifoutpkt, tvb, offset, 4, FALSE);
668 proto_tree_add_item(tree, hf_sflow_ifoutmcast, tvb, offset,
671 proto_tree_add_item(tree, hf_sflow_ifoutbcast, tvb, offset,
674 proto_tree_add_item(tree, hf_sflow_ifoutdisc, tvb, offset,
677 proto_tree_add_item(tree, hf_sflow_ifouterr, tvb, offset,
680 proto_tree_add_item(tree, hf_sflow_ifpromisc, tvb, offset,
686 /* Some counter types have other info to gather */
687 switch (g_ntohl(counters_header.counters_type)) {
688 case SFLOW_COUNTERS_ETHERNET:
689 tvb_memcpy(tvb,(guint8 *)ðc, offset, sizeof(ethc));
690 offset += sizeof(ethc);
692 case SFLOW_COUNTERS_TOKENRING:
693 tvb_memcpy(tvb,(guint8 *)&tokc, offset, sizeof(tokc));
694 offset += sizeof(tokc);
696 case SFLOW_COUNTERS_VG:
697 tvb_memcpy(tvb,(guint8 *)&vgc, offset, sizeof(vgc));
698 offset += sizeof(vgc);
700 case SFLOW_COUNTERS_VLAN:
701 tvb_memcpy(tvb,(guint8 *)&vlanc, offset, sizeof(vlanc));
702 offset += sizeof(vlanc);
710 /* Code to dissect the sflow samples */
712 dissect_sflow_samples(tvbuff_t *tvb, packet_info *pinfo,
713 proto_tree *tree, gint offset)
715 proto_tree *sflow_sample_tree;
716 proto_item *ti; /* tree item */
719 /* decide what kind of sample it is. */
720 sample_type = tvb_get_ntohl(tvb,offset);
722 ti = proto_tree_add_text(tree, tvb, offset, 4, "%s",
723 val_to_str(sample_type, sflow_sampletype,
724 "Unknown sample type"));
725 sflow_sample_tree = proto_item_add_subtree(ti, ett_sflow_sample);
727 proto_tree_add_item(sflow_sample_tree, hf_sflow_sampletype, tvb,
731 switch (sample_type) {
733 return dissect_sflow_flow_sample(tvb, pinfo, sflow_sample_tree,
737 return dissect_sflow_counters_sample(tvb, sflow_sample_tree,
746 /* Code to actually dissect the packets */
748 dissect_sflow(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
751 /* Set up structures needed to add the protocol subtree and manage it */
753 proto_tree *sflow_tree;
754 guint32 version, seqnum;
755 guint32 agent_address_type;
761 volatile guint offset=0;
764 /* Make entries in Protocol column and Info column on summary display */
765 if (check_col(pinfo->cinfo, COL_PROTOCOL))
766 col_set_str(pinfo->cinfo, COL_PROTOCOL, "sflow");
769 /* create display subtree for the protocol */
770 ti = proto_tree_add_item(tree, proto_sflow, tvb, 0, -1, FALSE);
772 sflow_tree = proto_item_add_subtree(ti, ett_sflow);
774 version = tvb_get_ntohl(tvb, offset);
775 if (check_col(pinfo->cinfo, COL_INFO))
776 col_add_fstr(pinfo->cinfo, COL_INFO, "sFlow V%u",
778 proto_tree_add_item(sflow_tree,
779 hf_sflow_version, tvb, offset, 4, FALSE);
782 agent_address_type = tvb_get_ntohl(tvb, offset);
784 switch (agent_address_type) {
786 tvb_memcpy(tvb, agent_address.v4, offset, 4);
787 if (check_col(pinfo->cinfo, COL_INFO))
788 col_append_fstr(pinfo->cinfo, COL_INFO, ", agent %s",
789 ip_to_str(agent_address.v4));
790 proto_tree_add_item(sflow_tree,
791 hf_sflow_agent_address_v4, tvb, offset,
796 tvb_memcpy(tvb, agent_address.v6, offset, 16);
797 if (check_col(pinfo->cinfo, COL_INFO))
798 col_append_fstr(pinfo->cinfo, COL_INFO, ", agent %s",
799 ip6_to_str((struct e_in6_addr *)agent_address.v6));
800 proto_tree_add_item(sflow_tree,
801 hf_sflow_agent_address_v6, tvb, offset,
806 /* unknown address. this will cause a malformed packet. */
810 seqnum = tvb_get_ntohl(tvb, offset);
811 proto_tree_add_item(sflow_tree, hf_sflow_seqnum, tvb,
814 proto_tree_add_item(sflow_tree, hf_sflow_sysuptime, tvb,
817 numsamples = tvb_get_ntohl(tvb,offset);
818 if (check_col(pinfo->cinfo, COL_INFO))
819 col_append_fstr(pinfo->cinfo, COL_INFO, ", seq %u, %u samples",
821 proto_tree_add_item(sflow_tree, hf_sflow_numsamples, tvb,
825 /* Ok, we're now at the end of the sflow datagram header;
826 * everything from here out should be samples. Loop over
827 * the expected number of samples, and pass them to the appropriate
830 for (i=0; i < numsamples; i++) {
831 offset = dissect_sflow_samples(tvb, pinfo, sflow_tree, offset);
837 /* Register the protocol with Ethereal */
839 /* this format is require because a script is used to build the C function
840 that calls all the protocol registration.
844 proto_register_sflow(void)
847 /* Setup list of header fields See Section 1.6.1 for details*/
848 static hf_register_info hf[] = {
850 { "datagram version", "sflow.version",
851 FT_UINT32, BASE_DEC, NULL, 0x0,
852 "sFlow datagram version", HFILL }
854 { &hf_sflow_agent_address_v4,
855 { "agent address", "sflow.agent",
856 FT_IPv4, BASE_NONE, NULL, 0x0,
857 "sFlow Agent IP address", HFILL }
859 { &hf_sflow_agent_address_v6,
860 { "agent address", "sflow.agent.v6",
861 FT_IPv6, BASE_NONE, NULL, 0x0,
862 "sFlow Agent IPv6 address", HFILL }
865 { "Sequence number", "sflow.sequence_number",
866 FT_UINT32, BASE_DEC, NULL, 0x0,
867 "sFlow datagram sequence number", HFILL }
869 { &hf_sflow_sysuptime,
870 { "SysUptime", "sflow.sysuptime",
871 FT_UINT32, BASE_DEC, NULL, 0x0,
872 "System Uptime", HFILL }
874 { &hf_sflow_numsamples,
875 { "NumSamples", "sflow.numsamples",
876 FT_UINT32, BASE_DEC, NULL, 0x0,
877 "Number of samples in sFlow datagram", HFILL }
879 { &hf_sflow_sampletype,
880 { "sFlow sample type", "sflow.sampletype",
881 FT_UINT32, BASE_DEC, VALS(sflow_sampletype), 0x0,
882 "Type of sFlow sample", HFILL }
884 { &hf_sflow_header_protocol,
885 { "Header protocol", "sflow.header_protocol",
886 FT_UINT32, BASE_DEC, VALS(sflow_header_protocol), 0x0,
887 "Protocol of sampled header", HFILL }
890 { "Header of sampled packet", "sflow.header",
891 FT_BYTES, BASE_HEX, NULL, 0x0,
892 "Data from sampled header", HFILL }
894 { &hf_sflow_packet_information_type,
895 { "Sample type", "sflow.packet_information_type",
896 FT_UINT32, BASE_DEC, VALS(sflow_packet_information_type), 0x0,
897 "Type of sampled information", HFILL }
900 { "Incoming 802.1q VLAN", "sflow.vlan.in",
901 FT_UINT32, BASE_DEC, NULL, 0x0,
902 "Incoming VLAN ID", HFILL }
904 { &hf_sflow_vlan_out,
905 { "Outgoing 802.1q VLAN", "sflow.vlan.out",
906 FT_UINT32, BASE_DEC, NULL, 0x0,
907 "Outgoing VLAN ID", HFILL }
910 { "Incoming 802.1p priority", "sflow.pri.in",
911 FT_UINT32, BASE_DEC, NULL, 0x0,
912 "Incoming 802.1p priority", HFILL }
915 { "Outgoing 802.1p priority", "sflow.pri.out",
916 FT_UINT32, BASE_DEC, NULL, 0x0,
917 "Outgoing 802.1p priority", HFILL }
919 { &hf_sflow_nexthop_v4,
920 { "Next Hop", "sflow.nexthop",
921 FT_IPv4, BASE_DEC, NULL, 0x0,
922 "Next Hop address", HFILL }
924 { &hf_sflow_nexthop_v6,
925 { "Next Hop", "sflow.nexthop",
926 FT_IPv6, BASE_HEX, NULL, 0x0,
927 "Next Hop address", HFILL }
930 { "Interface index", "sflow.ifindex",
931 FT_UINT32, BASE_DEC, NULL, 0x0,
932 "Interface Index", HFILL }
935 { "Interface Type", "sflow.iftype",
936 FT_UINT32, BASE_DEC, NULL, 0x0,
937 "Interface Type", HFILL }
940 { "Interface Speed", "sflow.ifspeed",
941 FT_UINT64, BASE_DEC, NULL, 0x0,
942 "Interface Speed", HFILL }
944 { &hf_sflow_ifdirection,
945 { "Interface Direction", "sflow.ifdirection",
946 FT_UINT32, BASE_DEC, NULL, 0x0,
947 "Interface Direction", HFILL }
949 { &hf_sflow_ifstatus,
950 { "Interface Status", "sflow.ifstatus",
951 FT_UINT32, BASE_DEC, NULL, 0x0,
952 "Interface Status", HFILL }
955 { "Input Octets", "sflow.ifinoct",
956 FT_UINT64, BASE_DEC, NULL, 0x0,
957 "Interface Input Octets", HFILL }
960 { "Input Packets", "sflow.ifinpkt",
961 FT_UINT32, BASE_DEC, NULL, 0x0,
962 "Interface Input Packets", HFILL }
964 { &hf_sflow_ifinmcast,
965 { "Input Multicast Packets", "sflow.ifinmcast",
966 FT_UINT32, BASE_DEC, NULL, 0x0,
967 "Interface Input Multicast Packets", HFILL }
969 { &hf_sflow_ifinbcast,
970 { "Input Broadcast Packets", "sflow.ifinbcast",
971 FT_UINT32, BASE_DEC, NULL, 0x0,
972 "Interface Input Broadcast Packets", HFILL }
974 { &hf_sflow_ifindisc,
975 { "Input Discarded Packets", "sflow.ifindisc",
976 FT_UINT32, BASE_DEC, NULL, 0x0,
977 "Interface Input Discarded Packets", HFILL }
980 { "Input Errors", "sflow.ifinerr",
981 FT_UINT32, BASE_DEC, NULL, 0x0,
982 "Interface Input Errors", HFILL }
985 { "Input Unknown Protocol Packets", "sflow.ifinunk",
986 FT_UINT32, BASE_DEC, NULL, 0x0,
987 "Interface Input Unknown Protocol Packets", HFILL }
989 { &hf_sflow_ifoutoct,
990 { "Output Octets", "sflow.ifoutoct",
991 FT_UINT64, BASE_DEC, NULL, 0x0,
992 "Outterface Output Octets", HFILL }
994 { &hf_sflow_ifoutpkt,
995 { "Output Packets", "sflow.ifoutpkt",
996 FT_UINT32, BASE_DEC, NULL, 0x0,
997 "Interface Output Packets", HFILL }
999 { &hf_sflow_ifoutmcast,
1000 { "Output Multicast Packets", "sflow.ifoutmcast",
1001 FT_UINT32, BASE_DEC, NULL, 0x0,
1002 "Interface Output Multicast Packets", HFILL }
1004 { &hf_sflow_ifoutbcast,
1005 { "Output Broadcast Packets", "sflow.ifoutbcast",
1006 FT_UINT32, BASE_DEC, NULL, 0x0,
1007 "Interface Output Broadcast Packets", HFILL }
1009 { &hf_sflow_ifoutdisc,
1010 { "Output Discarded Packets", "sflow.ifoutdisc",
1011 FT_UINT32, BASE_DEC, NULL, 0x0,
1012 "Interface Output Discarded Packets", HFILL }
1014 { &hf_sflow_ifouterr,
1015 { "Output Errors", "sflow.ifouterr",
1016 FT_UINT32, BASE_DEC, NULL, 0x0,
1017 "Interface Output Errors", HFILL }
1019 { &hf_sflow_ifpromisc,
1020 { "Promiscuous Mode", "sflow.ifpromisc",
1021 FT_UINT32, BASE_DEC, NULL, 0x0,
1022 "Interface Promiscuous Mode", HFILL }
1026 /* Setup protocol subtree array */
1027 static gint *ett[] = {
1030 &ett_sflow_extended_data,
1031 &ett_sflow_sampled_header,
1034 /* Register the protocol name and description */
1035 proto_sflow = proto_register_protocol("InMon sFlow",
1038 /* Required function calls to register the header fields and subtrees used */
1039 proto_register_field_array(proto_sflow, hf, array_length(hf));
1040 proto_register_subtree_array(ett, array_length(ett));
1044 /* If this dissector uses sub-dissector registration add a registration routine.
1045 This format is required because a script is used to find these routines and
1046 create the code that calls these routines.
1049 proto_reg_handoff_sflow(void)
1051 dissector_handle_t sflow_handle;
1053 eth_handle = find_dissector("eth");
1054 tr_handle = find_dissector("tr");
1055 fddi_handle = find_dissector("fddi");
1056 fr_handle = find_dissector("fr");
1057 x25_handle = find_dissector("x25");
1058 ppp_handle = find_dissector("ppp");
1059 smds_handle = find_dissector("smds");
1060 aal5_handle = find_dissector("atm");
1061 ipv4_handle = find_dissector("ip");
1062 ipv6_handle = find_dissector("ipv6");
1063 mpls_handle = find_dissector("mpls");
1065 sflow_handle = create_dissector_handle(dissect_sflow,
1067 dissector_add("udp.port", UDP_PORT_SFLOW, sflow_handle);