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