print-sflow.c 32 KB

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