2 * Routines for sFlow dissection
3 * Copyright 2003, Jeff Rizzo <riz@boogers.sf.ca.us>
7 * Wireshark - Network traffic analyzer
8 * By Gerald Combs <gerald@wireshark.org>
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 samples from the draft version 5 spec; see
40 * http://www.sflow.org/SFLOW-DATAGRAM5.txt (see epan/sminmpec.h
41 * for tables of SMI Network Management Private Enterprise Codes;
42 * use sminmpec_values, adding new values to epan/sminmpect.h and
43 * and sminmpec_values in epan/sminmpec.c if necessary - don't create
57 #include <epan/packet.h>
58 /*#include "packet-sflow.h"*/
60 #define UDP_PORT_SFLOW 6343
62 #define ADDRESS_IPV4 1
63 #define ADDRESS_IPV6 2
66 #define COUNTERSSAMPLE 2
68 static const value_string sflow_sampletype[] = {
69 { FLOWSAMPLE, "Flow sample" },
70 { COUNTERSSAMPLE, "Counters sample" },
74 /* interface counter types */
75 #define SFLOW_COUNTERS_GENERIC 1
76 #define SFLOW_COUNTERS_ETHERNET 2
77 #define SFLOW_COUNTERS_TOKENRING 3
78 #define SFLOW_COUNTERS_FDDI 4
79 #define SFLOW_COUNTERS_VG 5
80 #define SFLOW_COUNTERS_WAN 6
81 #define SFLOW_COUNTERS_VLAN 7
83 static const value_string sflow_counterstype [] = {
84 { SFLOW_COUNTERS_GENERIC, "Generic counters" },
85 { SFLOW_COUNTERS_ETHERNET, "Ethernet counters" },
86 { SFLOW_COUNTERS_FDDI, "FDDI counters" },
87 { SFLOW_COUNTERS_VG, "100baseVG counters" },
88 { SFLOW_COUNTERS_WAN, "WAN counters" },
89 { SFLOW_COUNTERS_VLAN, "VLAN counters" },
93 #define MAX_HEADER_SIZE 256
95 #define SFLOW_PACKET_DATA_TYPE_HEADER 1
96 #define SFLOW_PACKET_DATA_TYPE_IPV4 2
97 #define SFLOW_PACKET_DATA_TYPE_IPV6 3
99 static const value_string sflow_packet_information_type [] = {
100 { SFLOW_PACKET_DATA_TYPE_HEADER, "Packet headers are sampled" },
101 { SFLOW_PACKET_DATA_TYPE_IPV4, "IP Version 4 data" },
102 { SFLOW_PACKET_DATA_TYPE_IPV6, "IP Version 6 data" },
106 #define SFLOW_HEADER_ETHERNET 1
107 #define SFLOW_HEADER_TOKENBUS 2
108 #define SFLOW_HEADER_TOKENRING 3
109 #define SFLOW_HEADER_FDDI 4
110 #define SFLOW_HEADER_FRAME_RELAY 5
111 #define SFLOW_HEADER_X25 6
112 #define SFLOW_HEADER_PPP 7
113 #define SFLOW_HEADER_SMDS 8
114 #define SFLOW_HEADER_AAL5 9
115 #define SFLOW_HEADER_AAL5_IP 10
116 #define SFLOW_HEADER_IPv4 11
117 #define SFLOW_HEADER_IPv6 12
118 #define SFLOW_HEADER_MPLS 13
120 static const value_string sflow_header_protocol[] = {
121 { SFLOW_HEADER_ETHERNET, "Ethernet" },
122 { SFLOW_HEADER_TOKENBUS, "Token Bus" },
123 { SFLOW_HEADER_TOKENRING, "Token Ring" },
124 { SFLOW_HEADER_FDDI, "FDDI" },
125 { SFLOW_HEADER_FRAME_RELAY, "Frame Relay" },
126 { SFLOW_HEADER_X25, "X.25" },
127 { SFLOW_HEADER_PPP, "PPP" },
128 { SFLOW_HEADER_SMDS, "SMDS" },
129 { SFLOW_HEADER_AAL5, "ATM AAL5" },
130 { SFLOW_HEADER_AAL5_IP, "ATM AAL5-IP (e.g., Cisco AAL5 mux)" },
131 { SFLOW_HEADER_IPv4, "IPv4" },
132 { SFLOW_HEADER_IPv6, "IPv6" },
133 { SFLOW_HEADER_MPLS, "MPLS" },
137 /* extended data types */
138 #define SFLOW_EXTENDED_SWITCH 1
139 #define SFLOW_EXTENDED_ROUTER 2
140 #define SFLOW_EXTENDED_GATEWAY 3
141 #define SFLOW_EXTENDED_USER 4
142 #define SFLOW_EXTENDED_URL 5
144 static const value_string sflow_extended_data_types[] = {
145 { SFLOW_EXTENDED_SWITCH, "Extended switch information" },
146 { SFLOW_EXTENDED_ROUTER, "Extended router information" },
147 { SFLOW_EXTENDED_GATEWAY, "Extended gateway information" },
148 { SFLOW_EXTENDED_USER, "Extended user information" },
149 { SFLOW_EXTENDED_URL, "Extended URL information" },
154 /* flow sample header */
155 struct sflow_flow_sample_header {
156 guint32 sequence_number;
158 guint32 sampling_rate;
165 /* counters sample header */
166 struct sflow_counters_sample_header {
167 guint32 sequence_number;
169 guint32 sampling_interval;
170 guint32 counters_type;
173 /* generic interface counters */
181 guint32 ifInUcastPkts;
182 guint32 ifInMulticastPkts;
183 guint32 ifInBroadcastPkts;
184 guint32 ifInDiscards;
186 guint32 ifInUnknownProtos;
188 guint32 ifOutUcastPkts;
189 guint32 ifOutMulticastPkts;
190 guint32 ifOutBroadcastPkts;
191 guint32 ifOutDiscards;
193 guint32 ifPromiscuousMode;
196 /* ethernet counters. These will be preceded by generic counters. */
197 struct ethernet_counters {
198 guint32 dot3StatsAlignmentErrors;
199 guint32 dot3StatsFCSErrors;
200 guint32 dot3StatsSingleCollisionFrames;
201 guint32 dot3StatsMultipleCollisionFrames;
202 guint32 dot3StatsSQETestErrors;
203 guint32 dot3StatsDeferredTransmissions;
204 guint32 dot3StatsLateCollisions;
205 guint32 dot3StatsExcessiveCollisions;
206 guint32 dot3StatsInternalMacTransmitErrors;
207 guint32 dot3StatsCarrierSenseErrors;
208 guint32 dot3StatsFrameTooLongs;
209 guint32 dot3StatsInternalMacReceiveErrors;
210 guint32 dot3StatsSymbolErrors;
213 /* Token Ring counters */
214 struct token_ring_counters {
215 guint32 dot5StatsLineErrors;
216 guint32 dot5StatsBurstErrors;
217 guint32 dot5StatsACErrors;
218 guint32 dot5StatsAbortTransErrors;
219 guint32 dot5StatsInternalErrors;
220 guint32 dot5StatsLostFrameErrors;
221 guint32 dot5StatsReceiveCongestions;
222 guint32 dot5StatsFrameCopiedErrors;
223 guint32 dot5StatsTokenErrors;
224 guint32 dot5StatsSoftErrors;
225 guint32 dot5StatsHardErrors;
226 guint32 dot5StatsSignalLoss;
227 guint32 dot5StatsTransmitBeacons;
228 guint32 dot5StatsRecoverys;
229 guint32 dot5StatsLobeWires;
230 guint32 dot5StatsRemoves;
231 guint32 dot5StatsSingles;
232 guint32 dot5StatsFreqErrors;
235 /* 100BaseVG counters */
238 guint32 dot12InHighPriorityFrames;
239 guint64 dot12InHighPriorityOctets;
240 guint32 dot12InNormPriorityFrames;
241 guint64 dot12InNormPriorityOctets;
242 guint32 dot12InIPMErrors;
243 guint32 dot12InOversizeFrameErrors;
244 guint32 dot12InDataErrors;
245 guint32 dot12InNullAddressedFrames;
246 guint32 dot12OutHighPriorityFrames;
247 guint64 dot12OutHighPriorityOctets;
248 guint32 dot12TransitionIntoTrainings;
249 guint64 dot12HCInHighPriorityOctets;
250 guint64 dot12HCInNormPriorityOctets;
251 guint64 dot12HCOutHighPriorityOctets;
256 struct vlan_counters {
260 guint32 multicastPkts;
261 guint32 broadcastPkts;
265 /* Initialize the protocol and registered fields */
266 static int proto_sflow = -1;
267 static int hf_sflow_version = -1;
268 /*static int hf_sflow_agent_address_type = -1; */
269 static int hf_sflow_agent_address_v4 = -1;
270 static int hf_sflow_agent_address_v6 = -1;
271 static int hf_sflow_sub_agent_id = -1;
272 static int hf_sflow_seqnum = -1;
273 static int hf_sflow_sysuptime = -1;
274 static int hf_sflow_numsamples = -1;
275 static int hf_sflow_header_protocol = -1;
276 static int hf_sflow_sampletype = -1;
277 static int hf_sflow_header = -1;
278 static int hf_sflow_packet_information_type = -1;
279 static int hf_sflow_extended_information_type = -1;
280 static int hf_sflow_vlan_in = -1; /* incoming 802.1Q VLAN ID */
281 static int hf_sflow_vlan_out = -1; /* outgoing 802.1Q VLAN ID */
282 static int hf_sflow_pri_in = -1; /* incominging 802.1p priority */
283 static int hf_sflow_pri_out = -1; /* outgoing 802.1p priority */
284 static int hf_sflow_nexthop_v4 = -1; /* nexthop address */
285 static int hf_sflow_nexthop_v6 = -1; /* nexthop address */
286 static int hf_sflow_nexthop_src_mask = -1;
287 static int hf_sflow_nexthop_dst_mask = -1;
288 static int hf_sflow_ifindex = -1;
289 static int hf_sflow_iftype = -1;
290 static int hf_sflow_ifspeed = -1;
291 static int hf_sflow_ifdirection = -1;
292 static int hf_sflow_ifstatus = -1;
293 static int hf_sflow_ifinoct = -1;
294 static int hf_sflow_ifinpkt = -1;
295 static int hf_sflow_ifinmcast = -1;
296 static int hf_sflow_ifinbcast = -1;
297 static int hf_sflow_ifinerr = -1;
298 static int hf_sflow_ifindisc = -1;
299 static int hf_sflow_ifinunk = -1;
300 static int hf_sflow_ifoutoct = -1;
301 static int hf_sflow_ifoutpkt = -1;
302 static int hf_sflow_ifoutmcast = -1;
303 static int hf_sflow_ifoutbcast = -1;
304 static int hf_sflow_ifoutdisc = -1;
305 static int hf_sflow_ifouterr = -1;
306 static int hf_sflow_ifpromisc = -1;
308 /* Initialize the subtree pointers */
309 static gint ett_sflow = -1;
310 static gint ett_sflow_sample = -1;
311 static gint ett_sflow_extended_data = -1;
312 static gint ett_sflow_sampled_header = -1;
314 /* dissectors for other protocols */
315 static dissector_handle_t eth_withoutfcs_handle;
316 static dissector_handle_t tr_handle;
317 static dissector_handle_t fddi_handle;
318 static dissector_handle_t fr_handle;
319 static dissector_handle_t x25_handle;
320 static dissector_handle_t ppp_handle;
321 static dissector_handle_t smds_handle;
322 static dissector_handle_t aal5_handle;
323 static dissector_handle_t ipv4_handle;
324 static dissector_handle_t ipv6_handle;
325 static dissector_handle_t mpls_handle;
327 /* dissect a sampled header - layer 2 protocols */
329 dissect_sflow_sampled_header(tvbuff_t *tvb, packet_info *pinfo,
330 proto_tree *tree, volatile gint offset)
332 guint32 header_proto, frame_length;
333 volatile guint32 header_length;
335 proto_tree *sflow_header_tree;
337 /* stuff for saving column state before calling other dissectors.
338 * Thanks to Guy Harris for the tip. */
339 gboolean save_writable;
340 volatile address save_dl_src;
341 volatile address save_dl_dst;
342 volatile address save_net_src;
343 volatile address save_net_dst;
344 volatile address save_src;
345 volatile address save_dst;
347 header_proto = tvb_get_ntohl(tvb,offset);
348 proto_tree_add_item(tree, hf_sflow_header_protocol, tvb, offset,
351 frame_length = tvb_get_ntohl(tvb,offset);
352 proto_tree_add_text(tree, tvb, offset, 4, "Frame Length: %d bytes",
355 header_length = tvb_get_ntohl(tvb,offset);
358 if (header_length % 4) /* XDR requires 4-byte alignment */
359 header_length += 4 - (header_length % 4);
362 ti = proto_tree_add_item(tree, hf_sflow_header, tvb, offset,
363 header_length, FALSE);
364 sflow_header_tree = proto_item_add_subtree(ti, ett_sflow_sampled_header);
366 /* hand the header off to the appropriate dissector. It's probably
367 * a short frame, so ignore any exceptions. */
368 next_tvb = tvb_new_subset(tvb, offset, header_length, frame_length);
370 /* save some state */
371 save_writable = col_get_writable(pinfo->cinfo);
372 col_set_writable(pinfo->cinfo, FALSE);
373 save_dl_src = pinfo->dl_src;
374 save_dl_dst = pinfo->dl_dst;
375 save_net_src = pinfo->net_src;
376 save_net_dst = pinfo->net_dst;
377 save_src = pinfo->src;
378 save_dst = pinfo->dst;
381 switch (header_proto) {
382 case SFLOW_HEADER_ETHERNET:
383 call_dissector(eth_withoutfcs_handle, next_tvb, pinfo, sflow_header_tree);
385 case SFLOW_HEADER_TOKENRING:
386 call_dissector(tr_handle, next_tvb, pinfo, sflow_header_tree);
388 case SFLOW_HEADER_FDDI:
389 call_dissector(fddi_handle, next_tvb, pinfo, sflow_header_tree);
391 case SFLOW_HEADER_FRAME_RELAY:
392 call_dissector(fr_handle, next_tvb, pinfo, sflow_header_tree);
394 case SFLOW_HEADER_X25:
395 call_dissector(x25_handle, next_tvb, pinfo, sflow_header_tree);
397 case SFLOW_HEADER_PPP:
398 call_dissector(ppp_handle, next_tvb, pinfo, sflow_header_tree);
400 case SFLOW_HEADER_SMDS:
401 call_dissector(smds_handle, next_tvb, pinfo, sflow_header_tree);
403 case SFLOW_HEADER_AAL5:
404 case SFLOW_HEADER_AAL5_IP:
405 /* I'll be surprised if this works! I have no AAL5 captures
406 * to test with, and I'm not sure how the encapsulation goes */
407 call_dissector(aal5_handle, next_tvb, pinfo, sflow_header_tree);
409 case SFLOW_HEADER_IPv4:
410 call_dissector(ipv4_handle, next_tvb, pinfo, sflow_header_tree);
412 case SFLOW_HEADER_IPv6:
413 call_dissector(ipv6_handle, next_tvb, pinfo, sflow_header_tree);
415 case SFLOW_HEADER_MPLS:
416 call_dissector(mpls_handle, next_tvb, pinfo, sflow_header_tree);
419 /* some of the protocols, I have no clue where to begin. */
423 CATCH2(BoundsError, ReportedBoundsError) {
428 /* restore saved state */
429 col_set_writable(pinfo->cinfo, save_writable);
430 pinfo->dl_src = save_dl_src;
431 pinfo->dl_dst = save_dl_dst;
432 pinfo->net_src = save_net_src;
433 pinfo->net_dst = save_net_dst;
434 pinfo->src = save_src;
435 pinfo->dst = save_dst;
437 offset += header_length;
441 /* extended switch data, after the packet data */
443 dissect_sflow_extended_switch(tvbuff_t *tvb, proto_tree *tree, gint offset)
447 proto_tree_add_item(tree, hf_sflow_vlan_in, tvb, offset + len, 4, FALSE);
449 proto_tree_add_item(tree, hf_sflow_pri_in, tvb, offset + len, 4, FALSE);
451 proto_tree_add_item(tree, hf_sflow_vlan_out, tvb, offset + len, 4, FALSE);
453 proto_tree_add_item(tree, hf_sflow_pri_out, tvb, offset + len, 4, FALSE);
459 /* extended router data, after the packet data */
461 dissect_sflow_extended_router(tvbuff_t *tvb, proto_tree *tree, gint offset)
464 guint32 address_type;
466 address_type = tvb_get_ntohl(tvb, offset);
468 switch (address_type) {
470 proto_tree_add_item(tree, hf_sflow_nexthop_v4, tvb, offset + len,
475 proto_tree_add_item(tree, hf_sflow_nexthop_v6, tvb, offset + len,
480 proto_tree_add_text(tree, tvb, offset + len - 4, 4,
481 "Unknown address type (%d)", address_type);
482 len += 4; /* not perfect, but what else to do? */
483 return len; /* again, this is wrong. but... ? */
487 proto_tree_add_item(tree, hf_sflow_nexthop_src_mask, tvb, offset + len,
490 proto_tree_add_item(tree, hf_sflow_nexthop_dst_mask, tvb, offset + len,
496 /* dissect a flow sample */
498 dissect_sflow_flow_sample(tvbuff_t *tvb, packet_info *pinfo,
499 proto_tree *tree, gint offset, proto_item *parent)
501 struct sflow_flow_sample_header flow_header;
502 proto_tree *extended_data_tree;
504 guint32 packet_type, extended_data, ext_type, i;
506 /* grab the flow header. This will remain in network byte
507 order, so must convert each item before use */
508 tvb_memcpy(tvb,(guint8 *)&flow_header,offset,sizeof(flow_header));
509 proto_tree_add_text(tree, tvb, offset, 4,
510 "Sequence number: %u",
511 g_ntohl(flow_header.sequence_number));
512 proto_item_append_text(parent, ", seq %u",
513 g_ntohl(flow_header.sequence_number));
514 proto_tree_add_text(tree, tvb, offset+4, 4,
515 "Source ID class: %u index: %u",
516 g_ntohl(flow_header.source_id) >> 24,
517 g_ntohl(flow_header.source_id) & 0x00ffffff);
518 proto_tree_add_text(tree, tvb, offset+8, 4,
519 "Sampling rate: 1 out of %u packets",
520 g_ntohl(flow_header.sampling_rate));
521 proto_tree_add_text(tree, tvb, offset+12, 4,
522 "Sample pool: %u total packets",
523 g_ntohl(flow_header.sample_pool));
524 proto_tree_add_text(tree, tvb, offset+16, 4,
525 "Dropped packets: %u",
526 g_ntohl(flow_header.drops));
527 proto_tree_add_text(tree, tvb, offset+20, 4,
528 "Input Interface: ifIndex %u",
529 g_ntohl(flow_header.input));
530 if (g_ntohl(flow_header.output) >> 31)
531 proto_tree_add_text(tree, tvb, offset+24, 4,
532 "multiple outputs: %u interfaces",
533 g_ntohl(flow_header.output) & 0x00ffffff);
535 proto_tree_add_text(tree, tvb, offset+24, 4,
536 "Output interface: ifIndex %u",
537 g_ntohl(flow_header.output) & 0x00ffffff);
538 offset += sizeof(flow_header);
540 /* what kind of flow sample is it? */
541 packet_type = tvb_get_ntohl(tvb, offset);
542 proto_tree_add_uint(tree, hf_sflow_packet_information_type, tvb, offset,
545 switch (packet_type) {
546 case SFLOW_PACKET_DATA_TYPE_HEADER:
547 offset = dissect_sflow_sampled_header(tvb, pinfo, tree, offset);
549 case SFLOW_PACKET_DATA_TYPE_IPV4:
550 case SFLOW_PACKET_DATA_TYPE_IPV6:
554 /* still need to dissect extended data */
555 extended_data = tvb_get_ntohl(tvb,offset);
558 for (i=0; i < extended_data; i++) {
559 /* figure out what kind of extended data it is */
560 ext_type = tvb_get_ntohl(tvb,offset);
562 /* create a subtree. Might want to move this to
563 * the end, so more info can be correct.
565 ti = proto_tree_add_text(tree, tvb, offset, -1, "%s",
567 sflow_extended_data_types,
568 "Unknown extended information"));
569 extended_data_tree = proto_item_add_subtree(ti, ett_sflow_extended_data);
570 proto_tree_add_uint(extended_data_tree,
571 hf_sflow_extended_information_type, tvb, offset, 4,
576 case SFLOW_EXTENDED_SWITCH:
577 offset += dissect_sflow_extended_switch(tvb, extended_data_tree,
580 case SFLOW_EXTENDED_ROUTER:
581 offset += dissect_sflow_extended_router(tvb, extended_data_tree,
584 case SFLOW_EXTENDED_GATEWAY:
586 case SFLOW_EXTENDED_USER:
588 case SFLOW_EXTENDED_URL:
593 proto_item_set_end(ti, tvb, offset);
599 /* dissect a counters sample */
601 dissect_sflow_counters_sample(tvbuff_t *tvb, proto_tree *tree,
602 gint offset, proto_item *parent)
604 struct sflow_counters_sample_header counters_header;
605 struct if_counters ifc;
606 struct ethernet_counters ethc;
607 struct token_ring_counters tokc;
608 struct vg_counters vgc;
609 struct vlan_counters vlanc;
611 /* grab the flow header. This will remain in network byte
612 order, so must convert each item before use */
613 tvb_memcpy(tvb,(guint8 *)&counters_header,offset,sizeof(counters_header));
614 proto_tree_add_text(tree, tvb, offset, 4,
615 "Sequence number: %u",
616 g_ntohl(counters_header.sequence_number));
617 proto_item_append_text(parent, ", seq %u",
618 g_ntohl(counters_header.sequence_number));
619 proto_tree_add_text(tree, tvb, offset + 4, 4,
620 "Source ID class: %u index: %u",
621 g_ntohl(counters_header.source_id) >> 24,
622 g_ntohl(counters_header.source_id) & 0x00ffffff);
623 proto_tree_add_text(tree, tvb, offset + 8, 4,
624 "Sampling Interval: %u",
625 g_ntohl(counters_header.sampling_interval));
626 proto_tree_add_text(tree, tvb, offset + 12, 4, "Counters type: %s",
627 val_to_str(g_ntohl(counters_header.counters_type),
628 sflow_counterstype, "Unknown type"));
630 offset += sizeof(counters_header);
632 /* most counters types have the "generic" counters first */
633 switch (g_ntohl(counters_header.counters_type)) {
634 case SFLOW_COUNTERS_GENERIC:
635 case SFLOW_COUNTERS_ETHERNET:
636 case SFLOW_COUNTERS_TOKENRING:
637 case SFLOW_COUNTERS_FDDI:
638 case SFLOW_COUNTERS_VG:
639 case SFLOW_COUNTERS_WAN:
640 tvb_memcpy(tvb,(guint8 *)&ifc, offset, sizeof(ifc));
641 proto_item_append_text(parent, ", ifIndex %u",
642 g_ntohl(ifc.ifIndex));
643 proto_tree_add_item(tree, hf_sflow_ifindex, tvb, offset, 4, FALSE);
645 proto_tree_add_item(tree, hf_sflow_iftype, tvb, offset, 4, FALSE);
647 proto_tree_add_item(tree, hf_sflow_ifspeed, tvb, offset, 8, FALSE);
649 proto_tree_add_item(tree, hf_sflow_ifdirection, tvb, offset,
652 proto_tree_add_item(tree, hf_sflow_ifstatus, tvb, offset, 4, FALSE);
654 proto_tree_add_item(tree, hf_sflow_ifinoct, tvb, offset, 8, FALSE);
656 proto_tree_add_item(tree, hf_sflow_ifinpkt, tvb, offset, 4, FALSE);
658 proto_tree_add_item(tree, hf_sflow_ifinmcast, tvb, offset,
661 proto_tree_add_item(tree, hf_sflow_ifinbcast, tvb, offset,
664 proto_tree_add_item(tree, hf_sflow_ifindisc, tvb, offset,
667 proto_tree_add_item(tree, hf_sflow_ifinerr, tvb, offset,
670 proto_tree_add_item(tree, hf_sflow_ifinunk, tvb, offset,
673 proto_tree_add_item(tree, hf_sflow_ifoutoct, tvb, offset, 8, FALSE);
675 proto_tree_add_item(tree, hf_sflow_ifoutpkt, tvb, offset, 4, FALSE);
677 proto_tree_add_item(tree, hf_sflow_ifoutmcast, tvb, offset,
680 proto_tree_add_item(tree, hf_sflow_ifoutbcast, tvb, offset,
683 proto_tree_add_item(tree, hf_sflow_ifoutdisc, tvb, offset,
686 proto_tree_add_item(tree, hf_sflow_ifouterr, tvb, offset,
689 proto_tree_add_item(tree, hf_sflow_ifpromisc, tvb, offset,
695 /* Some counter types have other info to gather */
696 switch (g_ntohl(counters_header.counters_type)) {
697 case SFLOW_COUNTERS_ETHERNET:
698 tvb_memcpy(tvb,(guint8 *)ðc, offset, sizeof(ethc));
699 offset += sizeof(ethc);
701 case SFLOW_COUNTERS_TOKENRING:
702 tvb_memcpy(tvb,(guint8 *)&tokc, offset, sizeof(tokc));
703 offset += sizeof(tokc);
705 case SFLOW_COUNTERS_VG:
706 tvb_memcpy(tvb,(guint8 *)&vgc, offset, sizeof(vgc));
707 offset += sizeof(vgc);
709 case SFLOW_COUNTERS_VLAN:
710 tvb_memcpy(tvb,(guint8 *)&vlanc, offset, sizeof(vlanc));
711 offset += sizeof(vlanc);
719 /* Code to dissect the sflow samples */
721 dissect_sflow_samples(tvbuff_t *tvb, packet_info *pinfo,
722 proto_tree *tree, gint offset)
724 proto_tree *sflow_sample_tree;
725 proto_item *ti; /* tree item */
728 /* decide what kind of sample it is. */
729 sample_type = tvb_get_ntohl(tvb,offset);
731 ti = proto_tree_add_text(tree, tvb, offset, -1, "%s",
732 val_to_str(sample_type, sflow_sampletype,
733 "Unknown sample type"));
734 sflow_sample_tree = proto_item_add_subtree(ti, ett_sflow_sample);
736 proto_tree_add_item(sflow_sample_tree, hf_sflow_sampletype, tvb,
740 switch (sample_type) {
742 offset = dissect_sflow_flow_sample(tvb, pinfo, sflow_sample_tree,
746 offset = dissect_sflow_counters_sample(tvb, sflow_sample_tree,
752 proto_item_set_end(ti, tvb, offset);
756 /* Code to actually dissect the packets */
758 dissect_sflow(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
761 /* Set up structures needed to add the protocol subtree and manage it */
763 proto_tree *sflow_tree;
764 guint32 version, sub_agent_id, seqnum;
765 guint32 agent_address_type;
771 volatile guint offset=0;
774 /* Make entries in Protocol column and Info column on summary display */
775 if (check_col(pinfo->cinfo, COL_PROTOCOL))
776 col_set_str(pinfo->cinfo, COL_PROTOCOL, "sFlow");
779 /* create display subtree for the protocol */
780 ti = proto_tree_add_item(tree, proto_sflow, tvb, 0, -1, FALSE);
782 sflow_tree = proto_item_add_subtree(ti, ett_sflow);
784 version = tvb_get_ntohl(tvb, offset);
785 if (check_col(pinfo->cinfo, COL_INFO))
786 col_add_fstr(pinfo->cinfo, COL_INFO, "V%u",
788 proto_tree_add_item(sflow_tree,
789 hf_sflow_version, tvb, offset, 4, FALSE);
792 agent_address_type = tvb_get_ntohl(tvb, offset);
794 switch (agent_address_type) {
796 tvb_memcpy(tvb, agent_address.v4, offset, 4);
797 if (check_col(pinfo->cinfo, COL_INFO))
798 col_append_fstr(pinfo->cinfo, COL_INFO, ", agent %s",
799 ip_to_str(agent_address.v4));
800 proto_tree_add_item(sflow_tree,
801 hf_sflow_agent_address_v4, tvb, offset,
806 tvb_memcpy(tvb, agent_address.v6, offset, 16);
807 if (check_col(pinfo->cinfo, COL_INFO))
808 col_append_fstr(pinfo->cinfo, COL_INFO, ", agent %s",
809 ip6_to_str((struct e_in6_addr *)agent_address.v6));
810 proto_tree_add_item(sflow_tree,
811 hf_sflow_agent_address_v6, tvb, offset,
816 /* unknown address. this will cause a malformed packet. */
821 sub_agent_id = tvb_get_ntohl(tvb, offset);
822 if (check_col(pinfo->cinfo, COL_INFO))
823 col_append_fstr(pinfo->cinfo, COL_INFO, ", sub-agent ID %u",
825 proto_tree_add_uint(sflow_tree, hf_sflow_sub_agent_id, tvb,
826 offset, 4, sub_agent_id);
829 seqnum = tvb_get_ntohl(tvb, offset);
830 if (check_col(pinfo->cinfo, COL_INFO))
831 col_append_fstr(pinfo->cinfo, COL_INFO, ", seq %u", seqnum);
832 proto_tree_add_uint(sflow_tree, hf_sflow_seqnum, tvb,
835 proto_tree_add_item(sflow_tree, hf_sflow_sysuptime, tvb,
838 numsamples = tvb_get_ntohl(tvb,offset);
839 if (check_col(pinfo->cinfo, COL_INFO))
840 col_append_fstr(pinfo->cinfo, COL_INFO, ", %u samples",
842 proto_tree_add_uint(sflow_tree, hf_sflow_numsamples, tvb,
843 offset, 4, numsamples);
846 /* Ok, we're now at the end of the sflow datagram header;
847 * everything from here out should be samples. Loop over
848 * the expected number of samples, and pass them to the appropriate
852 proto_tree_add_text(sflow_tree, tvb, offset, -1,
853 "sFlow V5 samples (please write and contribute code to dissect them!)");
855 for (i=0; i < numsamples; i++) {
856 offset = dissect_sflow_samples(tvb, pinfo, sflow_tree,
863 /* Register the protocol with Wireshark */
865 /* this format is require because a script is used to build the C function
866 that calls all the protocol registration.
870 proto_register_sflow(void)
873 /* Setup list of header fields See Section 1.6.1 for details*/
874 static hf_register_info hf[] = {
876 { "datagram version", "sflow.version",
877 FT_UINT32, BASE_DEC, NULL, 0x0,
878 "sFlow datagram version", HFILL }
880 { &hf_sflow_agent_address_v4,
881 { "agent address", "sflow.agent",
882 FT_IPv4, BASE_NONE, NULL, 0x0,
883 "sFlow Agent IP address", HFILL }
885 { &hf_sflow_agent_address_v6,
886 { "agent address", "sflow.agent.v6",
887 FT_IPv6, BASE_NONE, NULL, 0x0,
888 "sFlow Agent IPv6 address", HFILL }
890 { &hf_sflow_sub_agent_id,
891 { "Sub-agent ID", "sflow.sub_agent_id",
892 FT_UINT32, BASE_DEC, NULL, 0x0,
893 "sFlow sub-agent ID", HFILL }
896 { "Sequence number", "sflow.sequence_number",
897 FT_UINT32, BASE_DEC, NULL, 0x0,
898 "sFlow datagram sequence number", HFILL }
900 { &hf_sflow_sysuptime,
901 { "SysUptime", "sflow.sysuptime",
902 FT_UINT32, BASE_DEC, NULL, 0x0,
903 "System Uptime", HFILL }
905 { &hf_sflow_numsamples,
906 { "NumSamples", "sflow.numsamples",
907 FT_UINT32, BASE_DEC, NULL, 0x0,
908 "Number of samples in sFlow datagram", HFILL }
910 { &hf_sflow_sampletype,
911 { "sFlow sample type", "sflow.sampletype",
912 FT_UINT32, BASE_DEC, VALS(sflow_sampletype), 0x0,
913 "Type of sFlow sample", HFILL }
915 { &hf_sflow_header_protocol,
916 { "Header protocol", "sflow.header_protocol",
917 FT_UINT32, BASE_DEC, VALS(sflow_header_protocol), 0x0,
918 "Protocol of sampled header", HFILL }
921 { "Header of sampled packet", "sflow.header",
922 FT_BYTES, BASE_HEX, NULL, 0x0,
923 "Data from sampled header", HFILL }
925 { &hf_sflow_packet_information_type,
926 { "Sample type", "sflow.packet_information_type",
927 FT_UINT32, BASE_DEC, VALS(sflow_packet_information_type), 0x0,
928 "Type of sampled information", HFILL }
930 { &hf_sflow_extended_information_type,
931 { "Extended information type", "sflow.extended_information_type",
932 FT_UINT32, BASE_DEC, VALS(sflow_extended_data_types), 0x0,
933 "Type of extended information", HFILL }
936 { "Incoming 802.1Q VLAN", "sflow.vlan.in",
937 FT_UINT32, BASE_DEC, NULL, 0x0,
938 "Incoming VLAN ID", HFILL }
940 { &hf_sflow_vlan_out,
941 { "Outgoing 802.1Q VLAN", "sflow.vlan.out",
942 FT_UINT32, BASE_DEC, NULL, 0x0,
943 "Outgoing VLAN ID", HFILL }
946 { "Incoming 802.1p priority", "sflow.pri.in",
947 FT_UINT32, BASE_DEC, NULL, 0x0,
948 "Incoming 802.1p priority", HFILL }
951 { "Outgoing 802.1p priority", "sflow.pri.out",
952 FT_UINT32, BASE_DEC, NULL, 0x0,
953 "Outgoing 802.1p priority", HFILL }
955 { &hf_sflow_nexthop_v4,
956 { "Next hop", "sflow.nexthop",
957 FT_IPv4, BASE_DEC, NULL, 0x0,
958 "Next hop address", HFILL }
960 { &hf_sflow_nexthop_v6,
961 { "Next hop", "sflow.nexthop",
962 FT_IPv6, BASE_HEX, NULL, 0x0,
963 "Next hop address", HFILL }
965 { &hf_sflow_nexthop_src_mask,
966 { "Next hop source mask", "sflow.nexthop.src_mask",
967 FT_UINT32, BASE_DEC, NULL, 0x0,
968 "Next hop source mask bits", HFILL }
970 { &hf_sflow_nexthop_dst_mask,
971 { "Next hop destination mask", "sflow.nexthop.dst_mask",
972 FT_UINT32, BASE_DEC, NULL, 0x0,
973 "Next hop destination mask bits", HFILL }
976 { "Interface index", "sflow.ifindex",
977 FT_UINT32, BASE_DEC, NULL, 0x0,
978 "Interface Index", HFILL }
981 { "Interface Type", "sflow.iftype",
982 FT_UINT32, BASE_DEC, NULL, 0x0,
983 "Interface Type", HFILL }
986 { "Interface Speed", "sflow.ifspeed",
987 FT_UINT64, BASE_DEC, NULL, 0x0,
988 "Interface Speed", HFILL }
990 { &hf_sflow_ifdirection,
991 { "Interface Direction", "sflow.ifdirection",
992 FT_UINT32, BASE_DEC, NULL, 0x0,
993 "Interface Direction", HFILL }
995 { &hf_sflow_ifstatus,
996 { "Interface Status", "sflow.ifstatus",
997 FT_UINT32, BASE_DEC, NULL, 0x0,
998 "Interface Status", HFILL }
1000 { &hf_sflow_ifinoct,
1001 { "Input Octets", "sflow.ifinoct",
1002 FT_UINT64, BASE_DEC, NULL, 0x0,
1003 "Interface Input Octets", HFILL }
1005 { &hf_sflow_ifinpkt,
1006 { "Input Packets", "sflow.ifinpkt",
1007 FT_UINT32, BASE_DEC, NULL, 0x0,
1008 "Interface Input Packets", HFILL }
1010 { &hf_sflow_ifinmcast,
1011 { "Input Multicast Packets", "sflow.ifinmcast",
1012 FT_UINT32, BASE_DEC, NULL, 0x0,
1013 "Interface Input Multicast Packets", HFILL }
1015 { &hf_sflow_ifinbcast,
1016 { "Input Broadcast Packets", "sflow.ifinbcast",
1017 FT_UINT32, BASE_DEC, NULL, 0x0,
1018 "Interface Input Broadcast Packets", HFILL }
1020 { &hf_sflow_ifindisc,
1021 { "Input Discarded Packets", "sflow.ifindisc",
1022 FT_UINT32, BASE_DEC, NULL, 0x0,
1023 "Interface Input Discarded Packets", HFILL }
1025 { &hf_sflow_ifinerr,
1026 { "Input Errors", "sflow.ifinerr",
1027 FT_UINT32, BASE_DEC, NULL, 0x0,
1028 "Interface Input Errors", HFILL }
1030 { &hf_sflow_ifinunk,
1031 { "Input Unknown Protocol Packets", "sflow.ifinunk",
1032 FT_UINT32, BASE_DEC, NULL, 0x0,
1033 "Interface Input Unknown Protocol Packets", HFILL }
1035 { &hf_sflow_ifoutoct,
1036 { "Output Octets", "sflow.ifoutoct",
1037 FT_UINT64, BASE_DEC, NULL, 0x0,
1038 "Outterface Output Octets", HFILL }
1040 { &hf_sflow_ifoutpkt,
1041 { "Output Packets", "sflow.ifoutpkt",
1042 FT_UINT32, BASE_DEC, NULL, 0x0,
1043 "Interface Output Packets", HFILL }
1045 { &hf_sflow_ifoutmcast,
1046 { "Output Multicast Packets", "sflow.ifoutmcast",
1047 FT_UINT32, BASE_DEC, NULL, 0x0,
1048 "Interface Output Multicast Packets", HFILL }
1050 { &hf_sflow_ifoutbcast,
1051 { "Output Broadcast Packets", "sflow.ifoutbcast",
1052 FT_UINT32, BASE_DEC, NULL, 0x0,
1053 "Interface Output Broadcast Packets", HFILL }
1055 { &hf_sflow_ifoutdisc,
1056 { "Output Discarded Packets", "sflow.ifoutdisc",
1057 FT_UINT32, BASE_DEC, NULL, 0x0,
1058 "Interface Output Discarded Packets", HFILL }
1060 { &hf_sflow_ifouterr,
1061 { "Output Errors", "sflow.ifouterr",
1062 FT_UINT32, BASE_DEC, NULL, 0x0,
1063 "Interface Output Errors", HFILL }
1065 { &hf_sflow_ifpromisc,
1066 { "Promiscuous Mode", "sflow.ifpromisc",
1067 FT_UINT32, BASE_DEC, NULL, 0x0,
1068 "Interface Promiscuous Mode", HFILL }
1072 /* Setup protocol subtree array */
1073 static gint *ett[] = {
1076 &ett_sflow_extended_data,
1077 &ett_sflow_sampled_header,
1080 /* Register the protocol name and description */
1081 proto_sflow = proto_register_protocol("InMon sFlow",
1084 /* Required function calls to register the header fields and subtrees used */
1085 proto_register_field_array(proto_sflow, hf, array_length(hf));
1086 proto_register_subtree_array(ett, array_length(ett));
1090 /* If this dissector uses sub-dissector registration add a registration routine.
1091 This format is required because a script is used to find these routines and
1092 create the code that calls these routines.
1095 proto_reg_handoff_sflow(void)
1097 dissector_handle_t sflow_handle;
1100 * XXX - should this be done with a dissector table?
1102 eth_withoutfcs_handle = find_dissector("eth_withoutfcs");
1103 tr_handle = find_dissector("tr");
1104 fddi_handle = find_dissector("fddi");
1105 fr_handle = find_dissector("fr");
1106 x25_handle = find_dissector("x.25");
1107 ppp_handle = find_dissector("ppp");
1109 smds_handle = find_dissector("smds");
1111 /* We don't have an SMDS dissector yet */
1112 smds_handle = find_dissector("data");
1115 aal5_handle = find_dissector("atm");
1117 /* What dissector should be used here? */
1118 aal5_handle = find_dissector("data");
1120 ipv4_handle = find_dissector("ip");
1121 ipv6_handle = find_dissector("ipv6");
1122 mpls_handle = find_dissector("mpls");
1124 sflow_handle = create_dissector_handle(dissect_sflow,
1126 dissector_add("udp.port", UDP_PORT_SFLOW, sflow_handle);