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