2 * Copyright (c) 2011, 2012, 2013, 2014, 2015 Nicira, Inc.
3 * Copyright (c) 2013 InMon Corp.
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:
9 * http://www.apache.org/licenses/LICENSE-2.0
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.
21 #include <arpa/inet.h>
28 #include "command-line.h"
30 #include "openvswitch/dynamic-string.h"
34 #include "poll-loop.h"
35 #include "socket-util.h"
38 #include "openvswitch/vlog.h"
40 OVS_NO_RETURN
static void usage(void);
41 static void parse_options(int argc
, char *argv
[]);
43 static unixctl_cb_func test_sflow_exit
;
46 #define SFLOW_VERSION_5 5
47 #define SFLOW_MIN_LEN 36
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
55 /* Structure element tag numbers. */
56 #define SFLOW_TAG_CTR_IFCOUNTERS 1
57 #define SFLOW_TAG_CTR_LACPCOUNTERS 7
58 #define SFLOW_TAG_CTR_OPENFLOWPORT 1004
59 #define SFLOW_TAG_CTR_PORTNAME 1005
60 #define SFLOW_TAG_PKT_HEADER 1
61 #define SFLOW_TAG_PKT_SWITCH 1001
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
66 #define SFLOW_TAG_PKT_MPLS 1006
69 #define SFL_MAX_PORTNAME_LEN 255
73 SFLOW_ADDRTYPE_undefined
= 0,
95 struct sflow_addr agentAddr
;
96 char agentIPStr
[INET6_ADDRSTRLEN
+ 2];
104 /* Sequence numbers. */
109 /* Structure offsets. */
113 uint32_t TUNNEL4_OUT
;
115 uint32_t TUNNEL_VNI_OUT
;
116 uint32_t TUNNEL_VNI_IN
;
119 uint32_t LACPCOUNTERS
;
120 uint32_t OPENFLOWPORT
;
124 /* Flow sample fields. */
125 uint32_t meanSkipCount
;
128 uint32_t inputPortFormat
;
130 uint32_t outputPortFormat
;
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)
139 sflowxdr_init(struct sflow_xdr
*x
, void *buf
, size_t len
)
146 sflowxdr_next(struct sflow_xdr
*x
)
148 return ntohl(x
->datap
[x
->i
++]);
152 sflowxdr_next_n(struct sflow_xdr
*x
)
154 return x
->datap
[x
->i
++];
158 sflowxdr_more(const struct sflow_xdr
*x
, uint32_t q
)
160 return q
+ x
->i
<= x
->quads
;
164 sflowxdr_skip(struct sflow_xdr
*x
, uint32_t q
)
170 sflowxdr_mark(const struct sflow_xdr
*x
, uint32_t q
)
176 sflowxdr_mark_ok(const struct sflow_xdr
*x
, uint32_t m
)
182 sflowxdr_mark_unique(struct sflow_xdr
*x
, uint32_t *pi
)
191 sflowxdr_setc(struct sflow_xdr
*x
, uint32_t j
)
197 sflowxdr_str(const struct sflow_xdr
*x
)
199 return (const char *) (x
->datap
+ x
->i
);
203 sflowxdr_next_int64(struct sflow_xdr
*x
)
206 scratch
= sflowxdr_next(x
);
208 scratch
+= sflowxdr_next(x
);
213 process_counter_sample(struct sflow_xdr
*x
)
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
));
243 if (x
->offset
.LACPCOUNTERS
) {
244 struct eth_addr
*mac
;
250 uint8_t partnerAdmin
;
255 sflowxdr_setc(x
, x
->offset
.LACPCOUNTERS
);
256 printf("LACPCOUNTERS");
257 mac
= (void *)sflowxdr_str(x
);
258 printf(" sysID="ETH_ADDR_FMT
, ETH_ADDR_ARGS(*mac
));
260 mac
= (void *)sflowxdr_str(x
);
261 printf(" partnerID="ETH_ADDR_FMT
, ETH_ADDR_ARGS(*mac
));
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(" LACPDUsRx=%"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(" LACPDUsTx=%"PRIu32
, sflowxdr_next(x
));
275 printf(" markerPDUsTx=%"PRIu32
, sflowxdr_next(x
));
276 printf(" markerRespPDUsTx=%"PRIu32
, sflowxdr_next(x
));
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
));
286 if (x
->offset
.PORTNAME
) {
289 char portName
[SFL_MAX_PORTNAME_LEN
+ 1];
290 sflowxdr_setc(x
, x
->offset
.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
);
303 bin_to_hex(int hexit
)
305 return "0123456789ABCDEF"[hexit
];
309 print_hex(const char *a
, int len
, char *buf
, int bufLen
)
311 unsigned char nextByte
;
315 for (i
= 0; i
< len
; i
++) {
316 if (b
> bufLen
- 10) {
320 buf
[b
++] = bin_to_hex(nextByte
>> 4);
321 buf
[b
++] = bin_to_hex(nextByte
& 0x0f);
331 print_struct_ipv4(struct sflow_xdr
*x
, const char *prefix
)
335 printf(" %s_length=%"PRIu32
, prefix
, sflowxdr_next(x
));
336 printf(" %s_protocol=%"PRIu32
, prefix
, sflowxdr_next(x
));
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
));
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
));
349 #define SFLOW_HEX_SCRATCH 1024
352 process_flow_sample(struct sflow_xdr
*x
)
354 if (x
->offset
.HEADER
) {
356 char scratch
[SFLOW_HEX_SCRATCH
];
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
);
364 if (x
->offset
.TUNNEL4_IN
) {
365 sflowxdr_setc(x
, x
->offset
.TUNNEL4_IN
);
366 print_struct_ipv4(x
, "tunnel4_in");
369 if (x
->offset
.TUNNEL4_OUT
) {
370 sflowxdr_setc(x
, x
->offset
.TUNNEL4_OUT
);
371 print_struct_ipv4(x
, "tunnel4_out");
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
));
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
));
384 if (x
->offset
.MPLS
) {
385 uint32_t addr_type
, stack_depth
, ii
;
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);
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
));
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
));
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
);
438 process_datagram(struct sflow_xdr
*x
)
442 SFLOWXDR_assert(x
, (sflowxdr_next(x
) == SFLOW_VERSION_5
));
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
);
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
);
458 case SFLOW_ADDRTYPE_undefined
:
463 x
->subAgentId
= sflowxdr_next(x
);
464 x
->dgramSeqNo
= sflowxdr_next(x
);
465 x
->uptime_mS
= sflowxdr_next(x
);
467 /* Store the agent address as a string. */
468 if (x
->agentAddr
.type
== SFLOW_ADDRTYPE_IP6
) {
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
);
474 snprintf(x
->agentIPStr
, sizeof x
->agentIPStr
,
475 IP_FMT
, IP_ARGS(x
->agentAddr
.a
.ip4
));
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
));
487 case SFLOW_COUNTERS_SAMPLE_EXPANDED
:
488 case SFLOW_COUNTERS_SAMPLE
:
490 uint32_t csElements
, e
;
491 uint32_t ceTag
, ceQuads
, ceMark
, csEnd
;
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
);
498 uint32_t dsCombined
= sflowxdr_next(x
);
499 x
->dsClass
= dsCombined
>> 24;
500 x
->dsIndex
= dsCombined
& 0x00FFFFFF;
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. */
513 case SFLOW_TAG_CTR_IFCOUNTERS
:
514 sflowxdr_mark_unique(x
, &x
->offset
.IFCOUNTERS
);
516 case SFLOW_TAG_CTR_LACPCOUNTERS
:
517 sflowxdr_mark_unique(x
, &x
->offset
.LACPCOUNTERS
);
519 case SFLOW_TAG_CTR_PORTNAME
:
520 sflowxdr_mark_unique(x
, &x
->offset
.PORTNAME
);
522 case SFLOW_TAG_CTR_OPENFLOWPORT
:
523 sflowxdr_mark_unique(x
, &x
->offset
.OPENFLOWPORT
);
526 /* Add others here... */
529 sflowxdr_skip(x
, ceQuads
);
530 SFLOWXDR_assert(x
, sflowxdr_mark_ok(x
, ceMark
));
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
);
538 /* Clear the offsets for the next sample. */
539 memset(&x
->offset
, 0, sizeof x
->offset
);
543 case SFLOW_FLOW_SAMPLE
:
544 case SFLOW_FLOW_SAMPLE_EXPANDED
:
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
);
553 uint32_t dsCombined
= sflowxdr_next(x
);
554 x
->dsClass
= dsCombined
>> 24;
555 x
->dsIndex
= dsCombined
& 0x00FFFFFF;
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
);
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;
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. */
585 case SFLOW_TAG_PKT_HEADER
:
586 sflowxdr_mark_unique(x
, &x
->offset
.HEADER
);
589 case SFLOW_TAG_PKT_SWITCH
:
590 sflowxdr_mark_unique(x
, &x
->offset
.SWITCH
);
593 case SFLOW_TAG_PKT_TUNNEL4_OUT
:
594 sflowxdr_mark_unique(x
, &x
->offset
.TUNNEL4_OUT
);
597 case SFLOW_TAG_PKT_TUNNEL4_IN
:
598 sflowxdr_mark_unique(x
, &x
->offset
.TUNNEL4_IN
);
601 case SFLOW_TAG_PKT_TUNNEL_VNI_OUT
:
602 sflowxdr_mark_unique(x
, &x
->offset
.TUNNEL_VNI_OUT
);
605 case SFLOW_TAG_PKT_TUNNEL_VNI_IN
:
606 sflowxdr_mark_unique(x
, &x
->offset
.TUNNEL_VNI_IN
);
609 case SFLOW_TAG_PKT_MPLS
:
610 sflowxdr_mark_unique(x
, &x
->offset
.MPLS
);
613 /* Add others here... */
616 sflowxdr_skip(x
, feQuads
);
617 SFLOWXDR_assert(x
, sflowxdr_mark_ok(x
, feMark
));
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
);
625 /* Clear the offsets for the next counter/flow sample. */
626 memset(&x
->offset
, 0, sizeof x
->offset
);
631 /* Skip other sample types. */
632 sflowxdr_skip(x
, sQuads
);
634 SFLOWXDR_assert(x
, sflowxdr_mark_ok(x
, sMark
));
639 print_sflow(struct ofpbuf
*buf
)
642 int dgram_len
= buf
->size
;
643 struct sflow_xdr xdrDatagram
;
644 struct sflow_xdr
*x
= &xdrDatagram
;
646 memset(x
, 0, sizeof *x
);
647 if (SFLOWXDR_try(x
)) {
648 SFLOWXDR_assert(x
, (dgram_buf
= ofpbuf_try_pull(buf
, buf
->size
)));
649 sflowxdr_init(x
, dgram_buf
, dgram_len
);
650 SFLOWXDR_assert(x
, dgram_len
>= SFLOW_MIN_LEN
);
654 printf("\n>>>>> ERROR in " __FILE__
" at line %u\n", x
->errline
);
659 test_sflow_main(int argc
, char *argv
[])
661 struct unixctl_server
*server
;
662 enum { MAX_RECV
= 1500 };
665 bool exiting
= false;
669 ovs_cmdl_proctitle_init(argc
, argv
);
670 set_program_name(argv
[0]);
671 service_start(&argc
, &argv
);
672 parse_options(argc
, argv
);
674 if (argc
- optind
!= 1) {
675 ovs_fatal(0, "exactly one non-option argument required "
676 "(use --help for help)");
678 target
= argv
[optind
];
680 sock
= inet_open_passive(SOCK_DGRAM
, target
, 0, NULL
, 0, true);
682 ovs_fatal(0, "%s: failed to open (%s)", target
, ovs_strerror(-sock
));
685 daemon_save_fd(STDOUT_FILENO
);
686 daemonize_start(false);
688 error
= unixctl_server_create(NULL
, &server
);
690 ovs_fatal(error
, "failed to create unixctl server");
692 unixctl_command_register("exit", "", 0, 0, test_sflow_exit
, &exiting
);
694 daemonize_complete();
696 ofpbuf_init(&buf
, MAX_RECV
);
700 unixctl_server_run(server
);
704 retval
= recv(sock
, buf
.data
, buf
.allocated
, 0);
705 } while (retval
< 0 && errno
== EINTR
);
707 ofpbuf_put_uninit(&buf
, retval
);
716 poll_fd_wait(sock
, POLLIN
);
717 unixctl_server_wait(server
);
721 unixctl_server_destroy(server
);
725 parse_options(int argc
, char *argv
[])
731 static const struct option long_options
[] = {
732 {"verbose", optional_argument
, NULL
, 'v'},
733 {"help", no_argument
, NULL
, 'h'},
738 char *short_options
= ovs_cmdl_long_options_to_short_options(long_options
);
741 int c
= getopt_long(argc
, argv
, short_options
, long_options
, NULL
);
750 DAEMON_OPTION_HANDLERS
766 printf("%s: sflow collector test utility\n"
767 "usage: %s [OPTIONS] PORT[:IP]\n"
768 "where PORT is the UDP port to listen on and IP is optionally\n"
769 "the IP address to listen on.\n",
770 program_name
, program_name
);
773 printf("\nOther options:\n"
774 " -h, --help display this help message\n");
779 test_sflow_exit(struct unixctl_conn
*conn
,
780 int argc OVS_UNUSED
, const char *argv
[] OVS_UNUSED
,
783 bool *exiting
= exiting_
;
785 unixctl_command_reply(conn
, NULL
);
788 OVSTEST_REGISTER("test-sflow", test_sflow_main
);