2 * Copyright (c) 1998-2007 The TCPDUMP project
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that: (1) source code
6 * distributions retain the above copyright notice and this paragraph
7 * in its entirety, and (2) distributions including binary code include
8 * the above copyright notice and this paragraph in its entirety in
9 * the documentation or other materials provided with the distribution.
10 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND
11 * WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT
12 * LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
13 * FOR A PARTICULAR PURPOSE.
15 * Original code by Carles Kishimoto <carles.kishimoto@gmail.com>
17 * Expansion and refactoring by Rick Jones <rick.jones2@hp.com>
20 /* \summary: sFlow protocol printer */
22 /* specification: https://sflow.org/developers/specifications.php */
28 #include "netdissect-stdinc.h"
30 #include "netdissect.h"
32 #include "addrtoname.h"
38 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
39 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
40 * | Sflow version (2,4,5) |
41 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
42 * | IP version (1 for IPv4 | 2 for IPv6) |
43 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
44 * | IP Address AGENT (4 or 16 bytes) |
45 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
47 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
48 * | Datagram sequence number |
49 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
50 * | Switch uptime in ms |
51 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
52 * | num samples in datagram |
53 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
57 struct sflow_datagram_t
{
59 nd_uint32_t ip_version
;
67 struct sflow_sample_header
{
72 #define SFLOW_FLOW_SAMPLE 1
73 #define SFLOW_COUNTER_SAMPLE 2
74 #define SFLOW_EXPANDED_FLOW_SAMPLE 3
75 #define SFLOW_EXPANDED_COUNTER_SAMPLE 4
77 static const struct tok sflow_format_values
[] = {
78 { SFLOW_FLOW_SAMPLE
, "flow sample" },
79 { SFLOW_COUNTER_SAMPLE
, "counter sample" },
80 { SFLOW_EXPANDED_FLOW_SAMPLE
, "expanded flow sample" },
81 { SFLOW_EXPANDED_COUNTER_SAMPLE
, "expanded counter sample" },
85 struct sflow_flow_sample_t
{
92 nd_uint32_t in_interface
;
93 nd_uint32_t out_interface
;
98 struct sflow_expanded_flow_sample_t
{
105 nd_uint32_t in_interface_format
;
106 nd_uint32_t in_interface_value
;
107 nd_uint32_t out_interface_format
;
108 nd_uint32_t out_interface_value
;
112 #define SFLOW_FLOW_RAW_PACKET 1
113 #define SFLOW_FLOW_ETHERNET_FRAME 2
114 #define SFLOW_FLOW_IPV4_DATA 3
115 #define SFLOW_FLOW_IPV6_DATA 4
116 #define SFLOW_FLOW_EXTENDED_SWITCH_DATA 1001
117 #define SFLOW_FLOW_EXTENDED_ROUTER_DATA 1002
118 #define SFLOW_FLOW_EXTENDED_GATEWAY_DATA 1003
119 #define SFLOW_FLOW_EXTENDED_USER_DATA 1004
120 #define SFLOW_FLOW_EXTENDED_URL_DATA 1005
121 #define SFLOW_FLOW_EXTENDED_MPLS_DATA 1006
122 #define SFLOW_FLOW_EXTENDED_NAT_DATA 1007
123 #define SFLOW_FLOW_EXTENDED_MPLS_TUNNEL 1008
124 #define SFLOW_FLOW_EXTENDED_MPLS_VC 1009
125 #define SFLOW_FLOW_EXTENDED_MPLS_FEC 1010
126 #define SFLOW_FLOW_EXTENDED_MPLS_LVP_FEC 1011
127 #define SFLOW_FLOW_EXTENDED_VLAN_TUNNEL 1012
129 static const struct tok sflow_flow_type_values
[] = {
130 { SFLOW_FLOW_RAW_PACKET
, "Raw packet"},
131 { SFLOW_FLOW_ETHERNET_FRAME
, "Ethernet frame"},
132 { SFLOW_FLOW_IPV4_DATA
, "IPv4 Data"},
133 { SFLOW_FLOW_IPV6_DATA
, "IPv6 Data"},
134 { SFLOW_FLOW_EXTENDED_SWITCH_DATA
, "Extended Switch data"},
135 { SFLOW_FLOW_EXTENDED_ROUTER_DATA
, "Extended Router data"},
136 { SFLOW_FLOW_EXTENDED_GATEWAY_DATA
, "Extended Gateway data"},
137 { SFLOW_FLOW_EXTENDED_USER_DATA
, "Extended User data"},
138 { SFLOW_FLOW_EXTENDED_URL_DATA
, "Extended URL data"},
139 { SFLOW_FLOW_EXTENDED_MPLS_DATA
, "Extended MPLS data"},
140 { SFLOW_FLOW_EXTENDED_NAT_DATA
, "Extended NAT data"},
141 { SFLOW_FLOW_EXTENDED_MPLS_TUNNEL
, "Extended MPLS tunnel"},
142 { SFLOW_FLOW_EXTENDED_MPLS_VC
, "Extended MPLS VC"},
143 { SFLOW_FLOW_EXTENDED_MPLS_FEC
, "Extended MPLS FEC"},
144 { SFLOW_FLOW_EXTENDED_MPLS_LVP_FEC
, "Extended MPLS LVP FEC"},
145 { SFLOW_FLOW_EXTENDED_VLAN_TUNNEL
, "Extended VLAN Tunnel"},
149 #define SFLOW_HEADER_PROTOCOL_ETHERNET 1
150 #define SFLOW_HEADER_PROTOCOL_IPV4 11
151 #define SFLOW_HEADER_PROTOCOL_IPV6 12
153 static const struct tok sflow_flow_raw_protocol_values
[] = {
154 { SFLOW_HEADER_PROTOCOL_ETHERNET
, "Ethernet"},
155 { SFLOW_HEADER_PROTOCOL_IPV4
, "IPv4"},
156 { SFLOW_HEADER_PROTOCOL_IPV6
, "IPv6"},
160 struct sflow_expanded_flow_raw_t
{
161 nd_uint32_t protocol
;
163 nd_uint32_t stripped_bytes
;
164 nd_uint32_t header_size
;
167 struct sflow_ethernet_frame_t
{
174 struct sflow_extended_switch_data_t
{
175 nd_uint32_t src_vlan
;
177 nd_uint32_t dst_vlan
;
181 struct sflow_counter_record_t
{
186 struct sflow_flow_record_t
{
191 struct sflow_counter_sample_t
{
198 struct sflow_expanded_counter_sample_t
{
205 #define SFLOW_COUNTER_GENERIC 1
206 #define SFLOW_COUNTER_ETHERNET 2
207 #define SFLOW_COUNTER_TOKEN_RING 3
208 #define SFLOW_COUNTER_BASEVG 4
209 #define SFLOW_COUNTER_VLAN 5
210 #define SFLOW_COUNTER_PROCESSOR 1001
212 static const struct tok sflow_counter_type_values
[] = {
213 { SFLOW_COUNTER_GENERIC
, "Generic counter"},
214 { SFLOW_COUNTER_ETHERNET
, "Ethernet counter"},
215 { SFLOW_COUNTER_TOKEN_RING
, "Token ring counter"},
216 { SFLOW_COUNTER_BASEVG
, "100 BaseVG counter"},
217 { SFLOW_COUNTER_VLAN
, "Vlan counter"},
218 { SFLOW_COUNTER_PROCESSOR
, "Processor counter"},
222 #define SFLOW_IFACE_DIRECTION_UNKNOWN 0
223 #define SFLOW_IFACE_DIRECTION_FULLDUPLEX 1
224 #define SFLOW_IFACE_DIRECTION_HALFDUPLEX 2
225 #define SFLOW_IFACE_DIRECTION_IN 3
226 #define SFLOW_IFACE_DIRECTION_OUT 4
228 static const struct tok sflow_iface_direction_values
[] = {
229 { SFLOW_IFACE_DIRECTION_UNKNOWN
, "unknown"},
230 { SFLOW_IFACE_DIRECTION_FULLDUPLEX
, "full-duplex"},
231 { SFLOW_IFACE_DIRECTION_HALFDUPLEX
, "half-duplex"},
232 { SFLOW_IFACE_DIRECTION_IN
, "in"},
233 { SFLOW_IFACE_DIRECTION_OUT
, "out"},
237 struct sflow_generic_counter_t
{
241 nd_uint32_t ifdirection
;
242 nd_uint32_t ifstatus
;
243 nd_uint64_t ifinoctets
;
244 nd_uint32_t ifinunicastpkts
;
245 nd_uint32_t ifinmulticastpkts
;
246 nd_uint32_t ifinbroadcastpkts
;
247 nd_uint32_t ifindiscards
;
248 nd_uint32_t ifinerrors
;
249 nd_uint32_t ifinunkownprotos
;
250 nd_uint64_t ifoutoctets
;
251 nd_uint32_t ifoutunicastpkts
;
252 nd_uint32_t ifoutmulticastpkts
;
253 nd_uint32_t ifoutbroadcastpkts
;
254 nd_uint32_t ifoutdiscards
;
255 nd_uint32_t ifouterrors
;
256 nd_uint32_t ifpromiscmode
;
259 struct sflow_ethernet_counter_t
{
260 nd_uint32_t alignerrors
;
261 nd_uint32_t fcserrors
;
262 nd_uint32_t single_collision_frames
;
263 nd_uint32_t multiple_collision_frames
;
264 nd_uint32_t test_errors
;
265 nd_uint32_t deferred_transmissions
;
266 nd_uint32_t late_collisions
;
267 nd_uint32_t excessive_collisions
;
268 nd_uint32_t mac_transmit_errors
;
269 nd_uint32_t carrier_sense_errors
;
270 nd_uint32_t frame_too_longs
;
271 nd_uint32_t mac_receive_errors
;
272 nd_uint32_t symbol_errors
;
275 struct sflow_100basevg_counter_t
{
276 nd_uint32_t in_highpriority_frames
;
277 nd_uint64_t in_highpriority_octets
;
278 nd_uint32_t in_normpriority_frames
;
279 nd_uint64_t in_normpriority_octets
;
280 nd_uint32_t in_ipmerrors
;
281 nd_uint32_t in_oversized
;
282 nd_uint32_t in_data_errors
;
283 nd_uint32_t in_null_addressed_frames
;
284 nd_uint32_t out_highpriority_frames
;
285 nd_uint64_t out_highpriority_octets
;
286 nd_uint32_t transitioninto_frames
;
287 nd_uint64_t hc_in_highpriority_octets
;
288 nd_uint64_t hc_in_normpriority_octets
;
289 nd_uint64_t hc_out_highpriority_octets
;
292 struct sflow_vlan_counter_t
{
295 nd_uint32_t unicast_pkt
;
296 nd_uint32_t multicast_pkt
;
297 nd_uint32_t broadcast_pkt
;
298 nd_uint32_t discards
;
302 print_sflow_counter_generic(netdissect_options
*ndo
,
303 const u_char
*pointer
, u_int len
)
305 const struct sflow_generic_counter_t
*sflow_gen_counter
;
307 if (len
< sizeof(struct sflow_generic_counter_t
))
310 sflow_gen_counter
= (const struct sflow_generic_counter_t
*)pointer
;
311 ND_TCHECK_SIZE(sflow_gen_counter
);
312 ND_PRINT("\n\t ifindex %u, iftype %u, ifspeed %" PRIu64
", ifdirection %u (%s)",
313 GET_BE_U_4(sflow_gen_counter
->ifindex
),
314 GET_BE_U_4(sflow_gen_counter
->iftype
),
315 GET_BE_U_8(sflow_gen_counter
->ifspeed
),
316 GET_BE_U_4(sflow_gen_counter
->ifdirection
),
317 tok2str(sflow_iface_direction_values
, "Unknown",
318 GET_BE_U_4(sflow_gen_counter
->ifdirection
)));
319 ND_PRINT("\n\t ifstatus %u, adminstatus: %s, operstatus: %s",
320 GET_BE_U_4(sflow_gen_counter
->ifstatus
),
321 GET_BE_U_4(sflow_gen_counter
->ifstatus
)&1 ? "up" : "down",
322 (GET_BE_U_4(sflow_gen_counter
->ifstatus
)>>1)&1 ? "up" : "down");
323 ND_PRINT("\n\t In octets %" PRIu64
324 ", unicast pkts %u, multicast pkts %u, broadcast pkts %u, discards %u",
325 GET_BE_U_8(sflow_gen_counter
->ifinoctets
),
326 GET_BE_U_4(sflow_gen_counter
->ifinunicastpkts
),
327 GET_BE_U_4(sflow_gen_counter
->ifinmulticastpkts
),
328 GET_BE_U_4(sflow_gen_counter
->ifinbroadcastpkts
),
329 GET_BE_U_4(sflow_gen_counter
->ifindiscards
));
330 ND_PRINT("\n\t In errors %u, unknown protos %u",
331 GET_BE_U_4(sflow_gen_counter
->ifinerrors
),
332 GET_BE_U_4(sflow_gen_counter
->ifinunkownprotos
));
333 ND_PRINT("\n\t Out octets %" PRIu64
334 ", unicast pkts %u, multicast pkts %u, broadcast pkts %u, discards %u",
335 GET_BE_U_8(sflow_gen_counter
->ifoutoctets
),
336 GET_BE_U_4(sflow_gen_counter
->ifoutunicastpkts
),
337 GET_BE_U_4(sflow_gen_counter
->ifoutmulticastpkts
),
338 GET_BE_U_4(sflow_gen_counter
->ifoutbroadcastpkts
),
339 GET_BE_U_4(sflow_gen_counter
->ifoutdiscards
));
340 ND_PRINT("\n\t Out errors %u, promisc mode %u",
341 GET_BE_U_4(sflow_gen_counter
->ifouterrors
),
342 GET_BE_U_4(sflow_gen_counter
->ifpromiscmode
));
351 print_sflow_counter_ethernet(netdissect_options
*ndo
,
352 const u_char
*pointer
, u_int len
)
354 const struct sflow_ethernet_counter_t
*sflow_eth_counter
;
356 if (len
< sizeof(struct sflow_ethernet_counter_t
))
359 sflow_eth_counter
= (const struct sflow_ethernet_counter_t
*)pointer
;
360 ND_TCHECK_SIZE(sflow_eth_counter
);
361 ND_PRINT("\n\t align errors %u, fcs errors %u, single collision %u, multiple collision %u, test error %u",
362 GET_BE_U_4(sflow_eth_counter
->alignerrors
),
363 GET_BE_U_4(sflow_eth_counter
->fcserrors
),
364 GET_BE_U_4(sflow_eth_counter
->single_collision_frames
),
365 GET_BE_U_4(sflow_eth_counter
->multiple_collision_frames
),
366 GET_BE_U_4(sflow_eth_counter
->test_errors
));
367 ND_PRINT("\n\t deferred %u, late collision %u, excessive collision %u, mac trans error %u",
368 GET_BE_U_4(sflow_eth_counter
->deferred_transmissions
),
369 GET_BE_U_4(sflow_eth_counter
->late_collisions
),
370 GET_BE_U_4(sflow_eth_counter
->excessive_collisions
),
371 GET_BE_U_4(sflow_eth_counter
->mac_transmit_errors
));
372 ND_PRINT("\n\t carrier error %u, frames too long %u, mac receive errors %u, symbol errors %u",
373 GET_BE_U_4(sflow_eth_counter
->carrier_sense_errors
),
374 GET_BE_U_4(sflow_eth_counter
->frame_too_longs
),
375 GET_BE_U_4(sflow_eth_counter
->mac_receive_errors
),
376 GET_BE_U_4(sflow_eth_counter
->symbol_errors
));
385 print_sflow_counter_token_ring(netdissect_options
*ndo _U_
,
386 const u_char
*pointer _U_
, u_int len _U_
)
392 print_sflow_counter_basevg(netdissect_options
*ndo
,
393 const u_char
*pointer
, u_int len
)
395 const struct sflow_100basevg_counter_t
*sflow_100basevg_counter
;
397 if (len
< sizeof(struct sflow_100basevg_counter_t
))
400 sflow_100basevg_counter
= (const struct sflow_100basevg_counter_t
*)pointer
;
401 ND_TCHECK_SIZE(sflow_100basevg_counter
);
402 ND_PRINT("\n\t in high prio frames %u, in high prio octets %" PRIu64
,
403 GET_BE_U_4(sflow_100basevg_counter
->in_highpriority_frames
),
404 GET_BE_U_8(sflow_100basevg_counter
->in_highpriority_octets
));
405 ND_PRINT("\n\t in norm prio frames %u, in norm prio octets %" PRIu64
,
406 GET_BE_U_4(sflow_100basevg_counter
->in_normpriority_frames
),
407 GET_BE_U_8(sflow_100basevg_counter
->in_normpriority_octets
));
408 ND_PRINT("\n\t in ipm errors %u, oversized %u, in data errors %u, null addressed frames %u",
409 GET_BE_U_4(sflow_100basevg_counter
->in_ipmerrors
),
410 GET_BE_U_4(sflow_100basevg_counter
->in_oversized
),
411 GET_BE_U_4(sflow_100basevg_counter
->in_data_errors
),
412 GET_BE_U_4(sflow_100basevg_counter
->in_null_addressed_frames
));
413 ND_PRINT("\n\t out high prio frames %u, out high prio octets %" PRIu64
414 ", trans into frames %u",
415 GET_BE_U_4(sflow_100basevg_counter
->out_highpriority_frames
),
416 GET_BE_U_8(sflow_100basevg_counter
->out_highpriority_octets
),
417 GET_BE_U_4(sflow_100basevg_counter
->transitioninto_frames
));
418 ND_PRINT("\n\t in hc high prio octets %" PRIu64
419 ", in hc norm prio octets %" PRIu64
420 ", out hc high prio octets %" PRIu64
,
421 GET_BE_U_8(sflow_100basevg_counter
->hc_in_highpriority_octets
),
422 GET_BE_U_8(sflow_100basevg_counter
->hc_in_normpriority_octets
),
423 GET_BE_U_8(sflow_100basevg_counter
->hc_out_highpriority_octets
));
432 print_sflow_counter_vlan(netdissect_options
*ndo
,
433 const u_char
*pointer
, u_int len
)
435 const struct sflow_vlan_counter_t
*sflow_vlan_counter
;
437 if (len
< sizeof(struct sflow_vlan_counter_t
))
440 sflow_vlan_counter
= (const struct sflow_vlan_counter_t
*)pointer
;
441 ND_TCHECK_SIZE(sflow_vlan_counter
);
442 ND_PRINT("\n\t vlan_id %u, octets %" PRIu64
443 ", unicast_pkt %u, multicast_pkt %u, broadcast_pkt %u, discards %u",
444 GET_BE_U_4(sflow_vlan_counter
->vlan_id
),
445 GET_BE_U_8(sflow_vlan_counter
->octets
),
446 GET_BE_U_4(sflow_vlan_counter
->unicast_pkt
),
447 GET_BE_U_4(sflow_vlan_counter
->multicast_pkt
),
448 GET_BE_U_4(sflow_vlan_counter
->broadcast_pkt
),
449 GET_BE_U_4(sflow_vlan_counter
->discards
));
457 struct sflow_processor_counter_t
{
458 nd_uint32_t five_sec_util
;
459 nd_uint32_t one_min_util
;
460 nd_uint32_t five_min_util
;
461 nd_uint64_t total_memory
;
462 nd_uint64_t free_memory
;
466 print_sflow_counter_processor(netdissect_options
*ndo
,
467 const u_char
*pointer
, u_int len
)
469 const struct sflow_processor_counter_t
*sflow_processor_counter
;
471 if (len
< sizeof(struct sflow_processor_counter_t
))
474 sflow_processor_counter
= (const struct sflow_processor_counter_t
*)pointer
;
475 ND_TCHECK_SIZE(sflow_processor_counter
);
476 ND_PRINT("\n\t 5sec %u, 1min %u, 5min %u, total_mem %" PRIu64
477 ", total_mem %" PRIu64
,
478 GET_BE_U_4(sflow_processor_counter
->five_sec_util
),
479 GET_BE_U_4(sflow_processor_counter
->one_min_util
),
480 GET_BE_U_4(sflow_processor_counter
->five_min_util
),
481 GET_BE_U_8(sflow_processor_counter
->total_memory
),
482 GET_BE_U_8(sflow_processor_counter
->free_memory
));
491 sflow_print_counter_records(netdissect_options
*ndo
,
492 const u_char
*pointer
, u_int len
, u_int records
)
500 const struct sflow_counter_record_t
*sflow_counter_record
;
506 while (nrecords
> 0) {
507 /* do we have the "header?" */
508 if (tlen
< sizeof(struct sflow_counter_record_t
))
510 sflow_counter_record
= (const struct sflow_counter_record_t
*)tptr
;
511 ND_TCHECK_SIZE(sflow_counter_record
);
513 enterprise
= GET_BE_U_4(sflow_counter_record
->format
);
514 counter_type
= enterprise
& 0x0FFF;
515 enterprise
= enterprise
>> 20;
516 counter_len
= GET_BE_U_4(sflow_counter_record
->length
);
517 ND_PRINT("\n\t enterprise %u, %s (%u) length %u",
519 (enterprise
== 0) ? tok2str(sflow_counter_type_values
,"Unknown",counter_type
) : "Unknown",
523 tptr
+= sizeof(struct sflow_counter_record_t
);
524 tlen
-= sizeof(struct sflow_counter_record_t
);
526 if (tlen
< counter_len
)
528 if (enterprise
== 0) {
529 switch (counter_type
) {
530 case SFLOW_COUNTER_GENERIC
:
531 if (print_sflow_counter_generic(ndo
, tptr
, tlen
))
534 case SFLOW_COUNTER_ETHERNET
:
535 if (print_sflow_counter_ethernet(ndo
, tptr
, tlen
))
538 case SFLOW_COUNTER_TOKEN_RING
:
539 if (print_sflow_counter_token_ring(ndo
, tptr
,tlen
))
542 case SFLOW_COUNTER_BASEVG
:
543 if (print_sflow_counter_basevg(ndo
, tptr
, tlen
))
546 case SFLOW_COUNTER_VLAN
:
547 if (print_sflow_counter_vlan(ndo
, tptr
, tlen
))
550 case SFLOW_COUNTER_PROCESSOR
:
551 if (print_sflow_counter_processor(ndo
, tptr
, tlen
))
555 if (ndo
->ndo_vflag
<= 1)
556 print_unknown_data(ndo
, tptr
, "\n\t\t", counter_len
);
573 sflow_print_counter_sample(netdissect_options
*ndo
,
574 const u_char
*pointer
, u_int len
)
576 const struct sflow_counter_sample_t
*sflow_counter_sample
;
579 if (len
< sizeof(struct sflow_counter_sample_t
))
582 sflow_counter_sample
= (const struct sflow_counter_sample_t
*)pointer
;
583 ND_TCHECK_SIZE(sflow_counter_sample
);
585 nrecords
= GET_BE_U_4(sflow_counter_sample
->records
);
587 ND_PRINT(" seqnum %u, type %u, idx %u, records %u",
588 GET_BE_U_4(sflow_counter_sample
->seqnum
),
589 GET_U_1(sflow_counter_sample
->type
),
590 GET_BE_U_3(sflow_counter_sample
->index
),
593 return sflow_print_counter_records(ndo
, pointer
+ sizeof(struct sflow_counter_sample_t
),
594 len
- sizeof(struct sflow_counter_sample_t
),
602 sflow_print_expanded_counter_sample(netdissect_options
*ndo
,
603 const u_char
*pointer
, u_int len
)
605 const struct sflow_expanded_counter_sample_t
*sflow_expanded_counter_sample
;
609 if (len
< sizeof(struct sflow_expanded_counter_sample_t
))
612 sflow_expanded_counter_sample
= (const struct sflow_expanded_counter_sample_t
*)pointer
;
613 ND_TCHECK_SIZE(sflow_expanded_counter_sample
);
615 nrecords
= GET_BE_U_4(sflow_expanded_counter_sample
->records
);
617 ND_PRINT(" seqnum %u, type %u, idx %u, records %u",
618 GET_BE_U_4(sflow_expanded_counter_sample
->seqnum
),
619 GET_BE_U_4(sflow_expanded_counter_sample
->type
),
620 GET_BE_U_4(sflow_expanded_counter_sample
->index
),
623 return sflow_print_counter_records(ndo
, pointer
+ sizeof(struct sflow_expanded_counter_sample_t
),
624 len
- sizeof(struct sflow_expanded_counter_sample_t
),
632 print_sflow_raw_packet(netdissect_options
*ndo
,
633 const u_char
*pointer
, u_int len
)
635 const struct sflow_expanded_flow_raw_t
*sflow_flow_raw
;
637 if (len
< sizeof(struct sflow_expanded_flow_raw_t
))
640 sflow_flow_raw
= (const struct sflow_expanded_flow_raw_t
*)pointer
;
641 ND_TCHECK_SIZE(sflow_flow_raw
);
642 ND_PRINT("\n\t protocol %s (%u), length %u, stripped bytes %u, header_size %u",
643 tok2str(sflow_flow_raw_protocol_values
,"Unknown",GET_BE_U_4(sflow_flow_raw
->protocol
)),
644 GET_BE_U_4(sflow_flow_raw
->protocol
),
645 GET_BE_U_4(sflow_flow_raw
->length
),
646 GET_BE_U_4(sflow_flow_raw
->stripped_bytes
),
647 GET_BE_U_4(sflow_flow_raw
->header_size
));
649 /* QUESTION - should we attempt to print the raw header itself?
650 assuming of course there is wnough data present to do so... */
659 print_sflow_ethernet_frame(netdissect_options
*ndo
,
660 const u_char
*pointer
, u_int len
)
662 const struct sflow_ethernet_frame_t
*sflow_ethernet_frame
;
664 if (len
< sizeof(struct sflow_ethernet_frame_t
))
667 sflow_ethernet_frame
= (const struct sflow_ethernet_frame_t
*)pointer
;
668 ND_TCHECK_SIZE(sflow_ethernet_frame
);
670 ND_PRINT("\n\t frame len %u, type %u",
671 GET_BE_U_4(sflow_ethernet_frame
->length
),
672 GET_BE_U_4(sflow_ethernet_frame
->type
));
681 print_sflow_extended_switch_data(netdissect_options
*ndo
,
682 const u_char
*pointer
, u_int len
)
684 const struct sflow_extended_switch_data_t
*sflow_extended_sw_data
;
686 if (len
< sizeof(struct sflow_extended_switch_data_t
))
689 sflow_extended_sw_data
= (const struct sflow_extended_switch_data_t
*)pointer
;
690 ND_TCHECK_SIZE(sflow_extended_sw_data
);
691 ND_PRINT("\n\t src vlan %u, src pri %u, dst vlan %u, dst pri %u",
692 GET_BE_U_4(sflow_extended_sw_data
->src_vlan
),
693 GET_BE_U_4(sflow_extended_sw_data
->src_pri
),
694 GET_BE_U_4(sflow_extended_sw_data
->dst_vlan
),
695 GET_BE_U_4(sflow_extended_sw_data
->dst_pri
));
704 sflow_print_flow_records(netdissect_options
*ndo
,
705 const u_char
*pointer
, u_int len
, u_int records
)
713 const struct sflow_flow_record_t
*sflow_flow_record
;
719 while (nrecords
> 0) {
720 /* do we have the "header?" */
721 if (tlen
< sizeof(struct sflow_flow_record_t
))
724 sflow_flow_record
= (const struct sflow_flow_record_t
*)tptr
;
725 ND_TCHECK_SIZE(sflow_flow_record
);
727 /* so, the funky encoding means we cannot blythly mask-off
728 bits, we must also check the enterprise. */
730 enterprise
= GET_BE_U_4(sflow_flow_record
->format
);
731 flow_type
= enterprise
& 0x0FFF;
732 enterprise
= enterprise
>> 12;
733 flow_len
= GET_BE_U_4(sflow_flow_record
->length
);
734 ND_PRINT("\n\t enterprise %u %s (%u) length %u",
736 (enterprise
== 0) ? tok2str(sflow_flow_type_values
,"Unknown",flow_type
) : "Unknown",
740 tptr
+= sizeof(struct sflow_flow_record_t
);
741 tlen
-= sizeof(struct sflow_flow_record_t
);
746 if (enterprise
== 0) {
748 case SFLOW_FLOW_RAW_PACKET
:
749 if (print_sflow_raw_packet(ndo
, tptr
, tlen
))
752 case SFLOW_FLOW_EXTENDED_SWITCH_DATA
:
753 if (print_sflow_extended_switch_data(ndo
, tptr
, tlen
))
756 case SFLOW_FLOW_ETHERNET_FRAME
:
757 if (print_sflow_ethernet_frame(ndo
, tptr
, tlen
))
760 /* FIXME these need a decoder */
761 case SFLOW_FLOW_IPV4_DATA
:
762 case SFLOW_FLOW_IPV6_DATA
:
763 case SFLOW_FLOW_EXTENDED_ROUTER_DATA
:
764 case SFLOW_FLOW_EXTENDED_GATEWAY_DATA
:
765 case SFLOW_FLOW_EXTENDED_USER_DATA
:
766 case SFLOW_FLOW_EXTENDED_URL_DATA
:
767 case SFLOW_FLOW_EXTENDED_MPLS_DATA
:
768 case SFLOW_FLOW_EXTENDED_NAT_DATA
:
769 case SFLOW_FLOW_EXTENDED_MPLS_TUNNEL
:
770 case SFLOW_FLOW_EXTENDED_MPLS_VC
:
771 case SFLOW_FLOW_EXTENDED_MPLS_FEC
:
772 case SFLOW_FLOW_EXTENDED_MPLS_LVP_FEC
:
773 case SFLOW_FLOW_EXTENDED_VLAN_TUNNEL
:
776 if (ndo
->ndo_vflag
<= 1)
777 print_unknown_data(ndo
, tptr
, "\n\t\t", flow_len
);
794 sflow_print_flow_sample(netdissect_options
*ndo
,
795 const u_char
*pointer
, u_int len
)
797 const struct sflow_flow_sample_t
*sflow_flow_sample
;
800 if (len
< sizeof(struct sflow_flow_sample_t
))
803 sflow_flow_sample
= (const struct sflow_flow_sample_t
*)pointer
;
804 ND_TCHECK_SIZE(sflow_flow_sample
);
806 nrecords
= GET_BE_U_4(sflow_flow_sample
->records
);
808 ND_PRINT(" seqnum %u, type %u, idx %u, rate %u, pool %u, drops %u, input %u output %u records %u",
809 GET_BE_U_4(sflow_flow_sample
->seqnum
),
810 GET_U_1(sflow_flow_sample
->type
),
811 GET_BE_U_3(sflow_flow_sample
->index
),
812 GET_BE_U_4(sflow_flow_sample
->rate
),
813 GET_BE_U_4(sflow_flow_sample
->pool
),
814 GET_BE_U_4(sflow_flow_sample
->drops
),
815 GET_BE_U_4(sflow_flow_sample
->in_interface
),
816 GET_BE_U_4(sflow_flow_sample
->out_interface
),
819 return sflow_print_flow_records(ndo
, pointer
+ sizeof(struct sflow_flow_sample_t
),
820 len
- sizeof(struct sflow_flow_sample_t
),
828 sflow_print_expanded_flow_sample(netdissect_options
*ndo
,
829 const u_char
*pointer
, u_int len
)
831 const struct sflow_expanded_flow_sample_t
*sflow_expanded_flow_sample
;
834 if (len
< sizeof(struct sflow_expanded_flow_sample_t
))
837 sflow_expanded_flow_sample
= (const struct sflow_expanded_flow_sample_t
*)pointer
;
838 ND_TCHECK_SIZE(sflow_expanded_flow_sample
);
840 nrecords
= GET_BE_U_4(sflow_expanded_flow_sample
->records
);
842 ND_PRINT(" seqnum %u, type %u, idx %u, rate %u, pool %u, drops %u, records %u",
843 GET_BE_U_4(sflow_expanded_flow_sample
->seqnum
),
844 GET_BE_U_4(sflow_expanded_flow_sample
->type
),
845 GET_BE_U_4(sflow_expanded_flow_sample
->index
),
846 GET_BE_U_4(sflow_expanded_flow_sample
->rate
),
847 GET_BE_U_4(sflow_expanded_flow_sample
->pool
),
848 GET_BE_U_4(sflow_expanded_flow_sample
->drops
),
849 GET_BE_U_4(sflow_expanded_flow_sample
->records
));
851 return sflow_print_flow_records(ndo
, pointer
+ sizeof(struct sflow_expanded_flow_sample_t
),
852 len
- sizeof(struct sflow_expanded_flow_sample_t
),
860 sflow_print(netdissect_options
*ndo
,
861 const u_char
*pptr
, u_int len
)
863 const struct sflow_datagram_t
*sflow_datagram
;
864 const struct sflow_sample_header
*sflow_sample
;
868 uint32_t sflow_sample_type
, sflow_sample_len
;
871 ndo
->ndo_protocol
= "sflow";
874 sflow_datagram
= (const struct sflow_datagram_t
*)pptr
;
875 if (len
< sizeof(struct sflow_datagram_t
)) {
876 ND_PRINT("sFlowv%u", GET_BE_U_4(sflow_datagram
->version
));
877 ND_PRINT(" [length %u < %zu]", len
, sizeof(struct sflow_datagram_t
));
878 nd_print_invalid(ndo
);
881 ND_TCHECK_SIZE(sflow_datagram
);
884 * Sanity checking of the header.
886 if (GET_BE_U_4(sflow_datagram
->version
) != 5) {
887 ND_PRINT("sFlow version %u packet not supported",
888 GET_BE_U_4(sflow_datagram
->version
));
892 if (ndo
->ndo_vflag
< 1) {
893 ND_PRINT("sFlowv%u, %s agent %s, agent-id %u, length %u",
894 GET_BE_U_4(sflow_datagram
->version
),
895 GET_BE_U_4(sflow_datagram
->ip_version
) == 1 ? "IPv4" : "IPv6",
896 GET_IPADDR_STRING(sflow_datagram
->agent
),
897 GET_BE_U_4(sflow_datagram
->agent_id
),
902 /* ok they seem to want to know everything - lets fully decode it */
903 nsamples
=GET_BE_U_4(sflow_datagram
->samples
);
904 ND_PRINT("sFlowv%u, %s agent %s, agent-id %u, seqnum %u, uptime %u, samples %u, length %u",
905 GET_BE_U_4(sflow_datagram
->version
),
906 GET_BE_U_4(sflow_datagram
->ip_version
) == 1 ? "IPv4" : "IPv6",
907 GET_IPADDR_STRING(sflow_datagram
->agent
),
908 GET_BE_U_4(sflow_datagram
->agent_id
),
909 GET_BE_U_4(sflow_datagram
->seqnum
),
910 GET_BE_U_4(sflow_datagram
->uptime
),
914 /* skip Common header */
915 tptr
+= sizeof(struct sflow_datagram_t
);
916 tlen
-= sizeof(struct sflow_datagram_t
);
918 while (nsamples
> 0 && tlen
> 0) {
919 sflow_sample
= (const struct sflow_sample_header
*)tptr
;
920 ND_TCHECK_SIZE(sflow_sample
);
922 sflow_sample_type
= (GET_BE_U_4(sflow_sample
->format
)&0x0FFF);
923 sflow_sample_len
= GET_BE_U_4(sflow_sample
->len
);
925 if (tlen
< sizeof(struct sflow_sample_header
))
928 tptr
+= sizeof(struct sflow_sample_header
);
929 tlen
-= sizeof(struct sflow_sample_header
);
931 ND_PRINT("\n\t%s (%u), length %u,",
932 tok2str(sflow_format_values
, "Unknown", sflow_sample_type
),
936 /* basic sanity check */
937 if (sflow_sample_type
== 0 || sflow_sample_len
==0) {
941 if (tlen
< sflow_sample_len
)
944 /* did we capture enough for fully decoding the sample ? */
945 ND_TCHECK_LEN(tptr
, sflow_sample_len
);
947 switch(sflow_sample_type
) {
948 case SFLOW_FLOW_SAMPLE
:
949 if (sflow_print_flow_sample(ndo
, tptr
, tlen
))
953 case SFLOW_COUNTER_SAMPLE
:
954 if (sflow_print_counter_sample(ndo
, tptr
,tlen
))
958 case SFLOW_EXPANDED_FLOW_SAMPLE
:
959 if (sflow_print_expanded_flow_sample(ndo
, tptr
, tlen
))
963 case SFLOW_EXPANDED_COUNTER_SAMPLE
:
964 if (sflow_print_expanded_counter_sample(ndo
, tptr
,tlen
))
969 if (ndo
->ndo_vflag
<= 1)
970 print_unknown_data(ndo
, tptr
, "\n\t ", sflow_sample_len
);
973 tptr
+= sflow_sample_len
;
974 tlen
-= sflow_sample_len
;