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