1190203Srpaulo/*
2190203Srpaulo * Copyright (c) 1998-2007 The TCPDUMP project
3190203Srpaulo *
4190203Srpaulo * Redistribution and use in source and binary forms, with or without
5190203Srpaulo * modification, are permitted provided that: (1) source code
6190203Srpaulo * distributions retain the above copyright notice and this paragraph
7190203Srpaulo * in its entirety, and (2) distributions including binary code include
8190203Srpaulo * the above copyright notice and this paragraph in its entirety in
9190203Srpaulo * the documentation or other materials provided with the distribution.
10190203Srpaulo * THIS SOFTWARE IS PROVIDED ``AS IS'' AND
11190203Srpaulo * WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT
12190203Srpaulo * LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
13190203Srpaulo * FOR A PARTICULAR PURPOSE.
14190203Srpaulo *
15190203Srpaulo * The SFLOW protocol as per http://www.sflow.org/developers/specifications.php
16190203Srpaulo *
17190203Srpaulo * Original code by Carles Kishimoto <carles.kishimoto@gmail.com>
18236192Sdelphij *
19236192Sdelphij * Expansion and refactoring by Rick Jones <rick.jones2@hp.com>
20190203Srpaulo */
21190203Srpaulo
22190203Srpaulo#ifndef lint
23190203Srpaulostatic const char rcsid[] _U_ =
24190203Srpaulo"@(#) $Header: /tcpdump/master/tcpdump/print-sflow.c,v 1.1 2007-08-08 17:20:58 hannes Exp $";
25190203Srpaulo#endif
26190203Srpaulo
27190203Srpaulo#ifdef HAVE_CONFIG_H
28190203Srpaulo#include "config.h"
29190203Srpaulo#endif
30190203Srpaulo
31190203Srpaulo#include <tcpdump-stdinc.h>
32190203Srpaulo
33190203Srpaulo#include <stdio.h>
34190203Srpaulo#include <stdlib.h>
35190203Srpaulo#include <string.h>
36190203Srpaulo
37190203Srpaulo#include "interface.h"
38190203Srpaulo#include "extract.h"
39190203Srpaulo#include "addrtoname.h"
40190203Srpaulo
41190203Srpaulo/*
42190203Srpaulo * sFlow datagram
43190203Srpaulo *
44190203Srpaulo * 0                   1                   2                   3
45190203Srpaulo * 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
46190203Srpaulo * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
47190203Srpaulo * |                     Sflow version (2,4,5)                     |
48190203Srpaulo * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
49190203Srpaulo * |               IP version (1 for IPv4 | 2 for IPv6)            |
50190203Srpaulo * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
51190203Srpaulo * |                     IP Address AGENT (4 or 16 bytes)          |
52190203Srpaulo * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
53190203Srpaulo * |                          Sub agent ID                         |
54190203Srpaulo * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
55190203Srpaulo * |                      Datagram sequence number                 |
56190203Srpaulo * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
57190203Srpaulo * |                      Switch uptime in ms                      |
58190203Srpaulo * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
59190203Srpaulo * |                    num samples in datagram                    |
60190203Srpaulo * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
61190203Srpaulo *
62190203Srpaulo */
63190203Srpaulo
64190203Srpaulostruct sflow_datagram_t {
65190203Srpaulo    u_int8_t 	version[4];
66190203Srpaulo    u_int8_t 	ip_version[4];
67190203Srpaulo    u_int8_t 	agent[4];
68190203Srpaulo    u_int8_t 	agent_id[4];
69190203Srpaulo    u_int8_t 	seqnum[4];
70190203Srpaulo    u_int8_t 	uptime[4];
71190203Srpaulo    u_int8_t 	samples[4];
72190203Srpaulo};
73190203Srpaulo
74190203Srpaulostruct sflow_sample_header {
75190203Srpaulo    u_int8_t	format[4];
76190203Srpaulo    u_int8_t	len[4];
77190203Srpaulo};
78190203Srpaulo
79190203Srpaulo#define		SFLOW_FLOW_SAMPLE		1
80190203Srpaulo#define		SFLOW_COUNTER_SAMPLE		2
81190203Srpaulo#define		SFLOW_EXPANDED_FLOW_SAMPLE	3
82190203Srpaulo#define		SFLOW_EXPANDED_COUNTER_SAMPLE	4
83190203Srpaulo
84190203Srpaulostatic const struct tok sflow_format_values[] = {
85190203Srpaulo    { SFLOW_FLOW_SAMPLE, "flow sample" },
86190203Srpaulo    { SFLOW_COUNTER_SAMPLE, "counter sample" },
87190203Srpaulo    { SFLOW_EXPANDED_FLOW_SAMPLE, "expanded flow sample" },
88190203Srpaulo    { SFLOW_EXPANDED_COUNTER_SAMPLE, "expanded counter sample" },
89190203Srpaulo    { 0, NULL}
90190203Srpaulo};
91190203Srpaulo
92236192Sdelphijstruct sflow_flow_sample_t {
93236192Sdelphij    u_int8_t    seqnum[4];
94236192Sdelphij    u_int8_t    typesource[4];
95236192Sdelphij    u_int8_t    rate[4];
96236192Sdelphij    u_int8_t    pool[4];
97236192Sdelphij    u_int8_t    drops[4];
98236192Sdelphij    u_int8_t    in_interface[4];
99236192Sdelphij    u_int8_t    out_interface[4];
100236192Sdelphij    u_int8_t    records[4];
101236192Sdelphij
102236192Sdelphij};
103236192Sdelphij
104190203Srpaulostruct sflow_expanded_flow_sample_t {
105190203Srpaulo    u_int8_t    seqnum[4];
106190203Srpaulo    u_int8_t    type[4];
107190203Srpaulo    u_int8_t    index[4];
108190203Srpaulo    u_int8_t    rate[4];
109190203Srpaulo    u_int8_t    pool[4];
110190203Srpaulo    u_int8_t    drops[4];
111190203Srpaulo    u_int8_t    in_interface_format[4];
112190203Srpaulo    u_int8_t    in_interface_value[4];
113190203Srpaulo    u_int8_t    out_interface_format[4];
114190203Srpaulo    u_int8_t    out_interface_value[4];
115190203Srpaulo    u_int8_t    records[4];
116190203Srpaulo};
117190203Srpaulo
118190203Srpaulo#define 	SFLOW_FLOW_RAW_PACKET			1
119190203Srpaulo#define 	SFLOW_FLOW_ETHERNET_FRAME		2
120190203Srpaulo#define 	SFLOW_FLOW_IPV4_DATA			3
121190203Srpaulo#define 	SFLOW_FLOW_IPV6_DATA			4
122190203Srpaulo#define 	SFLOW_FLOW_EXTENDED_SWITCH_DATA		1001
123190203Srpaulo#define 	SFLOW_FLOW_EXTENDED_ROUTER_DATA		1002
124190203Srpaulo#define 	SFLOW_FLOW_EXTENDED_GATEWAY_DATA 	1003
125190203Srpaulo#define 	SFLOW_FLOW_EXTENDED_USER_DATA		1004
126190203Srpaulo#define 	SFLOW_FLOW_EXTENDED_URL_DATA		1005
127190203Srpaulo#define 	SFLOW_FLOW_EXTENDED_MPLS_DATA		1006
128190203Srpaulo#define 	SFLOW_FLOW_EXTENDED_NAT_DATA		1007
129190203Srpaulo#define 	SFLOW_FLOW_EXTENDED_MPLS_TUNNEL		1008
130190203Srpaulo#define 	SFLOW_FLOW_EXTENDED_MPLS_VC		1009
131190203Srpaulo#define 	SFLOW_FLOW_EXTENDED_MPLS_FEC		1010
132190203Srpaulo#define 	SFLOW_FLOW_EXTENDED_MPLS_LVP_FEC	1011
133190203Srpaulo#define 	SFLOW_FLOW_EXTENDED_VLAN_TUNNEL		1012
134190203Srpaulo
135190203Srpaulostatic const struct tok sflow_flow_type_values[] = {
136190203Srpaulo    { SFLOW_FLOW_RAW_PACKET, "Raw packet"},
137190203Srpaulo    { SFLOW_FLOW_ETHERNET_FRAME, "Ethernet frame"},
138190203Srpaulo    { SFLOW_FLOW_IPV4_DATA, "IPv4 Data"},
139190203Srpaulo    { SFLOW_FLOW_IPV6_DATA, "IPv6 Data"},
140190203Srpaulo    { SFLOW_FLOW_EXTENDED_SWITCH_DATA, "Extended Switch data"},
141190203Srpaulo    { SFLOW_FLOW_EXTENDED_ROUTER_DATA, "Extended Router data"},
142190203Srpaulo    { SFLOW_FLOW_EXTENDED_GATEWAY_DATA, "Extended Gateway data"},
143190203Srpaulo    { SFLOW_FLOW_EXTENDED_USER_DATA, "Extended User data"},
144190203Srpaulo    { SFLOW_FLOW_EXTENDED_URL_DATA, "Extended URL data"},
145190203Srpaulo    { SFLOW_FLOW_EXTENDED_MPLS_DATA, "Extended MPLS data"},
146190203Srpaulo    { SFLOW_FLOW_EXTENDED_NAT_DATA, "Extended NAT data"},
147190203Srpaulo    { SFLOW_FLOW_EXTENDED_MPLS_TUNNEL, "Extended MPLS tunnel"},
148190203Srpaulo    { SFLOW_FLOW_EXTENDED_MPLS_VC, "Extended MPLS VC"},
149190203Srpaulo    { SFLOW_FLOW_EXTENDED_MPLS_FEC, "Extended MPLS FEC"},
150190203Srpaulo    { SFLOW_FLOW_EXTENDED_MPLS_LVP_FEC, "Extended MPLS LVP FEC"},
151190203Srpaulo    { SFLOW_FLOW_EXTENDED_VLAN_TUNNEL, "Extended VLAN Tunnel"},
152190203Srpaulo    { 0, NULL}
153190203Srpaulo};
154190203Srpaulo
155190203Srpaulo#define		SFLOW_HEADER_PROTOCOL_ETHERNET	1
156190203Srpaulo#define		SFLOW_HEADER_PROTOCOL_IPV4	11
157190203Srpaulo#define		SFLOW_HEADER_PROTOCOL_IPV6	12
158190203Srpaulo
159190203Srpaulostatic const struct tok sflow_flow_raw_protocol_values[] = {
160190203Srpaulo    { SFLOW_HEADER_PROTOCOL_ETHERNET, "Ethernet"},
161190203Srpaulo    { SFLOW_HEADER_PROTOCOL_IPV4, "IPv4"},
162190203Srpaulo    { SFLOW_HEADER_PROTOCOL_IPV6, "IPv6"},
163190203Srpaulo    { 0, NULL}
164190203Srpaulo};
165190203Srpaulo
166190203Srpaulostruct sflow_expanded_flow_raw_t {
167190203Srpaulo    u_int8_t    protocol[4];
168190203Srpaulo    u_int8_t    length[4];
169190203Srpaulo    u_int8_t    stripped_bytes[4];
170190203Srpaulo    u_int8_t    header_size[4];
171190203Srpaulo};
172190203Srpaulo
173236192Sdelphijstruct sflow_ethernet_frame_t {
174236192Sdelphij    u_int8_t length[4];
175236192Sdelphij    u_int8_t src_mac[8];
176236192Sdelphij    u_int8_t dst_mac[8];
177236192Sdelphij    u_int8_t type[4];
178236192Sdelphij};
179236192Sdelphij
180236192Sdelphijstruct sflow_extended_switch_data_t {
181236192Sdelphij    u_int8_t src_vlan[4];
182236192Sdelphij    u_int8_t src_pri[4];
183236192Sdelphij    u_int8_t dst_vlan[4];
184236192Sdelphij    u_int8_t dst_pri[4];
185236192Sdelphij};
186236192Sdelphij
187236192Sdelphijstruct sflow_counter_record_t {
188236192Sdelphij    u_int8_t    format[4];
189236192Sdelphij    u_int8_t    length[4];
190236192Sdelphij};
191236192Sdelphij
192236192Sdelphijstruct sflow_flow_record_t {
193236192Sdelphij    u_int8_t    format[4];
194236192Sdelphij    u_int8_t    length[4];
195236192Sdelphij};
196236192Sdelphij
197236192Sdelphijstruct sflow_counter_sample_t {
198236192Sdelphij    u_int8_t    seqnum[4];
199236192Sdelphij    u_int8_t    typesource[4];
200236192Sdelphij    u_int8_t    records[4];
201236192Sdelphij};
202236192Sdelphij
203190203Srpaulostruct sflow_expanded_counter_sample_t {
204190203Srpaulo    u_int8_t    seqnum[4];
205190203Srpaulo    u_int8_t    type[4];
206190203Srpaulo    u_int8_t    index[4];
207190203Srpaulo    u_int8_t    records[4];
208190203Srpaulo};
209190203Srpaulo
210190203Srpaulo#define         SFLOW_COUNTER_GENERIC           1
211190203Srpaulo#define         SFLOW_COUNTER_ETHERNET          2
212190203Srpaulo#define         SFLOW_COUNTER_TOKEN_RING        3
213190203Srpaulo#define         SFLOW_COUNTER_BASEVG            4
214190203Srpaulo#define         SFLOW_COUNTER_VLAN              5
215190203Srpaulo#define         SFLOW_COUNTER_PROCESSOR         1001
216190203Srpaulo
217190203Srpaulostatic const struct tok sflow_counter_type_values[] = {
218190203Srpaulo    { SFLOW_COUNTER_GENERIC, "Generic counter"},
219190203Srpaulo    { SFLOW_COUNTER_ETHERNET, "Ethernet counter"},
220190203Srpaulo    { SFLOW_COUNTER_TOKEN_RING, "Token ring counter"},
221190203Srpaulo    { SFLOW_COUNTER_BASEVG, "100 BaseVG counter"},
222190203Srpaulo    { SFLOW_COUNTER_VLAN, "Vlan counter"},
223190203Srpaulo    { SFLOW_COUNTER_PROCESSOR, "Processor counter"},
224190203Srpaulo    { 0, NULL}
225190203Srpaulo};
226190203Srpaulo
227190203Srpaulo#define		SFLOW_IFACE_DIRECTION_UNKNOWN		0
228190203Srpaulo#define		SFLOW_IFACE_DIRECTION_FULLDUPLEX	1
229190203Srpaulo#define		SFLOW_IFACE_DIRECTION_HALFDUPLEX	2
230190203Srpaulo#define		SFLOW_IFACE_DIRECTION_IN		3
231190203Srpaulo#define		SFLOW_IFACE_DIRECTION_OUT		4
232190203Srpaulo
233190203Srpaulostatic const struct tok sflow_iface_direction_values[] = {
234190203Srpaulo    { SFLOW_IFACE_DIRECTION_UNKNOWN, "unknown"},
235190203Srpaulo    { SFLOW_IFACE_DIRECTION_FULLDUPLEX, "full-duplex"},
236190203Srpaulo    { SFLOW_IFACE_DIRECTION_HALFDUPLEX, "half-duplex"},
237190203Srpaulo    { SFLOW_IFACE_DIRECTION_IN, "in"},
238190203Srpaulo    { SFLOW_IFACE_DIRECTION_OUT, "out"},
239190203Srpaulo    { 0, NULL}
240190203Srpaulo};
241190203Srpaulo
242190203Srpaulostruct sflow_generic_counter_t {
243190203Srpaulo    u_int8_t    ifindex[4];
244190203Srpaulo    u_int8_t    iftype[4];
245190203Srpaulo    u_int8_t    ifspeed[8];
246190203Srpaulo    u_int8_t    ifdirection[4];
247190203Srpaulo    u_int8_t    ifstatus[4];
248190203Srpaulo    u_int8_t    ifinoctets[8];
249190203Srpaulo    u_int8_t    ifinunicastpkts[4];
250190203Srpaulo    u_int8_t    ifinmulticastpkts[4];
251190203Srpaulo    u_int8_t    ifinbroadcastpkts[4];
252190203Srpaulo    u_int8_t    ifindiscards[4];
253190203Srpaulo    u_int8_t    ifinerrors[4];
254190203Srpaulo    u_int8_t    ifinunkownprotos[4];
255190203Srpaulo    u_int8_t    ifoutoctets[8];
256190203Srpaulo    u_int8_t    ifoutunicastpkts[4];
257190203Srpaulo    u_int8_t    ifoutmulticastpkts[4];
258190203Srpaulo    u_int8_t    ifoutbroadcastpkts[4];
259190203Srpaulo    u_int8_t    ifoutdiscards[4];
260190203Srpaulo    u_int8_t    ifouterrors[4];
261190203Srpaulo    u_int8_t    ifpromiscmode[4];
262190203Srpaulo};
263190203Srpaulo
264190203Srpaulostruct sflow_ethernet_counter_t {
265190203Srpaulo    u_int8_t    alignerrors[4];
266190203Srpaulo    u_int8_t    fcserrors[4];
267190203Srpaulo    u_int8_t    single_collision_frames[4];
268190203Srpaulo    u_int8_t    multiple_collision_frames[4];
269190203Srpaulo    u_int8_t    test_errors[4];
270190203Srpaulo    u_int8_t    deferred_transmissions[4];
271190203Srpaulo    u_int8_t    late_collisions[4];
272190203Srpaulo    u_int8_t    excessive_collisions[4];
273190203Srpaulo    u_int8_t    mac_transmit_errors[4];
274190203Srpaulo    u_int8_t    carrier_sense_errors[4];
275190203Srpaulo    u_int8_t    frame_too_longs[4];
276190203Srpaulo    u_int8_t    mac_receive_errors[4];
277190203Srpaulo    u_int8_t    symbol_errors[4];
278190203Srpaulo};
279190203Srpaulo
280190203Srpaulostruct sflow_100basevg_counter_t {
281190203Srpaulo    u_int8_t    in_highpriority_frames[4];
282190203Srpaulo    u_int8_t    in_highpriority_octets[8];
283190203Srpaulo    u_int8_t    in_normpriority_frames[4];
284190203Srpaulo    u_int8_t    in_normpriority_octets[8];
285190203Srpaulo    u_int8_t    in_ipmerrors[4];
286190203Srpaulo    u_int8_t    in_oversized[4];
287190203Srpaulo    u_int8_t    in_data_errors[4];
288190203Srpaulo    u_int8_t    in_null_addressed_frames[4];
289190203Srpaulo    u_int8_t    out_highpriority_frames[4];
290190203Srpaulo    u_int8_t    out_highpriority_octets[8];
291190203Srpaulo    u_int8_t    transitioninto_frames[4];
292190203Srpaulo    u_int8_t    hc_in_highpriority_octets[8];
293190203Srpaulo    u_int8_t    hc_in_normpriority_octets[8];
294190203Srpaulo    u_int8_t    hc_out_highpriority_octets[8];
295190203Srpaulo};
296190203Srpaulo
297190203Srpaulostruct sflow_vlan_counter_t {
298190203Srpaulo    u_int8_t    vlan_id[4];
299190203Srpaulo    u_int8_t    octets[8];
300190203Srpaulo    u_int8_t    unicast_pkt[4];
301190203Srpaulo    u_int8_t    multicast_pkt[4];
302190203Srpaulo    u_int8_t    broadcast_pkt[4];
303190203Srpaulo    u_int8_t    discards[4];
304190203Srpaulo};
305190203Srpaulo
306236192Sdelphijstatic int
307236192Sdelphijprint_sflow_counter_generic(const u_char *pointer, u_int len) {
308190203Srpaulo
309190203Srpaulo    const struct sflow_generic_counter_t *sflow_gen_counter;
310236192Sdelphij
311236192Sdelphij    if (len < sizeof(struct sflow_generic_counter_t))
312236192Sdelphij	return 1;
313236192Sdelphij
314236192Sdelphij
315236192Sdelphij    sflow_gen_counter = (const struct sflow_generic_counter_t *)pointer;
316236192Sdelphij    printf("\n\t      ifindex %u, iftype %u, ifspeed %" PRIu64 ", ifdirection %u (%s)",
317236192Sdelphij	   EXTRACT_32BITS(sflow_gen_counter->ifindex),
318236192Sdelphij	   EXTRACT_32BITS(sflow_gen_counter->iftype),
319236192Sdelphij	   EXTRACT_64BITS(sflow_gen_counter->ifspeed),
320236192Sdelphij	   EXTRACT_32BITS(sflow_gen_counter->ifdirection),
321236192Sdelphij	   tok2str(sflow_iface_direction_values, "Unknown",
322236192Sdelphij		   EXTRACT_32BITS(sflow_gen_counter->ifdirection)));
323236192Sdelphij    printf("\n\t      ifstatus %u, adminstatus: %s, operstatus: %s",
324236192Sdelphij	   EXTRACT_32BITS(sflow_gen_counter->ifstatus),
325236192Sdelphij	   EXTRACT_32BITS(sflow_gen_counter->ifstatus)&1 ? "up" : "down",
326236192Sdelphij	   (EXTRACT_32BITS(sflow_gen_counter->ifstatus)>>1)&1 ? "up" : "down");
327236192Sdelphij    printf("\n\t      In octets %" PRIu64
328236192Sdelphij	   ", unicast pkts %u, multicast pkts %u, broadcast pkts %u, discards %u",
329236192Sdelphij	   EXTRACT_64BITS(sflow_gen_counter->ifinoctets),
330236192Sdelphij	   EXTRACT_32BITS(sflow_gen_counter->ifinunicastpkts),
331236192Sdelphij	   EXTRACT_32BITS(sflow_gen_counter->ifinmulticastpkts),
332236192Sdelphij	   EXTRACT_32BITS(sflow_gen_counter->ifinbroadcastpkts),
333236192Sdelphij	   EXTRACT_32BITS(sflow_gen_counter->ifindiscards));
334236192Sdelphij    printf("\n\t      In errors %u, unknown protos %u",
335236192Sdelphij	   EXTRACT_32BITS(sflow_gen_counter->ifinerrors),
336236192Sdelphij	   EXTRACT_32BITS(sflow_gen_counter->ifinunkownprotos));
337236192Sdelphij    printf("\n\t      Out octets %" PRIu64
338236192Sdelphij	   ", unicast pkts %u, multicast pkts %u, broadcast pkts %u, discards %u",
339236192Sdelphij	   EXTRACT_64BITS(sflow_gen_counter->ifoutoctets),
340236192Sdelphij	   EXTRACT_32BITS(sflow_gen_counter->ifoutunicastpkts),
341236192Sdelphij	   EXTRACT_32BITS(sflow_gen_counter->ifoutmulticastpkts),
342236192Sdelphij	   EXTRACT_32BITS(sflow_gen_counter->ifoutbroadcastpkts),
343236192Sdelphij	   EXTRACT_32BITS(sflow_gen_counter->ifoutdiscards));
344236192Sdelphij    printf("\n\t      Out errors %u, promisc mode %u",
345236192Sdelphij	   EXTRACT_32BITS(sflow_gen_counter->ifouterrors),
346236192Sdelphij	   EXTRACT_32BITS(sflow_gen_counter->ifpromiscmode));
347236192Sdelphij
348236192Sdelphij    return 0;
349236192Sdelphij}
350236192Sdelphij
351236192Sdelphijstatic int
352236192Sdelphijprint_sflow_counter_ethernet(const u_char *pointer, u_int len){
353236192Sdelphij
354190203Srpaulo    const struct sflow_ethernet_counter_t *sflow_eth_counter;
355236192Sdelphij
356236192Sdelphij    if (len < sizeof(struct sflow_ethernet_counter_t))
357236192Sdelphij	return 1;
358236192Sdelphij
359236192Sdelphij    sflow_eth_counter = (const struct sflow_ethernet_counter_t *)pointer;
360236192Sdelphij    printf("\n\t      align errors %u, fcs errors %u, single collision %u, multiple collision %u, test error %u",
361236192Sdelphij	   EXTRACT_32BITS(sflow_eth_counter->alignerrors),
362236192Sdelphij	   EXTRACT_32BITS(sflow_eth_counter->fcserrors),
363236192Sdelphij	   EXTRACT_32BITS(sflow_eth_counter->single_collision_frames),
364236192Sdelphij	   EXTRACT_32BITS(sflow_eth_counter->multiple_collision_frames),
365236192Sdelphij	   EXTRACT_32BITS(sflow_eth_counter->test_errors));
366236192Sdelphij    printf("\n\t      deferred %u, late collision %u, excessive collision %u, mac trans error %u",
367236192Sdelphij	   EXTRACT_32BITS(sflow_eth_counter->deferred_transmissions),
368236192Sdelphij	   EXTRACT_32BITS(sflow_eth_counter->late_collisions),
369236192Sdelphij	   EXTRACT_32BITS(sflow_eth_counter->excessive_collisions),
370236192Sdelphij	   EXTRACT_32BITS(sflow_eth_counter->mac_transmit_errors));
371236192Sdelphij    printf("\n\t      carrier error %u, frames too long %u, mac receive errors %u, symbol errors %u",
372236192Sdelphij	   EXTRACT_32BITS(sflow_eth_counter->carrier_sense_errors),
373236192Sdelphij	   EXTRACT_32BITS(sflow_eth_counter->frame_too_longs),
374236192Sdelphij	   EXTRACT_32BITS(sflow_eth_counter->mac_receive_errors),
375236192Sdelphij	   EXTRACT_32BITS(sflow_eth_counter->symbol_errors));
376236192Sdelphij
377236192Sdelphij    return 0;
378236192Sdelphij}
379236192Sdelphij
380236192Sdelphijstatic int
381236192Sdelphijprint_sflow_counter_token_ring(const u_char *pointer _U_, u_int len _U_) {
382236192Sdelphij
383236192Sdelphij    return 0;
384236192Sdelphij}
385236192Sdelphij
386236192Sdelphijstatic int
387236192Sdelphijprint_sflow_counter_basevg(const u_char *pointer, u_int len) {
388236192Sdelphij
389190203Srpaulo    const struct sflow_100basevg_counter_t *sflow_100basevg_counter;
390236192Sdelphij
391236192Sdelphij    if (len < sizeof(struct sflow_100basevg_counter_t))
392236192Sdelphij	return 1;
393236192Sdelphij
394236192Sdelphij    sflow_100basevg_counter = (const struct sflow_100basevg_counter_t *)pointer;
395236192Sdelphij    printf("\n\t      in high prio frames %u, in high prio octets %" PRIu64,
396236192Sdelphij	   EXTRACT_32BITS(sflow_100basevg_counter->in_highpriority_frames),
397236192Sdelphij	   EXTRACT_64BITS(sflow_100basevg_counter->in_highpriority_octets));
398236192Sdelphij    printf("\n\t      in norm prio frames %u, in norm prio octets %" PRIu64,
399236192Sdelphij	   EXTRACT_32BITS(sflow_100basevg_counter->in_normpriority_frames),
400236192Sdelphij	   EXTRACT_64BITS(sflow_100basevg_counter->in_normpriority_octets));
401236192Sdelphij    printf("\n\t      in ipm errors %u, oversized %u, in data errors %u, null addressed frames %u",
402236192Sdelphij	   EXTRACT_32BITS(sflow_100basevg_counter->in_ipmerrors),
403236192Sdelphij	   EXTRACT_32BITS(sflow_100basevg_counter->in_oversized),
404236192Sdelphij	   EXTRACT_32BITS(sflow_100basevg_counter->in_data_errors),
405236192Sdelphij	   EXTRACT_32BITS(sflow_100basevg_counter->in_null_addressed_frames));
406236192Sdelphij    printf("\n\t      out high prio frames %u, out high prio octets %" PRIu64
407236192Sdelphij	   ", trans into frames %u",
408236192Sdelphij	   EXTRACT_32BITS(sflow_100basevg_counter->out_highpriority_frames),
409236192Sdelphij	   EXTRACT_64BITS(sflow_100basevg_counter->out_highpriority_octets),
410236192Sdelphij	   EXTRACT_32BITS(sflow_100basevg_counter->transitioninto_frames));
411236192Sdelphij    printf("\n\t      in hc high prio octets %" PRIu64
412236192Sdelphij	   ", in hc norm prio octets %" PRIu64
413236192Sdelphij	   ", out hc high prio octets %" PRIu64,
414236192Sdelphij	   EXTRACT_64BITS(sflow_100basevg_counter->hc_in_highpriority_octets),
415236192Sdelphij	   EXTRACT_64BITS(sflow_100basevg_counter->hc_in_normpriority_octets),
416236192Sdelphij	   EXTRACT_64BITS(sflow_100basevg_counter->hc_out_highpriority_octets));
417236192Sdelphij
418236192Sdelphij    return 0;
419236192Sdelphij}
420236192Sdelphij
421236192Sdelphijstatic int
422236192Sdelphijprint_sflow_counter_vlan(const u_char *pointer, u_int len) {
423236192Sdelphij
424190203Srpaulo    const struct sflow_vlan_counter_t *sflow_vlan_counter;
425236192Sdelphij
426236192Sdelphij    if (len < sizeof(struct sflow_vlan_counter_t))
427236192Sdelphij	return 1;
428236192Sdelphij
429236192Sdelphij    sflow_vlan_counter = (const struct sflow_vlan_counter_t *)pointer;
430236192Sdelphij    printf("\n\t      vlan_id %u, octets %" PRIu64
431236192Sdelphij	   ", unicast_pkt %u, multicast_pkt %u, broadcast_pkt %u, discards %u",
432236192Sdelphij	   EXTRACT_32BITS(sflow_vlan_counter->vlan_id),
433236192Sdelphij	   EXTRACT_64BITS(sflow_vlan_counter->octets),
434236192Sdelphij	   EXTRACT_32BITS(sflow_vlan_counter->unicast_pkt),
435236192Sdelphij	   EXTRACT_32BITS(sflow_vlan_counter->multicast_pkt),
436236192Sdelphij	   EXTRACT_32BITS(sflow_vlan_counter->broadcast_pkt),
437236192Sdelphij	   EXTRACT_32BITS(sflow_vlan_counter->discards));
438236192Sdelphij
439236192Sdelphij    return 0;
440236192Sdelphij}
441236192Sdelphij
442236192Sdelphijstruct sflow_processor_counter_t {
443236192Sdelphij    u_int8_t five_sec_util[4];
444236192Sdelphij    u_int8_t one_min_util[4];
445236192Sdelphij    u_int8_t five_min_util[4];
446236192Sdelphij    u_int8_t total_memory[8];
447236192Sdelphij    u_int8_t free_memory[8];
448236192Sdelphij};
449236192Sdelphij
450236192Sdelphijstatic int
451236192Sdelphijprint_sflow_counter_processor(const u_char *pointer, u_int len) {
452236192Sdelphij
453236192Sdelphij    const struct sflow_processor_counter_t *sflow_processor_counter;
454236192Sdelphij
455236192Sdelphij    if (len < sizeof(struct sflow_processor_counter_t))
456236192Sdelphij	return 1;
457236192Sdelphij
458236192Sdelphij    sflow_processor_counter = (const struct sflow_processor_counter_t *)pointer;
459236192Sdelphij    printf("\n\t      5sec %u, 1min %u, 5min %u, total_mem %" PRIu64
460236192Sdelphij	   ", total_mem %" PRIu64,
461236192Sdelphij	   EXTRACT_32BITS(sflow_processor_counter->five_sec_util),
462236192Sdelphij	   EXTRACT_32BITS(sflow_processor_counter->one_min_util),
463236192Sdelphij	   EXTRACT_32BITS(sflow_processor_counter->five_min_util),
464236192Sdelphij	   EXTRACT_64BITS(sflow_processor_counter->total_memory),
465236192Sdelphij	   EXTRACT_64BITS(sflow_processor_counter->free_memory));
466236192Sdelphij
467236192Sdelphij    return 0;
468236192Sdelphij}
469236192Sdelphij
470236192Sdelphijstatic int
471236192Sdelphijsflow_print_counter_records(const u_char *pointer, u_int len, u_int records) {
472236192Sdelphij
473236192Sdelphij    u_int nrecords;
474190203Srpaulo    const u_char *tptr;
475236192Sdelphij    u_int tlen;
476236192Sdelphij    u_int counter_type;
477236192Sdelphij    u_int counter_len;
478236192Sdelphij    u_int enterprise;
479236192Sdelphij    const struct sflow_counter_record_t *sflow_counter_record;
480236192Sdelphij
481236192Sdelphij    nrecords = records;
482236192Sdelphij    tptr = pointer;
483236192Sdelphij    tlen = len;
484236192Sdelphij
485236192Sdelphij    while (nrecords > 0) {
486236192Sdelphij	/* do we have the "header?" */
487236192Sdelphij	if (tlen < sizeof(struct sflow_counter_record_t))
488236192Sdelphij	    return 1;
489236192Sdelphij	sflow_counter_record = (const struct sflow_counter_record_t *)tptr;
490236192Sdelphij
491236192Sdelphij	enterprise = EXTRACT_32BITS(sflow_counter_record->format);
492236192Sdelphij	counter_type = enterprise & 0x0FFF;
493236192Sdelphij	enterprise = enterprise >> 20;
494236192Sdelphij	counter_len  = EXTRACT_32BITS(sflow_counter_record->length);
495236192Sdelphij	printf("\n\t    enterprise %u, %s (%u) length %u",
496236192Sdelphij	       enterprise,
497236192Sdelphij	       (enterprise == 0) ? tok2str(sflow_counter_type_values,"Unknown",counter_type) : "Unknown",
498236192Sdelphij	       counter_type,
499236192Sdelphij	       counter_len);
500236192Sdelphij
501236192Sdelphij	tptr += sizeof(struct sflow_counter_record_t);
502236192Sdelphij	tlen -= sizeof(struct sflow_counter_record_t);
503236192Sdelphij
504236192Sdelphij	if (tlen < counter_len)
505236192Sdelphij	    return 1;
506236192Sdelphij	if (enterprise == 0) {
507236192Sdelphij	    switch (counter_type) {
508236192Sdelphij	    case SFLOW_COUNTER_GENERIC:
509236192Sdelphij		if (print_sflow_counter_generic(tptr,tlen))
510236192Sdelphij		    return 1;
511236192Sdelphij		break;
512236192Sdelphij	    case SFLOW_COUNTER_ETHERNET:
513236192Sdelphij		if (print_sflow_counter_ethernet(tptr,tlen))
514236192Sdelphij		    return 1;
515236192Sdelphij		break;
516236192Sdelphij	    case SFLOW_COUNTER_TOKEN_RING:
517236192Sdelphij		if (print_sflow_counter_token_ring(tptr,tlen))
518236192Sdelphij		    return 1;
519236192Sdelphij		break;
520236192Sdelphij	    case SFLOW_COUNTER_BASEVG:
521236192Sdelphij		if (print_sflow_counter_basevg(tptr,tlen))
522236192Sdelphij		    return 1;
523236192Sdelphij		break;
524236192Sdelphij	    case SFLOW_COUNTER_VLAN:
525236192Sdelphij		if (print_sflow_counter_vlan(tptr,tlen))
526236192Sdelphij		    return 1;
527236192Sdelphij		break;
528236192Sdelphij	    case SFLOW_COUNTER_PROCESSOR:
529236192Sdelphij		if (print_sflow_counter_processor(tptr,tlen))
530236192Sdelphij		    return 1;
531236192Sdelphij		break;
532236192Sdelphij	    default:
533236192Sdelphij		if (vflag <= 1)
534236192Sdelphij		    print_unknown_data(tptr, "\n\t\t", counter_len);
535236192Sdelphij		break;
536236192Sdelphij	    }
537236192Sdelphij	}
538236192Sdelphij	tptr += counter_len;
539236192Sdelphij	tlen -= counter_len;
540236192Sdelphij	nrecords--;
541236192Sdelphij
542236192Sdelphij    }
543236192Sdelphij
544236192Sdelphij    return 0;
545236192Sdelphij}
546236192Sdelphij
547236192Sdelphij
548236192Sdelphijstatic int
549236192Sdelphijsflow_print_counter_sample(const u_char *pointer, u_int len) {
550236192Sdelphij
551236192Sdelphij    const struct sflow_counter_sample_t *sflow_counter_sample;
552236192Sdelphij    u_int           nrecords;
553236192Sdelphij    u_int           typesource;
554236192Sdelphij    u_int           type;
555236192Sdelphij    u_int           index;
556236192Sdelphij
557236192Sdelphij
558236192Sdelphij    if (len < sizeof(struct sflow_counter_sample_t))
559236192Sdelphij	return 1;
560236192Sdelphij
561236192Sdelphij    sflow_counter_sample = (const struct sflow_counter_sample_t *)pointer;
562236192Sdelphij
563236192Sdelphij    typesource = EXTRACT_32BITS(sflow_counter_sample->typesource);
564236192Sdelphij    nrecords   = EXTRACT_32BITS(sflow_counter_sample->records);
565236192Sdelphij    type = typesource >> 24;
566236192Sdelphij    index = typesource & 0x0FFF;
567236192Sdelphij
568236192Sdelphij    printf(" seqnum %u, type %u, idx %u, records %u",
569236192Sdelphij	   EXTRACT_32BITS(sflow_counter_sample->seqnum),
570236192Sdelphij	   type,
571236192Sdelphij	   index,
572236192Sdelphij	   nrecords);
573236192Sdelphij
574236192Sdelphij    return sflow_print_counter_records(pointer + sizeof(struct sflow_counter_sample_t),
575236192Sdelphij				       len - sizeof(struct sflow_counter_sample_t),
576236192Sdelphij				       nrecords);
577236192Sdelphij
578236192Sdelphij}
579236192Sdelphij
580236192Sdelphijstatic int
581236192Sdelphijsflow_print_expanded_counter_sample(const u_char *pointer, u_int len) {
582236192Sdelphij
583236192Sdelphij    const struct sflow_expanded_counter_sample_t *sflow_expanded_counter_sample;
584236192Sdelphij    u_int           nrecords;
585236192Sdelphij
586236192Sdelphij
587236192Sdelphij    if (len < sizeof(struct sflow_expanded_counter_sample_t))
588236192Sdelphij	return 1;
589236192Sdelphij
590236192Sdelphij    sflow_expanded_counter_sample = (const struct sflow_expanded_counter_sample_t *)pointer;
591236192Sdelphij
592236192Sdelphij    nrecords = EXTRACT_32BITS(sflow_expanded_counter_sample->records);
593236192Sdelphij
594236192Sdelphij    printf(" seqnum %u, type %u, idx %u, records %u",
595236192Sdelphij	   EXTRACT_32BITS(sflow_expanded_counter_sample->seqnum),
596236192Sdelphij	   EXTRACT_32BITS(sflow_expanded_counter_sample->type),
597236192Sdelphij	   EXTRACT_32BITS(sflow_expanded_counter_sample->index),
598236192Sdelphij	   nrecords);
599236192Sdelphij
600236192Sdelphij    return sflow_print_counter_records(pointer + sizeof(struct sflow_expanded_counter_sample_t),
601236192Sdelphij				       len - sizeof(struct sflow_expanded_counter_sample_t),
602236192Sdelphij				       nrecords);
603236192Sdelphij
604236192Sdelphij}
605236192Sdelphij
606236192Sdelphijstatic int
607236192Sdelphijprint_sflow_raw_packet(const u_char *pointer, u_int len) {
608236192Sdelphij
609236192Sdelphij    const struct sflow_expanded_flow_raw_t *sflow_flow_raw;
610236192Sdelphij
611236192Sdelphij    if (len < sizeof(struct sflow_expanded_flow_raw_t))
612236192Sdelphij	return 1;
613236192Sdelphij
614236192Sdelphij    sflow_flow_raw = (const struct sflow_expanded_flow_raw_t *)pointer;
615236192Sdelphij    printf("\n\t      protocol %s (%u), length %u, stripped bytes %u, header_size %u",
616236192Sdelphij	   tok2str(sflow_flow_raw_protocol_values,"Unknown",EXTRACT_32BITS(sflow_flow_raw->protocol)),
617236192Sdelphij	   EXTRACT_32BITS(sflow_flow_raw->protocol),
618236192Sdelphij	   EXTRACT_32BITS(sflow_flow_raw->length),
619236192Sdelphij	   EXTRACT_32BITS(sflow_flow_raw->stripped_bytes),
620236192Sdelphij	   EXTRACT_32BITS(sflow_flow_raw->header_size));
621236192Sdelphij
622236192Sdelphij    /* QUESTION - should we attempt to print the raw header itself?
623236192Sdelphij       assuming of course there is wnough data present to do so... */
624236192Sdelphij
625236192Sdelphij    return 0;
626236192Sdelphij}
627236192Sdelphij
628236192Sdelphijstatic int
629236192Sdelphijprint_sflow_ethernet_frame(const u_char *pointer, u_int len) {
630236192Sdelphij
631236192Sdelphij    const struct sflow_ethernet_frame_t *sflow_ethernet_frame;
632236192Sdelphij
633236192Sdelphij    if (len < sizeof(struct sflow_ethernet_frame_t))
634236192Sdelphij	return 1;
635236192Sdelphij
636236192Sdelphij    sflow_ethernet_frame = (const struct sflow_ethernet_frame_t *)pointer;
637236192Sdelphij
638236192Sdelphij    printf("\n\t      frame len %u, type %u",
639236192Sdelphij	   EXTRACT_32BITS(sflow_ethernet_frame->length),
640236192Sdelphij	   EXTRACT_32BITS(sflow_ethernet_frame->type));
641236192Sdelphij
642236192Sdelphij    return 0;
643236192Sdelphij}
644236192Sdelphij
645236192Sdelphijstatic int
646236192Sdelphijprint_sflow_extended_switch_data(const u_char *pointer, u_int len) {
647236192Sdelphij
648236192Sdelphij    const struct sflow_extended_switch_data_t *sflow_extended_sw_data;
649236192Sdelphij
650236192Sdelphij    if (len < sizeof(struct sflow_extended_switch_data_t))
651236192Sdelphij	return 1;
652236192Sdelphij
653236192Sdelphij    sflow_extended_sw_data = (const struct sflow_extended_switch_data_t *)pointer;
654236192Sdelphij    printf("\n\t      src vlan %u, src pri %u, dst vlan %u, dst pri %u",
655236192Sdelphij	   EXTRACT_32BITS(sflow_extended_sw_data->src_vlan),
656236192Sdelphij	   EXTRACT_32BITS(sflow_extended_sw_data->src_pri),
657236192Sdelphij	   EXTRACT_32BITS(sflow_extended_sw_data->dst_vlan),
658236192Sdelphij	   EXTRACT_32BITS(sflow_extended_sw_data->dst_pri));
659236192Sdelphij
660236192Sdelphij    return 0;
661236192Sdelphij}
662236192Sdelphij
663236192Sdelphijstatic int
664236192Sdelphijsflow_print_flow_records(const u_char *pointer, u_int len, u_int records) {
665236192Sdelphij
666236192Sdelphij    u_int nrecords;
667236192Sdelphij    const u_char *tptr;
668236192Sdelphij    u_int tlen;
669236192Sdelphij    u_int flow_type;
670236192Sdelphij    u_int enterprise;
671236192Sdelphij    u_int flow_len;
672236192Sdelphij    const struct sflow_flow_record_t *sflow_flow_record;
673236192Sdelphij
674236192Sdelphij    nrecords = records;
675236192Sdelphij    tptr = pointer;
676236192Sdelphij    tlen = len;
677236192Sdelphij
678236192Sdelphij    while (nrecords > 0) {
679236192Sdelphij	/* do we have the "header?" */
680236192Sdelphij	if (tlen < sizeof(struct sflow_flow_record_t))
681236192Sdelphij	    return 1;
682236192Sdelphij
683236192Sdelphij	sflow_flow_record = (const struct sflow_flow_record_t *)tptr;
684236192Sdelphij
685236192Sdelphij	/* so, the funky encoding means we cannot blythly mask-off
686236192Sdelphij	   bits, we must also check the enterprise. */
687236192Sdelphij
688236192Sdelphij	enterprise = EXTRACT_32BITS(sflow_flow_record->format);
689236192Sdelphij	flow_type = enterprise & 0x0FFF;
690236192Sdelphij	enterprise = enterprise >> 12;
691236192Sdelphij	flow_len  = EXTRACT_32BITS(sflow_flow_record->length);
692236192Sdelphij	printf("\n\t    enterprise %u %s (%u) length %u",
693236192Sdelphij	       enterprise,
694236192Sdelphij	       (enterprise == 0) ? tok2str(sflow_flow_type_values,"Unknown",flow_type) : "Unknown",
695236192Sdelphij	       flow_type,
696236192Sdelphij	       flow_len);
697236192Sdelphij
698236192Sdelphij	tptr += sizeof(struct sflow_flow_record_t);
699236192Sdelphij	tlen -= sizeof(struct sflow_flow_record_t);
700236192Sdelphij
701236192Sdelphij	if (tlen < flow_len)
702236192Sdelphij	    return 1;
703236192Sdelphij
704236192Sdelphij	if (enterprise == 0) {
705236192Sdelphij	    switch (flow_type) {
706236192Sdelphij	    case SFLOW_FLOW_RAW_PACKET:
707236192Sdelphij		if (print_sflow_raw_packet(tptr,tlen))
708236192Sdelphij		    return 1;
709236192Sdelphij		break;
710236192Sdelphij	    case SFLOW_FLOW_EXTENDED_SWITCH_DATA:
711236192Sdelphij		if (print_sflow_extended_switch_data(tptr,tlen))
712236192Sdelphij		    return 1;
713236192Sdelphij		break;
714236192Sdelphij	    case SFLOW_FLOW_ETHERNET_FRAME:
715236192Sdelphij		if (print_sflow_ethernet_frame(tptr,tlen))
716236192Sdelphij		    return 1;
717236192Sdelphij		break;
718236192Sdelphij		/* FIXME these need a decoder */
719236192Sdelphij	    case SFLOW_FLOW_IPV4_DATA:
720236192Sdelphij	    case SFLOW_FLOW_IPV6_DATA:
721236192Sdelphij	    case SFLOW_FLOW_EXTENDED_ROUTER_DATA:
722236192Sdelphij	    case SFLOW_FLOW_EXTENDED_GATEWAY_DATA:
723236192Sdelphij	    case SFLOW_FLOW_EXTENDED_USER_DATA:
724236192Sdelphij	    case SFLOW_FLOW_EXTENDED_URL_DATA:
725236192Sdelphij	    case SFLOW_FLOW_EXTENDED_MPLS_DATA:
726236192Sdelphij	    case SFLOW_FLOW_EXTENDED_NAT_DATA:
727236192Sdelphij	    case SFLOW_FLOW_EXTENDED_MPLS_TUNNEL:
728236192Sdelphij	    case SFLOW_FLOW_EXTENDED_MPLS_VC:
729236192Sdelphij	    case SFLOW_FLOW_EXTENDED_MPLS_FEC:
730236192Sdelphij	    case SFLOW_FLOW_EXTENDED_MPLS_LVP_FEC:
731236192Sdelphij	    case SFLOW_FLOW_EXTENDED_VLAN_TUNNEL:
732236192Sdelphij		break;
733236192Sdelphij	    default:
734236192Sdelphij		if (vflag <= 1)
735236192Sdelphij		    print_unknown_data(tptr, "\n\t\t", flow_len);
736236192Sdelphij		break;
737236192Sdelphij	    }
738236192Sdelphij	}
739236192Sdelphij	tptr += flow_len;
740236192Sdelphij	tlen -= flow_len;
741236192Sdelphij	nrecords--;
742236192Sdelphij
743236192Sdelphij    }
744236192Sdelphij
745236192Sdelphij    return 0;
746236192Sdelphij}
747236192Sdelphij
748236192Sdelphijstatic int
749236192Sdelphijsflow_print_flow_sample(const u_char *pointer, u_int len) {
750236192Sdelphij
751236192Sdelphij    const struct sflow_flow_sample_t *sflow_flow_sample;
752236192Sdelphij    u_int          nrecords;
753236192Sdelphij    u_int          typesource;
754236192Sdelphij    u_int          type;
755236192Sdelphij    u_int          index;
756236192Sdelphij
757236192Sdelphij    if (len < sizeof(struct sflow_flow_sample_t))
758236192Sdelphij	return 1;
759236192Sdelphij
760236192Sdelphij    sflow_flow_sample = (struct sflow_flow_sample_t *)pointer;
761236192Sdelphij
762236192Sdelphij    typesource = EXTRACT_32BITS(sflow_flow_sample->typesource);
763236192Sdelphij    nrecords = EXTRACT_32BITS(sflow_flow_sample->records);
764236192Sdelphij    type = typesource >> 24;
765236192Sdelphij    index = typesource & 0x0FFF;
766236192Sdelphij
767236192Sdelphij    printf(" seqnum %u, type %u, idx %u, rate %u, pool %u, drops %u, input %u output %u records %u",
768236192Sdelphij	   EXTRACT_32BITS(sflow_flow_sample->seqnum),
769236192Sdelphij	   type,
770236192Sdelphij	   index,
771236192Sdelphij	   EXTRACT_32BITS(sflow_flow_sample->rate),
772236192Sdelphij	   EXTRACT_32BITS(sflow_flow_sample->pool),
773236192Sdelphij	   EXTRACT_32BITS(sflow_flow_sample->drops),
774236192Sdelphij	   EXTRACT_32BITS(sflow_flow_sample->in_interface),
775236192Sdelphij	   EXTRACT_32BITS(sflow_flow_sample->out_interface),
776236192Sdelphij	   nrecords);
777236192Sdelphij
778236192Sdelphij    return sflow_print_flow_records(pointer + sizeof(struct sflow_flow_sample_t),
779236192Sdelphij				    len - sizeof(struct sflow_flow_sample_t),
780236192Sdelphij				    nrecords);
781236192Sdelphij
782236192Sdelphij}
783236192Sdelphij
784236192Sdelphijstatic int
785236192Sdelphijsflow_print_expanded_flow_sample(const u_char *pointer, u_int len) {
786236192Sdelphij
787236192Sdelphij    const struct sflow_expanded_flow_sample_t *sflow_expanded_flow_sample;
788236192Sdelphij    u_int nrecords;
789236192Sdelphij
790236192Sdelphij    if (len < sizeof(struct sflow_expanded_flow_sample_t))
791236192Sdelphij	return 1;
792236192Sdelphij
793236192Sdelphij    sflow_expanded_flow_sample = (const struct sflow_expanded_flow_sample_t *)pointer;
794236192Sdelphij
795236192Sdelphij    nrecords = EXTRACT_32BITS(sflow_expanded_flow_sample->records);
796236192Sdelphij
797236192Sdelphij    printf(" seqnum %u, type %u, idx %u, rate %u, pool %u, drops %u, records %u",
798236192Sdelphij	   EXTRACT_32BITS(sflow_expanded_flow_sample->seqnum),
799236192Sdelphij	   EXTRACT_32BITS(sflow_expanded_flow_sample->type),
800236192Sdelphij	   EXTRACT_32BITS(sflow_expanded_flow_sample->index),
801236192Sdelphij	   EXTRACT_32BITS(sflow_expanded_flow_sample->rate),
802236192Sdelphij	   EXTRACT_32BITS(sflow_expanded_flow_sample->pool),
803236192Sdelphij	   EXTRACT_32BITS(sflow_expanded_flow_sample->drops),
804236192Sdelphij	   EXTRACT_32BITS(sflow_expanded_flow_sample->records));
805236192Sdelphij
806236192Sdelphij    return sflow_print_flow_records(pointer + sizeof(struct sflow_expanded_flow_sample_t),
807236192Sdelphij				    len - sizeof(struct sflow_expanded_flow_sample_t),
808236192Sdelphij				    nrecords);
809236192Sdelphij
810236192Sdelphij}
811236192Sdelphij
812236192Sdelphijvoid
813236192Sdelphijsflow_print(const u_char *pptr, u_int len) {
814236192Sdelphij
815236192Sdelphij    const struct sflow_datagram_t *sflow_datagram;
816236192Sdelphij    const struct sflow_sample_header *sflow_sample;
817236192Sdelphij
818236192Sdelphij    const u_char *tptr;
819236192Sdelphij    u_int tlen;
820190203Srpaulo    u_int32_t sflow_sample_type, sflow_sample_len;
821236192Sdelphij    u_int32_t nsamples;
822190203Srpaulo
823236192Sdelphij
824236192Sdelphij    tptr = pptr;
825190203Srpaulo    tlen = len;
826190203Srpaulo    sflow_datagram = (const struct sflow_datagram_t *)pptr;
827190203Srpaulo    TCHECK(*sflow_datagram);
828190203Srpaulo
829190203Srpaulo    /*
830190203Srpaulo     * Sanity checking of the header.
831190203Srpaulo     */
832190203Srpaulo    if (EXTRACT_32BITS(sflow_datagram->version) != 5) {
833190203Srpaulo        printf("sFlow version %u packet not supported",
834190203Srpaulo               EXTRACT_32BITS(sflow_datagram->version));
835190203Srpaulo        return;
836190203Srpaulo    }
837190203Srpaulo
838190203Srpaulo    if (vflag < 1) {
839190203Srpaulo        printf("sFlowv%u, %s agent %s, agent-id %u, length %u",
840190203Srpaulo               EXTRACT_32BITS(sflow_datagram->version),
841190203Srpaulo               EXTRACT_32BITS(sflow_datagram->ip_version) == 1 ? "IPv4" : "IPv6",
842190203Srpaulo	       ipaddr_string(sflow_datagram->agent),
843190203Srpaulo               EXTRACT_32BITS(sflow_datagram->samples),
844190203Srpaulo               len);
845190203Srpaulo        return;
846190203Srpaulo    }
847190203Srpaulo
848190203Srpaulo    /* ok they seem to want to know everything - lets fully decode it */
849190203Srpaulo    nsamples=EXTRACT_32BITS(sflow_datagram->samples);
850190203Srpaulo    printf("sFlowv%u, %s agent %s, agent-id %u, seqnum %u, uptime %u, samples %u, length %u",
851190203Srpaulo           EXTRACT_32BITS(sflow_datagram->version),
852190203Srpaulo           EXTRACT_32BITS(sflow_datagram->ip_version) == 1 ? "IPv4" : "IPv6",
853190203Srpaulo           ipaddr_string(sflow_datagram->agent),
854190203Srpaulo           EXTRACT_32BITS(sflow_datagram->agent_id),
855190203Srpaulo           EXTRACT_32BITS(sflow_datagram->seqnum),
856190203Srpaulo           EXTRACT_32BITS(sflow_datagram->uptime),
857190203Srpaulo           nsamples,
858190203Srpaulo           len);
859190203Srpaulo
860190203Srpaulo    /* skip Common header */
861236192Sdelphij    tptr += sizeof(const struct sflow_datagram_t);
862236192Sdelphij    tlen -= sizeof(const struct sflow_datagram_t);
863190203Srpaulo
864190203Srpaulo    while (nsamples > 0 && tlen > 0) {
865190203Srpaulo        sflow_sample = (const struct sflow_sample_header *)tptr;
866236192Sdelphij        TCHECK(*sflow_sample);
867236192Sdelphij
868190203Srpaulo        sflow_sample_type = (EXTRACT_32BITS(sflow_sample->format)&0x0FFF);
869190203Srpaulo        sflow_sample_len = EXTRACT_32BITS(sflow_sample->len);
870190203Srpaulo
871236192Sdelphij	if (tlen < sizeof(struct sflow_sample_header))
872236192Sdelphij	    goto trunc;
873236192Sdelphij
874236192Sdelphij        tptr += sizeof(struct sflow_sample_header);
875236192Sdelphij        tlen -= sizeof(struct sflow_sample_header);
876190203Srpaulo
877190203Srpaulo        printf("\n\t%s (%u), length %u,",
878190203Srpaulo               tok2str(sflow_format_values, "Unknown", sflow_sample_type),
879190203Srpaulo               sflow_sample_type,
880190203Srpaulo               sflow_sample_len);
881190203Srpaulo
882190203Srpaulo        /* basic sanity check */
883190203Srpaulo        if (sflow_sample_type == 0 || sflow_sample_len ==0) {
884190203Srpaulo            return;
885190203Srpaulo        }
886190203Srpaulo
887236192Sdelphij	if (tlen < sflow_sample_len)
888236192Sdelphij	    goto trunc;
889236192Sdelphij
890190203Srpaulo        /* did we capture enough for fully decoding the sample ? */
891236192Sdelphij        TCHECK2(*tptr, sflow_sample_len);
892190203Srpaulo
893190203Srpaulo	switch(sflow_sample_type) {
894236192Sdelphij        case SFLOW_FLOW_SAMPLE:
895236192Sdelphij	    if (sflow_print_flow_sample(tptr,tlen))
896236192Sdelphij		goto trunc;
897190203Srpaulo            break;
898190203Srpaulo
899236192Sdelphij        case SFLOW_COUNTER_SAMPLE:
900236192Sdelphij	    if (sflow_print_counter_sample(tptr,tlen))
901236192Sdelphij		goto trunc;
902190203Srpaulo            break;
903190203Srpaulo
904190203Srpaulo        case SFLOW_EXPANDED_FLOW_SAMPLE:
905236192Sdelphij	    if (sflow_print_expanded_flow_sample(tptr,tlen))
906236192Sdelphij		goto trunc;
907236192Sdelphij	    break;
908190203Srpaulo
909190203Srpaulo        case SFLOW_EXPANDED_COUNTER_SAMPLE:
910236192Sdelphij	    if (sflow_print_expanded_counter_sample(tptr,tlen))
911236192Sdelphij		goto trunc;
912236192Sdelphij	    break;
913190203Srpaulo
914190203Srpaulo        default:
915190203Srpaulo            if (vflag <= 1)
916190203Srpaulo                print_unknown_data(tptr, "\n\t    ", sflow_sample_len);
917190203Srpaulo            break;
918190203Srpaulo        }
919190203Srpaulo        tptr += sflow_sample_len;
920190203Srpaulo        tlen -= sflow_sample_len;
921190203Srpaulo        nsamples--;
922190203Srpaulo    }
923190203Srpaulo    return;
924190203Srpaulo
925190203Srpaulo trunc:
926190203Srpaulo    printf("[|SFLOW]");
927190203Srpaulo}
928190203Srpaulo
929190203Srpaulo/*
930190203Srpaulo * Local Variables:
931190203Srpaulo * c-style: whitesmith
932190203Srpaulo * c-basic-offset: 4
933190203Srpaulo * End:
934190203Srpaulo */
935