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