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