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