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 57struct 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 67struct 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 77static 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 85struct 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 97struct 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 128static 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 152static 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 159struct 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 166struct 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 173struct 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 180struct sflow_counter_record_t { 181 uint8_t format[4]; 182 uint8_t length[4]; 183}; 184 185struct sflow_flow_record_t { 186 uint8_t format[4]; 187 uint8_t length[4]; 188}; 189 190struct sflow_counter_sample_t { 191 uint8_t seqnum[4]; 192 uint8_t typesource[4]; 193 uint8_t records[4]; 194}; 195 196struct 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 210static 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 226static 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 235struct 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 257struct 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 273struct 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 290struct 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 299static int 300print_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 344trunc: 345 return 1; 346} 347 348static int 349print_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 378trunc: 379 return 1; 380} 381 382static int 383print_sflow_counter_token_ring(netdissect_options *ndo _U_, 384 const u_char *pointer _U_, u_int len _U_) 385{ 386 return 0; 387} 388 389static int 390print_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 425trunc: 426 return 1; 427} 428 429static int 430print_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 451trunc: 452 return 1; 453} 454 455struct 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 463static int 464print_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 484trunc: 485 return 1; 486} 487 488static int 489sflow_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 566trunc: 567 return 1; 568} 569 570static int 571sflow_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 601trunc: 602 return 1; 603} 604 605static int 606sflow_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 631trunc: 632 return 1; 633} 634 635static int 636print_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 658trunc: 659 return 1; 660} 661 662static int 663print_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 680trunc: 681 return 1; 682} 683 684static int 685print_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 703trunc: 704 return 1; 705} 706 707static int 708sflow_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 793trunc: 794 return 1; 795} 796 797static int 798sflow_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 833trunc: 834 return 1; 835} 836 837static int 838sflow_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 865trunc: 866 return 1; 867} 868 869void 870sflow_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