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