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 <epan/prefs.h>
60 /*#include "packet-sflow.h"*/
62 #define SFLOW_UDP_PORTS "6343"
64 static dissector_handle_t sflow_handle;
67 * global_sflow_ports : holds the configured range of ports for sflow
69 static range_t *global_sflow_ports = NULL;
72 * sflow_ports : holds the currently used range of ports for sflow
74 static range_t *sflow_ports = NULL;
75 static gboolean global_dissect_samp_headers = TRUE;
76 static gboolean global_analyze_samp_ip_headers = FALSE;
80 #define ADDRESS_IPV4 1
81 #define ADDRESS_IPV6 2
84 #define COUNTERSSAMPLE 2
86 static const value_string sflow_sampletype[] = {
87 { FLOWSAMPLE, "Flow sample" },
88 { COUNTERSSAMPLE, "Counters sample" },
92 /* interface counter types */
93 #define SFLOW_COUNTERS_GENERIC 1
94 #define SFLOW_COUNTERS_ETHERNET 2
95 #define SFLOW_COUNTERS_TOKENRING 3
96 #define SFLOW_COUNTERS_FDDI 4
97 #define SFLOW_COUNTERS_VG 5
98 #define SFLOW_COUNTERS_WAN 6
99 #define SFLOW_COUNTERS_VLAN 7
101 static const value_string sflow_counterstype [] = {
102 { SFLOW_COUNTERS_GENERIC, "Generic counters" },
103 { SFLOW_COUNTERS_ETHERNET, "Ethernet counters" },
104 { SFLOW_COUNTERS_FDDI, "FDDI counters" },
105 { SFLOW_COUNTERS_VG, "100baseVG counters" },
106 { SFLOW_COUNTERS_WAN, "WAN counters" },
107 { SFLOW_COUNTERS_VLAN, "VLAN counters" },
111 #define MAX_HEADER_SIZE 256
113 #define SFLOW_PACKET_DATA_TYPE_HEADER 1
114 #define SFLOW_PACKET_DATA_TYPE_IPV4 2
115 #define SFLOW_PACKET_DATA_TYPE_IPV6 3
117 static const value_string sflow_packet_information_type [] = {
118 { SFLOW_PACKET_DATA_TYPE_HEADER, "Packet headers are sampled" },
119 { SFLOW_PACKET_DATA_TYPE_IPV4, "IP Version 4 data" },
120 { SFLOW_PACKET_DATA_TYPE_IPV6, "IP Version 6 data" },
124 #define SFLOW_HEADER_ETHERNET 1
125 #define SFLOW_HEADER_TOKENBUS 2
126 #define SFLOW_HEADER_TOKENRING 3
127 #define SFLOW_HEADER_FDDI 4
128 #define SFLOW_HEADER_FRAME_RELAY 5
129 #define SFLOW_HEADER_X25 6
130 #define SFLOW_HEADER_PPP 7
131 #define SFLOW_HEADER_SMDS 8
132 #define SFLOW_HEADER_AAL5 9
133 #define SFLOW_HEADER_AAL5_IP 10
134 #define SFLOW_HEADER_IPv4 11
135 #define SFLOW_HEADER_IPv6 12
136 #define SFLOW_HEADER_MPLS 13
138 static const value_string sflow_header_protocol[] = {
139 { SFLOW_HEADER_ETHERNET, "Ethernet" },
140 { SFLOW_HEADER_TOKENBUS, "Token Bus" },
141 { SFLOW_HEADER_TOKENRING, "Token Ring" },
142 { SFLOW_HEADER_FDDI, "FDDI" },
143 { SFLOW_HEADER_FRAME_RELAY, "Frame Relay" },
144 { SFLOW_HEADER_X25, "X.25" },
145 { SFLOW_HEADER_PPP, "PPP" },
146 { SFLOW_HEADER_SMDS, "SMDS" },
147 { SFLOW_HEADER_AAL5, "ATM AAL5" },
148 { SFLOW_HEADER_AAL5_IP, "ATM AAL5-IP (e.g., Cisco AAL5 mux)" },
149 { SFLOW_HEADER_IPv4, "IPv4" },
150 { SFLOW_HEADER_IPv6, "IPv6" },
151 { SFLOW_HEADER_MPLS, "MPLS" },
155 /* extended data types */
156 #define SFLOW_EXTENDED_SWITCH 1
157 #define SFLOW_EXTENDED_ROUTER 2
158 #define SFLOW_EXTENDED_GATEWAY 3
159 #define SFLOW_EXTENDED_USER 4
160 #define SFLOW_EXTENDED_URL 5
162 static const value_string sflow_extended_data_types[] = {
163 { SFLOW_EXTENDED_SWITCH, "Extended switch information" },
164 { SFLOW_EXTENDED_ROUTER, "Extended router information" },
165 { SFLOW_EXTENDED_GATEWAY, "Extended gateway information" },
166 { SFLOW_EXTENDED_USER, "Extended user information" },
167 { SFLOW_EXTENDED_URL, "Extended URL information" },
172 /* flow sample header */
173 struct sflow_flow_sample_header {
174 guint32 sequence_number;
176 guint32 sampling_rate;
183 /* counters sample header */
184 struct sflow_counters_sample_header {
185 guint32 sequence_number;
187 guint32 sampling_interval;
188 guint32 counters_type;
191 /* generic interface counters */
199 guint32 ifInUcastPkts;
200 guint32 ifInMulticastPkts;
201 guint32 ifInBroadcastPkts;
202 guint32 ifInDiscards;
204 guint32 ifInUnknownProtos;
206 guint32 ifOutUcastPkts;
207 guint32 ifOutMulticastPkts;
208 guint32 ifOutBroadcastPkts;
209 guint32 ifOutDiscards;
211 guint32 ifPromiscuousMode;
214 /* ethernet counters. These will be preceded by generic counters. */
215 struct ethernet_counters {
216 guint32 dot3StatsAlignmentErrors;
217 guint32 dot3StatsFCSErrors;
218 guint32 dot3StatsSingleCollisionFrames;
219 guint32 dot3StatsMultipleCollisionFrames;
220 guint32 dot3StatsSQETestErrors;
221 guint32 dot3StatsDeferredTransmissions;
222 guint32 dot3StatsLateCollisions;
223 guint32 dot3StatsExcessiveCollisions;
224 guint32 dot3StatsInternalMacTransmitErrors;
225 guint32 dot3StatsCarrierSenseErrors;
226 guint32 dot3StatsFrameTooLongs;
227 guint32 dot3StatsInternalMacReceiveErrors;
228 guint32 dot3StatsSymbolErrors;
231 /* Token Ring counters */
232 struct token_ring_counters {
233 guint32 dot5StatsLineErrors;
234 guint32 dot5StatsBurstErrors;
235 guint32 dot5StatsACErrors;
236 guint32 dot5StatsAbortTransErrors;
237 guint32 dot5StatsInternalErrors;
238 guint32 dot5StatsLostFrameErrors;
239 guint32 dot5StatsReceiveCongestions;
240 guint32 dot5StatsFrameCopiedErrors;
241 guint32 dot5StatsTokenErrors;
242 guint32 dot5StatsSoftErrors;
243 guint32 dot5StatsHardErrors;
244 guint32 dot5StatsSignalLoss;
245 guint32 dot5StatsTransmitBeacons;
246 guint32 dot5StatsRecoverys;
247 guint32 dot5StatsLobeWires;
248 guint32 dot5StatsRemoves;
249 guint32 dot5StatsSingles;
250 guint32 dot5StatsFreqErrors;
253 /* 100BaseVG counters */
256 guint32 dot12InHighPriorityFrames;
257 guint64 dot12InHighPriorityOctets;
258 guint32 dot12InNormPriorityFrames;
259 guint64 dot12InNormPriorityOctets;
260 guint32 dot12InIPMErrors;
261 guint32 dot12InOversizeFrameErrors;
262 guint32 dot12InDataErrors;
263 guint32 dot12InNullAddressedFrames;
264 guint32 dot12OutHighPriorityFrames;
265 guint64 dot12OutHighPriorityOctets;
266 guint32 dot12TransitionIntoTrainings;
267 guint64 dot12HCInHighPriorityOctets;
268 guint64 dot12HCInNormPriorityOctets;
269 guint64 dot12HCOutHighPriorityOctets;
274 struct vlan_counters {
278 guint32 multicastPkts;
279 guint32 broadcastPkts;
283 /* Initialize the protocol and registered fields */
284 static int proto_sflow = -1;
285 static int hf_sflow_version = -1;
286 /*static int hf_sflow_agent_address_type = -1; */
287 static int hf_sflow_agent_address_v4 = -1;
288 static int hf_sflow_agent_address_v6 = -1;
289 static int hf_sflow_sub_agent_id = -1;
290 static int hf_sflow_seqnum = -1;
291 static int hf_sflow_sysuptime = -1;
292 static int hf_sflow_numsamples = -1;
293 static int hf_sflow_header_protocol = -1;
294 static int hf_sflow_sampletype = -1;
295 static int hf_sflow_header = -1;
296 static int hf_sflow_packet_information_type = -1;
297 static int hf_sflow_extended_information_type = -1;
298 static int hf_sflow_vlan_in = -1; /* incoming 802.1Q VLAN ID */
299 static int hf_sflow_vlan_out = -1; /* outgoing 802.1Q VLAN ID */
300 static int hf_sflow_pri_in = -1; /* incominging 802.1p priority */
301 static int hf_sflow_pri_out = -1; /* outgoing 802.1p priority */
302 static int hf_sflow_nexthop_v4 = -1; /* nexthop address */
303 static int hf_sflow_nexthop_v6 = -1; /* nexthop address */
304 static int hf_sflow_nexthop_src_mask = -1;
305 static int hf_sflow_nexthop_dst_mask = -1;
306 static int hf_sflow_ifindex = -1;
307 static int hf_sflow_iftype = -1;
308 static int hf_sflow_ifspeed = -1;
309 static int hf_sflow_ifdirection = -1;
310 static int hf_sflow_ifstatus = -1;
311 static int hf_sflow_ifinoct = -1;
312 static int hf_sflow_ifinpkt = -1;
313 static int hf_sflow_ifinmcast = -1;
314 static int hf_sflow_ifinbcast = -1;
315 static int hf_sflow_ifinerr = -1;
316 static int hf_sflow_ifindisc = -1;
317 static int hf_sflow_ifinunk = -1;
318 static int hf_sflow_ifoutoct = -1;
319 static int hf_sflow_ifoutpkt = -1;
320 static int hf_sflow_ifoutmcast = -1;
321 static int hf_sflow_ifoutbcast = -1;
322 static int hf_sflow_ifoutdisc = -1;
323 static int hf_sflow_ifouterr = -1;
324 static int hf_sflow_ifpromisc = -1;
326 /* Initialize the subtree pointers */
327 static gint ett_sflow = -1;
328 static gint ett_sflow_sample = -1;
329 static gint ett_sflow_extended_data = -1;
330 static gint ett_sflow_sampled_header = -1;
332 /* dissectors for other protocols */
333 static dissector_handle_t eth_withoutfcs_handle;
334 static dissector_handle_t tr_handle;
335 static dissector_handle_t fddi_handle;
336 static dissector_handle_t fr_handle;
337 static dissector_handle_t x25_handle;
338 static dissector_handle_t ppp_handle;
339 static dissector_handle_t smds_handle;
340 static dissector_handle_t aal5_handle;
341 static dissector_handle_t ipv4_handle;
342 static dissector_handle_t ipv6_handle;
343 static dissector_handle_t mpls_handle;
345 static dissector_handle_t data_handle;
347 void proto_reg_handoff_sflow(void);
349 /* dissect a sampled header - layer 2 protocols */
351 dissect_sflow_sampled_header(tvbuff_t *tvb, packet_info *pinfo,
352 proto_tree *tree, volatile gint offset)
354 guint32 header_proto, frame_length;
355 volatile guint32 header_length;
357 proto_tree *sflow_header_tree;
359 /* stuff for saving column state before calling other dissectors.
360 * Thanks to Guy Harris for the tip. */
361 gboolean save_writable;
362 gboolean save_in_error_pkt;
363 volatile address save_dl_src;
364 volatile address save_dl_dst;
365 volatile address save_net_src;
366 volatile address save_net_dst;
367 volatile address save_src;
368 volatile address save_dst;
370 header_proto = tvb_get_ntohl(tvb,offset);
371 proto_tree_add_item(tree, hf_sflow_header_protocol, tvb, offset,
374 frame_length = tvb_get_ntohl(tvb,offset);
375 proto_tree_add_text(tree, tvb, offset, 4, "Frame Length: %d bytes",
378 header_length = tvb_get_ntohl(tvb,offset);
381 if (header_length % 4) /* XDR requires 4-byte alignment */
382 header_length += 4 - (header_length % 4);
385 ti = proto_tree_add_item(tree, hf_sflow_header, tvb, offset,
386 header_length, FALSE);
387 sflow_header_tree = proto_item_add_subtree(ti, ett_sflow_sampled_header);
389 /* hand the header off to the appropriate dissector. It's probably
390 * a short frame, so ignore any exceptions. */
391 next_tvb = tvb_new_subset(tvb, offset, header_length, frame_length);
393 /* save some state */
394 save_writable = col_get_writable(pinfo->cinfo);
397 If sFlow samples a TCP packet it is very likely that the
398 TCP analysis will flag the packet as having some error with
399 the sequence numbers. sFlow only report on a "sample" of
400 traffic so many packets will not be reported on. This is
401 most obvious if the colorizing rules are on, but will also
402 cause confusion if you attempt to filter on
403 "tcp.analysis.flags".
405 The following only works to suppress IP/TCP errors, but
406 it is a start anyway. Other protocols carried as payloads
407 may exhibit similar issues.
409 I think what is really needed is a more general
410 "protocol_as_payload" flag. Of course then someone has to
411 play whack-a-mole and add code to implement it to any
412 protocols that could be carried as a payload. In the case
413 of sFlow that pretty much means anything on your network.
415 save_in_error_pkt = pinfo->in_error_pkt;
416 if (!global_analyze_samp_ip_headers) {
417 pinfo->in_error_pkt = TRUE;
420 col_set_writable(pinfo->cinfo, FALSE);
421 save_dl_src = pinfo->dl_src;
422 save_dl_dst = pinfo->dl_dst;
423 save_net_src = pinfo->net_src;
424 save_net_dst = pinfo->net_dst;
425 save_src = pinfo->src;
426 save_dst = pinfo->dst;
429 switch (header_proto) {
430 case SFLOW_HEADER_ETHERNET:
431 call_dissector(eth_withoutfcs_handle, next_tvb, pinfo, sflow_header_tree);
433 case SFLOW_HEADER_TOKENRING:
434 call_dissector(tr_handle, next_tvb, pinfo, sflow_header_tree);
436 case SFLOW_HEADER_FDDI:
437 call_dissector(fddi_handle, next_tvb, pinfo, sflow_header_tree);
439 case SFLOW_HEADER_FRAME_RELAY:
440 call_dissector(fr_handle, next_tvb, pinfo, sflow_header_tree);
442 case SFLOW_HEADER_X25:
443 call_dissector(x25_handle, next_tvb, pinfo, sflow_header_tree);
445 case SFLOW_HEADER_PPP:
446 call_dissector(ppp_handle, next_tvb, pinfo, sflow_header_tree);
448 case SFLOW_HEADER_SMDS:
449 call_dissector(smds_handle, next_tvb, pinfo, sflow_header_tree);
451 case SFLOW_HEADER_AAL5:
452 case SFLOW_HEADER_AAL5_IP:
453 /* I'll be surprised if this works! I have no AAL5 captures
454 * to test with, and I'm not sure how the encapsulation goes */
455 call_dissector(aal5_handle, next_tvb, pinfo, sflow_header_tree);
457 case SFLOW_HEADER_IPv4:
458 call_dissector(ipv4_handle, next_tvb, pinfo, sflow_header_tree);
460 case SFLOW_HEADER_IPv6:
461 call_dissector(ipv6_handle, next_tvb, pinfo, sflow_header_tree);
463 case SFLOW_HEADER_MPLS:
464 call_dissector(mpls_handle, next_tvb, pinfo, sflow_header_tree);
467 /* some of the protocols, I have no clue where to begin. */
471 CATCH2(BoundsError, ReportedBoundsError) {
476 /* restore saved state */
477 col_set_writable(pinfo->cinfo, save_writable);
478 pinfo->in_error_pkt = save_in_error_pkt;
480 pinfo->dl_src = save_dl_src;
481 pinfo->dl_dst = save_dl_dst;
482 pinfo->net_src = save_net_src;
483 pinfo->net_dst = save_net_dst;
484 pinfo->src = save_src;
485 pinfo->dst = save_dst;
487 offset += header_length;
491 /* extended switch data, after the packet data */
493 dissect_sflow_extended_switch(tvbuff_t *tvb, proto_tree *tree, gint offset)
497 proto_tree_add_item(tree, hf_sflow_vlan_in, tvb, offset + len, 4, FALSE);
499 proto_tree_add_item(tree, hf_sflow_pri_in, tvb, offset + len, 4, FALSE);
501 proto_tree_add_item(tree, hf_sflow_vlan_out, tvb, offset + len, 4, FALSE);
503 proto_tree_add_item(tree, hf_sflow_pri_out, tvb, offset + len, 4, FALSE);
509 /* extended router data, after the packet data */
511 dissect_sflow_extended_router(tvbuff_t *tvb, proto_tree *tree, gint offset)
514 guint32 address_type;
516 address_type = tvb_get_ntohl(tvb, offset);
518 switch (address_type) {
520 proto_tree_add_item(tree, hf_sflow_nexthop_v4, tvb, offset + len,
525 proto_tree_add_item(tree, hf_sflow_nexthop_v6, tvb, offset + len,
530 proto_tree_add_text(tree, tvb, offset + len - 4, 4,
531 "Unknown address type (%d)", address_type);
532 len += 4; /* not perfect, but what else to do? */
533 return len; /* again, this is wrong. but... ? */
537 proto_tree_add_item(tree, hf_sflow_nexthop_src_mask, tvb, offset + len,
540 proto_tree_add_item(tree, hf_sflow_nexthop_dst_mask, tvb, offset + len,
546 /* dissect a flow sample */
548 dissect_sflow_flow_sample(tvbuff_t *tvb, packet_info *pinfo,
549 proto_tree *tree, gint offset, proto_item *parent)
551 struct sflow_flow_sample_header flow_header;
552 proto_tree *extended_data_tree;
554 guint32 packet_type, extended_data, ext_type, i;
556 /* grab the flow header. This will remain in network byte
557 order, so must convert each item before use */
558 tvb_memcpy(tvb,(guint8 *)&flow_header,offset,sizeof(flow_header));
559 proto_tree_add_text(tree, tvb, offset, 4,
560 "Sequence number: %u",
561 g_ntohl(flow_header.sequence_number));
562 proto_item_append_text(parent, ", seq %u",
563 g_ntohl(flow_header.sequence_number));
564 proto_tree_add_text(tree, tvb, offset+4, 4,
565 "Source ID class: %u index: %u",
566 g_ntohl(flow_header.source_id) >> 24,
567 g_ntohl(flow_header.source_id) & 0x00ffffff);
568 proto_tree_add_text(tree, tvb, offset+8, 4,
569 "Sampling rate: 1 out of %u packets",
570 g_ntohl(flow_header.sampling_rate));
571 proto_tree_add_text(tree, tvb, offset+12, 4,
572 "Sample pool: %u total packets",
573 g_ntohl(flow_header.sample_pool));
574 proto_tree_add_text(tree, tvb, offset+16, 4,
575 "Dropped packets: %u",
576 g_ntohl(flow_header.drops));
577 proto_tree_add_text(tree, tvb, offset+20, 4,
578 "Input Interface: ifIndex %u",
579 g_ntohl(flow_header.input));
580 if (g_ntohl(flow_header.output) >> 31)
581 proto_tree_add_text(tree, tvb, offset+24, 4,
582 "multiple outputs: %u interfaces",
583 g_ntohl(flow_header.output) & 0x00ffffff);
585 proto_tree_add_text(tree, tvb, offset+24, 4,
586 "Output interface: ifIndex %u",
587 g_ntohl(flow_header.output) & 0x00ffffff);
588 offset += sizeof(flow_header);
590 /* what kind of flow sample is it? */
591 packet_type = tvb_get_ntohl(tvb, offset);
592 proto_tree_add_uint(tree, hf_sflow_packet_information_type, tvb, offset,
595 switch (packet_type) {
596 case SFLOW_PACKET_DATA_TYPE_HEADER:
597 offset = dissect_sflow_sampled_header(tvb, pinfo, tree, offset);
599 case SFLOW_PACKET_DATA_TYPE_IPV4:
600 case SFLOW_PACKET_DATA_TYPE_IPV6:
604 /* still need to dissect extended data */
605 extended_data = tvb_get_ntohl(tvb,offset);
608 for (i=0; i < extended_data; i++) {
609 /* figure out what kind of extended data it is */
610 ext_type = tvb_get_ntohl(tvb,offset);
612 /* create a subtree. Might want to move this to
613 * the end, so more info can be correct.
615 ti = proto_tree_add_text(tree, tvb, offset, -1, "%s",
617 sflow_extended_data_types,
618 "Unknown extended information"));
619 extended_data_tree = proto_item_add_subtree(ti, ett_sflow_extended_data);
620 proto_tree_add_uint(extended_data_tree,
621 hf_sflow_extended_information_type, tvb, offset, 4,
626 case SFLOW_EXTENDED_SWITCH:
627 offset += dissect_sflow_extended_switch(tvb, extended_data_tree,
630 case SFLOW_EXTENDED_ROUTER:
631 offset += dissect_sflow_extended_router(tvb, extended_data_tree,
634 case SFLOW_EXTENDED_GATEWAY:
636 case SFLOW_EXTENDED_USER:
638 case SFLOW_EXTENDED_URL:
643 proto_item_set_end(ti, tvb, offset);
649 /* dissect a counters sample */
651 dissect_sflow_counters_sample(tvbuff_t *tvb, proto_tree *tree,
652 gint offset, proto_item *parent)
654 struct sflow_counters_sample_header counters_header;
655 struct if_counters ifc;
656 struct ethernet_counters ethc;
657 struct token_ring_counters tokc;
658 struct vg_counters vgc;
659 struct vlan_counters vlanc;
661 /* grab the flow header. This will remain in network byte
662 order, so must convert each item before use */
663 tvb_memcpy(tvb,(guint8 *)&counters_header,offset,sizeof(counters_header));
664 proto_tree_add_text(tree, tvb, offset, 4,
665 "Sequence number: %u",
666 g_ntohl(counters_header.sequence_number));
667 proto_item_append_text(parent, ", seq %u",
668 g_ntohl(counters_header.sequence_number));
669 proto_tree_add_text(tree, tvb, offset + 4, 4,
670 "Source ID class: %u index: %u",
671 g_ntohl(counters_header.source_id) >> 24,
672 g_ntohl(counters_header.source_id) & 0x00ffffff);
673 proto_tree_add_text(tree, tvb, offset + 8, 4,
674 "Sampling Interval: %u",
675 g_ntohl(counters_header.sampling_interval));
676 proto_tree_add_text(tree, tvb, offset + 12, 4, "Counters type: %s",
677 val_to_str(g_ntohl(counters_header.counters_type),
678 sflow_counterstype, "Unknown type"));
680 offset += sizeof(counters_header);
682 /* most counters types have the "generic" counters first */
683 switch (g_ntohl(counters_header.counters_type)) {
684 case SFLOW_COUNTERS_GENERIC:
685 case SFLOW_COUNTERS_ETHERNET:
686 case SFLOW_COUNTERS_TOKENRING:
687 case SFLOW_COUNTERS_FDDI:
688 case SFLOW_COUNTERS_VG:
689 case SFLOW_COUNTERS_WAN:
690 tvb_memcpy(tvb,(guint8 *)&ifc, offset, sizeof(ifc));
691 proto_item_append_text(parent, ", ifIndex %u",
692 g_ntohl(ifc.ifIndex));
693 proto_tree_add_item(tree, hf_sflow_ifindex, tvb, offset, 4, FALSE);
695 proto_tree_add_item(tree, hf_sflow_iftype, tvb, offset, 4, FALSE);
697 proto_tree_add_item(tree, hf_sflow_ifspeed, tvb, offset, 8, FALSE);
699 proto_tree_add_item(tree, hf_sflow_ifdirection, tvb, offset,
702 proto_tree_add_item(tree, hf_sflow_ifstatus, tvb, offset, 4, FALSE);
704 proto_tree_add_item(tree, hf_sflow_ifinoct, tvb, offset, 8, FALSE);
706 proto_tree_add_item(tree, hf_sflow_ifinpkt, tvb, offset, 4, FALSE);
708 proto_tree_add_item(tree, hf_sflow_ifinmcast, tvb, offset,
711 proto_tree_add_item(tree, hf_sflow_ifinbcast, tvb, offset,
714 proto_tree_add_item(tree, hf_sflow_ifindisc, tvb, offset,
717 proto_tree_add_item(tree, hf_sflow_ifinerr, tvb, offset,
720 proto_tree_add_item(tree, hf_sflow_ifinunk, tvb, offset,
723 proto_tree_add_item(tree, hf_sflow_ifoutoct, tvb, offset, 8, FALSE);
725 proto_tree_add_item(tree, hf_sflow_ifoutpkt, tvb, offset, 4, FALSE);
727 proto_tree_add_item(tree, hf_sflow_ifoutmcast, tvb, offset,
730 proto_tree_add_item(tree, hf_sflow_ifoutbcast, tvb, offset,
733 proto_tree_add_item(tree, hf_sflow_ifoutdisc, tvb, offset,
736 proto_tree_add_item(tree, hf_sflow_ifouterr, tvb, offset,
739 proto_tree_add_item(tree, hf_sflow_ifpromisc, tvb, offset,
745 /* Some counter types have other info to gather */
746 switch (g_ntohl(counters_header.counters_type)) {
747 case SFLOW_COUNTERS_ETHERNET:
748 tvb_memcpy(tvb,(guint8 *)ðc, offset, sizeof(ethc));
749 offset += sizeof(ethc);
751 case SFLOW_COUNTERS_TOKENRING:
752 tvb_memcpy(tvb,(guint8 *)&tokc, offset, sizeof(tokc));
753 offset += sizeof(tokc);
755 case SFLOW_COUNTERS_VG:
756 tvb_memcpy(tvb,(guint8 *)&vgc, offset, sizeof(vgc));
757 offset += sizeof(vgc);
759 case SFLOW_COUNTERS_VLAN:
760 tvb_memcpy(tvb,(guint8 *)&vlanc, offset, sizeof(vlanc));
761 offset += sizeof(vlanc);
769 /* Code to dissect the sflow samples */
771 dissect_sflow_samples(tvbuff_t *tvb, packet_info *pinfo,
772 proto_tree *tree, gint offset)
774 proto_tree *sflow_sample_tree;
775 proto_item *ti; /* tree item */
778 /* decide what kind of sample it is. */
779 sample_type = tvb_get_ntohl(tvb,offset);
781 ti = proto_tree_add_text(tree, tvb, offset, -1, "%s",
782 val_to_str(sample_type, sflow_sampletype,
783 "Unknown sample type"));
784 sflow_sample_tree = proto_item_add_subtree(ti, ett_sflow_sample);
786 proto_tree_add_item(sflow_sample_tree, hf_sflow_sampletype, tvb,
790 switch (sample_type) {
792 offset = dissect_sflow_flow_sample(tvb, pinfo, sflow_sample_tree,
796 offset = dissect_sflow_counters_sample(tvb, sflow_sample_tree,
802 proto_item_set_end(ti, tvb, offset);
806 /* Code to actually dissect the packets */
808 dissect_sflow(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
811 /* Set up structures needed to add the protocol subtree and manage it */
813 proto_tree *sflow_tree;
814 guint32 version, sub_agent_id, seqnum;
815 guint32 agent_address_type;
821 volatile guint offset=0;
824 /* Make entries in Protocol column and Info column on summary display */
825 if (check_col(pinfo->cinfo, COL_PROTOCOL))
826 col_set_str(pinfo->cinfo, COL_PROTOCOL, "sFlow");
829 /* create display subtree for the protocol */
830 ti = proto_tree_add_item(tree, proto_sflow, tvb, 0, -1, FALSE);
832 sflow_tree = proto_item_add_subtree(ti, ett_sflow);
834 version = tvb_get_ntohl(tvb, offset);
835 if (check_col(pinfo->cinfo, COL_INFO))
836 col_add_fstr(pinfo->cinfo, COL_INFO, "V%u",
838 proto_tree_add_item(sflow_tree,
839 hf_sflow_version, tvb, offset, 4, FALSE);
842 agent_address_type = tvb_get_ntohl(tvb, offset);
844 switch (agent_address_type) {
846 tvb_memcpy(tvb, agent_address.v4, offset, 4);
847 if (check_col(pinfo->cinfo, COL_INFO))
848 col_append_fstr(pinfo->cinfo, COL_INFO, ", agent %s",
849 ip_to_str(agent_address.v4));
850 proto_tree_add_item(sflow_tree,
851 hf_sflow_agent_address_v4, tvb, offset,
856 tvb_memcpy(tvb, agent_address.v6, offset, 16);
857 if (check_col(pinfo->cinfo, COL_INFO))
858 col_append_fstr(pinfo->cinfo, COL_INFO, ", agent %s",
859 ip6_to_str((struct e_in6_addr *)agent_address.v6));
860 proto_tree_add_item(sflow_tree,
861 hf_sflow_agent_address_v6, tvb, offset,
867 /* unknown address. this will cause a malformed packet. */
872 sub_agent_id = tvb_get_ntohl(tvb, offset);
873 if (check_col(pinfo->cinfo, COL_INFO))
874 col_append_fstr(pinfo->cinfo, COL_INFO, ", sub-agent ID %u",
876 proto_tree_add_uint(sflow_tree, hf_sflow_sub_agent_id, tvb,
877 offset, 4, sub_agent_id);
880 seqnum = tvb_get_ntohl(tvb, offset);
881 if (check_col(pinfo->cinfo, COL_INFO))
882 col_append_fstr(pinfo->cinfo, COL_INFO, ", seq %u", seqnum);
883 proto_tree_add_uint(sflow_tree, hf_sflow_seqnum, tvb,
886 proto_tree_add_item(sflow_tree, hf_sflow_sysuptime, tvb,
889 numsamples = tvb_get_ntohl(tvb,offset);
890 if (check_col(pinfo->cinfo, COL_INFO))
891 col_append_fstr(pinfo->cinfo, COL_INFO, ", %u samples",
893 proto_tree_add_uint(sflow_tree, hf_sflow_numsamples, tvb,
894 offset, 4, numsamples);
897 /* Ok, we're now at the end of the sflow datagram header;
898 * everything from here out should be samples. Loop over
899 * the expected number of samples, and pass them to the appropriate
903 proto_tree_add_text(sflow_tree, tvb, offset, -1,
904 "sFlow V5 samples (please write and contribute code to dissect them!)");
906 for (i=0; i < numsamples; i++) {
907 offset = dissect_sflow_samples(tvb, pinfo, sflow_tree,
912 return tvb_length(tvb);
917 sflow_delete_callback(guint32 port)
920 dissector_delete("udp.port", port, sflow_handle);
924 sflow_add_callback(guint32 port)
927 dissector_add("udp.port", port, sflow_handle);
936 range_foreach(sflow_ports, sflow_delete_callback);
940 sflow_ports = range_copy(global_sflow_ports);
942 range_foreach(sflow_ports, sflow_add_callback);
946 /* Register the protocol with Wireshark */
948 /* this format is require because a script is used to build the C function
949 that calls all the protocol registration.
953 proto_register_sflow(void)
955 module_t *sflow_module;
957 /* Setup list of header fields See Section 1.6.1 for details*/
958 static hf_register_info hf[] = {
960 { "datagram version", "sflow.version",
961 FT_UINT32, BASE_DEC, NULL, 0x0,
962 "sFlow datagram version", HFILL }
964 { &hf_sflow_agent_address_v4,
965 { "agent address", "sflow.agent",
966 FT_IPv4, BASE_NONE, NULL, 0x0,
967 "sFlow Agent IP address", HFILL }
969 { &hf_sflow_agent_address_v6,
970 { "agent address", "sflow.agent.v6",
971 FT_IPv6, BASE_NONE, NULL, 0x0,
972 "sFlow Agent IPv6 address", HFILL }
974 { &hf_sflow_sub_agent_id,
975 { "Sub-agent ID", "sflow.sub_agent_id",
976 FT_UINT32, BASE_DEC, NULL, 0x0,
977 "sFlow sub-agent ID", HFILL }
980 { "Sequence number", "sflow.sequence_number",
981 FT_UINT32, BASE_DEC, NULL, 0x0,
982 "sFlow datagram sequence number", HFILL }
984 { &hf_sflow_sysuptime,
985 { "SysUptime", "sflow.sysuptime",
986 FT_UINT32, BASE_DEC, NULL, 0x0,
987 "System Uptime", HFILL }
989 { &hf_sflow_numsamples,
990 { "NumSamples", "sflow.numsamples",
991 FT_UINT32, BASE_DEC, NULL, 0x0,
992 "Number of samples in sFlow datagram", HFILL }
994 { &hf_sflow_sampletype,
995 { "sFlow sample type", "sflow.sampletype",
996 FT_UINT32, BASE_DEC, VALS(sflow_sampletype), 0x0,
997 "Type of sFlow sample", HFILL }
999 { &hf_sflow_header_protocol,
1000 { "Header protocol", "sflow.header_protocol",
1001 FT_UINT32, BASE_DEC, VALS(sflow_header_protocol), 0x0,
1002 "Protocol of sampled header", HFILL }
1005 { "Header of sampled packet", "sflow.header",
1006 FT_BYTES, BASE_HEX, NULL, 0x0,
1007 "Data from sampled header", HFILL }
1009 { &hf_sflow_packet_information_type,
1010 { "Sample type", "sflow.packet_information_type",
1011 FT_UINT32, BASE_DEC, VALS(sflow_packet_information_type), 0x0,
1012 "Type of sampled information", HFILL }
1014 { &hf_sflow_extended_information_type,
1015 { "Extended information type", "sflow.extended_information_type",
1016 FT_UINT32, BASE_DEC, VALS(sflow_extended_data_types), 0x0,
1017 "Type of extended information", HFILL }
1019 { &hf_sflow_vlan_in,
1020 { "Incoming 802.1Q VLAN", "sflow.vlan.in",
1021 FT_UINT32, BASE_DEC, NULL, 0x0,
1022 "Incoming VLAN ID", HFILL }
1024 { &hf_sflow_vlan_out,
1025 { "Outgoing 802.1Q VLAN", "sflow.vlan.out",
1026 FT_UINT32, BASE_DEC, NULL, 0x0,
1027 "Outgoing VLAN ID", HFILL }
1030 { "Incoming 802.1p priority", "sflow.pri.in",
1031 FT_UINT32, BASE_DEC, NULL, 0x0,
1032 "Incoming 802.1p priority", HFILL }
1034 { &hf_sflow_pri_out,
1035 { "Outgoing 802.1p priority", "sflow.pri.out",
1036 FT_UINT32, BASE_DEC, NULL, 0x0,
1037 "Outgoing 802.1p priority", HFILL }
1039 { &hf_sflow_nexthop_v4,
1040 { "Next hop", "sflow.nexthop",
1041 FT_IPv4, BASE_DEC, NULL, 0x0,
1042 "Next hop address", HFILL }
1044 { &hf_sflow_nexthop_v6,
1045 { "Next hop", "sflow.nexthop",
1046 FT_IPv6, BASE_HEX, NULL, 0x0,
1047 "Next hop address", HFILL }
1049 { &hf_sflow_nexthop_src_mask,
1050 { "Next hop source mask", "sflow.nexthop.src_mask",
1051 FT_UINT32, BASE_DEC, NULL, 0x0,
1052 "Next hop source mask bits", HFILL }
1054 { &hf_sflow_nexthop_dst_mask,
1055 { "Next hop destination mask", "sflow.nexthop.dst_mask",
1056 FT_UINT32, BASE_DEC, NULL, 0x0,
1057 "Next hop destination mask bits", HFILL }
1059 { &hf_sflow_ifindex,
1060 { "Interface index", "sflow.ifindex",
1061 FT_UINT32, BASE_DEC, NULL, 0x0,
1062 "Interface Index", HFILL }
1065 { "Interface Type", "sflow.iftype",
1066 FT_UINT32, BASE_DEC, NULL, 0x0,
1067 "Interface Type", HFILL }
1069 { &hf_sflow_ifspeed,
1070 { "Interface Speed", "sflow.ifspeed",
1071 FT_UINT64, BASE_DEC, NULL, 0x0,
1072 "Interface Speed", HFILL }
1074 { &hf_sflow_ifdirection,
1075 { "Interface Direction", "sflow.ifdirection",
1076 FT_UINT32, BASE_DEC, NULL, 0x0,
1077 "Interface Direction", HFILL }
1079 { &hf_sflow_ifstatus,
1080 { "Interface Status", "sflow.ifstatus",
1081 FT_UINT32, BASE_DEC, NULL, 0x0,
1082 "Interface Status", HFILL }
1084 { &hf_sflow_ifinoct,
1085 { "Input Octets", "sflow.ifinoct",
1086 FT_UINT64, BASE_DEC, NULL, 0x0,
1087 "Interface Input Octets", HFILL }
1089 { &hf_sflow_ifinpkt,
1090 { "Input Packets", "sflow.ifinpkt",
1091 FT_UINT32, BASE_DEC, NULL, 0x0,
1092 "Interface Input Packets", HFILL }
1094 { &hf_sflow_ifinmcast,
1095 { "Input Multicast Packets", "sflow.ifinmcast",
1096 FT_UINT32, BASE_DEC, NULL, 0x0,
1097 "Interface Input Multicast Packets", HFILL }
1099 { &hf_sflow_ifinbcast,
1100 { "Input Broadcast Packets", "sflow.ifinbcast",
1101 FT_UINT32, BASE_DEC, NULL, 0x0,
1102 "Interface Input Broadcast Packets", HFILL }
1104 { &hf_sflow_ifindisc,
1105 { "Input Discarded Packets", "sflow.ifindisc",
1106 FT_UINT32, BASE_DEC, NULL, 0x0,
1107 "Interface Input Discarded Packets", HFILL }
1109 { &hf_sflow_ifinerr,
1110 { "Input Errors", "sflow.ifinerr",
1111 FT_UINT32, BASE_DEC, NULL, 0x0,
1112 "Interface Input Errors", HFILL }
1114 { &hf_sflow_ifinunk,
1115 { "Input Unknown Protocol Packets", "sflow.ifinunk",
1116 FT_UINT32, BASE_DEC, NULL, 0x0,
1117 "Interface Input Unknown Protocol Packets", HFILL }
1119 { &hf_sflow_ifoutoct,
1120 { "Output Octets", "sflow.ifoutoct",
1121 FT_UINT64, BASE_DEC, NULL, 0x0,
1122 "Outterface Output Octets", HFILL }
1124 { &hf_sflow_ifoutpkt,
1125 { "Output Packets", "sflow.ifoutpkt",
1126 FT_UINT32, BASE_DEC, NULL, 0x0,
1127 "Interface Output Packets", HFILL }
1129 { &hf_sflow_ifoutmcast,
1130 { "Output Multicast Packets", "sflow.ifoutmcast",
1131 FT_UINT32, BASE_DEC, NULL, 0x0,
1132 "Interface Output Multicast Packets", HFILL }
1134 { &hf_sflow_ifoutbcast,
1135 { "Output Broadcast Packets", "sflow.ifoutbcast",
1136 FT_UINT32, BASE_DEC, NULL, 0x0,
1137 "Interface Output Broadcast Packets", HFILL }
1139 { &hf_sflow_ifoutdisc,
1140 { "Output Discarded Packets", "sflow.ifoutdisc",
1141 FT_UINT32, BASE_DEC, NULL, 0x0,
1142 "Interface Output Discarded Packets", HFILL }
1144 { &hf_sflow_ifouterr,
1145 { "Output Errors", "sflow.ifouterr",
1146 FT_UINT32, BASE_DEC, NULL, 0x0,
1147 "Interface Output Errors", HFILL }
1149 { &hf_sflow_ifpromisc,
1150 { "Promiscuous Mode", "sflow.ifpromisc",
1151 FT_UINT32, BASE_DEC, NULL, 0x0,
1152 "Interface Promiscuous Mode", HFILL }
1156 /* Setup protocol subtree array */
1157 static gint *ett[] = {
1160 &ett_sflow_extended_data,
1161 &ett_sflow_sampled_header,
1164 /* Register the protocol name and description */
1165 proto_sflow = proto_register_protocol("InMon sFlow",
1168 /* Required function calls to register the header fields and subtrees used */
1169 proto_register_field_array(proto_sflow, hf, array_length(hf));
1170 proto_register_subtree_array(ett, array_length(ett));
1172 /* Register our configuration options for sFlow */
1173 sflow_module = prefs_register_protocol(proto_sflow,
1174 proto_reg_handoff_sflow);
1176 /* Set default Neflow port(s) */
1177 range_convert_str(&global_sflow_ports, SFLOW_UDP_PORTS,
1180 prefs_register_obsolete_preference(sflow_module, "udp.port");
1182 prefs_register_range_preference(sflow_module, "ports",
1183 "sFlow UDP Port(s)",
1184 "Set the port(s) for sFlow messages"
1185 " (default: " SFLOW_UDP_PORTS ")",
1186 &global_sflow_ports, MAX_UDP_PORT);
1189 If I use a filter like "ip.src == 10.1.1.1" this will, in
1190 addition to the usual suspects, find every sFlow packet
1191 where *any* of the payload headers contain 10.1.1.1 as a
1192 src addr. I think this may not be the desired behavior.
1193 It can certainly be confusing since the ip.src being found
1194 is buried about 3 subtrees deep and the subtrees might be
1195 under any one of the sampled (payload) header trees. It is
1196 certainly not quickly obvious why the filter matched.
1198 prefs_register_bool_preference(sflow_module, "enable_dissection",
1199 "Dissect data in sampled headers",
1200 "Enabling dissection makes it easy to view protocol details in each of the sampled headers. Disabling dissection may reduce noise caused when display filters match the contents of any sampled header(s).",
1201 &global_dissect_samp_headers);
1203 It is not clear to me that it *ever* makes sense to enable
1204 this option. However, it was previously the default
1205 behavior so I'll leave it as an option if someone thinks
1206 they have a use for it.
1208 prefs_register_bool_preference(sflow_module, "enable_analysis",
1209 "Analyze data in sampled IP headers",
1210 "This option only makes sense if dissection of sampled headers is enabled and probably not even then.",
1211 &global_analyze_samp_ip_headers );
1214 register_init_routine(&sflow_reinit);
1218 /* If this dissector uses sub-dissector registration add a
1219 registration routine. This format is required because a script is
1220 used to find these routines and create the code that calls these
1224 proto_reg_handoff_sflow(void)
1226 static int sflow_prefs_initialized = FALSE;
1227 if (!sflow_prefs_initialized) {
1228 sflow_handle = new_create_dissector_handle(dissect_sflow,
1231 sflow_prefs_initialized = TRUE;
1237 /*dissector_handle_t sflow_handle;*/
1240 * XXX - should this be done with a dissector table?
1242 data_handle = find_dissector("data");
1244 if (global_dissect_samp_headers) {
1245 eth_withoutfcs_handle = find_dissector("eth_withoutfcs");
1246 tr_handle = find_dissector("tr");
1247 fddi_handle = find_dissector("fddi");
1248 fr_handle = find_dissector("fr");
1249 x25_handle = find_dissector("x.25");
1250 ppp_handle = find_dissector("ppp");
1252 smds_handle = find_dissector("smds");
1254 /* We don't have an SMDS dissector yet */
1255 smds_handle = data_handle;
1258 aal5_handle = find_dissector("atm");
1260 /* What dissector should be used here? */
1261 aal5_handle = data_handle;
1263 ipv4_handle = find_dissector("ip");
1264 ipv6_handle = find_dissector("ipv6");
1265 mpls_handle = find_dissector("mpls");
1267 eth_withoutfcs_handle = data_handle;
1268 tr_handle = data_handle;
1269 fddi_handle = data_handle;
1270 fr_handle = data_handle;
1271 x25_handle = data_handle;
1272 ppp_handle = data_handle;
1273 smds_handle = data_handle;
1274 aal5_handle = data_handle;
1275 ipv4_handle = data_handle;
1276 ipv6_handle = data_handle;
1277 mpls_handle = data_handle;