Home | History | Annotate | Download | only in tcpdump
      1 /*
      2  * Copyright (c) 1998-2007 The TCPDUMP project
      3  *
      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.
     14  *
     15  * The SFLOW protocol as per http://www.sflow.org/developers/specifications.php
     16  *
     17  * Original code by Carles Kishimoto <carles.kishimoto (at) gmail.com>
     18  *
     19  * Expansion and refactoring by Rick Jones <rick.jones2 (at) hp.com>
     20  */
     21 
     22 #define NETDISSECT_REWORKED
     23 #ifdef HAVE_CONFIG_H
     24 #include "config.h"
     25 #endif
     26 
     27 #include <tcpdump-stdinc.h>
     28 
     29 #include "interface.h"
     30 #include "extract.h"
     31 #include "addrtoname.h"
     32 
     33 /*
     34  * sFlow datagram
     35  *
     36  * 0                   1                   2                   3
     37  * 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
     38  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     39  * |                     Sflow version (2,4,5)                     |
     40  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     41  * |               IP version (1 for IPv4 | 2 for IPv6)            |
     42  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     43  * |                     IP Address AGENT (4 or 16 bytes)          |
     44  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     45  * |                          Sub agent ID                         |
     46  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     47  * |                      Datagram sequence number                 |
     48  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     49  * |                      Switch uptime in ms                      |
     50  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     51  * |                    num samples in datagram                    |
     52  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     53  *
     54  */
     55 
     56 struct sflow_datagram_t {
     57     uint8_t 	version[4];
     58     uint8_t 	ip_version[4];
     59     uint8_t 	agent[4];
     60     uint8_t 	agent_id[4];
     61     uint8_t 	seqnum[4];
     62     uint8_t 	uptime[4];
     63     uint8_t 	samples[4];
     64 };
     65 
     66 struct sflow_sample_header {
     67     uint8_t	format[4];
     68     uint8_t	len[4];
     69 };
     70 
     71 #define		SFLOW_FLOW_SAMPLE		1
     72 #define		SFLOW_COUNTER_SAMPLE		2
     73 #define		SFLOW_EXPANDED_FLOW_SAMPLE	3
     74 #define		SFLOW_EXPANDED_COUNTER_SAMPLE	4
     75 
     76 static const struct tok sflow_format_values[] = {
     77     { SFLOW_FLOW_SAMPLE, "flow sample" },
     78     { SFLOW_COUNTER_SAMPLE, "counter sample" },
     79     { SFLOW_EXPANDED_FLOW_SAMPLE, "expanded flow sample" },
     80     { SFLOW_EXPANDED_COUNTER_SAMPLE, "expanded counter sample" },
     81     { 0, NULL}
     82 };
     83 
     84 struct sflow_flow_sample_t {
     85     uint8_t    seqnum[4];
     86     uint8_t    typesource[4];
     87     uint8_t    rate[4];
     88     uint8_t    pool[4];
     89     uint8_t    drops[4];
     90     uint8_t    in_interface[4];
     91     uint8_t    out_interface[4];
     92     uint8_t    records[4];
     93 
     94 };
     95 
     96 struct sflow_expanded_flow_sample_t {
     97     uint8_t    seqnum[4];
     98     uint8_t    type[4];
     99     uint8_t    index[4];
    100     uint8_t    rate[4];
    101     uint8_t    pool[4];
    102     uint8_t    drops[4];
    103     uint8_t    in_interface_format[4];
    104     uint8_t    in_interface_value[4];
    105     uint8_t    out_interface_format[4];
    106     uint8_t    out_interface_value[4];
    107     uint8_t    records[4];
    108 };
    109 
    110 #define 	SFLOW_FLOW_RAW_PACKET			1
    111 #define 	SFLOW_FLOW_ETHERNET_FRAME		2
    112 #define 	SFLOW_FLOW_IPV4_DATA			3
    113 #define 	SFLOW_FLOW_IPV6_DATA			4
    114 #define 	SFLOW_FLOW_EXTENDED_SWITCH_DATA		1001
    115 #define 	SFLOW_FLOW_EXTENDED_ROUTER_DATA		1002
    116 #define 	SFLOW_FLOW_EXTENDED_GATEWAY_DATA 	1003
    117 #define 	SFLOW_FLOW_EXTENDED_USER_DATA		1004
    118 #define 	SFLOW_FLOW_EXTENDED_URL_DATA		1005
    119 #define 	SFLOW_FLOW_EXTENDED_MPLS_DATA		1006
    120 #define 	SFLOW_FLOW_EXTENDED_NAT_DATA		1007
    121 #define 	SFLOW_FLOW_EXTENDED_MPLS_TUNNEL		1008
    122 #define 	SFLOW_FLOW_EXTENDED_MPLS_VC		1009
    123 #define 	SFLOW_FLOW_EXTENDED_MPLS_FEC		1010
    124 #define 	SFLOW_FLOW_EXTENDED_MPLS_LVP_FEC	1011
    125 #define 	SFLOW_FLOW_EXTENDED_VLAN_TUNNEL		1012
    126 
    127 static const struct tok sflow_flow_type_values[] = {
    128     { SFLOW_FLOW_RAW_PACKET, "Raw packet"},
    129     { SFLOW_FLOW_ETHERNET_FRAME, "Ethernet frame"},
    130     { SFLOW_FLOW_IPV4_DATA, "IPv4 Data"},
    131     { SFLOW_FLOW_IPV6_DATA, "IPv6 Data"},
    132     { SFLOW_FLOW_EXTENDED_SWITCH_DATA, "Extended Switch data"},
    133     { SFLOW_FLOW_EXTENDED_ROUTER_DATA, "Extended Router data"},
    134     { SFLOW_FLOW_EXTENDED_GATEWAY_DATA, "Extended Gateway data"},
    135     { SFLOW_FLOW_EXTENDED_USER_DATA, "Extended User data"},
    136     { SFLOW_FLOW_EXTENDED_URL_DATA, "Extended URL data"},
    137     { SFLOW_FLOW_EXTENDED_MPLS_DATA, "Extended MPLS data"},
    138     { SFLOW_FLOW_EXTENDED_NAT_DATA, "Extended NAT data"},
    139     { SFLOW_FLOW_EXTENDED_MPLS_TUNNEL, "Extended MPLS tunnel"},
    140     { SFLOW_FLOW_EXTENDED_MPLS_VC, "Extended MPLS VC"},
    141     { SFLOW_FLOW_EXTENDED_MPLS_FEC, "Extended MPLS FEC"},
    142     { SFLOW_FLOW_EXTENDED_MPLS_LVP_FEC, "Extended MPLS LVP FEC"},
    143     { SFLOW_FLOW_EXTENDED_VLAN_TUNNEL, "Extended VLAN Tunnel"},
    144     { 0, NULL}
    145 };
    146 
    147 #define		SFLOW_HEADER_PROTOCOL_ETHERNET	1
    148 #define		SFLOW_HEADER_PROTOCOL_IPV4	11
    149 #define		SFLOW_HEADER_PROTOCOL_IPV6	12
    150 
    151 static const struct tok sflow_flow_raw_protocol_values[] = {
    152     { SFLOW_HEADER_PROTOCOL_ETHERNET, "Ethernet"},
    153     { SFLOW_HEADER_PROTOCOL_IPV4, "IPv4"},
    154     { SFLOW_HEADER_PROTOCOL_IPV6, "IPv6"},
    155     { 0, NULL}
    156 };
    157 
    158 struct sflow_expanded_flow_raw_t {
    159     uint8_t    protocol[4];
    160     uint8_t    length[4];
    161     uint8_t    stripped_bytes[4];
    162     uint8_t    header_size[4];
    163 };
    164 
    165 struct sflow_ethernet_frame_t {
    166     uint8_t length[4];
    167     uint8_t src_mac[8];
    168     uint8_t dst_mac[8];
    169     uint8_t type[4];
    170 };
    171 
    172 struct sflow_extended_switch_data_t {
    173     uint8_t src_vlan[4];
    174     uint8_t src_pri[4];
    175     uint8_t dst_vlan[4];
    176     uint8_t dst_pri[4];
    177 };
    178 
    179 struct sflow_counter_record_t {
    180     uint8_t    format[4];
    181     uint8_t    length[4];
    182 };
    183 
    184 struct sflow_flow_record_t {
    185     uint8_t    format[4];
    186     uint8_t    length[4];
    187 };
    188 
    189 struct sflow_counter_sample_t {
    190     uint8_t    seqnum[4];
    191     uint8_t    typesource[4];
    192     uint8_t    records[4];
    193 };
    194 
    195 struct sflow_expanded_counter_sample_t {
    196     uint8_t    seqnum[4];
    197     uint8_t    type[4];
    198     uint8_t    index[4];
    199     uint8_t    records[4];
    200 };
    201 
    202 #define         SFLOW_COUNTER_GENERIC           1
    203 #define         SFLOW_COUNTER_ETHERNET          2
    204 #define         SFLOW_COUNTER_TOKEN_RING        3
    205 #define         SFLOW_COUNTER_BASEVG            4
    206 #define         SFLOW_COUNTER_VLAN              5
    207 #define         SFLOW_COUNTER_PROCESSOR         1001
    208 
    209 static const struct tok sflow_counter_type_values[] = {
    210     { SFLOW_COUNTER_GENERIC, "Generic counter"},
    211     { SFLOW_COUNTER_ETHERNET, "Ethernet counter"},
    212     { SFLOW_COUNTER_TOKEN_RING, "Token ring counter"},
    213     { SFLOW_COUNTER_BASEVG, "100 BaseVG counter"},
    214     { SFLOW_COUNTER_VLAN, "Vlan counter"},
    215     { SFLOW_COUNTER_PROCESSOR, "Processor counter"},
    216     { 0, NULL}
    217 };
    218 
    219 #define		SFLOW_IFACE_DIRECTION_UNKNOWN		0
    220 #define		SFLOW_IFACE_DIRECTION_FULLDUPLEX	1
    221 #define		SFLOW_IFACE_DIRECTION_HALFDUPLEX	2
    222 #define		SFLOW_IFACE_DIRECTION_IN		3
    223 #define		SFLOW_IFACE_DIRECTION_OUT		4
    224 
    225 static const struct tok sflow_iface_direction_values[] = {
    226     { SFLOW_IFACE_DIRECTION_UNKNOWN, "unknown"},
    227     { SFLOW_IFACE_DIRECTION_FULLDUPLEX, "full-duplex"},
    228     { SFLOW_IFACE_DIRECTION_HALFDUPLEX, "half-duplex"},
    229     { SFLOW_IFACE_DIRECTION_IN, "in"},
    230     { SFLOW_IFACE_DIRECTION_OUT, "out"},
    231     { 0, NULL}
    232 };
    233 
    234 struct sflow_generic_counter_t {
    235     uint8_t    ifindex[4];
    236     uint8_t    iftype[4];
    237     uint8_t    ifspeed[8];
    238     uint8_t    ifdirection[4];
    239     uint8_t    ifstatus[4];
    240     uint8_t    ifinoctets[8];
    241     uint8_t    ifinunicastpkts[4];
    242     uint8_t    ifinmulticastpkts[4];
    243     uint8_t    ifinbroadcastpkts[4];
    244     uint8_t    ifindiscards[4];
    245     uint8_t    ifinerrors[4];
    246     uint8_t    ifinunkownprotos[4];
    247     uint8_t    ifoutoctets[8];
    248     uint8_t    ifoutunicastpkts[4];
    249     uint8_t    ifoutmulticastpkts[4];
    250     uint8_t    ifoutbroadcastpkts[4];
    251     uint8_t    ifoutdiscards[4];
    252     uint8_t    ifouterrors[4];
    253     uint8_t    ifpromiscmode[4];
    254 };
    255 
    256 struct sflow_ethernet_counter_t {
    257     uint8_t    alignerrors[4];
    258     uint8_t    fcserrors[4];
    259     uint8_t    single_collision_frames[4];
    260     uint8_t    multiple_collision_frames[4];
    261     uint8_t    test_errors[4];
    262     uint8_t    deferred_transmissions[4];
    263     uint8_t    late_collisions[4];
    264     uint8_t    excessive_collisions[4];
    265     uint8_t    mac_transmit_errors[4];
    266     uint8_t    carrier_sense_errors[4];
    267     uint8_t    frame_too_longs[4];
    268     uint8_t    mac_receive_errors[4];
    269     uint8_t    symbol_errors[4];
    270 };
    271 
    272 struct sflow_100basevg_counter_t {
    273     uint8_t    in_highpriority_frames[4];
    274     uint8_t    in_highpriority_octets[8];
    275     uint8_t    in_normpriority_frames[4];
    276     uint8_t    in_normpriority_octets[8];
    277     uint8_t    in_ipmerrors[4];
    278     uint8_t    in_oversized[4];
    279     uint8_t    in_data_errors[4];
    280     uint8_t    in_null_addressed_frames[4];
    281     uint8_t    out_highpriority_frames[4];
    282     uint8_t    out_highpriority_octets[8];
    283     uint8_t    transitioninto_frames[4];
    284     uint8_t    hc_in_highpriority_octets[8];
    285     uint8_t    hc_in_normpriority_octets[8];
    286     uint8_t    hc_out_highpriority_octets[8];
    287 };
    288 
    289 struct sflow_vlan_counter_t {
    290     uint8_t    vlan_id[4];
    291     uint8_t    octets[8];
    292     uint8_t    unicast_pkt[4];
    293     uint8_t    multicast_pkt[4];
    294     uint8_t    broadcast_pkt[4];
    295     uint8_t    discards[4];
    296 };
    297 
    298 static int
    299 print_sflow_counter_generic(netdissect_options *ndo,
    300                             const u_char *pointer, u_int len)
    301 {
    302     const struct sflow_generic_counter_t *sflow_gen_counter;
    303 
    304     if (len < sizeof(struct sflow_generic_counter_t))
    305 	return 1;
    306 
    307 
    308     sflow_gen_counter = (const struct sflow_generic_counter_t *)pointer;
    309     ND_PRINT((ndo, "\n\t      ifindex %u, iftype %u, ifspeed %" PRIu64 ", ifdirection %u (%s)",
    310 	   EXTRACT_32BITS(sflow_gen_counter->ifindex),
    311 	   EXTRACT_32BITS(sflow_gen_counter->iftype),
    312 	   EXTRACT_64BITS(sflow_gen_counter->ifspeed),
    313 	   EXTRACT_32BITS(sflow_gen_counter->ifdirection),
    314 	   tok2str(sflow_iface_direction_values, "Unknown",
    315 	   EXTRACT_32BITS(sflow_gen_counter->ifdirection))));
    316     ND_PRINT((ndo, "\n\t      ifstatus %u, adminstatus: %s, operstatus: %s",
    317 	   EXTRACT_32BITS(sflow_gen_counter->ifstatus),
    318 	   EXTRACT_32BITS(sflow_gen_counter->ifstatus)&1 ? "up" : "down",
    319 	   (EXTRACT_32BITS(sflow_gen_counter->ifstatus)>>1)&1 ? "up" : "down"));
    320     ND_PRINT((ndo, "\n\t      In octets %" PRIu64
    321 	   ", unicast pkts %u, multicast pkts %u, broadcast pkts %u, discards %u",
    322 	   EXTRACT_64BITS(sflow_gen_counter->ifinoctets),
    323 	   EXTRACT_32BITS(sflow_gen_counter->ifinunicastpkts),
    324 	   EXTRACT_32BITS(sflow_gen_counter->ifinmulticastpkts),
    325 	   EXTRACT_32BITS(sflow_gen_counter->ifinbroadcastpkts),
    326 	   EXTRACT_32BITS(sflow_gen_counter->ifindiscards)));
    327     ND_PRINT((ndo, "\n\t      In errors %u, unknown protos %u",
    328 	   EXTRACT_32BITS(sflow_gen_counter->ifinerrors),
    329 	   EXTRACT_32BITS(sflow_gen_counter->ifinunkownprotos)));
    330     ND_PRINT((ndo, "\n\t      Out octets %" PRIu64
    331 	   ", unicast pkts %u, multicast pkts %u, broadcast pkts %u, discards %u",
    332 	   EXTRACT_64BITS(sflow_gen_counter->ifoutoctets),
    333 	   EXTRACT_32BITS(sflow_gen_counter->ifoutunicastpkts),
    334 	   EXTRACT_32BITS(sflow_gen_counter->ifoutmulticastpkts),
    335 	   EXTRACT_32BITS(sflow_gen_counter->ifoutbroadcastpkts),
    336 	   EXTRACT_32BITS(sflow_gen_counter->ifoutdiscards)));
    337     ND_PRINT((ndo, "\n\t      Out errors %u, promisc mode %u",
    338 	   EXTRACT_32BITS(sflow_gen_counter->ifouterrors),
    339 	   EXTRACT_32BITS(sflow_gen_counter->ifpromiscmode)));
    340 
    341     return 0;
    342 }
    343 
    344 static int
    345 print_sflow_counter_ethernet(netdissect_options *ndo,
    346                              const u_char *pointer, u_int len)
    347 {
    348     const struct sflow_ethernet_counter_t *sflow_eth_counter;
    349 
    350     if (len < sizeof(struct sflow_ethernet_counter_t))
    351 	return 1;
    352 
    353     sflow_eth_counter = (const struct sflow_ethernet_counter_t *)pointer;
    354     ND_PRINT((ndo, "\n\t      align errors %u, fcs errors %u, single collision %u, multiple collision %u, test error %u",
    355 	   EXTRACT_32BITS(sflow_eth_counter->alignerrors),
    356 	   EXTRACT_32BITS(sflow_eth_counter->fcserrors),
    357 	   EXTRACT_32BITS(sflow_eth_counter->single_collision_frames),
    358 	   EXTRACT_32BITS(sflow_eth_counter->multiple_collision_frames),
    359 	   EXTRACT_32BITS(sflow_eth_counter->test_errors)));
    360     ND_PRINT((ndo, "\n\t      deferred %u, late collision %u, excessive collision %u, mac trans error %u",
    361 	   EXTRACT_32BITS(sflow_eth_counter->deferred_transmissions),
    362 	   EXTRACT_32BITS(sflow_eth_counter->late_collisions),
    363 	   EXTRACT_32BITS(sflow_eth_counter->excessive_collisions),
    364 	   EXTRACT_32BITS(sflow_eth_counter->mac_transmit_errors)));
    365     ND_PRINT((ndo, "\n\t      carrier error %u, frames too long %u, mac receive errors %u, symbol errors %u",
    366 	   EXTRACT_32BITS(sflow_eth_counter->carrier_sense_errors),
    367 	   EXTRACT_32BITS(sflow_eth_counter->frame_too_longs),
    368 	   EXTRACT_32BITS(sflow_eth_counter->mac_receive_errors),
    369 	   EXTRACT_32BITS(sflow_eth_counter->symbol_errors)));
    370 
    371     return 0;
    372 }
    373 
    374 static int
    375 print_sflow_counter_token_ring(netdissect_options *ndo _U_,
    376                                const u_char *pointer _U_, u_int len _U_)
    377 {
    378     return 0;
    379 }
    380 
    381 static int
    382 print_sflow_counter_basevg(netdissect_options *ndo,
    383                            const u_char *pointer, u_int len)
    384 {
    385     const struct sflow_100basevg_counter_t *sflow_100basevg_counter;
    386 
    387     if (len < sizeof(struct sflow_100basevg_counter_t))
    388 	return 1;
    389 
    390     sflow_100basevg_counter = (const struct sflow_100basevg_counter_t *)pointer;
    391     ND_PRINT((ndo, "\n\t      in high prio frames %u, in high prio octets %" PRIu64,
    392 	   EXTRACT_32BITS(sflow_100basevg_counter->in_highpriority_frames),
    393 	   EXTRACT_64BITS(sflow_100basevg_counter->in_highpriority_octets)));
    394     ND_PRINT((ndo, "\n\t      in norm prio frames %u, in norm prio octets %" PRIu64,
    395 	   EXTRACT_32BITS(sflow_100basevg_counter->in_normpriority_frames),
    396 	   EXTRACT_64BITS(sflow_100basevg_counter->in_normpriority_octets)));
    397     ND_PRINT((ndo, "\n\t      in ipm errors %u, oversized %u, in data errors %u, null addressed frames %u",
    398 	   EXTRACT_32BITS(sflow_100basevg_counter->in_ipmerrors),
    399 	   EXTRACT_32BITS(sflow_100basevg_counter->in_oversized),
    400 	   EXTRACT_32BITS(sflow_100basevg_counter->in_data_errors),
    401 	   EXTRACT_32BITS(sflow_100basevg_counter->in_null_addressed_frames)));
    402     ND_PRINT((ndo, "\n\t      out high prio frames %u, out high prio octets %" PRIu64
    403 	   ", trans into frames %u",
    404 	   EXTRACT_32BITS(sflow_100basevg_counter->out_highpriority_frames),
    405 	   EXTRACT_64BITS(sflow_100basevg_counter->out_highpriority_octets),
    406 	   EXTRACT_32BITS(sflow_100basevg_counter->transitioninto_frames)));
    407     ND_PRINT((ndo, "\n\t      in hc high prio octets %" PRIu64
    408 	   ", in hc norm prio octets %" PRIu64
    409 	   ", out hc high prio octets %" PRIu64,
    410 	   EXTRACT_64BITS(sflow_100basevg_counter->hc_in_highpriority_octets),
    411 	   EXTRACT_64BITS(sflow_100basevg_counter->hc_in_normpriority_octets),
    412 	   EXTRACT_64BITS(sflow_100basevg_counter->hc_out_highpriority_octets)));
    413 
    414     return 0;
    415 }
    416 
    417 static int
    418 print_sflow_counter_vlan(netdissect_options *ndo,
    419                          const u_char *pointer, u_int len)
    420 {
    421     const struct sflow_vlan_counter_t *sflow_vlan_counter;
    422 
    423     if (len < sizeof(struct sflow_vlan_counter_t))
    424 	return 1;
    425 
    426     sflow_vlan_counter = (const struct sflow_vlan_counter_t *)pointer;
    427     ND_PRINT((ndo, "\n\t      vlan_id %u, octets %" PRIu64
    428 	   ", unicast_pkt %u, multicast_pkt %u, broadcast_pkt %u, discards %u",
    429 	   EXTRACT_32BITS(sflow_vlan_counter->vlan_id),
    430 	   EXTRACT_64BITS(sflow_vlan_counter->octets),
    431 	   EXTRACT_32BITS(sflow_vlan_counter->unicast_pkt),
    432 	   EXTRACT_32BITS(sflow_vlan_counter->multicast_pkt),
    433 	   EXTRACT_32BITS(sflow_vlan_counter->broadcast_pkt),
    434 	   EXTRACT_32BITS(sflow_vlan_counter->discards)));
    435 
    436     return 0;
    437 }
    438 
    439 struct sflow_processor_counter_t {
    440     uint8_t five_sec_util[4];
    441     uint8_t one_min_util[4];
    442     uint8_t five_min_util[4];
    443     uint8_t total_memory[8];
    444     uint8_t free_memory[8];
    445 };
    446 
    447 static int
    448 print_sflow_counter_processor(netdissect_options *ndo,
    449                               const u_char *pointer, u_int len)
    450 {
    451     const struct sflow_processor_counter_t *sflow_processor_counter;
    452 
    453     if (len < sizeof(struct sflow_processor_counter_t))
    454 	return 1;
    455 
    456     sflow_processor_counter = (const struct sflow_processor_counter_t *)pointer;
    457     ND_PRINT((ndo, "\n\t      5sec %u, 1min %u, 5min %u, total_mem %" PRIu64
    458 	   ", total_mem %" PRIu64,
    459 	   EXTRACT_32BITS(sflow_processor_counter->five_sec_util),
    460 	   EXTRACT_32BITS(sflow_processor_counter->one_min_util),
    461 	   EXTRACT_32BITS(sflow_processor_counter->five_min_util),
    462 	   EXTRACT_64BITS(sflow_processor_counter->total_memory),
    463 	   EXTRACT_64BITS(sflow_processor_counter->free_memory)));
    464 
    465     return 0;
    466 }
    467 
    468 static int
    469 sflow_print_counter_records(netdissect_options *ndo,
    470                             const u_char *pointer, u_int len, u_int records)
    471 {
    472     u_int nrecords;
    473     const u_char *tptr;
    474     u_int tlen;
    475     u_int counter_type;
    476     u_int counter_len;
    477     u_int enterprise;
    478     const struct sflow_counter_record_t *sflow_counter_record;
    479 
    480     nrecords = records;
    481     tptr = pointer;
    482     tlen = len;
    483 
    484     while (nrecords > 0) {
    485 	/* do we have the "header?" */
    486 	if (tlen < sizeof(struct sflow_counter_record_t))
    487 	    return 1;
    488 	sflow_counter_record = (const struct sflow_counter_record_t *)tptr;
    489 
    490 	enterprise = EXTRACT_32BITS(sflow_counter_record->format);
    491 	counter_type = enterprise & 0x0FFF;
    492 	enterprise = enterprise >> 20;
    493 	counter_len  = EXTRACT_32BITS(sflow_counter_record->length);
    494 	ND_PRINT((ndo, "\n\t    enterprise %u, %s (%u) length %u",
    495 	       enterprise,
    496 	       (enterprise == 0) ? tok2str(sflow_counter_type_values,"Unknown",counter_type) : "Unknown",
    497 	       counter_type,
    498 	       counter_len));
    499 
    500 	tptr += sizeof(struct sflow_counter_record_t);
    501 	tlen -= sizeof(struct sflow_counter_record_t);
    502 
    503 	if (tlen < counter_len)
    504 	    return 1;
    505 	if (enterprise == 0) {
    506 	    switch (counter_type) {
    507 	    case SFLOW_COUNTER_GENERIC:
    508 		if (print_sflow_counter_generic(ndo, tptr, tlen))
    509 		    return 1;
    510 		break;
    511 	    case SFLOW_COUNTER_ETHERNET:
    512 		if (print_sflow_counter_ethernet(ndo, tptr, tlen))
    513 		    return 1;
    514 		break;
    515 	    case SFLOW_COUNTER_TOKEN_RING:
    516 		if (print_sflow_counter_token_ring(ndo, tptr,tlen))
    517 		    return 1;
    518 		break;
    519 	    case SFLOW_COUNTER_BASEVG:
    520 		if (print_sflow_counter_basevg(ndo, tptr, tlen))
    521 		    return 1;
    522 		break;
    523 	    case SFLOW_COUNTER_VLAN:
    524 		if (print_sflow_counter_vlan(ndo, tptr, tlen))
    525 		    return 1;
    526 		break;
    527 	    case SFLOW_COUNTER_PROCESSOR:
    528 		if (print_sflow_counter_processor(ndo, tptr, tlen))
    529 		    return 1;
    530 		break;
    531 	    default:
    532 		if (ndo->ndo_vflag <= 1)
    533 		    print_unknown_data(ndo, tptr, "\n\t\t", counter_len);
    534 		break;
    535 	    }
    536 	}
    537 	tptr += counter_len;
    538 	tlen -= counter_len;
    539 	nrecords--;
    540 
    541     }
    542 
    543     return 0;
    544 }
    545 
    546 static int
    547 sflow_print_counter_sample(netdissect_options *ndo,
    548                            const u_char *pointer, u_int len)
    549 {
    550     const struct sflow_counter_sample_t *sflow_counter_sample;
    551     u_int           nrecords;
    552     u_int           typesource;
    553     u_int           type;
    554     u_int           index;
    555 
    556 
    557     if (len < sizeof(struct sflow_counter_sample_t))
    558 	return 1;
    559 
    560     sflow_counter_sample = (const struct sflow_counter_sample_t *)pointer;
    561 
    562     typesource = EXTRACT_32BITS(sflow_counter_sample->typesource);
    563     nrecords   = EXTRACT_32BITS(sflow_counter_sample->records);
    564     type = typesource >> 24;
    565     index = typesource & 0x0FFF;
    566 
    567     ND_PRINT((ndo, " seqnum %u, type %u, idx %u, records %u",
    568 	   EXTRACT_32BITS(sflow_counter_sample->seqnum),
    569 	   type,
    570 	   index,
    571 	   nrecords));
    572 
    573     return sflow_print_counter_records(ndo, pointer + sizeof(struct sflow_counter_sample_t),
    574 				       len - sizeof(struct sflow_counter_sample_t),
    575 				       nrecords);
    576 
    577 }
    578 
    579 static int
    580 sflow_print_expanded_counter_sample(netdissect_options *ndo,
    581                                     const u_char *pointer, u_int len)
    582 {
    583     const struct sflow_expanded_counter_sample_t *sflow_expanded_counter_sample;
    584     u_int           nrecords;
    585 
    586 
    587     if (len < sizeof(struct sflow_expanded_counter_sample_t))
    588 	return 1;
    589 
    590     sflow_expanded_counter_sample = (const struct sflow_expanded_counter_sample_t *)pointer;
    591 
    592     nrecords = EXTRACT_32BITS(sflow_expanded_counter_sample->records);
    593 
    594     ND_PRINT((ndo, " seqnum %u, type %u, idx %u, records %u",
    595 	   EXTRACT_32BITS(sflow_expanded_counter_sample->seqnum),
    596 	   EXTRACT_32BITS(sflow_expanded_counter_sample->type),
    597 	   EXTRACT_32BITS(sflow_expanded_counter_sample->index),
    598 	   nrecords));
    599 
    600     return sflow_print_counter_records(ndo, pointer + sizeof(struct sflow_expanded_counter_sample_t),
    601 				       len - sizeof(struct sflow_expanded_counter_sample_t),
    602 				       nrecords);
    603 
    604 }
    605 
    606 static int
    607 print_sflow_raw_packet(netdissect_options *ndo,
    608                        const u_char *pointer, u_int len)
    609 {
    610     const struct sflow_expanded_flow_raw_t *sflow_flow_raw;
    611 
    612     if (len < sizeof(struct sflow_expanded_flow_raw_t))
    613 	return 1;
    614 
    615     sflow_flow_raw = (const struct sflow_expanded_flow_raw_t *)pointer;
    616     ND_PRINT((ndo, "\n\t      protocol %s (%u), length %u, stripped bytes %u, header_size %u",
    617 	   tok2str(sflow_flow_raw_protocol_values,"Unknown",EXTRACT_32BITS(sflow_flow_raw->protocol)),
    618 	   EXTRACT_32BITS(sflow_flow_raw->protocol),
    619 	   EXTRACT_32BITS(sflow_flow_raw->length),
    620 	   EXTRACT_32BITS(sflow_flow_raw->stripped_bytes),
    621 	   EXTRACT_32BITS(sflow_flow_raw->header_size)));
    622 
    623     /* QUESTION - should we attempt to print the raw header itself?
    624        assuming of course there is wnough data present to do so... */
    625 
    626     return 0;
    627 }
    628 
    629 static int
    630 print_sflow_ethernet_frame(netdissect_options *ndo,
    631                            const u_char *pointer, u_int len)
    632 {
    633     const struct sflow_ethernet_frame_t *sflow_ethernet_frame;
    634 
    635     if (len < sizeof(struct sflow_ethernet_frame_t))
    636 	return 1;
    637 
    638     sflow_ethernet_frame = (const struct sflow_ethernet_frame_t *)pointer;
    639 
    640     ND_PRINT((ndo, "\n\t      frame len %u, type %u",
    641 	   EXTRACT_32BITS(sflow_ethernet_frame->length),
    642 	   EXTRACT_32BITS(sflow_ethernet_frame->type)));
    643 
    644     return 0;
    645 }
    646 
    647 static int
    648 print_sflow_extended_switch_data(netdissect_options *ndo,
    649                                  const u_char *pointer, u_int len)
    650 {
    651     const struct sflow_extended_switch_data_t *sflow_extended_sw_data;
    652 
    653     if (len < sizeof(struct sflow_extended_switch_data_t))
    654 	return 1;
    655 
    656     sflow_extended_sw_data = (const struct sflow_extended_switch_data_t *)pointer;
    657     ND_PRINT((ndo, "\n\t      src vlan %u, src pri %u, dst vlan %u, dst pri %u",
    658 	   EXTRACT_32BITS(sflow_extended_sw_data->src_vlan),
    659 	   EXTRACT_32BITS(sflow_extended_sw_data->src_pri),
    660 	   EXTRACT_32BITS(sflow_extended_sw_data->dst_vlan),
    661 	   EXTRACT_32BITS(sflow_extended_sw_data->dst_pri)));
    662 
    663     return 0;
    664 }
    665 
    666 static int
    667 sflow_print_flow_records(netdissect_options *ndo,
    668                          const u_char *pointer, u_int len, u_int records)
    669 {
    670     u_int nrecords;
    671     const u_char *tptr;
    672     u_int tlen;
    673     u_int flow_type;
    674     u_int enterprise;
    675     u_int flow_len;
    676     const struct sflow_flow_record_t *sflow_flow_record;
    677 
    678     nrecords = records;
    679     tptr = pointer;
    680     tlen = len;
    681 
    682     while (nrecords > 0) {
    683 	/* do we have the "header?" */
    684 	if (tlen < sizeof(struct sflow_flow_record_t))
    685 	    return 1;
    686 
    687 	sflow_flow_record = (const struct sflow_flow_record_t *)tptr;
    688 
    689 	/* so, the funky encoding means we cannot blythly mask-off
    690 	   bits, we must also check the enterprise. */
    691 
    692 	enterprise = EXTRACT_32BITS(sflow_flow_record->format);
    693 	flow_type = enterprise & 0x0FFF;
    694 	enterprise = enterprise >> 12;
    695 	flow_len  = EXTRACT_32BITS(sflow_flow_record->length);
    696 	ND_PRINT((ndo, "\n\t    enterprise %u %s (%u) length %u",
    697 	       enterprise,
    698 	       (enterprise == 0) ? tok2str(sflow_flow_type_values,"Unknown",flow_type) : "Unknown",
    699 	       flow_type,
    700 	       flow_len));
    701 
    702 	tptr += sizeof(struct sflow_flow_record_t);
    703 	tlen -= sizeof(struct sflow_flow_record_t);
    704 
    705 	if (tlen < flow_len)
    706 	    return 1;
    707 
    708 	if (enterprise == 0) {
    709 	    switch (flow_type) {
    710 	    case SFLOW_FLOW_RAW_PACKET:
    711 		if (print_sflow_raw_packet(ndo, tptr, tlen))
    712 		    return 1;
    713 		break;
    714 	    case SFLOW_FLOW_EXTENDED_SWITCH_DATA:
    715 		if (print_sflow_extended_switch_data(ndo, tptr, tlen))
    716 		    return 1;
    717 		break;
    718 	    case SFLOW_FLOW_ETHERNET_FRAME:
    719 		if (print_sflow_ethernet_frame(ndo, tptr, tlen))
    720 		    return 1;
    721 		break;
    722 		/* FIXME these need a decoder */
    723 	    case SFLOW_FLOW_IPV4_DATA:
    724 	    case SFLOW_FLOW_IPV6_DATA:
    725 	    case SFLOW_FLOW_EXTENDED_ROUTER_DATA:
    726 	    case SFLOW_FLOW_EXTENDED_GATEWAY_DATA:
    727 	    case SFLOW_FLOW_EXTENDED_USER_DATA:
    728 	    case SFLOW_FLOW_EXTENDED_URL_DATA:
    729 	    case SFLOW_FLOW_EXTENDED_MPLS_DATA:
    730 	    case SFLOW_FLOW_EXTENDED_NAT_DATA:
    731 	    case SFLOW_FLOW_EXTENDED_MPLS_TUNNEL:
    732 	    case SFLOW_FLOW_EXTENDED_MPLS_VC:
    733 	    case SFLOW_FLOW_EXTENDED_MPLS_FEC:
    734 	    case SFLOW_FLOW_EXTENDED_MPLS_LVP_FEC:
    735 	    case SFLOW_FLOW_EXTENDED_VLAN_TUNNEL:
    736 		break;
    737 	    default:
    738 		if (ndo->ndo_vflag <= 1)
    739 		    print_unknown_data(ndo, tptr, "\n\t\t", flow_len);
    740 		break;
    741 	    }
    742 	}
    743 	tptr += flow_len;
    744 	tlen -= flow_len;
    745 	nrecords--;
    746 
    747     }
    748 
    749     return 0;
    750 }
    751 
    752 static int
    753 sflow_print_flow_sample(netdissect_options *ndo,
    754                         const u_char *pointer, u_int len)
    755 {
    756     const struct sflow_flow_sample_t *sflow_flow_sample;
    757     u_int          nrecords;
    758     u_int          typesource;
    759     u_int          type;
    760     u_int          index;
    761 
    762     if (len < sizeof(struct sflow_flow_sample_t))
    763 	return 1;
    764 
    765     sflow_flow_sample = (struct sflow_flow_sample_t *)pointer;
    766 
    767     typesource = EXTRACT_32BITS(sflow_flow_sample->typesource);
    768     nrecords = EXTRACT_32BITS(sflow_flow_sample->records);
    769     type = typesource >> 24;
    770     index = typesource & 0x0FFF;
    771 
    772     ND_PRINT((ndo, " seqnum %u, type %u, idx %u, rate %u, pool %u, drops %u, input %u output %u records %u",
    773 	   EXTRACT_32BITS(sflow_flow_sample->seqnum),
    774 	   type,
    775 	   index,
    776 	   EXTRACT_32BITS(sflow_flow_sample->rate),
    777 	   EXTRACT_32BITS(sflow_flow_sample->pool),
    778 	   EXTRACT_32BITS(sflow_flow_sample->drops),
    779 	   EXTRACT_32BITS(sflow_flow_sample->in_interface),
    780 	   EXTRACT_32BITS(sflow_flow_sample->out_interface),
    781 	   nrecords));
    782 
    783     return sflow_print_flow_records(ndo, pointer + sizeof(struct sflow_flow_sample_t),
    784 				    len - sizeof(struct sflow_flow_sample_t),
    785 				    nrecords);
    786 
    787 }
    788 
    789 static int
    790 sflow_print_expanded_flow_sample(netdissect_options *ndo,
    791                                  const u_char *pointer, u_int len)
    792 {
    793     const struct sflow_expanded_flow_sample_t *sflow_expanded_flow_sample;
    794     u_int nrecords;
    795 
    796     if (len < sizeof(struct sflow_expanded_flow_sample_t))
    797 	return 1;
    798 
    799     sflow_expanded_flow_sample = (const struct sflow_expanded_flow_sample_t *)pointer;
    800 
    801     nrecords = EXTRACT_32BITS(sflow_expanded_flow_sample->records);
    802 
    803     ND_PRINT((ndo, " seqnum %u, type %u, idx %u, rate %u, pool %u, drops %u, records %u",
    804 	   EXTRACT_32BITS(sflow_expanded_flow_sample->seqnum),
    805 	   EXTRACT_32BITS(sflow_expanded_flow_sample->type),
    806 	   EXTRACT_32BITS(sflow_expanded_flow_sample->index),
    807 	   EXTRACT_32BITS(sflow_expanded_flow_sample->rate),
    808 	   EXTRACT_32BITS(sflow_expanded_flow_sample->pool),
    809 	   EXTRACT_32BITS(sflow_expanded_flow_sample->drops),
    810 	   EXTRACT_32BITS(sflow_expanded_flow_sample->records)));
    811 
    812     return sflow_print_flow_records(ndo, pointer + sizeof(struct sflow_expanded_flow_sample_t),
    813 				    len - sizeof(struct sflow_expanded_flow_sample_t),
    814 				    nrecords);
    815 
    816 }
    817 
    818 void
    819 sflow_print(netdissect_options *ndo,
    820             const u_char *pptr, u_int len)
    821 {
    822     const struct sflow_datagram_t *sflow_datagram;
    823     const struct sflow_sample_header *sflow_sample;
    824 
    825     const u_char *tptr;
    826     u_int tlen;
    827     uint32_t sflow_sample_type, sflow_sample_len;
    828     uint32_t nsamples;
    829 
    830 
    831     tptr = pptr;
    832     tlen = len;
    833     sflow_datagram = (const struct sflow_datagram_t *)pptr;
    834     ND_TCHECK(*sflow_datagram);
    835 
    836     /*
    837      * Sanity checking of the header.
    838      */
    839     if (EXTRACT_32BITS(sflow_datagram->version) != 5) {
    840         ND_PRINT((ndo, "sFlow version %u packet not supported",
    841                EXTRACT_32BITS(sflow_datagram->version)));
    842         return;
    843     }
    844 
    845     if (ndo->ndo_vflag < 1) {
    846         ND_PRINT((ndo, "sFlowv%u, %s agent %s, agent-id %u, length %u",
    847                EXTRACT_32BITS(sflow_datagram->version),
    848                EXTRACT_32BITS(sflow_datagram->ip_version) == 1 ? "IPv4" : "IPv6",
    849                ipaddr_string(ndo, sflow_datagram->agent),
    850                EXTRACT_32BITS(sflow_datagram->agent_id),
    851                len));
    852         return;
    853     }
    854 
    855     /* ok they seem to want to know everything - lets fully decode it */
    856     nsamples=EXTRACT_32BITS(sflow_datagram->samples);
    857     ND_PRINT((ndo, "sFlowv%u, %s agent %s, agent-id %u, seqnum %u, uptime %u, samples %u, length %u",
    858            EXTRACT_32BITS(sflow_datagram->version),
    859            EXTRACT_32BITS(sflow_datagram->ip_version) == 1 ? "IPv4" : "IPv6",
    860            ipaddr_string(ndo, sflow_datagram->agent),
    861            EXTRACT_32BITS(sflow_datagram->agent_id),
    862            EXTRACT_32BITS(sflow_datagram->seqnum),
    863            EXTRACT_32BITS(sflow_datagram->uptime),
    864            nsamples,
    865            len));
    866 
    867     /* skip Common header */
    868     tptr += sizeof(const struct sflow_datagram_t);
    869     tlen -= sizeof(const struct sflow_datagram_t);
    870 
    871     while (nsamples > 0 && tlen > 0) {
    872         sflow_sample = (const struct sflow_sample_header *)tptr;
    873         ND_TCHECK(*sflow_sample);
    874 
    875         sflow_sample_type = (EXTRACT_32BITS(sflow_sample->format)&0x0FFF);
    876         sflow_sample_len = EXTRACT_32BITS(sflow_sample->len);
    877 
    878 	if (tlen < sizeof(struct sflow_sample_header))
    879 	    goto trunc;
    880 
    881         tptr += sizeof(struct sflow_sample_header);
    882         tlen -= sizeof(struct sflow_sample_header);
    883 
    884         ND_PRINT((ndo, "\n\t%s (%u), length %u,",
    885                tok2str(sflow_format_values, "Unknown", sflow_sample_type),
    886                sflow_sample_type,
    887                sflow_sample_len));
    888 
    889         /* basic sanity check */
    890         if (sflow_sample_type == 0 || sflow_sample_len ==0) {
    891             return;
    892         }
    893 
    894 	if (tlen < sflow_sample_len)
    895 	    goto trunc;
    896 
    897         /* did we capture enough for fully decoding the sample ? */
    898         ND_TCHECK2(*tptr, sflow_sample_len);
    899 
    900 	switch(sflow_sample_type) {
    901         case SFLOW_FLOW_SAMPLE:
    902 	    if (sflow_print_flow_sample(ndo, tptr, tlen))
    903 		goto trunc;
    904             break;
    905 
    906         case SFLOW_COUNTER_SAMPLE:
    907 	    if (sflow_print_counter_sample(ndo, tptr,tlen))
    908 		goto trunc;
    909             break;
    910 
    911         case SFLOW_EXPANDED_FLOW_SAMPLE:
    912 	    if (sflow_print_expanded_flow_sample(ndo, tptr, tlen))
    913 		goto trunc;
    914 	    break;
    915 
    916         case SFLOW_EXPANDED_COUNTER_SAMPLE:
    917 	    if (sflow_print_expanded_counter_sample(ndo, tptr,tlen))
    918 		goto trunc;
    919 	    break;
    920 
    921         default:
    922             if (ndo->ndo_vflag <= 1)
    923                 print_unknown_data(ndo, tptr, "\n\t    ", sflow_sample_len);
    924             break;
    925         }
    926         tptr += sflow_sample_len;
    927         tlen -= sflow_sample_len;
    928         nsamples--;
    929     }
    930     return;
    931 
    932  trunc:
    933     ND_PRINT((ndo, "[|SFLOW]"));
    934 }
    935 
    936 /*
    937  * Local Variables:
    938  * c-style: whitesmith
    939  * c-basic-offset: 4
    940  * End:
    941  */
    942