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