10f74e101Schristos /* 20f74e101Schristos * Copyright (c) 1998-2007 The TCPDUMP project 30f74e101Schristos * 40f74e101Schristos * Redistribution and use in source and binary forms, with or without 50f74e101Schristos * modification, are permitted provided that: (1) source code 60f74e101Schristos * distributions retain the above copyright notice and this paragraph 70f74e101Schristos * in its entirety, and (2) distributions including binary code include 80f74e101Schristos * the above copyright notice and this paragraph in its entirety in 90f74e101Schristos * the documentation or other materials provided with the distribution. 100f74e101Schristos * THIS SOFTWARE IS PROVIDED ``AS IS'' AND 110f74e101Schristos * WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT 120f74e101Schristos * LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 130f74e101Schristos * FOR A PARTICULAR PURPOSE. 140f74e101Schristos * 150f74e101Schristos * Original code by Carles Kishimoto <carles.kishimoto@gmail.com> 160e9868baSchristos * 170e9868baSchristos * Expansion and refactoring by Rick Jones <rick.jones2@hp.com> 180f74e101Schristos */ 190f74e101Schristos 20dc860a36Sspz /* \summary: sFlow protocol printer */ 21dc860a36Sspz 22c74ad251Schristos /* specification: https://sflow.org/developers/specifications.php */ 23dc860a36Sspz 2411b3aaa1Schristos #include <sys/cdefs.h> 250f74e101Schristos #ifndef lint 26*26ba0b50Schristos __RCSID("$NetBSD: print-sflow.c,v 1.11 2024/09/02 16:15:33 christos Exp $"); 270f74e101Schristos #endif 280f74e101Schristos 29c74ad251Schristos #include <config.h> 300f74e101Schristos 31c74ad251Schristos #include "netdissect-stdinc.h" 320f74e101Schristos 33c74ad251Schristos #define ND_LONGJMP_FROM_TCHECK 34fdccd7e4Schristos #include "netdissect.h" 350f74e101Schristos #include "extract.h" 360f74e101Schristos #include "addrtoname.h" 370f74e101Schristos 380f74e101Schristos /* 390f74e101Schristos * sFlow datagram 400f74e101Schristos * 410f74e101Schristos * 0 1 2 3 420f74e101Schristos * 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 430f74e101Schristos * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 440f74e101Schristos * | Sflow version (2,4,5) | 450f74e101Schristos * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 460f74e101Schristos * | IP version (1 for IPv4 | 2 for IPv6) | 470f74e101Schristos * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 480f74e101Schristos * | IP Address AGENT (4 or 16 bytes) | 490f74e101Schristos * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 500f74e101Schristos * | Sub agent ID | 510f74e101Schristos * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 520f74e101Schristos * | Datagram sequence number | 530f74e101Schristos * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 540f74e101Schristos * | Switch uptime in ms | 550f74e101Schristos * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 560f74e101Schristos * | num samples in datagram | 570f74e101Schristos * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 580f74e101Schristos * 590f74e101Schristos */ 600f74e101Schristos 610f74e101Schristos struct sflow_datagram_t { 62c74ad251Schristos nd_uint32_t version; 63c74ad251Schristos nd_uint32_t ip_version; 64c74ad251Schristos nd_ipv4 agent; 65c74ad251Schristos nd_uint32_t agent_id; 66c74ad251Schristos nd_uint32_t seqnum; 67c74ad251Schristos nd_uint32_t uptime; 68c74ad251Schristos nd_uint32_t samples; 69c74ad251Schristos }; 70c74ad251Schristos 71c74ad251Schristos struct sflow_v6_datagram_t { 72c74ad251Schristos nd_uint32_t version; 73c74ad251Schristos nd_uint32_t ip_version; 74c74ad251Schristos nd_ipv6 agent; 75c74ad251Schristos nd_uint32_t agent_id; 76c74ad251Schristos nd_uint32_t seqnum; 77c74ad251Schristos nd_uint32_t uptime; 78c74ad251Schristos nd_uint32_t samples; 790f74e101Schristos }; 800f74e101Schristos 810f74e101Schristos struct sflow_sample_header { 82c74ad251Schristos nd_uint32_t format; 83c74ad251Schristos nd_uint32_t len; 840f74e101Schristos }; 850f74e101Schristos 860f74e101Schristos #define SFLOW_FLOW_SAMPLE 1 870f74e101Schristos #define SFLOW_COUNTER_SAMPLE 2 880f74e101Schristos #define SFLOW_EXPANDED_FLOW_SAMPLE 3 890f74e101Schristos #define SFLOW_EXPANDED_COUNTER_SAMPLE 4 900f74e101Schristos 910f74e101Schristos static const struct tok sflow_format_values[] = { 920f74e101Schristos { SFLOW_FLOW_SAMPLE, "flow sample" }, 930f74e101Schristos { SFLOW_COUNTER_SAMPLE, "counter sample" }, 940f74e101Schristos { SFLOW_EXPANDED_FLOW_SAMPLE, "expanded flow sample" }, 950f74e101Schristos { SFLOW_EXPANDED_COUNTER_SAMPLE, "expanded counter sample" }, 960f74e101Schristos { 0, NULL} 970f74e101Schristos }; 980f74e101Schristos 990e9868baSchristos struct sflow_flow_sample_t { 100c74ad251Schristos nd_uint32_t seqnum; 101c74ad251Schristos nd_uint8_t type; 102c74ad251Schristos nd_uint24_t index; 103c74ad251Schristos nd_uint32_t rate; 104c74ad251Schristos nd_uint32_t pool; 105c74ad251Schristos nd_uint32_t drops; 106c74ad251Schristos nd_uint32_t in_interface; 107c74ad251Schristos nd_uint32_t out_interface; 108c74ad251Schristos nd_uint32_t records; 1090e9868baSchristos 1100e9868baSchristos }; 1110e9868baSchristos 1120f74e101Schristos struct sflow_expanded_flow_sample_t { 113c74ad251Schristos nd_uint32_t seqnum; 114c74ad251Schristos nd_uint32_t type; 115c74ad251Schristos nd_uint32_t index; 116c74ad251Schristos nd_uint32_t rate; 117c74ad251Schristos nd_uint32_t pool; 118c74ad251Schristos nd_uint32_t drops; 119c74ad251Schristos nd_uint32_t in_interface_format; 120c74ad251Schristos nd_uint32_t in_interface_value; 121c74ad251Schristos nd_uint32_t out_interface_format; 122c74ad251Schristos nd_uint32_t out_interface_value; 123c74ad251Schristos nd_uint32_t records; 1240f74e101Schristos }; 1250f74e101Schristos 1260f74e101Schristos #define SFLOW_FLOW_RAW_PACKET 1 1270f74e101Schristos #define SFLOW_FLOW_ETHERNET_FRAME 2 1280f74e101Schristos #define SFLOW_FLOW_IPV4_DATA 3 1290f74e101Schristos #define SFLOW_FLOW_IPV6_DATA 4 1300f74e101Schristos #define SFLOW_FLOW_EXTENDED_SWITCH_DATA 1001 1310f74e101Schristos #define SFLOW_FLOW_EXTENDED_ROUTER_DATA 1002 1320f74e101Schristos #define SFLOW_FLOW_EXTENDED_GATEWAY_DATA 1003 1330f74e101Schristos #define SFLOW_FLOW_EXTENDED_USER_DATA 1004 1340f74e101Schristos #define SFLOW_FLOW_EXTENDED_URL_DATA 1005 1350f74e101Schristos #define SFLOW_FLOW_EXTENDED_MPLS_DATA 1006 1360f74e101Schristos #define SFLOW_FLOW_EXTENDED_NAT_DATA 1007 1370f74e101Schristos #define SFLOW_FLOW_EXTENDED_MPLS_TUNNEL 1008 1380f74e101Schristos #define SFLOW_FLOW_EXTENDED_MPLS_VC 1009 1390f74e101Schristos #define SFLOW_FLOW_EXTENDED_MPLS_FEC 1010 1400f74e101Schristos #define SFLOW_FLOW_EXTENDED_MPLS_LVP_FEC 1011 1410f74e101Schristos #define SFLOW_FLOW_EXTENDED_VLAN_TUNNEL 1012 1420f74e101Schristos 1430f74e101Schristos static const struct tok sflow_flow_type_values[] = { 1440f74e101Schristos { SFLOW_FLOW_RAW_PACKET, "Raw packet"}, 1450f74e101Schristos { SFLOW_FLOW_ETHERNET_FRAME, "Ethernet frame"}, 1460f74e101Schristos { SFLOW_FLOW_IPV4_DATA, "IPv4 Data"}, 1470f74e101Schristos { SFLOW_FLOW_IPV6_DATA, "IPv6 Data"}, 1480f74e101Schristos { SFLOW_FLOW_EXTENDED_SWITCH_DATA, "Extended Switch data"}, 1490f74e101Schristos { SFLOW_FLOW_EXTENDED_ROUTER_DATA, "Extended Router data"}, 1500f74e101Schristos { SFLOW_FLOW_EXTENDED_GATEWAY_DATA, "Extended Gateway data"}, 1510f74e101Schristos { SFLOW_FLOW_EXTENDED_USER_DATA, "Extended User data"}, 1520f74e101Schristos { SFLOW_FLOW_EXTENDED_URL_DATA, "Extended URL data"}, 1530f74e101Schristos { SFLOW_FLOW_EXTENDED_MPLS_DATA, "Extended MPLS data"}, 1540f74e101Schristos { SFLOW_FLOW_EXTENDED_NAT_DATA, "Extended NAT data"}, 1550f74e101Schristos { SFLOW_FLOW_EXTENDED_MPLS_TUNNEL, "Extended MPLS tunnel"}, 1560f74e101Schristos { SFLOW_FLOW_EXTENDED_MPLS_VC, "Extended MPLS VC"}, 1570f74e101Schristos { SFLOW_FLOW_EXTENDED_MPLS_FEC, "Extended MPLS FEC"}, 1580f74e101Schristos { SFLOW_FLOW_EXTENDED_MPLS_LVP_FEC, "Extended MPLS LVP FEC"}, 1590f74e101Schristos { SFLOW_FLOW_EXTENDED_VLAN_TUNNEL, "Extended VLAN Tunnel"}, 1600f74e101Schristos { 0, NULL} 1610f74e101Schristos }; 1620f74e101Schristos 1630f74e101Schristos #define SFLOW_HEADER_PROTOCOL_ETHERNET 1 1640f74e101Schristos #define SFLOW_HEADER_PROTOCOL_IPV4 11 1650f74e101Schristos #define SFLOW_HEADER_PROTOCOL_IPV6 12 1660f74e101Schristos 1670f74e101Schristos static const struct tok sflow_flow_raw_protocol_values[] = { 1680f74e101Schristos { SFLOW_HEADER_PROTOCOL_ETHERNET, "Ethernet"}, 1690f74e101Schristos { SFLOW_HEADER_PROTOCOL_IPV4, "IPv4"}, 1700f74e101Schristos { SFLOW_HEADER_PROTOCOL_IPV6, "IPv6"}, 1710f74e101Schristos { 0, NULL} 1720f74e101Schristos }; 1730f74e101Schristos 1740f74e101Schristos struct sflow_expanded_flow_raw_t { 175c74ad251Schristos nd_uint32_t protocol; 176c74ad251Schristos nd_uint32_t length; 177c74ad251Schristos nd_uint32_t stripped_bytes; 178c74ad251Schristos nd_uint32_t header_size; 1790f74e101Schristos }; 1800f74e101Schristos 1810e9868baSchristos struct sflow_ethernet_frame_t { 182c74ad251Schristos nd_uint32_t length; 183c74ad251Schristos nd_byte src_mac[8]; 184c74ad251Schristos nd_byte dst_mac[8]; 185c74ad251Schristos nd_uint32_t type; 1860e9868baSchristos }; 1870e9868baSchristos 1880e9868baSchristos struct sflow_extended_switch_data_t { 189c74ad251Schristos nd_uint32_t src_vlan; 190c74ad251Schristos nd_uint32_t src_pri; 191c74ad251Schristos nd_uint32_t dst_vlan; 192c74ad251Schristos nd_uint32_t dst_pri; 1930e9868baSchristos }; 1940e9868baSchristos 1950e9868baSchristos struct sflow_counter_record_t { 196c74ad251Schristos nd_uint32_t format; 197c74ad251Schristos nd_uint32_t length; 1980e9868baSchristos }; 1990e9868baSchristos 2000e9868baSchristos struct sflow_flow_record_t { 201c74ad251Schristos nd_uint32_t format; 202c74ad251Schristos nd_uint32_t length; 2030e9868baSchristos }; 2040e9868baSchristos 2050e9868baSchristos struct sflow_counter_sample_t { 206c74ad251Schristos nd_uint32_t seqnum; 207c74ad251Schristos nd_uint8_t type; 208c74ad251Schristos nd_uint24_t index; 209c74ad251Schristos nd_uint32_t records; 2100e9868baSchristos }; 2110e9868baSchristos 2120f74e101Schristos struct sflow_expanded_counter_sample_t { 213c74ad251Schristos nd_uint32_t seqnum; 214c74ad251Schristos nd_uint32_t type; 215c74ad251Schristos nd_uint32_t index; 216c74ad251Schristos nd_uint32_t records; 2170f74e101Schristos }; 2180f74e101Schristos 2190f74e101Schristos #define SFLOW_COUNTER_GENERIC 1 2200f74e101Schristos #define SFLOW_COUNTER_ETHERNET 2 2210f74e101Schristos #define SFLOW_COUNTER_TOKEN_RING 3 2220f74e101Schristos #define SFLOW_COUNTER_BASEVG 4 2230f74e101Schristos #define SFLOW_COUNTER_VLAN 5 2240f74e101Schristos #define SFLOW_COUNTER_PROCESSOR 1001 2250f74e101Schristos 2260f74e101Schristos static const struct tok sflow_counter_type_values[] = { 2270f74e101Schristos { SFLOW_COUNTER_GENERIC, "Generic counter"}, 2280f74e101Schristos { SFLOW_COUNTER_ETHERNET, "Ethernet counter"}, 2290f74e101Schristos { SFLOW_COUNTER_TOKEN_RING, "Token ring counter"}, 2300f74e101Schristos { SFLOW_COUNTER_BASEVG, "100 BaseVG counter"}, 2310f74e101Schristos { SFLOW_COUNTER_VLAN, "Vlan counter"}, 2320f74e101Schristos { SFLOW_COUNTER_PROCESSOR, "Processor counter"}, 2330f74e101Schristos { 0, NULL} 2340f74e101Schristos }; 2350f74e101Schristos 2360f74e101Schristos #define SFLOW_IFACE_DIRECTION_UNKNOWN 0 2370f74e101Schristos #define SFLOW_IFACE_DIRECTION_FULLDUPLEX 1 2380f74e101Schristos #define SFLOW_IFACE_DIRECTION_HALFDUPLEX 2 2390f74e101Schristos #define SFLOW_IFACE_DIRECTION_IN 3 2400f74e101Schristos #define SFLOW_IFACE_DIRECTION_OUT 4 2410f74e101Schristos 2420f74e101Schristos static const struct tok sflow_iface_direction_values[] = { 2430f74e101Schristos { SFLOW_IFACE_DIRECTION_UNKNOWN, "unknown"}, 2440f74e101Schristos { SFLOW_IFACE_DIRECTION_FULLDUPLEX, "full-duplex"}, 2450f74e101Schristos { SFLOW_IFACE_DIRECTION_HALFDUPLEX, "half-duplex"}, 2460f74e101Schristos { SFLOW_IFACE_DIRECTION_IN, "in"}, 2470f74e101Schristos { SFLOW_IFACE_DIRECTION_OUT, "out"}, 2480f74e101Schristos { 0, NULL} 2490f74e101Schristos }; 2500f74e101Schristos 2510f74e101Schristos struct sflow_generic_counter_t { 252c74ad251Schristos nd_uint32_t ifindex; 253c74ad251Schristos nd_uint32_t iftype; 254c74ad251Schristos nd_uint64_t ifspeed; 255c74ad251Schristos nd_uint32_t ifdirection; 256c74ad251Schristos nd_uint32_t ifstatus; 257c74ad251Schristos nd_uint64_t ifinoctets; 258c74ad251Schristos nd_uint32_t ifinunicastpkts; 259c74ad251Schristos nd_uint32_t ifinmulticastpkts; 260c74ad251Schristos nd_uint32_t ifinbroadcastpkts; 261c74ad251Schristos nd_uint32_t ifindiscards; 262c74ad251Schristos nd_uint32_t ifinerrors; 263c74ad251Schristos nd_uint32_t ifinunkownprotos; 264c74ad251Schristos nd_uint64_t ifoutoctets; 265c74ad251Schristos nd_uint32_t ifoutunicastpkts; 266c74ad251Schristos nd_uint32_t ifoutmulticastpkts; 267c74ad251Schristos nd_uint32_t ifoutbroadcastpkts; 268c74ad251Schristos nd_uint32_t ifoutdiscards; 269c74ad251Schristos nd_uint32_t ifouterrors; 270c74ad251Schristos nd_uint32_t ifpromiscmode; 2710f74e101Schristos }; 2720f74e101Schristos 2730f74e101Schristos struct sflow_ethernet_counter_t { 274c74ad251Schristos nd_uint32_t alignerrors; 275c74ad251Schristos nd_uint32_t fcserrors; 276c74ad251Schristos nd_uint32_t single_collision_frames; 277c74ad251Schristos nd_uint32_t multiple_collision_frames; 278c74ad251Schristos nd_uint32_t test_errors; 279c74ad251Schristos nd_uint32_t deferred_transmissions; 280c74ad251Schristos nd_uint32_t late_collisions; 281c74ad251Schristos nd_uint32_t excessive_collisions; 282c74ad251Schristos nd_uint32_t mac_transmit_errors; 283c74ad251Schristos nd_uint32_t carrier_sense_errors; 284c74ad251Schristos nd_uint32_t frame_too_longs; 285c74ad251Schristos nd_uint32_t mac_receive_errors; 286c74ad251Schristos nd_uint32_t symbol_errors; 2870f74e101Schristos }; 2880f74e101Schristos 2890f74e101Schristos struct sflow_100basevg_counter_t { 290c74ad251Schristos nd_uint32_t in_highpriority_frames; 291c74ad251Schristos nd_uint64_t in_highpriority_octets; 292c74ad251Schristos nd_uint32_t in_normpriority_frames; 293c74ad251Schristos nd_uint64_t in_normpriority_octets; 294c74ad251Schristos nd_uint32_t in_ipmerrors; 295c74ad251Schristos nd_uint32_t in_oversized; 296c74ad251Schristos nd_uint32_t in_data_errors; 297c74ad251Schristos nd_uint32_t in_null_addressed_frames; 298c74ad251Schristos nd_uint32_t out_highpriority_frames; 299c74ad251Schristos nd_uint64_t out_highpriority_octets; 300c74ad251Schristos nd_uint32_t transitioninto_frames; 301c74ad251Schristos nd_uint64_t hc_in_highpriority_octets; 302c74ad251Schristos nd_uint64_t hc_in_normpriority_octets; 303c74ad251Schristos nd_uint64_t hc_out_highpriority_octets; 3040f74e101Schristos }; 3050f74e101Schristos 3060f74e101Schristos struct sflow_vlan_counter_t { 307c74ad251Schristos nd_uint32_t vlan_id; 308c74ad251Schristos nd_uint64_t octets; 309c74ad251Schristos nd_uint32_t unicast_pkt; 310c74ad251Schristos nd_uint32_t multicast_pkt; 311c74ad251Schristos nd_uint32_t broadcast_pkt; 312c74ad251Schristos nd_uint32_t discards; 3130f74e101Schristos }; 3140f74e101Schristos 3150e9868baSchristos static int 316b3a00663Schristos print_sflow_counter_generic(netdissect_options *ndo, 317ba2ff121Schristos const u_char *pointer, u_int len) 318ba2ff121Schristos { 3190e9868baSchristos const struct sflow_generic_counter_t *sflow_gen_counter; 3200e9868baSchristos 3210e9868baSchristos if (len < sizeof(struct sflow_generic_counter_t)) 3220e9868baSchristos return 1; 3230e9868baSchristos 3240e9868baSchristos sflow_gen_counter = (const struct sflow_generic_counter_t *)pointer; 325c74ad251Schristos ND_PRINT("\n\t ifindex %u, iftype %u, ifspeed %" PRIu64 ", ifdirection %u (%s)", 326c74ad251Schristos GET_BE_U_4(sflow_gen_counter->ifindex), 327c74ad251Schristos GET_BE_U_4(sflow_gen_counter->iftype), 328c74ad251Schristos GET_BE_U_8(sflow_gen_counter->ifspeed), 329c74ad251Schristos GET_BE_U_4(sflow_gen_counter->ifdirection), 3300e9868baSchristos tok2str(sflow_iface_direction_values, "Unknown", 331c74ad251Schristos GET_BE_U_4(sflow_gen_counter->ifdirection))); 332c74ad251Schristos ND_PRINT("\n\t ifstatus %u, adminstatus: %s, operstatus: %s", 333c74ad251Schristos GET_BE_U_4(sflow_gen_counter->ifstatus), 334c74ad251Schristos GET_BE_U_4(sflow_gen_counter->ifstatus)&1 ? "up" : "down", 335c74ad251Schristos (GET_BE_U_4(sflow_gen_counter->ifstatus)>>1)&1 ? "up" : "down"); 336c74ad251Schristos ND_PRINT("\n\t In octets %" PRIu64 3370e9868baSchristos ", unicast pkts %u, multicast pkts %u, broadcast pkts %u, discards %u", 338c74ad251Schristos GET_BE_U_8(sflow_gen_counter->ifinoctets), 339c74ad251Schristos GET_BE_U_4(sflow_gen_counter->ifinunicastpkts), 340c74ad251Schristos GET_BE_U_4(sflow_gen_counter->ifinmulticastpkts), 341c74ad251Schristos GET_BE_U_4(sflow_gen_counter->ifinbroadcastpkts), 342c74ad251Schristos GET_BE_U_4(sflow_gen_counter->ifindiscards)); 343c74ad251Schristos ND_PRINT("\n\t In errors %u, unknown protos %u", 344c74ad251Schristos GET_BE_U_4(sflow_gen_counter->ifinerrors), 345c74ad251Schristos GET_BE_U_4(sflow_gen_counter->ifinunkownprotos)); 346c74ad251Schristos ND_PRINT("\n\t Out octets %" PRIu64 3470e9868baSchristos ", unicast pkts %u, multicast pkts %u, broadcast pkts %u, discards %u", 348c74ad251Schristos GET_BE_U_8(sflow_gen_counter->ifoutoctets), 349c74ad251Schristos GET_BE_U_4(sflow_gen_counter->ifoutunicastpkts), 350c74ad251Schristos GET_BE_U_4(sflow_gen_counter->ifoutmulticastpkts), 351c74ad251Schristos GET_BE_U_4(sflow_gen_counter->ifoutbroadcastpkts), 352c74ad251Schristos GET_BE_U_4(sflow_gen_counter->ifoutdiscards)); 353c74ad251Schristos ND_PRINT("\n\t Out errors %u, promisc mode %u", 354c74ad251Schristos GET_BE_U_4(sflow_gen_counter->ifouterrors), 355c74ad251Schristos GET_BE_U_4(sflow_gen_counter->ifpromiscmode)); 3560e9868baSchristos 3570e9868baSchristos return 0; 3580e9868baSchristos } 3590e9868baSchristos 3600e9868baSchristos static int 361b3a00663Schristos print_sflow_counter_ethernet(netdissect_options *ndo, 362ba2ff121Schristos const u_char *pointer, u_int len) 363ba2ff121Schristos { 3640e9868baSchristos const struct sflow_ethernet_counter_t *sflow_eth_counter; 3650e9868baSchristos 3660e9868baSchristos if (len < sizeof(struct sflow_ethernet_counter_t)) 3670e9868baSchristos return 1; 3680e9868baSchristos 3690e9868baSchristos sflow_eth_counter = (const struct sflow_ethernet_counter_t *)pointer; 370c74ad251Schristos ND_PRINT("\n\t align errors %u, fcs errors %u, single collision %u, multiple collision %u, test error %u", 371c74ad251Schristos GET_BE_U_4(sflow_eth_counter->alignerrors), 372c74ad251Schristos GET_BE_U_4(sflow_eth_counter->fcserrors), 373c74ad251Schristos GET_BE_U_4(sflow_eth_counter->single_collision_frames), 374c74ad251Schristos GET_BE_U_4(sflow_eth_counter->multiple_collision_frames), 375c74ad251Schristos GET_BE_U_4(sflow_eth_counter->test_errors)); 376c74ad251Schristos ND_PRINT("\n\t deferred %u, late collision %u, excessive collision %u, mac trans error %u", 377c74ad251Schristos GET_BE_U_4(sflow_eth_counter->deferred_transmissions), 378c74ad251Schristos GET_BE_U_4(sflow_eth_counter->late_collisions), 379c74ad251Schristos GET_BE_U_4(sflow_eth_counter->excessive_collisions), 380c74ad251Schristos GET_BE_U_4(sflow_eth_counter->mac_transmit_errors)); 381c74ad251Schristos ND_PRINT("\n\t carrier error %u, frames too long %u, mac receive errors %u, symbol errors %u", 382c74ad251Schristos GET_BE_U_4(sflow_eth_counter->carrier_sense_errors), 383c74ad251Schristos GET_BE_U_4(sflow_eth_counter->frame_too_longs), 384c74ad251Schristos GET_BE_U_4(sflow_eth_counter->mac_receive_errors), 385c74ad251Schristos GET_BE_U_4(sflow_eth_counter->symbol_errors)); 3860e9868baSchristos 3870e9868baSchristos return 0; 3880e9868baSchristos } 3890e9868baSchristos 3900e9868baSchristos static int 391b3a00663Schristos print_sflow_counter_token_ring(netdissect_options *ndo _U_, 392ba2ff121Schristos const u_char *pointer _U_, u_int len _U_) 393ba2ff121Schristos { 3940e9868baSchristos return 0; 3950e9868baSchristos } 3960e9868baSchristos 3970e9868baSchristos static int 398b3a00663Schristos print_sflow_counter_basevg(netdissect_options *ndo, 399ba2ff121Schristos const u_char *pointer, u_int len) 400ba2ff121Schristos { 4010e9868baSchristos const struct sflow_100basevg_counter_t *sflow_100basevg_counter; 4020e9868baSchristos 4030e9868baSchristos if (len < sizeof(struct sflow_100basevg_counter_t)) 4040e9868baSchristos return 1; 4050e9868baSchristos 4060e9868baSchristos sflow_100basevg_counter = (const struct sflow_100basevg_counter_t *)pointer; 407c74ad251Schristos ND_PRINT("\n\t in high prio frames %u, in high prio octets %" PRIu64, 408c74ad251Schristos GET_BE_U_4(sflow_100basevg_counter->in_highpriority_frames), 409c74ad251Schristos GET_BE_U_8(sflow_100basevg_counter->in_highpriority_octets)); 410c74ad251Schristos ND_PRINT("\n\t in norm prio frames %u, in norm prio octets %" PRIu64, 411c74ad251Schristos GET_BE_U_4(sflow_100basevg_counter->in_normpriority_frames), 412c74ad251Schristos GET_BE_U_8(sflow_100basevg_counter->in_normpriority_octets)); 413c74ad251Schristos ND_PRINT("\n\t in ipm errors %u, oversized %u, in data errors %u, null addressed frames %u", 414c74ad251Schristos GET_BE_U_4(sflow_100basevg_counter->in_ipmerrors), 415c74ad251Schristos GET_BE_U_4(sflow_100basevg_counter->in_oversized), 416c74ad251Schristos GET_BE_U_4(sflow_100basevg_counter->in_data_errors), 417c74ad251Schristos GET_BE_U_4(sflow_100basevg_counter->in_null_addressed_frames)); 418c74ad251Schristos ND_PRINT("\n\t out high prio frames %u, out high prio octets %" PRIu64 4190e9868baSchristos ", trans into frames %u", 420c74ad251Schristos GET_BE_U_4(sflow_100basevg_counter->out_highpriority_frames), 421c74ad251Schristos GET_BE_U_8(sflow_100basevg_counter->out_highpriority_octets), 422c74ad251Schristos GET_BE_U_4(sflow_100basevg_counter->transitioninto_frames)); 423c74ad251Schristos ND_PRINT("\n\t in hc high prio octets %" PRIu64 4240e9868baSchristos ", in hc norm prio octets %" PRIu64 4250e9868baSchristos ", out hc high prio octets %" PRIu64, 426c74ad251Schristos GET_BE_U_8(sflow_100basevg_counter->hc_in_highpriority_octets), 427c74ad251Schristos GET_BE_U_8(sflow_100basevg_counter->hc_in_normpriority_octets), 428c74ad251Schristos GET_BE_U_8(sflow_100basevg_counter->hc_out_highpriority_octets)); 4290e9868baSchristos 4300e9868baSchristos return 0; 4310e9868baSchristos } 4320e9868baSchristos 4330e9868baSchristos static int 434b3a00663Schristos print_sflow_counter_vlan(netdissect_options *ndo, 435ba2ff121Schristos const u_char *pointer, u_int len) 436ba2ff121Schristos { 4370e9868baSchristos const struct sflow_vlan_counter_t *sflow_vlan_counter; 4380e9868baSchristos 4390e9868baSchristos if (len < sizeof(struct sflow_vlan_counter_t)) 4400e9868baSchristos return 1; 4410e9868baSchristos 4420e9868baSchristos sflow_vlan_counter = (const struct sflow_vlan_counter_t *)pointer; 443c74ad251Schristos ND_PRINT("\n\t vlan_id %u, octets %" PRIu64 4440e9868baSchristos ", unicast_pkt %u, multicast_pkt %u, broadcast_pkt %u, discards %u", 445c74ad251Schristos GET_BE_U_4(sflow_vlan_counter->vlan_id), 446c74ad251Schristos GET_BE_U_8(sflow_vlan_counter->octets), 447c74ad251Schristos GET_BE_U_4(sflow_vlan_counter->unicast_pkt), 448c74ad251Schristos GET_BE_U_4(sflow_vlan_counter->multicast_pkt), 449c74ad251Schristos GET_BE_U_4(sflow_vlan_counter->broadcast_pkt), 450c74ad251Schristos GET_BE_U_4(sflow_vlan_counter->discards)); 4510e9868baSchristos 4520e9868baSchristos return 0; 4530e9868baSchristos } 4540e9868baSchristos 4550e9868baSchristos struct sflow_processor_counter_t { 456c74ad251Schristos nd_uint32_t five_sec_util; 457c74ad251Schristos nd_uint32_t one_min_util; 458c74ad251Schristos nd_uint32_t five_min_util; 459c74ad251Schristos nd_uint64_t total_memory; 460c74ad251Schristos nd_uint64_t free_memory; 4610e9868baSchristos }; 4620e9868baSchristos 4630e9868baSchristos static int 464b3a00663Schristos print_sflow_counter_processor(netdissect_options *ndo, 465ba2ff121Schristos const u_char *pointer, u_int len) 466ba2ff121Schristos { 4670e9868baSchristos const struct sflow_processor_counter_t *sflow_processor_counter; 4680e9868baSchristos 4690e9868baSchristos if (len < sizeof(struct sflow_processor_counter_t)) 4700e9868baSchristos return 1; 4710e9868baSchristos 4720e9868baSchristos sflow_processor_counter = (const struct sflow_processor_counter_t *)pointer; 473c74ad251Schristos ND_PRINT("\n\t 5sec %u, 1min %u, 5min %u, total_mem %" PRIu64 4740e9868baSchristos ", total_mem %" PRIu64, 475c74ad251Schristos GET_BE_U_4(sflow_processor_counter->five_sec_util), 476c74ad251Schristos GET_BE_U_4(sflow_processor_counter->one_min_util), 477c74ad251Schristos GET_BE_U_4(sflow_processor_counter->five_min_util), 478c74ad251Schristos GET_BE_U_8(sflow_processor_counter->total_memory), 479c74ad251Schristos GET_BE_U_8(sflow_processor_counter->free_memory)); 4800e9868baSchristos 4810e9868baSchristos return 0; 4820e9868baSchristos } 4830e9868baSchristos 4840e9868baSchristos static int 485b3a00663Schristos sflow_print_counter_records(netdissect_options *ndo, 486ba2ff121Schristos const u_char *pointer, u_int len, u_int records) 487ba2ff121Schristos { 4880e9868baSchristos u_int nrecords; 4890e9868baSchristos const u_char *tptr; 4900e9868baSchristos u_int tlen; 4910e9868baSchristos u_int counter_type; 4920e9868baSchristos u_int counter_len; 4930e9868baSchristos u_int enterprise; 4940e9868baSchristos const struct sflow_counter_record_t *sflow_counter_record; 4950e9868baSchristos 4960e9868baSchristos nrecords = records; 4970e9868baSchristos tptr = pointer; 4980e9868baSchristos tlen = len; 4990e9868baSchristos 5000e9868baSchristos while (nrecords > 0) { 5010e9868baSchristos /* do we have the "header?" */ 5020e9868baSchristos if (tlen < sizeof(struct sflow_counter_record_t)) 5030e9868baSchristos return 1; 5040e9868baSchristos sflow_counter_record = (const struct sflow_counter_record_t *)tptr; 5050e9868baSchristos 506c74ad251Schristos enterprise = GET_BE_U_4(sflow_counter_record->format); 5070e9868baSchristos counter_type = enterprise & 0x0FFF; 5080e9868baSchristos enterprise = enterprise >> 20; 509c74ad251Schristos counter_len = GET_BE_U_4(sflow_counter_record->length); 510c74ad251Schristos ND_PRINT("\n\t enterprise %u, %s (%u) length %u", 5110e9868baSchristos enterprise, 5120e9868baSchristos (enterprise == 0) ? tok2str(sflow_counter_type_values,"Unknown",counter_type) : "Unknown", 5130e9868baSchristos counter_type, 514c74ad251Schristos counter_len); 5150e9868baSchristos 5160e9868baSchristos tptr += sizeof(struct sflow_counter_record_t); 5170e9868baSchristos tlen -= sizeof(struct sflow_counter_record_t); 5180e9868baSchristos 5190e9868baSchristos if (tlen < counter_len) 5200e9868baSchristos return 1; 5210e9868baSchristos if (enterprise == 0) { 5220e9868baSchristos switch (counter_type) { 5230e9868baSchristos case SFLOW_COUNTER_GENERIC: 524b3a00663Schristos if (print_sflow_counter_generic(ndo, tptr, tlen)) 5250e9868baSchristos return 1; 5260e9868baSchristos break; 5270e9868baSchristos case SFLOW_COUNTER_ETHERNET: 528b3a00663Schristos if (print_sflow_counter_ethernet(ndo, tptr, tlen)) 5290e9868baSchristos return 1; 5300e9868baSchristos break; 5310e9868baSchristos case SFLOW_COUNTER_TOKEN_RING: 532b3a00663Schristos if (print_sflow_counter_token_ring(ndo, tptr,tlen)) 5330e9868baSchristos return 1; 5340e9868baSchristos break; 5350e9868baSchristos case SFLOW_COUNTER_BASEVG: 536b3a00663Schristos if (print_sflow_counter_basevg(ndo, tptr, tlen)) 5370e9868baSchristos return 1; 5380e9868baSchristos break; 5390e9868baSchristos case SFLOW_COUNTER_VLAN: 540b3a00663Schristos if (print_sflow_counter_vlan(ndo, tptr, tlen)) 5410e9868baSchristos return 1; 5420e9868baSchristos break; 5430e9868baSchristos case SFLOW_COUNTER_PROCESSOR: 544b3a00663Schristos if (print_sflow_counter_processor(ndo, tptr, tlen)) 5450e9868baSchristos return 1; 5460e9868baSchristos break; 5470e9868baSchristos default: 548b3a00663Schristos if (ndo->ndo_vflag <= 1) 549b3a00663Schristos print_unknown_data(ndo, tptr, "\n\t\t", counter_len); 5500e9868baSchristos break; 5510e9868baSchristos } 5520e9868baSchristos } 5530e9868baSchristos tptr += counter_len; 5540e9868baSchristos tlen -= counter_len; 5550e9868baSchristos nrecords--; 5560e9868baSchristos 5570e9868baSchristos } 5580e9868baSchristos 5590e9868baSchristos return 0; 5600e9868baSchristos } 5610e9868baSchristos 5620e9868baSchristos static int 563b3a00663Schristos sflow_print_counter_sample(netdissect_options *ndo, 564ba2ff121Schristos const u_char *pointer, u_int len) 565ba2ff121Schristos { 5660e9868baSchristos const struct sflow_counter_sample_t *sflow_counter_sample; 5670e9868baSchristos u_int nrecords; 5680e9868baSchristos 5690e9868baSchristos if (len < sizeof(struct sflow_counter_sample_t)) 5700e9868baSchristos return 1; 5710e9868baSchristos 5720e9868baSchristos sflow_counter_sample = (const struct sflow_counter_sample_t *)pointer; 5730e9868baSchristos 574c74ad251Schristos nrecords = GET_BE_U_4(sflow_counter_sample->records); 5750e9868baSchristos 576c74ad251Schristos ND_PRINT(" seqnum %u, type %u, idx %u, records %u", 577c74ad251Schristos GET_BE_U_4(sflow_counter_sample->seqnum), 578c74ad251Schristos GET_U_1(sflow_counter_sample->type), 579c74ad251Schristos GET_BE_U_3(sflow_counter_sample->index), 580c74ad251Schristos nrecords); 5810e9868baSchristos 582b3a00663Schristos return sflow_print_counter_records(ndo, pointer + sizeof(struct sflow_counter_sample_t), 5830e9868baSchristos len - sizeof(struct sflow_counter_sample_t), 5840e9868baSchristos nrecords); 5850e9868baSchristos } 5860e9868baSchristos 5870e9868baSchristos static int 588b3a00663Schristos sflow_print_expanded_counter_sample(netdissect_options *ndo, 589ba2ff121Schristos const u_char *pointer, u_int len) 590ba2ff121Schristos { 5910e9868baSchristos const struct sflow_expanded_counter_sample_t *sflow_expanded_counter_sample; 5920e9868baSchristos u_int nrecords; 5930e9868baSchristos 5940e9868baSchristos 5950e9868baSchristos if (len < sizeof(struct sflow_expanded_counter_sample_t)) 5960e9868baSchristos return 1; 5970e9868baSchristos 5980e9868baSchristos sflow_expanded_counter_sample = (const struct sflow_expanded_counter_sample_t *)pointer; 5990e9868baSchristos 600c74ad251Schristos nrecords = GET_BE_U_4(sflow_expanded_counter_sample->records); 6010e9868baSchristos 602c74ad251Schristos ND_PRINT(" seqnum %u, type %u, idx %u, records %u", 603c74ad251Schristos GET_BE_U_4(sflow_expanded_counter_sample->seqnum), 604c74ad251Schristos GET_BE_U_4(sflow_expanded_counter_sample->type), 605c74ad251Schristos GET_BE_U_4(sflow_expanded_counter_sample->index), 606c74ad251Schristos nrecords); 6070e9868baSchristos 608b3a00663Schristos return sflow_print_counter_records(ndo, pointer + sizeof(struct sflow_expanded_counter_sample_t), 6090e9868baSchristos len - sizeof(struct sflow_expanded_counter_sample_t), 6100e9868baSchristos nrecords); 6110e9868baSchristos } 6120e9868baSchristos 6130e9868baSchristos static int 614b3a00663Schristos print_sflow_raw_packet(netdissect_options *ndo, 615ba2ff121Schristos const u_char *pointer, u_int len) 616ba2ff121Schristos { 6170e9868baSchristos const struct sflow_expanded_flow_raw_t *sflow_flow_raw; 6180e9868baSchristos 6190e9868baSchristos if (len < sizeof(struct sflow_expanded_flow_raw_t)) 6200e9868baSchristos return 1; 6210e9868baSchristos 6220e9868baSchristos sflow_flow_raw = (const struct sflow_expanded_flow_raw_t *)pointer; 623c74ad251Schristos ND_PRINT("\n\t protocol %s (%u), length %u, stripped bytes %u, header_size %u", 624c74ad251Schristos tok2str(sflow_flow_raw_protocol_values,"Unknown",GET_BE_U_4(sflow_flow_raw->protocol)), 625c74ad251Schristos GET_BE_U_4(sflow_flow_raw->protocol), 626c74ad251Schristos GET_BE_U_4(sflow_flow_raw->length), 627c74ad251Schristos GET_BE_U_4(sflow_flow_raw->stripped_bytes), 628c74ad251Schristos GET_BE_U_4(sflow_flow_raw->header_size)); 6290e9868baSchristos 6300e9868baSchristos /* QUESTION - should we attempt to print the raw header itself? 631c74ad251Schristos assuming of course there is enough data present to do so... */ 6320e9868baSchristos 6330e9868baSchristos return 0; 6340e9868baSchristos } 6350e9868baSchristos 6360e9868baSchristos static int 637b3a00663Schristos print_sflow_ethernet_frame(netdissect_options *ndo, 638ba2ff121Schristos const u_char *pointer, u_int len) 639ba2ff121Schristos { 6400e9868baSchristos const struct sflow_ethernet_frame_t *sflow_ethernet_frame; 6410e9868baSchristos 6420e9868baSchristos if (len < sizeof(struct sflow_ethernet_frame_t)) 6430e9868baSchristos return 1; 6440e9868baSchristos 6450e9868baSchristos sflow_ethernet_frame = (const struct sflow_ethernet_frame_t *)pointer; 6460e9868baSchristos 647c74ad251Schristos ND_PRINT("\n\t frame len %u, type %u", 648c74ad251Schristos GET_BE_U_4(sflow_ethernet_frame->length), 649c74ad251Schristos GET_BE_U_4(sflow_ethernet_frame->type)); 6500e9868baSchristos 6510e9868baSchristos return 0; 6520e9868baSchristos } 6530e9868baSchristos 6540e9868baSchristos static int 655b3a00663Schristos print_sflow_extended_switch_data(netdissect_options *ndo, 656ba2ff121Schristos const u_char *pointer, u_int len) 657ba2ff121Schristos { 6580e9868baSchristos const struct sflow_extended_switch_data_t *sflow_extended_sw_data; 6590e9868baSchristos 6600e9868baSchristos if (len < sizeof(struct sflow_extended_switch_data_t)) 6610e9868baSchristos return 1; 6620e9868baSchristos 6630e9868baSchristos sflow_extended_sw_data = (const struct sflow_extended_switch_data_t *)pointer; 664c74ad251Schristos ND_PRINT("\n\t src vlan %u, src pri %u, dst vlan %u, dst pri %u", 665c74ad251Schristos GET_BE_U_4(sflow_extended_sw_data->src_vlan), 666c74ad251Schristos GET_BE_U_4(sflow_extended_sw_data->src_pri), 667c74ad251Schristos GET_BE_U_4(sflow_extended_sw_data->dst_vlan), 668c74ad251Schristos GET_BE_U_4(sflow_extended_sw_data->dst_pri)); 6690e9868baSchristos 6700e9868baSchristos return 0; 6710e9868baSchristos } 6720e9868baSchristos 6730e9868baSchristos static int 674b3a00663Schristos sflow_print_flow_records(netdissect_options *ndo, 675ba2ff121Schristos const u_char *pointer, u_int len, u_int records) 676ba2ff121Schristos { 6770e9868baSchristos u_int nrecords; 6780e9868baSchristos const u_char *tptr; 6790e9868baSchristos u_int tlen; 6800e9868baSchristos u_int flow_type; 6810e9868baSchristos u_int enterprise; 6820e9868baSchristos u_int flow_len; 6830e9868baSchristos const struct sflow_flow_record_t *sflow_flow_record; 6840e9868baSchristos 6850e9868baSchristos nrecords = records; 6860e9868baSchristos tptr = pointer; 6870e9868baSchristos tlen = len; 6880e9868baSchristos 6890e9868baSchristos while (nrecords > 0) { 6900e9868baSchristos /* do we have the "header?" */ 6910e9868baSchristos if (tlen < sizeof(struct sflow_flow_record_t)) 6920e9868baSchristos return 1; 6930e9868baSchristos 6940e9868baSchristos sflow_flow_record = (const struct sflow_flow_record_t *)tptr; 6950e9868baSchristos 696*26ba0b50Schristos /* so, the funky encoding means we cannot blithely mask-off 6970e9868baSchristos bits, we must also check the enterprise. */ 6980e9868baSchristos 699c74ad251Schristos enterprise = GET_BE_U_4(sflow_flow_record->format); 7000e9868baSchristos flow_type = enterprise & 0x0FFF; 7010e9868baSchristos enterprise = enterprise >> 12; 702c74ad251Schristos flow_len = GET_BE_U_4(sflow_flow_record->length); 703c74ad251Schristos ND_PRINT("\n\t enterprise %u %s (%u) length %u", 7040e9868baSchristos enterprise, 7050e9868baSchristos (enterprise == 0) ? tok2str(sflow_flow_type_values,"Unknown",flow_type) : "Unknown", 7060e9868baSchristos flow_type, 707c74ad251Schristos flow_len); 7080e9868baSchristos 7090e9868baSchristos tptr += sizeof(struct sflow_flow_record_t); 7100e9868baSchristos tlen -= sizeof(struct sflow_flow_record_t); 7110e9868baSchristos 7120e9868baSchristos if (tlen < flow_len) 7130e9868baSchristos return 1; 7140e9868baSchristos 7150e9868baSchristos if (enterprise == 0) { 7160e9868baSchristos switch (flow_type) { 7170e9868baSchristos case SFLOW_FLOW_RAW_PACKET: 718b3a00663Schristos if (print_sflow_raw_packet(ndo, tptr, tlen)) 7190e9868baSchristos return 1; 7200e9868baSchristos break; 7210e9868baSchristos case SFLOW_FLOW_EXTENDED_SWITCH_DATA: 722b3a00663Schristos if (print_sflow_extended_switch_data(ndo, tptr, tlen)) 7230e9868baSchristos return 1; 7240e9868baSchristos break; 7250e9868baSchristos case SFLOW_FLOW_ETHERNET_FRAME: 726b3a00663Schristos if (print_sflow_ethernet_frame(ndo, tptr, tlen)) 7270e9868baSchristos return 1; 7280e9868baSchristos break; 7290e9868baSchristos /* FIXME these need a decoder */ 7300e9868baSchristos case SFLOW_FLOW_IPV4_DATA: 7310e9868baSchristos case SFLOW_FLOW_IPV6_DATA: 7320e9868baSchristos case SFLOW_FLOW_EXTENDED_ROUTER_DATA: 7330e9868baSchristos case SFLOW_FLOW_EXTENDED_GATEWAY_DATA: 7340e9868baSchristos case SFLOW_FLOW_EXTENDED_USER_DATA: 7350e9868baSchristos case SFLOW_FLOW_EXTENDED_URL_DATA: 7360e9868baSchristos case SFLOW_FLOW_EXTENDED_MPLS_DATA: 7370e9868baSchristos case SFLOW_FLOW_EXTENDED_NAT_DATA: 7380e9868baSchristos case SFLOW_FLOW_EXTENDED_MPLS_TUNNEL: 7390e9868baSchristos case SFLOW_FLOW_EXTENDED_MPLS_VC: 7400e9868baSchristos case SFLOW_FLOW_EXTENDED_MPLS_FEC: 7410e9868baSchristos case SFLOW_FLOW_EXTENDED_MPLS_LVP_FEC: 7420e9868baSchristos case SFLOW_FLOW_EXTENDED_VLAN_TUNNEL: 7430e9868baSchristos break; 7440e9868baSchristos default: 745b3a00663Schristos if (ndo->ndo_vflag <= 1) 746b3a00663Schristos print_unknown_data(ndo, tptr, "\n\t\t", flow_len); 7470e9868baSchristos break; 7480e9868baSchristos } 7490e9868baSchristos } 7500e9868baSchristos tptr += flow_len; 7510e9868baSchristos tlen -= flow_len; 7520e9868baSchristos nrecords--; 7530e9868baSchristos 7540e9868baSchristos } 7550e9868baSchristos 7560e9868baSchristos return 0; 7570e9868baSchristos } 7580e9868baSchristos 7590e9868baSchristos static int 760b3a00663Schristos sflow_print_flow_sample(netdissect_options *ndo, 761ba2ff121Schristos const u_char *pointer, u_int len) 762ba2ff121Schristos { 7630e9868baSchristos const struct sflow_flow_sample_t *sflow_flow_sample; 7640e9868baSchristos u_int nrecords; 7650e9868baSchristos 7660e9868baSchristos if (len < sizeof(struct sflow_flow_sample_t)) 7670e9868baSchristos return 1; 7680e9868baSchristos 769fdccd7e4Schristos sflow_flow_sample = (const struct sflow_flow_sample_t *)pointer; 7700e9868baSchristos 771c74ad251Schristos nrecords = GET_BE_U_4(sflow_flow_sample->records); 7720e9868baSchristos 773c74ad251Schristos ND_PRINT(" seqnum %u, type %u, idx %u, rate %u, pool %u, drops %u, input %u output %u records %u", 774c74ad251Schristos GET_BE_U_4(sflow_flow_sample->seqnum), 775c74ad251Schristos GET_U_1(sflow_flow_sample->type), 776c74ad251Schristos GET_BE_U_3(sflow_flow_sample->index), 777c74ad251Schristos GET_BE_U_4(sflow_flow_sample->rate), 778c74ad251Schristos GET_BE_U_4(sflow_flow_sample->pool), 779c74ad251Schristos GET_BE_U_4(sflow_flow_sample->drops), 780c74ad251Schristos GET_BE_U_4(sflow_flow_sample->in_interface), 781c74ad251Schristos GET_BE_U_4(sflow_flow_sample->out_interface), 782c74ad251Schristos nrecords); 7830e9868baSchristos 784b3a00663Schristos return sflow_print_flow_records(ndo, pointer + sizeof(struct sflow_flow_sample_t), 7850e9868baSchristos len - sizeof(struct sflow_flow_sample_t), 7860e9868baSchristos nrecords); 7870e9868baSchristos } 7880e9868baSchristos 7890e9868baSchristos static int 790b3a00663Schristos sflow_print_expanded_flow_sample(netdissect_options *ndo, 791ba2ff121Schristos const u_char *pointer, u_int len) 792ba2ff121Schristos { 7930e9868baSchristos const struct sflow_expanded_flow_sample_t *sflow_expanded_flow_sample; 7940e9868baSchristos u_int nrecords; 7950e9868baSchristos 7960e9868baSchristos if (len < sizeof(struct sflow_expanded_flow_sample_t)) 7970e9868baSchristos return 1; 7980e9868baSchristos 7990e9868baSchristos sflow_expanded_flow_sample = (const struct sflow_expanded_flow_sample_t *)pointer; 8000e9868baSchristos 801c74ad251Schristos nrecords = GET_BE_U_4(sflow_expanded_flow_sample->records); 8020e9868baSchristos 803c74ad251Schristos ND_PRINT(" seqnum %u, type %u, idx %u, rate %u, pool %u, drops %u, records %u", 804c74ad251Schristos GET_BE_U_4(sflow_expanded_flow_sample->seqnum), 805c74ad251Schristos GET_BE_U_4(sflow_expanded_flow_sample->type), 806c74ad251Schristos GET_BE_U_4(sflow_expanded_flow_sample->index), 807c74ad251Schristos GET_BE_U_4(sflow_expanded_flow_sample->rate), 808c74ad251Schristos GET_BE_U_4(sflow_expanded_flow_sample->pool), 809c74ad251Schristos GET_BE_U_4(sflow_expanded_flow_sample->drops), 810c74ad251Schristos nrecords); 8110e9868baSchristos 812b3a00663Schristos return sflow_print_flow_records(ndo, pointer + sizeof(struct sflow_expanded_flow_sample_t), 8130e9868baSchristos len - sizeof(struct sflow_expanded_flow_sample_t), 8140e9868baSchristos nrecords); 8150e9868baSchristos } 8160e9868baSchristos 8170f74e101Schristos void 818b3a00663Schristos sflow_print(netdissect_options *ndo, 819ba2ff121Schristos const u_char *pptr, u_int len) 820ba2ff121Schristos { 8210f74e101Schristos const struct sflow_datagram_t *sflow_datagram; 822c74ad251Schristos const struct sflow_v6_datagram_t *sflow_v6_datagram; 8230f74e101Schristos const struct sflow_sample_header *sflow_sample; 8240e9868baSchristos 8250f74e101Schristos const u_char *tptr; 8260e9868baSchristos u_int tlen; 827b3a00663Schristos uint32_t sflow_sample_type, sflow_sample_len; 828b3a00663Schristos uint32_t nsamples; 829c74ad251Schristos uint32_t ip_version; 8300e9868baSchristos 831c74ad251Schristos ndo->ndo_protocol = "sflow"; 8320f74e101Schristos tptr = pptr; 8330f74e101Schristos tlen = len; 8340f74e101Schristos sflow_datagram = (const struct sflow_datagram_t *)pptr; 835c74ad251Schristos sflow_v6_datagram = (const struct sflow_v6_datagram_t *)pptr; 836c74ad251Schristos ip_version = GET_BE_U_4(sflow_datagram->ip_version); 837c74ad251Schristos 838c74ad251Schristos if ((len < sizeof(struct sflow_datagram_t) && (ip_version == 1)) || 839c74ad251Schristos (len < sizeof(struct sflow_v6_datagram_t) && (ip_version == 2))) { 840c74ad251Schristos ND_PRINT("sFlowv%u", GET_BE_U_4(sflow_datagram->version)); 841c74ad251Schristos ND_PRINT(" [length %u < %zu]", len, sizeof(struct sflow_datagram_t)); 842c74ad251Schristos nd_print_invalid(ndo); 843817e9a7eSchristos return; 844817e9a7eSchristos } 845c74ad251Schristos ND_TCHECK_SIZE(sflow_datagram); 8460f74e101Schristos 8470f74e101Schristos /* 8480f74e101Schristos * Sanity checking of the header. 8490f74e101Schristos */ 850c74ad251Schristos if (GET_BE_U_4(sflow_datagram->version) != 5) { 851c74ad251Schristos ND_PRINT("sFlow version %u packet not supported", 852c74ad251Schristos GET_BE_U_4(sflow_datagram->version)); 8530f74e101Schristos return; 8540f74e101Schristos } 8550f74e101Schristos 856b3a00663Schristos if (ndo->ndo_vflag < 1) { 857c74ad251Schristos ND_PRINT("sFlowv%u, %s agent %s, agent-id %u, length %u", 858c74ad251Schristos GET_BE_U_4(sflow_datagram->version), 859c74ad251Schristos ip_version == 1 ? "IPv4" : "IPv6", 860c74ad251Schristos ip_version == 1 ? GET_IPADDR_STRING(sflow_datagram->agent) : 861c74ad251Schristos GET_IP6ADDR_STRING( sflow_v6_datagram->agent), 862c74ad251Schristos ip_version == 1 ? GET_BE_U_4(sflow_datagram->agent_id) : 863c74ad251Schristos GET_BE_U_4(sflow_v6_datagram->agent_id), 864c74ad251Schristos len); 8650f74e101Schristos return; 8660f74e101Schristos } 8670f74e101Schristos 8680f74e101Schristos /* ok they seem to want to know everything - lets fully decode it */ 869c74ad251Schristos if (ip_version == 1) { 870c74ad251Schristos nsamples=GET_BE_U_4(sflow_datagram->samples); 871c74ad251Schristos ND_PRINT("sFlowv%u, %s agent %s, agent-id %u, seqnum %u, uptime %u, samples %u, length %u", 872c74ad251Schristos GET_BE_U_4(sflow_datagram->version), 873c74ad251Schristos "IPv4", 874c74ad251Schristos GET_IPADDR_STRING(sflow_datagram->agent), 875c74ad251Schristos GET_BE_U_4(sflow_datagram->agent_id), 876c74ad251Schristos GET_BE_U_4(sflow_datagram->seqnum), 877c74ad251Schristos GET_BE_U_4(sflow_datagram->uptime), 8780f74e101Schristos nsamples, 879c74ad251Schristos len); 8800f74e101Schristos 8810f74e101Schristos /* skip Common header */ 882*26ba0b50Schristos ND_ICHECK_ZU(tlen, <, sizeof(struct sflow_datagram_t)); 883c74ad251Schristos tptr += sizeof(struct sflow_datagram_t); 884c74ad251Schristos tlen -= sizeof(struct sflow_datagram_t); 885c74ad251Schristos } else { 886c74ad251Schristos nsamples=GET_BE_U_4(sflow_v6_datagram->samples); 887c74ad251Schristos ND_PRINT("sFlowv%u, %s agent %s, agent-id %u, seqnum %u, uptime %u, samples %u, length %u", 888c74ad251Schristos GET_BE_U_4(sflow_v6_datagram->version), 889c74ad251Schristos "IPv6", 890c74ad251Schristos GET_IP6ADDR_STRING(sflow_v6_datagram->agent), 891c74ad251Schristos GET_BE_U_4(sflow_v6_datagram->agent_id), 892c74ad251Schristos GET_BE_U_4(sflow_v6_datagram->seqnum), 893c74ad251Schristos GET_BE_U_4(sflow_v6_datagram->uptime), 894c74ad251Schristos nsamples, 895c74ad251Schristos len); 896817e9a7eSchristos 897c74ad251Schristos /* skip Common header */ 898*26ba0b50Schristos ND_ICHECK_ZU(tlen, <, sizeof(struct sflow_v6_datagram_t)); 899c74ad251Schristos tptr += sizeof(struct sflow_v6_datagram_t); 900c74ad251Schristos tlen -= sizeof(struct sflow_v6_datagram_t); 901c74ad251Schristos } 9020f74e101Schristos while (nsamples > 0 && tlen > 0) { 9030f74e101Schristos sflow_sample = (const struct sflow_sample_header *)tptr; 9040e9868baSchristos 905c74ad251Schristos sflow_sample_type = (GET_BE_U_4(sflow_sample->format)&0x0FFF); 906c74ad251Schristos sflow_sample_len = GET_BE_U_4(sflow_sample->len); 9070f74e101Schristos 9080e9868baSchristos if (tlen < sizeof(struct sflow_sample_header)) 909c74ad251Schristos goto invalid; 9100e9868baSchristos 9110f74e101Schristos tptr += sizeof(struct sflow_sample_header); 9120f74e101Schristos tlen -= sizeof(struct sflow_sample_header); 9130f74e101Schristos 914c74ad251Schristos ND_PRINT("\n\t%s (%u), length %u,", 9150f74e101Schristos tok2str(sflow_format_values, "Unknown", sflow_sample_type), 9160f74e101Schristos sflow_sample_type, 917c74ad251Schristos sflow_sample_len); 9180f74e101Schristos 9190f74e101Schristos /* basic sanity check */ 9200f74e101Schristos if (sflow_sample_type == 0 || sflow_sample_len ==0) { 9210f74e101Schristos return; 9220f74e101Schristos } 9230f74e101Schristos 9240e9868baSchristos if (tlen < sflow_sample_len) 925c74ad251Schristos goto invalid; 9260f74e101Schristos 9270e9868baSchristos /* did we capture enough for fully decoding the sample ? */ 928c74ad251Schristos ND_TCHECK_LEN(tptr, sflow_sample_len); 9290e9868baSchristos 9300f74e101Schristos switch(sflow_sample_type) { 9310e9868baSchristos case SFLOW_FLOW_SAMPLE: 932b3a00663Schristos if (sflow_print_flow_sample(ndo, tptr, tlen)) 933c74ad251Schristos goto invalid; 9340f74e101Schristos break; 9350f74e101Schristos 9360e9868baSchristos case SFLOW_COUNTER_SAMPLE: 937b3a00663Schristos if (sflow_print_counter_sample(ndo, tptr,tlen)) 938c74ad251Schristos goto invalid; 9390f74e101Schristos break; 9400f74e101Schristos 9410f74e101Schristos case SFLOW_EXPANDED_FLOW_SAMPLE: 942b3a00663Schristos if (sflow_print_expanded_flow_sample(ndo, tptr, tlen)) 943c74ad251Schristos goto invalid; 9440f74e101Schristos break; 9450f74e101Schristos 9460f74e101Schristos case SFLOW_EXPANDED_COUNTER_SAMPLE: 947b3a00663Schristos if (sflow_print_expanded_counter_sample(ndo, tptr,tlen)) 948c74ad251Schristos goto invalid; 9490e9868baSchristos break; 9500f74e101Schristos 9510f74e101Schristos default: 952b3a00663Schristos if (ndo->ndo_vflag <= 1) 953b3a00663Schristos print_unknown_data(ndo, tptr, "\n\t ", sflow_sample_len); 9540f74e101Schristos break; 9550f74e101Schristos } 9560f74e101Schristos tptr += sflow_sample_len; 9570f74e101Schristos tlen -= sflow_sample_len; 9580f74e101Schristos nsamples--; 9590f74e101Schristos } 9600f74e101Schristos return; 9610f74e101Schristos 962c74ad251Schristos invalid: 963c74ad251Schristos nd_print_invalid(ndo); 964c74ad251Schristos ND_TCHECK_LEN(tptr, tlen); 9650f74e101Schristos } 966