]> git.proxmox.com Git - ovs.git/blame - tests/test-sflow.c
Fix ovs-dpctl-top by removing 3 wrong hunks in py3-compat.patch.
[ovs.git] / tests / test-sflow.c
CommitLineData
8073dd31 1/*
2dd88e5d 2 * Copyright (c) 2011, 2012, 2013, 2014, 2015 Nicira, Inc.
8073dd31
NM
3 * Copyright (c) 2013 InMon Corp.
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at:
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18#include <config.h>
3f636c7e
JR
19#undef NDEBUG
20#include "netflow.h"
b2befd5b
BP
21#include <sys/types.h>
22#include <netinet/in.h>
b7807e4f 23#include <arpa/inet.h>
8073dd31
NM
24#include <errno.h>
25#include <getopt.h>
26#include <signal.h>
27#include <stdlib.h>
28#include <unistd.h>
29#include <setjmp.h>
8073dd31
NM
30#include "command-line.h"
31#include "daemon.h"
3e8a2ad1 32#include "openvswitch/dynamic-string.h"
64c96779 33#include "openvswitch/ofpbuf.h"
3f636c7e 34#include "ovstest.h"
8073dd31 35#include "packets.h"
fd016ae3 36#include "openvswitch/poll-loop.h"
8073dd31
NM
37#include "socket-util.h"
38#include "unixctl.h"
39#include "util.h"
e6211adc 40#include "openvswitch/vlog.h"
8073dd31 41
cab50449 42OVS_NO_RETURN static void usage(void);
8073dd31
NM
43static void parse_options(int argc, char *argv[]);
44
45static unixctl_cb_func test_sflow_exit;
46
47/* Datagram. */
48#define SFLOW_VERSION_5 5
49#define SFLOW_MIN_LEN 36
8073dd31
NM
50
51/* Sample tag numbers. */
52#define SFLOW_FLOW_SAMPLE 1
53#define SFLOW_COUNTERS_SAMPLE 2
54#define SFLOW_FLOW_SAMPLE_EXPANDED 3
55#define SFLOW_COUNTERS_SAMPLE_EXPANDED 4
56
57/* Structure element tag numbers. */
58#define SFLOW_TAG_CTR_IFCOUNTERS 1
934386dd 59#define SFLOW_TAG_CTR_ETHCOUNTERS 2
50b9699f
NM
60#define SFLOW_TAG_CTR_LACPCOUNTERS 7
61#define SFLOW_TAG_CTR_OPENFLOWPORT 1004
62#define SFLOW_TAG_CTR_PORTNAME 1005
8073dd31
NM
63#define SFLOW_TAG_PKT_HEADER 1
64#define SFLOW_TAG_PKT_SWITCH 1001
50b9699f
NM
65#define SFLOW_TAG_PKT_TUNNEL4_OUT 1023
66#define SFLOW_TAG_PKT_TUNNEL4_IN 1024
67#define SFLOW_TAG_PKT_TUNNEL_VNI_OUT 1029
68#define SFLOW_TAG_PKT_TUNNEL_VNI_IN 1030
7321bda3 69#define SFLOW_TAG_PKT_MPLS 1006
50b9699f
NM
70
71/* string sizes */
72#define SFL_MAX_PORTNAME_LEN 255
8073dd31
NM
73
74struct sflow_addr {
75 enum {
76 SFLOW_ADDRTYPE_undefined = 0,
77 SFLOW_ADDRTYPE_IP4,
78 SFLOW_ADDRTYPE_IP6
79 } type;
80
81 union {
82 ovs_be32 ip4;
83 ovs_be32 ip6[4];
84 } a;
85};
86
87struct sflow_xdr {
88 /* Exceptions. */
89 jmp_buf env;
90 int errline;
91
92 /* Cursor. */
93 ovs_be32 *datap;
94 uint32_t i;
95 uint32_t quads;
96
97 /* Agent. */
98 struct sflow_addr agentAddr;
e731d71b 99 char agentIPStr[INET6_ADDRSTRLEN + 2];
8073dd31
NM
100 uint32_t subAgentId;
101 uint32_t uptime_mS;
102
103 /* Datasource. */
104 uint32_t dsClass;
105 uint32_t dsIndex;
106
107 /* Sequence numbers. */
108 uint32_t dgramSeqNo;
109 uint32_t fsSeqNo;
110 uint32_t csSeqNo;
111
112 /* Structure offsets. */
113 struct {
114 uint32_t HEADER;
115 uint32_t SWITCH;
5a0e4aec
BP
116 uint32_t TUNNEL4_OUT;
117 uint32_t TUNNEL4_IN;
118 uint32_t TUNNEL_VNI_OUT;
119 uint32_t TUNNEL_VNI_IN;
120 uint32_t MPLS;
121 uint32_t IFCOUNTERS;
122 uint32_t ETHCOUNTERS;
123 uint32_t LACPCOUNTERS;
124 uint32_t OPENFLOWPORT;
125 uint32_t PORTNAME;
8073dd31
NM
126 } offset;
127
128 /* Flow sample fields. */
129 uint32_t meanSkipCount;
130 uint32_t samplePool;
131 uint32_t dropEvents;
132 uint32_t inputPortFormat;
133 uint32_t inputPort;
134 uint32_t outputPortFormat;
135 uint32_t outputPort;
136};
137
138#define SFLOWXDR_try(x) ((x->errline = setjmp(x->env)) == 0)
139#define SFLOWXDR_throw(x) longjmp(x->env, __LINE__)
140#define SFLOWXDR_assert(x, t) if (!(t)) SFLOWXDR_throw(x)
141
142static void
143sflowxdr_init(struct sflow_xdr *x, void *buf, size_t len)
144{
145 x->datap = buf;
146 x->quads = len >> 2;
147}
148
149static uint32_t
150sflowxdr_next(struct sflow_xdr *x)
151{
152 return ntohl(x->datap[x->i++]);
153}
154
155static ovs_be32
156sflowxdr_next_n(struct sflow_xdr *x)
157{
158 return x->datap[x->i++];
159}
160
161static bool
162sflowxdr_more(const struct sflow_xdr *x, uint32_t q)
163{
164 return q + x->i <= x->quads;
165}
166
167static void
168sflowxdr_skip(struct sflow_xdr *x, uint32_t q)
169{
170 x->i += q;
171}
172
173static uint32_t
174sflowxdr_mark(const struct sflow_xdr *x, uint32_t q)
175{
176 return x->i + q;
177}
178
179static bool
180sflowxdr_mark_ok(const struct sflow_xdr *x, uint32_t m)
181{
182 return m == x->i;
183}
184
185static void
186sflowxdr_mark_unique(struct sflow_xdr *x, uint32_t *pi)
187{
188 if (*pi) {
189 SFLOWXDR_throw(x);
190 }
191 *pi = x->i;
192}
193
194static void
195sflowxdr_setc(struct sflow_xdr *x, uint32_t j)
196{
197 x->i = j;
198}
199
200static const char *
201sflowxdr_str(const struct sflow_xdr *x)
202{
203 return (const char *) (x->datap + x->i);
204}
205
206static uint64_t
207sflowxdr_next_int64(struct sflow_xdr *x)
208{
209 uint64_t scratch;
210 scratch = sflowxdr_next(x);
211 scratch <<= 32;
212 scratch += sflowxdr_next(x);
213 return scratch;
214}
215
216static void
217process_counter_sample(struct sflow_xdr *x)
218{
219 if (x->offset.IFCOUNTERS) {
220 sflowxdr_setc(x, x->offset.IFCOUNTERS);
221 printf("IFCOUNTERS");
222 printf(" dgramSeqNo=%"PRIu32, x->dgramSeqNo);
223 printf(" ds=%s>%"PRIu32":%"PRIu32,
224 x->agentIPStr, x->dsClass, x->dsIndex);
225 printf(" csSeqNo=%"PRIu32, x->csSeqNo);
226 printf(" ifindex=%"PRIu32, sflowxdr_next(x));
227 printf(" type=%"PRIu32, sflowxdr_next(x));
228 printf(" ifspeed=%"PRIu64, sflowxdr_next_int64(x));
229 printf(" direction=%"PRIu32, sflowxdr_next(x));
230 printf(" status=%"PRIu32, sflowxdr_next(x));
231 printf(" in_octets=%"PRIu64, sflowxdr_next_int64(x));
232 printf(" in_unicasts=%"PRIu32, sflowxdr_next(x));
233 printf(" in_multicasts=%"PRIu32, sflowxdr_next(x));
234 printf(" in_broadcasts=%"PRIu32, sflowxdr_next(x));
235 printf(" in_discards=%"PRIu32, sflowxdr_next(x));
236 printf(" in_errors=%"PRIu32, sflowxdr_next(x));
237 printf(" in_unknownprotos=%"PRIu32, sflowxdr_next(x));
238 printf(" out_octets=%"PRIu64, sflowxdr_next_int64(x));
239 printf(" out_unicasts=%"PRIu32, sflowxdr_next(x));
240 printf(" out_multicasts=%"PRIu32, sflowxdr_next(x));
241 printf(" out_broadcasts=%"PRIu32, sflowxdr_next(x));
242 printf(" out_discards=%"PRIu32, sflowxdr_next(x));
243 printf(" out_errors=%"PRIu32, sflowxdr_next(x));
244 printf(" promiscuous=%"PRIu32, sflowxdr_next(x));
245 printf("\n");
246 }
50b9699f 247 if (x->offset.LACPCOUNTERS) {
5a0e4aec
BP
248 struct eth_addr *mac;
249 union {
250 ovs_be32 all;
251 struct {
252 uint8_t actorAdmin;
253 uint8_t actorOper;
254 uint8_t partnerAdmin;
255 uint8_t partnerOper;
256 } v;
257 } state;
50b9699f
NM
258
259 sflowxdr_setc(x, x->offset.LACPCOUNTERS);
260 printf("LACPCOUNTERS");
5a0e4aec
BP
261 mac = (void *)sflowxdr_str(x);
262 printf(" sysID="ETH_ADDR_FMT, ETH_ADDR_ARGS(*mac));
263 sflowxdr_skip(x, 2);
264 mac = (void *)sflowxdr_str(x);
265 printf(" partnerID="ETH_ADDR_FMT, ETH_ADDR_ARGS(*mac));
266 sflowxdr_skip(x, 2);
267 printf(" aggID=%"PRIu32, sflowxdr_next(x));
268 state.all = sflowxdr_next_n(x);
269 printf(" actorAdmin=0x%"PRIx32, state.v.actorAdmin);
270 printf(" actorOper=0x%"PRIx32, state.v.actorOper);
271 printf(" partnerAdmin=0x%"PRIx32, state.v.partnerAdmin);
272 printf(" partnerOper=0x%"PRIx32, state.v.partnerOper);
273 printf(" LACPDUsRx=%"PRIu32, sflowxdr_next(x));
274 printf(" markerPDUsRx=%"PRIu32, sflowxdr_next(x));
275 printf(" markerRespPDUsRx=%"PRIu32, sflowxdr_next(x));
276 printf(" unknownRx=%"PRIu32, sflowxdr_next(x));
277 printf(" illegalRx=%"PRIu32, sflowxdr_next(x));
278 printf(" LACPDUsTx=%"PRIu32, sflowxdr_next(x));
279 printf(" markerPDUsTx=%"PRIu32, sflowxdr_next(x));
280 printf(" markerRespPDUsTx=%"PRIu32, sflowxdr_next(x));
50b9699f
NM
281 printf("\n");
282 }
283 if (x->offset.OPENFLOWPORT) {
284 sflowxdr_setc(x, x->offset.OPENFLOWPORT);
285 printf("OPENFLOWPORT");
286 printf(" datapath_id=%"PRIu64, sflowxdr_next_int64(x));
287 printf(" port_no=%"PRIu32, sflowxdr_next(x));
5a0e4aec 288 printf("\n");
50b9699f
NM
289 }
290 if (x->offset.PORTNAME) {
5a0e4aec
BP
291 uint32_t pnLen;
292 const char *pnBytes;
293 char portName[SFL_MAX_PORTNAME_LEN + 1];
50b9699f
NM
294 sflowxdr_setc(x, x->offset.PORTNAME);
295 printf("PORTNAME");
5a0e4aec
BP
296 pnLen = sflowxdr_next(x);
297 SFLOWXDR_assert(x, (pnLen <= SFL_MAX_PORTNAME_LEN));
298 pnBytes = sflowxdr_str(x);
299 memcpy(portName, pnBytes, pnLen);
300 portName[pnLen] = '\0';
301 printf(" portName=%s", portName);
302 printf("\n");
50b9699f 303 }
934386dd
RW
304 if (x->offset.ETHCOUNTERS) {
305 sflowxdr_setc(x, x->offset.ETHCOUNTERS);
306 printf("ETHCOUNTERS");
307 printf(" dot3StatsAlignmentErrors=%"PRIu32, sflowxdr_next(x));
308 printf(" dot3StatsFCSErrors=%"PRIu32, sflowxdr_next(x));
309 printf(" dot3StatsSingleCollisionFrames=%"PRIu32, sflowxdr_next(x));
310 printf(" dot3StatsMultipleCollisionFrames=%"PRIu32, sflowxdr_next(x));
311 printf(" dot3StatsSQETestErrors=%"PRIu32, sflowxdr_next(x));
312 printf(" dot3StatsDeferredTransmissions=%"PRIu32, sflowxdr_next(x));
313 printf(" dot3StatsLateCollisions=%"PRIu32, sflowxdr_next(x));
314 printf(" dot3StatsExcessiveCollisions=%"PRIu32, sflowxdr_next(x));
315 printf(" dot3StatsInternalMacTransmitErrors=%"PRIu32,
316 sflowxdr_next(x));
317 printf(" dot3StatsCarrierSenseErrors=%"PRIu32, sflowxdr_next(x));
318 printf(" dot3StatsFrameTooLongs=%"PRIu32, sflowxdr_next(x));
319 printf(" dot3StatsInternalMacReceiveErrors=%"PRIu32, sflowxdr_next(x));
320 printf(" dot3StatsSymbolErrors=%"PRIu32, sflowxdr_next(x));
321 printf("\n");
322 }
8073dd31
NM
323}
324
325static char
326bin_to_hex(int hexit)
327{
328 return "0123456789ABCDEF"[hexit];
329}
330
331static int
332print_hex(const char *a, int len, char *buf, int bufLen)
333{
334 unsigned char nextByte;
335 int b = 0;
336 int i;
337
338 for (i = 0; i < len; i++) {
339 if (b > bufLen - 10) {
340 break;
341 }
342 nextByte = a[i];
343 buf[b++] = bin_to_hex(nextByte >> 4);
344 buf[b++] = bin_to_hex(nextByte & 0x0f);
345 if (i < len - 1) {
346 buf[b++] = '-';
347 }
348 }
349 buf[b] = '\0';
350 return b;
351}
352
50b9699f
NM
353static void
354print_struct_ipv4(struct sflow_xdr *x, const char *prefix)
355{
356 ovs_be32 src, dst;
357
358 printf(" %s_length=%"PRIu32, prefix, sflowxdr_next(x));
359 printf(" %s_protocol=%"PRIu32, prefix, sflowxdr_next(x));
360
361 src = sflowxdr_next_n(x);
362 dst = sflowxdr_next_n(x);
363 printf(" %s_src="IP_FMT, prefix, IP_ARGS(src));
364 printf(" %s_dst="IP_FMT, prefix, IP_ARGS(dst));
365
366 printf(" %s_src_port=%"PRIu32, prefix, sflowxdr_next(x));
367 printf(" %s_dst_port=%"PRIu32, prefix, sflowxdr_next(x));
368 printf(" %s_tcp_flags=%"PRIu32, prefix, sflowxdr_next(x));
369 printf(" %s_tos=%"PRIu32, prefix, sflowxdr_next(x));
370}
371
8073dd31
NM
372#define SFLOW_HEX_SCRATCH 1024
373
374static void
375process_flow_sample(struct sflow_xdr *x)
376{
377 if (x->offset.HEADER) {
378 uint32_t headerLen;
379 char scratch[SFLOW_HEX_SCRATCH];
380
381 printf("HEADER");
382 printf(" dgramSeqNo=%"PRIu32, x->dgramSeqNo);
383 printf(" ds=%s>%"PRIu32":%"PRIu32,
384 x->agentIPStr, x->dsClass, x->dsIndex);
385 printf(" fsSeqNo=%"PRIu32, x->fsSeqNo);
386
50b9699f
NM
387 if (x->offset.TUNNEL4_IN) {
388 sflowxdr_setc(x, x->offset.TUNNEL4_IN);
5a0e4aec 389 print_struct_ipv4(x, "tunnel4_in");
50b9699f
NM
390 }
391
392 if (x->offset.TUNNEL4_OUT) {
393 sflowxdr_setc(x, x->offset.TUNNEL4_OUT);
5a0e4aec 394 print_struct_ipv4(x, "tunnel4_out");
50b9699f
NM
395 }
396
397 if (x->offset.TUNNEL_VNI_IN) {
398 sflowxdr_setc(x, x->offset.TUNNEL_VNI_IN);
5a0e4aec 399 printf( " tunnel_in_vni=%"PRIu32, sflowxdr_next(x));
50b9699f
NM
400 }
401
402 if (x->offset.TUNNEL_VNI_OUT) {
403 sflowxdr_setc(x, x->offset.TUNNEL_VNI_OUT);
5a0e4aec 404 printf( " tunnel_out_vni=%"PRIu32, sflowxdr_next(x));
50b9699f
NM
405 }
406
7321bda3
NM
407 if (x->offset.MPLS) {
408 uint32_t addr_type, stack_depth, ii;
409 ovs_be32 mpls_lse;
410 sflowxdr_setc(x, x->offset.MPLS);
411 /* OVS only sets the out_stack. The rest will be blank. */
412 /* skip next hop address */
413 addr_type = sflowxdr_next(x);
414 sflowxdr_skip(x, addr_type == SFLOW_ADDRTYPE_IP6 ? 4 : 1);
415 /* skip in_stack */
416 stack_depth = sflowxdr_next(x);
417 sflowxdr_skip(x, stack_depth);
418 /* print out_stack */
419 stack_depth = sflowxdr_next(x);
420 for(ii = 0; ii < stack_depth; ii++) {
421 mpls_lse=sflowxdr_next_n(x);
422 printf(" mpls_label_%"PRIu32"=%"PRIu32,
423 ii, mpls_lse_to_label(mpls_lse));
424 printf(" mpls_tc_%"PRIu32"=%"PRIu32,
425 ii, mpls_lse_to_tc(mpls_lse));
426 printf(" mpls_ttl_%"PRIu32"=%"PRIu32,
427 ii, mpls_lse_to_ttl(mpls_lse));
428 printf(" mpls_bos_%"PRIu32"=%"PRIu32,
429 ii, mpls_lse_to_bos(mpls_lse));
430 }
431 }
432
8073dd31
NM
433 if (x->offset.SWITCH) {
434 sflowxdr_setc(x, x->offset.SWITCH);
435 printf(" in_vlan=%"PRIu32, sflowxdr_next(x));
436 printf(" in_priority=%"PRIu32, sflowxdr_next(x));
437 printf(" out_vlan=%"PRIu32, sflowxdr_next(x));
438 printf(" out_priority=%"PRIu32, sflowxdr_next(x));
439 }
440
441 sflowxdr_setc(x, x->offset.HEADER);
442 printf(" meanSkip=%"PRIu32, x->meanSkipCount);
443 printf(" samplePool=%"PRIu32, x->samplePool);
444 printf(" dropEvents=%"PRIu32, x->dropEvents);
445 printf(" in_ifindex=%"PRIu32, x->inputPort);
446 printf(" in_format=%"PRIu32, x->inputPortFormat);
447 printf(" out_ifindex=%"PRIu32, x->outputPort);
448 printf(" out_format=%"PRIu32, x->outputPortFormat);
449 printf(" hdr_prot=%"PRIu32, sflowxdr_next(x));
450 printf(" pkt_len=%"PRIu32, sflowxdr_next(x));
451 printf(" stripped=%"PRIu32, sflowxdr_next(x));
452 headerLen = sflowxdr_next(x);
453 printf(" hdr_len=%"PRIu32, headerLen);
454 print_hex(sflowxdr_str(x), headerLen, scratch, SFLOW_HEX_SCRATCH);
455 printf(" hdr=%s", scratch);
456 printf("\n");
457 }
458}
459
460static void
461process_datagram(struct sflow_xdr *x)
462{
463 uint32_t samples, s;
464
465 SFLOWXDR_assert(x, (sflowxdr_next(x) == SFLOW_VERSION_5));
466
467 /* Read the sFlow header. */
468 x->agentAddr.type = sflowxdr_next(x);
469 switch (x->agentAddr.type) {
470 case SFLOW_ADDRTYPE_IP4:
471 x->agentAddr.a.ip4 = sflowxdr_next_n(x);
472 break;
473
474 case SFLOW_ADDRTYPE_IP6:
475 x->agentAddr.a.ip6[0] = sflowxdr_next_n(x);
476 x->agentAddr.a.ip6[1] = sflowxdr_next_n(x);
477 x->agentAddr.a.ip6[2] = sflowxdr_next_n(x);
478 x->agentAddr.a.ip6[3] = sflowxdr_next_n(x);
479 break;
480
481 case SFLOW_ADDRTYPE_undefined:
482 default:
483 SFLOWXDR_throw(x);
484 break;
485 }
486 x->subAgentId = sflowxdr_next(x);
487 x->dgramSeqNo = sflowxdr_next(x);
488 x->uptime_mS = sflowxdr_next(x);
489
490 /* Store the agent address as a string. */
491 if (x->agentAddr.type == SFLOW_ADDRTYPE_IP6) {
e731d71b
AS
492 char ipstr[INET6_ADDRSTRLEN];
493 inet_ntop(AF_INET6, (const void *) &x->agentAddr.a.ip6,
494 ipstr, INET6_ADDRSTRLEN);
495 snprintf(x->agentIPStr, sizeof x->agentIPStr, "[%s]", ipstr);
8073dd31 496 } else {
e731d71b 497 snprintf(x->agentIPStr, sizeof x->agentIPStr,
8073dd31
NM
498 IP_FMT, IP_ARGS(x->agentAddr.a.ip4));
499 }
500
501 /* Array of flow/counter samples. */
502 samples = sflowxdr_next(x);
503 for (s = 0; s < samples; s++) {
504 uint32_t sType = sflowxdr_next(x);
505 uint32_t sQuads = sflowxdr_next(x) >> 2;
506 uint32_t sMark = sflowxdr_mark(x, sQuads);
507 SFLOWXDR_assert(x, sflowxdr_more(x, sQuads));
508
509 switch (sType) {
510 case SFLOW_COUNTERS_SAMPLE_EXPANDED:
511 case SFLOW_COUNTERS_SAMPLE:
512 {
513 uint32_t csElements, e;
514 uint32_t ceTag, ceQuads, ceMark, csEnd;
515
516 x->csSeqNo = sflowxdr_next(x);
517 if (sType == SFLOW_COUNTERS_SAMPLE_EXPANDED) {
518 x->dsClass = sflowxdr_next(x);
519 x->dsIndex = sflowxdr_next(x);
520 } else {
521 uint32_t dsCombined = sflowxdr_next(x);
522 x->dsClass = dsCombined >> 24;
523 x->dsIndex = dsCombined & 0x00FFFFFF;
524 }
525
526 csElements = sflowxdr_next(x);
527 for (e = 0; e < csElements; e++) {
528 SFLOWXDR_assert(x, sflowxdr_more(x,2));
529 ceTag = sflowxdr_next(x);
530 ceQuads = sflowxdr_next(x) >> 2;
531 ceMark = sflowxdr_mark(x, ceQuads);
532 SFLOWXDR_assert(x, sflowxdr_more(x,ceQuads));
533 /* Only care about selected structures. Just record their
534 * offsets here. We'll read the fields out later. */
535 switch (ceTag) {
536 case SFLOW_TAG_CTR_IFCOUNTERS:
537 sflowxdr_mark_unique(x, &x->offset.IFCOUNTERS);
934386dd
RW
538 break;
539 case SFLOW_TAG_CTR_ETHCOUNTERS:
540 sflowxdr_mark_unique(x, &x->offset.ETHCOUNTERS);
8073dd31 541 break;
50b9699f
NM
542 case SFLOW_TAG_CTR_LACPCOUNTERS:
543 sflowxdr_mark_unique(x, &x->offset.LACPCOUNTERS);
544 break;
545 case SFLOW_TAG_CTR_PORTNAME:
546 sflowxdr_mark_unique(x, &x->offset.PORTNAME);
547 break;
548 case SFLOW_TAG_CTR_OPENFLOWPORT:
549 sflowxdr_mark_unique(x, &x->offset.OPENFLOWPORT);
550 break;
8073dd31
NM
551
552 /* Add others here... */
553 }
554
555 sflowxdr_skip(x, ceQuads);
556 SFLOWXDR_assert(x, sflowxdr_mark_ok(x, ceMark));
557 }
558
559 csEnd = sflowxdr_mark(x, 0);
560 process_counter_sample(x);
561 /* Make sure we pick up the decoding where we left off. */
562 sflowxdr_setc(x, csEnd);
563
564 /* Clear the offsets for the next sample. */
565 memset(&x->offset, 0, sizeof x->offset);
566 }
567 break;
568
569 case SFLOW_FLOW_SAMPLE:
570 case SFLOW_FLOW_SAMPLE_EXPANDED:
571 {
572 uint32_t fsElements, e;
573 uint32_t feTag, feQuads, feMark, fsEnd;
574 x->fsSeqNo = sflowxdr_next(x);
575 if (sType == SFLOW_FLOW_SAMPLE_EXPANDED) {
576 x->dsClass = sflowxdr_next(x);
577 x->dsIndex = sflowxdr_next(x);
578 } else {
579 uint32_t dsCombined = sflowxdr_next(x);
580 x->dsClass = dsCombined >> 24;
581 x->dsIndex = dsCombined & 0x00FFFFFF;
582 }
583 x->meanSkipCount = sflowxdr_next(x);
584 x->samplePool = sflowxdr_next(x);
585 x->dropEvents = sflowxdr_next(x);
586 if (sType == SFLOW_FLOW_SAMPLE_EXPANDED) {
587 x->inputPortFormat = sflowxdr_next(x);
588 x->inputPort = sflowxdr_next(x);
589 x->outputPortFormat = sflowxdr_next(x);
590 x->outputPort = sflowxdr_next(x);
591 } else {
592 uint32_t inp, outp;
593
594 inp = sflowxdr_next(x);
595 outp = sflowxdr_next(x);
596 x->inputPortFormat = inp >> 30;
597 x->inputPort = inp & 0x3fffffff;
598 x->outputPortFormat = outp >> 30;
599 x->outputPort = outp & 0x3fffffff;
600 }
601 fsElements = sflowxdr_next(x);
602 for (e = 0; e < fsElements; e++) {
603 SFLOWXDR_assert(x, sflowxdr_more(x,2));
604 feTag = sflowxdr_next(x);
605 feQuads = sflowxdr_next(x) >> 2;
606 feMark = sflowxdr_mark(x, feQuads);
607 SFLOWXDR_assert(x, sflowxdr_more(x,feQuads));
608 /* Only care about selected structures. Just record their
609 * offsets here. We'll read the fields out below. */
610 switch (feTag) {
611 case SFLOW_TAG_PKT_HEADER:
612 sflowxdr_mark_unique(x, &x->offset.HEADER);
613 break;
614
615 case SFLOW_TAG_PKT_SWITCH:
616 sflowxdr_mark_unique(x, &x->offset.SWITCH);
617 break;
618
5a0e4aec 619 case SFLOW_TAG_PKT_TUNNEL4_OUT:
50b9699f
NM
620 sflowxdr_mark_unique(x, &x->offset.TUNNEL4_OUT);
621 break;
622
5a0e4aec 623 case SFLOW_TAG_PKT_TUNNEL4_IN:
50b9699f
NM
624 sflowxdr_mark_unique(x, &x->offset.TUNNEL4_IN);
625 break;
626
5a0e4aec 627 case SFLOW_TAG_PKT_TUNNEL_VNI_OUT:
50b9699f
NM
628 sflowxdr_mark_unique(x, &x->offset.TUNNEL_VNI_OUT);
629 break;
630
5a0e4aec 631 case SFLOW_TAG_PKT_TUNNEL_VNI_IN:
50b9699f
NM
632 sflowxdr_mark_unique(x, &x->offset.TUNNEL_VNI_IN);
633 break;
634
5a0e4aec 635 case SFLOW_TAG_PKT_MPLS:
7321bda3
NM
636 sflowxdr_mark_unique(x, &x->offset.MPLS);
637 break;
638
8073dd31
NM
639 /* Add others here... */
640 }
641
642 sflowxdr_skip(x, feQuads);
643 SFLOWXDR_assert(x, sflowxdr_mark_ok(x, feMark));
644 }
645
646 fsEnd = sflowxdr_mark(x, 0);
647 process_flow_sample(x);
648 /* Make sure we pick up the decoding where we left off. */
649 sflowxdr_setc(x, fsEnd);
650
651 /* Clear the offsets for the next counter/flow sample. */
652 memset(&x->offset, 0, sizeof x->offset);
653 }
654 break;
655
656 default:
657 /* Skip other sample types. */
658 sflowxdr_skip(x, sQuads);
659 }
660 SFLOWXDR_assert(x, sflowxdr_mark_ok(x, sMark));
661 }
662}
663
664static void
665print_sflow(struct ofpbuf *buf)
666{
667 char *dgram_buf;
6fd6ed71 668 int dgram_len = buf->size;
8073dd31
NM
669 struct sflow_xdr xdrDatagram;
670 struct sflow_xdr *x = &xdrDatagram;
671
672 memset(x, 0, sizeof *x);
673 if (SFLOWXDR_try(x)) {
6fd6ed71 674 SFLOWXDR_assert(x, (dgram_buf = ofpbuf_try_pull(buf, buf->size)));
8073dd31
NM
675 sflowxdr_init(x, dgram_buf, dgram_len);
676 SFLOWXDR_assert(x, dgram_len >= SFLOW_MIN_LEN);
677 process_datagram(x);
678 } else {
679 // CATCH
89387713 680 printf("\n>>>>> ERROR in " __FILE__ " at line %d\n", x->errline);
8073dd31
NM
681 }
682}
683
eadd1644
AZ
684static void
685test_sflow_main(int argc, char *argv[])
8073dd31
NM
686{
687 struct unixctl_server *server;
688 enum { MAX_RECV = 1500 };
689 const char *target;
690 struct ofpbuf buf;
691 bool exiting = false;
692 int error;
693 int sock;
694
5f383751 695 ovs_cmdl_proctitle_init(argc, argv);
8073dd31 696 set_program_name(argv[0]);
8f26aeb9 697 service_start(&argc, &argv);
8073dd31
NM
698 parse_options(argc, argv);
699
700 if (argc - optind != 1) {
701 ovs_fatal(0, "exactly one non-option argument required "
702 "(use --help for help)");
703 }
704 target = argv[optind];
705
b52ecd96 706 sock = inet_open_passive(SOCK_DGRAM, target, 0, NULL, 0, true);
8073dd31 707 if (sock < 0) {
2dd88e5d 708 ovs_fatal(0, "%s: failed to open (%s)", target, ovs_strerror(-sock));
8073dd31
NM
709 }
710
711 daemon_save_fd(STDOUT_FILENO);
e91b927d 712 daemonize_start(false);
8073dd31
NM
713
714 error = unixctl_server_create(NULL, &server);
715 if (error) {
716 ovs_fatal(error, "failed to create unixctl server");
717 }
718 unixctl_command_register("exit", "", 0, 0, test_sflow_exit, &exiting);
719
720 daemonize_complete();
721
722 ofpbuf_init(&buf, MAX_RECV);
723 for (;;) {
724 int retval;
725
726 unixctl_server_run(server);
727
728 ofpbuf_clear(&buf);
729 do {
6fd6ed71 730 retval = recv(sock, buf.data, buf.allocated, 0);
8073dd31
NM
731 } while (retval < 0 && errno == EINTR);
732 if (retval > 0) {
733 ofpbuf_put_uninit(&buf, retval);
734 print_sflow(&buf);
735 fflush(stdout);
736 }
737
738 if (exiting) {
739 break;
740 }
741
742 poll_fd_wait(sock, POLLIN);
743 unixctl_server_wait(server);
744 poll_block();
745 }
d1a74e5e
IM
746 ofpbuf_uninit(&buf);
747 unixctl_server_destroy(server);
8073dd31
NM
748}
749
750static void
751parse_options(int argc, char *argv[])
752{
753 enum {
977529e4
BP
754 DAEMON_OPTION_ENUMS,
755 VLOG_OPTION_ENUMS
8073dd31 756 };
07fc4ed3 757 static const struct option long_options[] = {
8073dd31
NM
758 {"verbose", optional_argument, NULL, 'v'},
759 {"help", no_argument, NULL, 'h'},
760 DAEMON_LONG_OPTIONS,
977529e4 761 VLOG_LONG_OPTIONS,
8073dd31
NM
762 {NULL, 0, NULL, 0},
763 };
5f383751 764 char *short_options = ovs_cmdl_long_options_to_short_options(long_options);
8073dd31
NM
765
766 for (;;) {
767 int c = getopt_long(argc, argv, short_options, long_options, NULL);
768 if (c == -1) {
769 break;
770 }
771
772 switch (c) {
773 case 'h':
774 usage();
775
977529e4
BP
776 DAEMON_OPTION_HANDLERS
777 VLOG_OPTION_HANDLERS
8073dd31
NM
778
779 case '?':
780 exit(EXIT_FAILURE);
781
782 default:
783 abort();
784 }
785 }
786 free(short_options);
787}
788
789static void
790usage(void)
791{
792 printf("%s: sflow collector test utility\n"
793 "usage: %s [OPTIONS] PORT[:IP]\n"
794 "where PORT is the UDP port to listen on and IP is optionally\n"
795 "the IP address to listen on.\n",
796 program_name, program_name);
797 daemon_usage();
798 vlog_usage();
799 printf("\nOther options:\n"
800 " -h, --help display this help message\n");
801 exit(EXIT_SUCCESS);
802}
803
804static void
805test_sflow_exit(struct unixctl_conn *conn,
806 int argc OVS_UNUSED, const char *argv[] OVS_UNUSED,
807 void *exiting_)
808{
809 bool *exiting = exiting_;
810 *exiting = true;
811 unixctl_command_reply(conn, NULL);
812}
eadd1644
AZ
813
814OVSTEST_REGISTER("test-sflow", test_sflow_main);