As per a patch from Lars Roland, make RC_VERSION comma-separated.
[obnox/wireshark/wip.git] / packet-sflow.c
1 /* packet-sflow.c
2  * Routines for sFlow dissection
3  * Copyright 2003, Jeff Rizzo <riz@boogers.sf.ca.us>
4  *
5  * $Id: packet-sflow.c,v 1.1 2003/06/13 22:31:11 guy Exp $
6  *
7  * Ethereal - Network traffic analyzer
8  * By Gerald Combs <gerald@ethereal.com>
9  * Copyright 1998 Gerald Combs
10  * 
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.
15  * 
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.
20  * 
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.
24  */
25
26 /* This file (mostly) implements a dissector for sFlow (RFC3176), 
27  * from the version 4 spec at http://www.sflow.org/SFLOW-DATAGRAM.txt . 
28  *
29  * TODO:
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
40  */
41
42 #ifdef HAVE_CONFIG_H
43 # include "config.h"
44 #endif
45
46 #include <stdio.h>
47 #include <stdlib.h>
48 #include <string.h>
49
50 #include <glib.h>
51
52 #ifdef NEED_SNPRINTF_H
53 # include "snprintf.h"
54 #endif
55
56 #include <epan/packet.h>
57 /*#include "packet-sflow.h"*/
58
59 #define UDP_PORT_SFLOW 6343
60
61 #define ADDRESS_IPV4 1
62 #define ADDRESS_IPV6 2
63
64 #define FLOWSAMPLE 1
65 #define COUNTERSSAMPLE 2
66
67 static const value_string sflow_sampletype[] = {
68         { FLOWSAMPLE, "Flow sample" },
69         { COUNTERSSAMPLE, "Counters sample" },
70         { 0, NULL }
71 };
72
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
81
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" },
89         { 0, NULL }
90 };
91
92 #define MAX_HEADER_SIZE 256
93
94 #define SFLOW_PACKET_DATA_TYPE_HEADER 1
95 #define SFLOW_PACKET_DATA_TYPE_IPV4 2
96 #define SFLOW_PACKET_DATA_TYPE_IPV6 3
97
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" },
102         { 0, NULL}
103 };
104
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
118
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" },
133         { 0, NULL }
134 };
135
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
142
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" },     
149         { 0, NULL }
150 };
151
152
153 /* flow sample header */
154 struct sflow_flow_sample_header {
155         guint32         sequence_number;
156         guint32         source_id;
157         guint32         sampling_rate;
158         guint32         sample_pool;
159         guint32         drops;
160         guint32         input;
161         guint32         output;
162 };
163
164 /* counters sample header */
165 struct sflow_counters_sample_header {
166         guint32         sequence_number;
167         guint32         source_id;
168         guint32         sampling_interval;
169         guint32     counters_type;
170 };
171
172 /* generic interface counters */
173 struct if_counters {
174         guint32         ifIndex;
175         guint32         ifType;
176         guint64         ifSpeed;
177         guint32         ifDirection;
178         guint32         ifStatus;
179         guint64         ifInOctets;
180         guint32         ifInUcastPkts;
181         guint32         ifInMulticastPkts;
182         guint32         ifInBroadcastPkts;
183         guint32         ifInDiscards;
184         guint32         ifInErrors;
185         guint32         ifInUnknownProtos;
186         guint64         ifOutOctets;
187         guint32         ifOutUcastPkts;
188         guint32         ifOutMulticastPkts;
189         guint32         ifOutBroadcastPkts;
190         guint32         ifOutDiscards;
191         guint32         ifOutErrors;
192         guint32         ifPromiscuousMode;
193 };
194
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;
210 };
211
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;
232 };
233
234 /* 100BaseVG counters */
235
236 struct vg_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;
251 };
252
253 /* VLAN counters */
254
255 struct vlan_counters {
256         guint32         vlan_id;
257         guint32         octets;
258         guint32         ucastPkts;
259         guint32         multicastPkts;
260         guint32         broadcastPkts;
261         guint32         discards;
262 };
263
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;
302
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;
308
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;
321
322 /* dissect a sampled header - layer 2 protocols */
323 static gint
324 dissect_sflow_sampled_header(tvbuff_t *tvb, packet_info *pinfo,
325                                                          proto_tree *tree, volatile gint offset)
326 {
327         guint32         header_proto, frame_length;
328         volatile        guint32         header_length;
329         tvbuff_t        *next_tvb;
330         proto_tree      *sflow_header_tree;
331         proto_item      *ti;
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;
341
342         header_proto = tvb_get_ntohl(tvb,offset);
343         proto_tree_add_item(tree, hf_sflow_header_protocol, tvb, offset,
344                                                 4, FALSE);
345         offset += 4;
346         frame_length = tvb_get_ntohl(tvb,offset);
347         proto_tree_add_text(tree, tvb, offset, 4, "Frame Length: %d bytes",
348                                                 frame_length);
349         offset += 4;
350         header_length = tvb_get_ntohl(tvb,offset);
351         offset += 4;
352
353         if (header_length % 4) /* XDR requires 4-byte alignment */
354                 header_length += 4 - (header_length % 4);
355
356         
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);
360
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);
364
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;
374
375         TRY {
376                 switch (header_proto) {
377                 case SFLOW_HEADER_ETHERNET:
378                         call_dissector(eth_handle, next_tvb, pinfo, sflow_header_tree);
379                         break;
380                 case SFLOW_HEADER_TOKENRING:
381                         call_dissector(tr_handle, next_tvb, pinfo, sflow_header_tree);
382                         break;
383                 case SFLOW_HEADER_FDDI:
384                         call_dissector(fddi_handle, next_tvb, pinfo, sflow_header_tree);
385                         break;
386                 case SFLOW_HEADER_FRAME_RELAY:
387                         call_dissector(fr_handle, next_tvb, pinfo, sflow_header_tree);
388                         break;
389                 case SFLOW_HEADER_X25:
390                         call_dissector(x25_handle, next_tvb, pinfo, sflow_header_tree);
391                         break;
392                 case SFLOW_HEADER_PPP:
393                         call_dissector(ppp_handle, next_tvb, pinfo, sflow_header_tree);
394                         break;
395                 case SFLOW_HEADER_SMDS:
396                         call_dissector(smds_handle, next_tvb, pinfo, sflow_header_tree);
397                         break;
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);
403                         break;
404                 case SFLOW_HEADER_IPv4:
405                         call_dissector(ipv4_handle, next_tvb, pinfo, sflow_header_tree);
406                         break;
407                 case SFLOW_HEADER_IPv6:
408                         call_dissector(ipv6_handle, next_tvb, pinfo, sflow_header_tree);
409                         break;
410                 case SFLOW_HEADER_MPLS:
411                         call_dissector(mpls_handle, next_tvb, pinfo, sflow_header_tree);
412                         break;
413                 default:
414                         /* some of the protocols, I have no clue where to begin. */
415                         break;
416                 };
417         }
418         CATCH2(BoundsError, ReportedBoundsError) {
419                 ; /* do nothing */
420         }
421         ENDTRY;
422
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;
431         
432         offset += header_length;
433         return offset;
434 }
435
436 /* extended switch data, after the packet data */
437 static gint
438 dissect_sflow_extended_switch(tvbuff_t *tvb, proto_tree *tree, gint offset)
439 {
440         gint32 len = 0;
441         
442         proto_tree_add_item(tree, hf_sflow_vlan_in, tvb, offset + len, 4, FALSE);
443         len += 4;
444         proto_tree_add_item(tree, hf_sflow_vlan_out, tvb, offset + len, 4, FALSE);
445         len += 4;
446         proto_tree_add_item(tree, hf_sflow_pri_in, tvb, offset + len, 4, FALSE);
447         len += 4;
448         proto_tree_add_item(tree, hf_sflow_pri_out, tvb, offset + len, 4, FALSE);
449         len += 4;
450
451         return len;
452 }
453
454 /* extended router data, after the packet data */
455 static gint
456 dissect_sflow_extended_router(tvbuff_t *tvb, proto_tree *tree, gint offset)
457 {
458         gint32  len = 0;
459         guint32 address_type, mask_bits;
460
461         address_type = tvb_get_ntohl(tvb, offset);
462         switch (address_type) {
463         case ADDRESS_IPV4:
464                 proto_tree_add_ipv4(tree, hf_sflow_nexthop_v4, tvb, offset + len,
465                                                         8, FALSE);
466                 len += 8;
467                 break;
468         case ADDRESS_IPV6:
469                 proto_tree_add_ipv6(tree, hf_sflow_nexthop_v6, tvb, offset + len,
470                                                         20, FALSE);
471                 len += 20;
472                 break;
473         default:
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... ? */
478                 break;
479         };
480         
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);
484         len += 4;
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", 
488                                                 mask_bits);
489         len += 4;
490         return len;
491 }
492
493 /* dissect a flow sample */
494 static gint
495 dissect_sflow_flow_sample(tvbuff_t *tvb, packet_info *pinfo,
496                                                   proto_tree *tree, gint offset, proto_item *parent)
497 {
498         struct sflow_flow_sample_header         flow_header;
499         proto_tree      *sflow_sample_tree;
500         proto_item *ti;
501         guint32         packet_type, extended_data, ext_type, i;
502
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);
531         else 
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);
536
537         /* what kind of flow sample is it? */
538         packet_type = tvb_get_ntohl(tvb, offset);
539         offset += 4;
540         switch (packet_type) {
541         case SFLOW_PACKET_DATA_TYPE_HEADER:
542                 offset = dissect_sflow_sampled_header(tvb, pinfo, tree, offset);
543                 break;
544         case SFLOW_PACKET_DATA_TYPE_IPV4:
545         case SFLOW_PACKET_DATA_TYPE_IPV6:
546         default:
547         };
548         /* still need to dissect extended data */
549         extended_data = tvb_get_ntohl(tvb,offset);
550         offset += 4; 
551
552         for (i=0; i < extended_data; i++) {
553                 /* figure out what kind of extended data it is */
554                 ext_type = tvb_get_ntohl(tvb,offset);
555
556                 /* create a subtree.  Might want to move this to
557                  * the end, so more info can be correct.
558                  */
559                 ti = proto_tree_add_text(tree, tvb, offset, 4, "%s",
560                                                                  val_to_str(ext_type, 
561                                                                                         sflow_extended_data_types,
562                                                                                         "Unknown extended information"));
563                 offset += 4;
564                 sflow_sample_tree = proto_item_add_subtree(ti, ett_sflow_sample);
565
566                 switch (ext_type) {
567                 case SFLOW_EXTENDED_SWITCH:
568                         offset += dissect_sflow_extended_switch(tvb, sflow_sample_tree,
569                                                                                                         offset);
570                         break;
571                 case SFLOW_EXTENDED_ROUTER:
572                         offset += dissect_sflow_extended_router(tvb, sflow_sample_tree,
573                                                                                                         offset);
574                         break;
575                 case SFLOW_EXTENDED_GATEWAY:
576                         break;
577                 case SFLOW_EXTENDED_USER:
578                         break;
579                 case SFLOW_EXTENDED_URL:
580                         break;
581                 default:
582                         break;
583                 }       
584         }
585         return offset;
586         
587 }
588
589 /* dissect a counters sample */
590 static gint
591 dissect_sflow_counters_sample(tvbuff_t *tvb, proto_tree *tree,
592                                                           gint offset, proto_item *parent)
593 {
594         struct sflow_counters_sample_header     counters_header;
595         struct if_counters ifc;
596         struct ethernet_counters ethc;
597         struct token_ring_counters tokc;
598         struct vg_counters vgc;
599         struct vlan_counters vlanc;
600         
601         /* grab the flow header.  This will remain in network byte
602            order, so must convert each item before use */
603         tvb_memcpy(tvb,(guint8 *)&counters_header,offset,sizeof(counters_header));
604         proto_tree_add_text(tree, tvb, offset, 4,
605                                                 "Sequence number: %u",
606                                                 g_ntohl(counters_header.sequence_number));
607         proto_item_append_text(parent, ", seq %u",
608                                                    g_ntohl(counters_header.sequence_number));
609         proto_tree_add_text(tree, tvb, offset + 4, 4,
610                                                 "Source ID class: %u index: %u",
611                                                 g_ntohl(counters_header.source_id) >> 24,
612                                                 g_ntohl(counters_header.source_id) & 0x00ffffff);
613         proto_tree_add_text(tree, tvb, offset + 8, 4,
614                                                 "Sampling Interval: %u",
615                                                 g_ntohl(counters_header.sampling_interval));
616         proto_tree_add_text(tree, tvb, offset + 12, 4, "Counters type: %s",
617                                                 val_to_str(g_ntohl(counters_header.counters_type),
618                                                                    sflow_counterstype, "Unknown type"));
619
620         offset += sizeof(counters_header);
621
622         /* most counters types have the "generic" counters first */
623         switch (g_ntohl(counters_header.counters_type)) {
624         case SFLOW_COUNTERS_GENERIC:
625         case SFLOW_COUNTERS_ETHERNET:
626         case SFLOW_COUNTERS_TOKENRING:
627         case SFLOW_COUNTERS_FDDI:
628         case SFLOW_COUNTERS_VG:
629         case SFLOW_COUNTERS_WAN:
630                 tvb_memcpy(tvb,(guint8 *)&ifc, offset, sizeof(ifc));
631                 proto_item_append_text(parent, ", ifIndex %u",
632                                                            g_ntohl(ifc.ifIndex));
633                 proto_tree_add_item(tree, hf_sflow_ifindex, tvb, offset, 4, FALSE);
634                 offset += 4;
635                 proto_tree_add_item(tree, hf_sflow_iftype, tvb, offset, 4, FALSE);
636                 offset += 4;
637                 proto_tree_add_item(tree, hf_sflow_ifspeed, tvb, offset, 8, FALSE);
638                 offset += 8;
639                 proto_tree_add_item(tree, hf_sflow_ifdirection, tvb, offset, 
640                                                         4, FALSE);
641                 offset += 4;
642                 proto_tree_add_item(tree, hf_sflow_ifstatus, tvb, offset, 4, FALSE);
643                 offset += 4;
644                 proto_tree_add_item(tree, hf_sflow_ifinoct, tvb, offset, 8, FALSE);
645                 offset += 8;
646                 proto_tree_add_item(tree, hf_sflow_ifinpkt, tvb, offset, 4, FALSE);
647                 offset += 4;
648                 proto_tree_add_item(tree, hf_sflow_ifinmcast, tvb, offset,
649                                                         4, FALSE);
650                 offset += 4;
651                 proto_tree_add_item(tree, hf_sflow_ifinbcast, tvb, offset,
652                                                         4, FALSE);
653                 offset += 4;
654                 proto_tree_add_item(tree, hf_sflow_ifindisc, tvb, offset,
655                                                         4, FALSE);
656                 offset += 4;
657                 proto_tree_add_item(tree, hf_sflow_ifinerr, tvb, offset,
658                                                         4, FALSE);
659                 offset += 4;
660                 proto_tree_add_item(tree, hf_sflow_ifinunk, tvb, offset,
661                                                         4, FALSE);
662                 offset += 4;
663                 proto_tree_add_item(tree, hf_sflow_ifoutoct, tvb, offset, 8, FALSE);
664                 offset += 8;
665                 proto_tree_add_item(tree, hf_sflow_ifoutpkt, tvb, offset, 4, FALSE);
666                 offset += 4;
667                 proto_tree_add_item(tree, hf_sflow_ifoutmcast, tvb, offset,
668                                                         4, FALSE);
669                 offset += 4;
670                 proto_tree_add_item(tree, hf_sflow_ifoutbcast, tvb, offset,
671                                                         4, FALSE);
672                 offset += 4;
673                 proto_tree_add_item(tree, hf_sflow_ifoutdisc, tvb, offset,
674                                                         4, FALSE);
675                 offset += 4;
676                 proto_tree_add_item(tree, hf_sflow_ifouterr, tvb, offset,
677                                                         4, FALSE);
678                 offset += 4;
679                 proto_tree_add_item(tree, hf_sflow_ifpromisc, tvb, offset,
680                                                         4, FALSE);
681                 offset += 4;
682                 break;
683         };
684         
685         /* Some counter types have other info to gather */
686         switch (g_ntohl(counters_header.counters_type)) {
687         case SFLOW_COUNTERS_ETHERNET:
688                 tvb_memcpy(tvb,(guint8 *)&ethc, offset, sizeof(ethc));
689                 offset += sizeof(ethc);
690                 break;
691         case SFLOW_COUNTERS_TOKENRING:
692                 tvb_memcpy(tvb,(guint8 *)&tokc, offset, sizeof(tokc));
693                 offset += sizeof(tokc);
694                 break;
695         case SFLOW_COUNTERS_VG:
696                 tvb_memcpy(tvb,(guint8 *)&vgc, offset, sizeof(vgc));
697                 offset += sizeof(vgc);
698                 break;
699         case SFLOW_COUNTERS_VLAN:
700                 tvb_memcpy(tvb,(guint8 *)&vlanc, offset, sizeof(vlanc));
701                 offset += sizeof(vlanc);
702                 break;
703         default:
704                 break;
705         }
706         return offset;
707 }
708
709 /* Code to dissect the sflow samples */
710 static gint
711 dissect_sflow_samples(tvbuff_t *tvb, packet_info *pinfo,
712                                           proto_tree *tree, gint offset)
713 {
714         proto_tree      *sflow_sample_tree;
715         proto_item      *ti; /* tree item */
716         guint32         sample_type;
717         
718         /* decide what kind of sample it is. */
719         sample_type = tvb_get_ntohl(tvb,offset);
720
721         ti = proto_tree_add_text(tree, tvb, offset, 4, "%s",
722                                                          val_to_str(sample_type, sflow_sampletype,
723                                                                                 "Unknown sample type"));
724         sflow_sample_tree = proto_item_add_subtree(ti, ett_sflow_sample);
725
726         proto_tree_add_item(sflow_sample_tree, hf_sflow_sampletype, tvb,
727                                                 offset, 4, FALSE);
728         offset += 4;
729
730         switch (sample_type) {
731         case FLOWSAMPLE:
732                 return dissect_sflow_flow_sample(tvb, pinfo, sflow_sample_tree,
733                                                                                  offset, ti);
734                 break;
735         case COUNTERSSAMPLE:
736                 return dissect_sflow_counters_sample(tvb, sflow_sample_tree,
737                                                                                          offset, ti);
738                 break;
739         default:
740                 break;
741         };
742         return offset;
743 }
744
745 /* Code to actually dissect the packets */
746 static void
747 dissect_sflow(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
748 {
749
750 /* Set up structures needed to add the protocol subtree and manage it */
751         proto_item *ti;
752         proto_tree *sflow_tree;
753         guint32         version, seqnum;
754         guint32         agent_address_type;
755         union {
756                 guint8  v4[4];
757                 guint8  v6[16];
758         } agent_address;
759         guint32         numsamples;
760         volatile guint          offset=0;
761         guint   i=0;
762
763 /* Make entries in Protocol column and Info column on summary display */
764         if (check_col(pinfo->cinfo, COL_PROTOCOL)) 
765                 col_set_str(pinfo->cinfo, COL_PROTOCOL, "sflow");
766     
767
768         /* create display subtree for the protocol */
769         ti = proto_tree_add_item(tree, proto_sflow, tvb, 0, -1, FALSE);
770         
771         sflow_tree = proto_item_add_subtree(ti, ett_sflow);
772                 
773         version = tvb_get_ntohl(tvb, offset);
774         if (check_col(pinfo->cinfo, COL_INFO)) 
775                 col_add_fstr(pinfo->cinfo, COL_INFO, "sFlow V%u",
776                                          version);
777         proto_tree_add_item(sflow_tree,
778                                                 hf_sflow_version, tvb, offset, 4, FALSE);
779         offset += 4;
780
781         agent_address_type = tvb_get_ntohl(tvb, offset);
782         offset += 4;
783         switch (agent_address_type) {
784         case ADDRESS_IPV4:
785                 tvb_memcpy(tvb, agent_address.v4, offset, 4);
786                 if (check_col(pinfo->cinfo, COL_INFO)) 
787                         col_append_fstr(pinfo->cinfo, COL_INFO, ", agent %s",
788                                                  ip_to_str(agent_address.v4));
789                 proto_tree_add_item(sflow_tree,
790                                                         hf_sflow_agent_address_v4, tvb, offset,
791                                                         4, FALSE);
792                 offset += 4;
793                 break;
794         case ADDRESS_IPV6:
795                 tvb_memcpy(tvb, agent_address.v6, offset, 16);
796                 if (check_col(pinfo->cinfo, COL_INFO)) 
797                         col_append_fstr(pinfo->cinfo, COL_INFO, ", agent %s",
798                                                         ip6_to_str((struct e_in6_addr *)agent_address.v6));
799                 proto_tree_add_item(sflow_tree,
800                                                         hf_sflow_agent_address_v6, tvb, offset,
801                                                         16, FALSE);
802                 offset += 16;
803                 break;
804         default:
805                 /* unknown address.  this will cause a malformed packet.  */
806                 break;
807         };
808
809         seqnum = tvb_get_ntohl(tvb, offset);
810         proto_tree_add_item(sflow_tree, hf_sflow_seqnum, tvb,
811                                                 offset, 4, FALSE);
812         offset += 4;
813         proto_tree_add_item(sflow_tree, hf_sflow_sysuptime, tvb,
814                                                 offset+4, 4, FALSE);
815         offset += 4;
816         numsamples = tvb_get_ntohl(tvb,offset);
817         if (check_col(pinfo->cinfo, COL_INFO)) 
818                 col_append_fstr(pinfo->cinfo, COL_INFO, ", seq %u, %u samples",
819                                                 seqnum, numsamples);
820         proto_tree_add_item(sflow_tree, hf_sflow_numsamples, tvb,
821                                                 offset, 4, FALSE);
822         offset += 4;
823
824         /* Ok, we're now at the end of the sflow datagram header;
825          * everything from here out should be samples. Loop over
826          * the expected number of samples, and pass them to the appropriate
827          * dissectors.
828          */
829         for (i=0; i < numsamples; i++) {
830                 offset = dissect_sflow_samples(tvb, pinfo, sflow_tree, offset);
831         }
832
833 }
834
835
836 /* Register the protocol with Ethereal */
837
838 /* this format is require because a script is used to build the C function
839    that calls all the protocol registration.
840 */
841
842 void
843 proto_register_sflow(void)
844 {                 
845
846 /* Setup list of header fields  See Section 1.6.1 for details*/
847         static hf_register_info hf[] = {
848                 { &hf_sflow_version,
849                         { "datagram version", "sflow.version",
850                         FT_UINT32, BASE_DEC, NULL, 0x0,          
851                         "sFlow datagram version", HFILL }
852                 },
853                 { &hf_sflow_agent_address_v4,
854                         { "agent address", "sflow.agent",
855                         FT_IPv4, BASE_NONE, NULL, 0x0,          
856                         "sFlow Agent IP address", HFILL }
857                 },
858                 { &hf_sflow_agent_address_v6,
859                         { "agent address", "sflow.agent.v6",
860                         FT_IPv6, BASE_NONE, NULL, 0x0,          
861                         "sFlow Agent IPv6 address", HFILL }
862                 },
863                 { &hf_sflow_seqnum,
864                         { "Sequence number", "sflow.sequence_number",
865                         FT_UINT32, BASE_DEC, NULL, 0x0,          
866                         "sFlow datagram sequence number", HFILL }
867                 },
868                 { &hf_sflow_sysuptime,
869                         { "SysUptime", "sflow.sysuptime",
870                         FT_UINT32, BASE_DEC, NULL, 0x0,          
871                         "System Uptime", HFILL }
872                 },
873                 { &hf_sflow_numsamples,
874                         { "NumSamples", "sflow.numsamples",
875                         FT_UINT32, BASE_DEC, NULL, 0x0,          
876                         "Number of samples in sFlow datagram", HFILL }
877                 },
878                 { &hf_sflow_sampletype,
879                         { "sFlow sample type", "sflow.sampletype",
880                         FT_UINT32, BASE_DEC, VALS(sflow_sampletype), 0x0,          
881                         "Type of sFlow sample", HFILL }
882                 },
883                 { &hf_sflow_header_protocol,
884                         { "Header protocol", "sflow.header_protocol",
885                         FT_UINT32, BASE_DEC, VALS(sflow_header_protocol), 0x0,          
886                         "Protocol of sampled header", HFILL }
887                 },
888                 { &hf_sflow_header,
889                         { "Header of sampled packet", "sflow.header",
890                         FT_BYTES, BASE_HEX, NULL, 0x0,          
891                         "Data from sampled header", HFILL }
892                 },
893                 { &hf_sflow_packet_information_type,
894                         { "Sample type", "sflow.packet_information_type",
895                         FT_UINT32, BASE_DEC, VALS(sflow_packet_information_type), 0x0,
896                         "Type of sampled information", HFILL }
897                 },
898                 { &hf_sflow_vlan_in,
899                         { "Incoming 802.1q VLAN", "sflow.vlan.in",
900                         FT_UINT32, BASE_DEC, NULL, 0x0,
901                         "Incoming VLAN ID", HFILL }
902                 },
903                 { &hf_sflow_vlan_out,
904                         { "Outgoing 802.1q VLAN", "sflow.vlan.out",
905                         FT_UINT32, BASE_DEC, NULL, 0x0,
906                         "Outgoing VLAN ID", HFILL }
907                 },
908                 { &hf_sflow_pri_in,
909                         { "Incoming 802.1p priority", "sflow.pri.in",
910                         FT_UINT32, BASE_DEC, NULL, 0x0,
911                         "Incoming 802.1p priority", HFILL }
912                 },
913                 { &hf_sflow_pri_out,
914                         { "Outgoing 802.1p priority", "sflow.pri.out",
915                         FT_UINT32, BASE_DEC, NULL, 0x0,
916                         "Outgoing 802.1p priority", HFILL }
917                 },
918                 { &hf_sflow_nexthop_v4,
919                         { "Next Hop", "sflow.nexthop",
920                         FT_IPv4, BASE_DEC, NULL, 0x0,
921                         "Next Hop address", HFILL }
922                 },
923                 { &hf_sflow_nexthop_v6,
924                         { "Next Hop", "sflow.nexthop",
925                         FT_IPv6, BASE_HEX, NULL, 0x0,
926                         "Next Hop address", HFILL }
927                 },
928                 { &hf_sflow_ifindex,
929                   { "Interface index", "sflow.ifindex",
930                         FT_UINT32, BASE_DEC, NULL, 0x0,
931                         "Interface Index", HFILL }
932                 },
933                 { &hf_sflow_iftype,
934                   { "Interface Type", "sflow.iftype",
935                         FT_UINT32, BASE_DEC, NULL, 0x0,
936                         "Interface Type", HFILL }
937                 },
938                 { &hf_sflow_ifspeed,
939                   { "Interface Speed", "sflow.ifspeed",
940                         FT_UINT64, BASE_DEC, NULL, 0x0,
941                         "Interface Speed", HFILL }
942                 },
943                 { &hf_sflow_ifdirection,
944                   { "Interface Direction", "sflow.ifdirection",
945                         FT_UINT32, BASE_DEC, NULL, 0x0,
946                         "Interface Direction", HFILL }
947                 },
948                 { &hf_sflow_ifstatus,
949                   { "Interface Status", "sflow.ifstatus",
950                         FT_UINT32, BASE_DEC, NULL, 0x0,
951                         "Interface Status", HFILL }
952                 },
953                 { &hf_sflow_ifinoct,
954                   { "Input Octets", "sflow.ifinoct",
955                         FT_UINT64, BASE_DEC, NULL, 0x0,
956                         "Interface Input Octets", HFILL }
957                 },
958                 { &hf_sflow_ifinpkt,
959                   { "Input Packets", "sflow.ifinpkt",
960                         FT_UINT32, BASE_DEC, NULL, 0x0,
961                         "Interface Input Packets", HFILL }
962                 },
963                 { &hf_sflow_ifinmcast,
964                   { "Input Multicast Packets", "sflow.ifinmcast",
965                         FT_UINT32, BASE_DEC, NULL, 0x0,
966                         "Interface Input Multicast Packets", HFILL }
967                 },
968                 { &hf_sflow_ifinbcast,
969                   { "Input Broadcast Packets", "sflow.ifinbcast",
970                         FT_UINT32, BASE_DEC, NULL, 0x0,
971                         "Interface Input Broadcast Packets", HFILL }
972                 },
973                 { &hf_sflow_ifindisc,
974                   { "Input Discarded Packets", "sflow.ifindisc",
975                         FT_UINT32, BASE_DEC, NULL, 0x0,
976                         "Interface Input Discarded Packets", HFILL }
977                 },
978                 { &hf_sflow_ifinerr,
979                   { "Input Errors", "sflow.ifinerr",
980                         FT_UINT32, BASE_DEC, NULL, 0x0,
981                         "Interface Input Errors", HFILL }
982                 },
983                 { &hf_sflow_ifinunk,
984                   { "Input Unknown Protocol Packets", "sflow.ifinunk",
985                         FT_UINT32, BASE_DEC, NULL, 0x0,
986                         "Interface Input Unknown Protocol Packets", HFILL }
987                 },
988                 { &hf_sflow_ifoutoct,
989                   { "Output Octets", "sflow.ifoutoct",
990                         FT_UINT64, BASE_DEC, NULL, 0x0,
991                         "Outterface Output Octets", HFILL }
992                 },
993                 { &hf_sflow_ifoutpkt,
994                   { "Output Packets", "sflow.ifoutpkt",
995                         FT_UINT32, BASE_DEC, NULL, 0x0,
996                         "Interface Output Packets", HFILL }
997                 },
998                 { &hf_sflow_ifoutmcast,
999                   { "Output Multicast Packets", "sflow.ifoutmcast",
1000                         FT_UINT32, BASE_DEC, NULL, 0x0,
1001                         "Interface Output Multicast Packets", HFILL }
1002                 },
1003                 { &hf_sflow_ifoutbcast,
1004                   { "Output Broadcast Packets", "sflow.ifoutbcast",
1005                         FT_UINT32, BASE_DEC, NULL, 0x0,
1006                         "Interface Output Broadcast Packets", HFILL }
1007                 },
1008                 { &hf_sflow_ifoutdisc,
1009                   { "Output Discarded Packets", "sflow.ifoutdisc",
1010                         FT_UINT32, BASE_DEC, NULL, 0x0,
1011                         "Interface Output Discarded Packets", HFILL }
1012                 },
1013                 { &hf_sflow_ifouterr,
1014                   { "Output Errors", "sflow.ifouterr",
1015                         FT_UINT32, BASE_DEC, NULL, 0x0,
1016                         "Interface Output Errors", HFILL }
1017                 },
1018                 { &hf_sflow_ifpromisc,
1019                   { "Promiscuous Mode", "sflow.ifpromisc",
1020                         FT_UINT32, BASE_DEC, NULL, 0x0,
1021                         "Interface Promiscuous Mode", HFILL }
1022                 },
1023         };
1024
1025 /* Setup protocol subtree array */
1026         static gint *ett[] = {
1027                 &ett_sflow,
1028                 &ett_sflow_sample,
1029                 &ett_sflow_extended_data,
1030                 &ett_sflow_sampled_header,
1031         };
1032
1033 /* Register the protocol name and description */
1034         proto_sflow = proto_register_protocol("InMon sFlow",
1035             "sFlow", "sflow");
1036
1037 /* Required function calls to register the header fields and subtrees used */
1038         proto_register_field_array(proto_sflow, hf, array_length(hf));
1039         proto_register_subtree_array(ett, array_length(ett));
1040 }
1041
1042
1043 /* If this dissector uses sub-dissector registration add a registration routine.
1044    This format is required because a script is used to find these routines and
1045    create the code that calls these routines.
1046 */
1047 void
1048 proto_reg_handoff_sflow(void)
1049 {
1050         dissector_handle_t sflow_handle;
1051
1052         eth_handle = find_dissector("eth");
1053         tr_handle = find_dissector("tr");
1054         fddi_handle = find_dissector("fddi");
1055         fr_handle = find_dissector("fr");
1056         x25_handle = find_dissector("x25");
1057         ppp_handle = find_dissector("ppp");
1058         smds_handle = find_dissector("smds");
1059         aal5_handle = find_dissector("atm");
1060         ipv4_handle = find_dissector("ip");
1061         ipv6_handle = find_dissector("ipv6");
1062         mpls_handle = find_dissector("mpls");
1063
1064         sflow_handle = create_dissector_handle(dissect_sflow,
1065             proto_sflow);
1066         dissector_add("udp.port", UDP_PORT_SFLOW, sflow_handle);
1067 }