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 <sys/types.h>
22 #include <netinet/in.h>
23 #include <arpa/inet.h>
30 #include "command-line.h"
32 #include "openvswitch/dynamic-string.h"
33 #include "openvswitch/ofpbuf.h"
36 #include "openvswitch/poll-loop.h"
37 #include "socket-util.h"
40 #include "openvswitch/vlog.h"
42 OVS_NO_RETURN
static void usage(void);
43 static void parse_options(int argc
, char *argv
[]);
45 static unixctl_cb_func test_sflow_exit
;
48 #define SFLOW_VERSION_5 5
49 #define SFLOW_MIN_LEN 36
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
57 /* Structure element tag numbers. */
58 #define SFLOW_TAG_CTR_IFCOUNTERS 1
59 #define SFLOW_TAG_CTR_ETHCOUNTERS 2
60 #define SFLOW_TAG_CTR_LACPCOUNTERS 7
61 #define SFLOW_TAG_CTR_OPENFLOWPORT 1004
62 #define SFLOW_TAG_CTR_PORTNAME 1005
63 #define SFLOW_TAG_PKT_HEADER 1
64 #define SFLOW_TAG_PKT_SWITCH 1001
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
69 #define SFLOW_TAG_PKT_MPLS 1006
72 #define SFL_MAX_PORTNAME_LEN 255
76 SFLOW_ADDRTYPE_undefined
= 0,
98 struct sflow_addr agentAddr
;
99 char agentIPStr
[INET6_ADDRSTRLEN
+ 2];
107 /* Sequence numbers. */
112 /* Structure offsets. */
116 uint32_t TUNNEL4_OUT
;
118 uint32_t TUNNEL_VNI_OUT
;
119 uint32_t TUNNEL_VNI_IN
;
122 uint32_t ETHCOUNTERS
;
123 uint32_t LACPCOUNTERS
;
124 uint32_t OPENFLOWPORT
;
128 /* Flow sample fields. */
129 uint32_t meanSkipCount
;
132 uint32_t inputPortFormat
;
134 uint32_t outputPortFormat
;
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)
143 sflowxdr_init(struct sflow_xdr
*x
, void *buf
, size_t len
)
150 sflowxdr_next(struct sflow_xdr
*x
)
152 return ntohl(x
->datap
[x
->i
++]);
156 sflowxdr_next_n(struct sflow_xdr
*x
)
158 return x
->datap
[x
->i
++];
162 sflowxdr_more(const struct sflow_xdr
*x
, uint32_t q
)
164 return q
+ x
->i
<= x
->quads
;
168 sflowxdr_skip(struct sflow_xdr
*x
, uint32_t q
)
174 sflowxdr_mark(const struct sflow_xdr
*x
, uint32_t q
)
180 sflowxdr_mark_ok(const struct sflow_xdr
*x
, uint32_t m
)
186 sflowxdr_mark_unique(struct sflow_xdr
*x
, uint32_t *pi
)
195 sflowxdr_setc(struct sflow_xdr
*x
, uint32_t j
)
201 sflowxdr_str(const struct sflow_xdr
*x
)
203 return (const char *) (x
->datap
+ x
->i
);
207 sflowxdr_next_int64(struct sflow_xdr
*x
)
210 scratch
= sflowxdr_next(x
);
212 scratch
+= sflowxdr_next(x
);
217 process_counter_sample(struct sflow_xdr
*x
)
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
));
247 if (x
->offset
.LACPCOUNTERS
) {
248 struct eth_addr
*mac
;
254 uint8_t partnerAdmin
;
259 sflowxdr_setc(x
, x
->offset
.LACPCOUNTERS
);
260 printf("LACPCOUNTERS");
261 mac
= (void *)sflowxdr_str(x
);
262 printf(" sysID="ETH_ADDR_FMT
, ETH_ADDR_ARGS(*mac
));
264 mac
= (void *)sflowxdr_str(x
);
265 printf(" partnerID="ETH_ADDR_FMT
, ETH_ADDR_ARGS(*mac
));
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
));
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
));
290 if (x
->offset
.PORTNAME
) {
293 char portName
[SFL_MAX_PORTNAME_LEN
+ 1];
294 sflowxdr_setc(x
, x
->offset
.PORTNAME
);
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
);
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
,
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
));
326 bin_to_hex(int hexit
)
328 return "0123456789ABCDEF"[hexit
];
332 print_hex(const char *a
, int len
, char *buf
, int bufLen
)
334 unsigned char nextByte
;
338 for (i
= 0; i
< len
; i
++) {
339 if (b
> bufLen
- 10) {
343 buf
[b
++] = bin_to_hex(nextByte
>> 4);
344 buf
[b
++] = bin_to_hex(nextByte
& 0x0f);
354 print_struct_ipv4(struct sflow_xdr
*x
, const char *prefix
)
358 printf(" %s_length=%"PRIu32
, prefix
, sflowxdr_next(x
));
359 printf(" %s_protocol=%"PRIu32
, prefix
, sflowxdr_next(x
));
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
));
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
));
372 #define SFLOW_HEX_SCRATCH 1024
375 process_flow_sample(struct sflow_xdr
*x
)
377 if (x
->offset
.HEADER
) {
379 char scratch
[SFLOW_HEX_SCRATCH
];
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
);
387 if (x
->offset
.TUNNEL4_IN
) {
388 sflowxdr_setc(x
, x
->offset
.TUNNEL4_IN
);
389 print_struct_ipv4(x
, "tunnel4_in");
392 if (x
->offset
.TUNNEL4_OUT
) {
393 sflowxdr_setc(x
, x
->offset
.TUNNEL4_OUT
);
394 print_struct_ipv4(x
, "tunnel4_out");
397 if (x
->offset
.TUNNEL_VNI_IN
) {
398 sflowxdr_setc(x
, x
->offset
.TUNNEL_VNI_IN
);
399 printf( " tunnel_in_vni=%"PRIu32
, sflowxdr_next(x
));
402 if (x
->offset
.TUNNEL_VNI_OUT
) {
403 sflowxdr_setc(x
, x
->offset
.TUNNEL_VNI_OUT
);
404 printf( " tunnel_out_vni=%"PRIu32
, sflowxdr_next(x
));
407 if (x
->offset
.MPLS
) {
408 uint32_t addr_type
, stack_depth
, ii
;
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);
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
));
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
));
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
);
461 process_datagram(struct sflow_xdr
*x
)
465 SFLOWXDR_assert(x
, (sflowxdr_next(x
) == SFLOW_VERSION_5
));
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
);
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
);
481 case SFLOW_ADDRTYPE_undefined
:
486 x
->subAgentId
= sflowxdr_next(x
);
487 x
->dgramSeqNo
= sflowxdr_next(x
);
488 x
->uptime_mS
= sflowxdr_next(x
);
490 /* Store the agent address as a string. */
491 if (x
->agentAddr
.type
== SFLOW_ADDRTYPE_IP6
) {
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
);
497 snprintf(x
->agentIPStr
, sizeof x
->agentIPStr
,
498 IP_FMT
, IP_ARGS(x
->agentAddr
.a
.ip4
));
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
));
510 case SFLOW_COUNTERS_SAMPLE_EXPANDED
:
511 case SFLOW_COUNTERS_SAMPLE
:
513 uint32_t csElements
, e
;
514 uint32_t ceTag
, ceQuads
, ceMark
, csEnd
;
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
);
521 uint32_t dsCombined
= sflowxdr_next(x
);
522 x
->dsClass
= dsCombined
>> 24;
523 x
->dsIndex
= dsCombined
& 0x00FFFFFF;
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. */
536 case SFLOW_TAG_CTR_IFCOUNTERS
:
537 sflowxdr_mark_unique(x
, &x
->offset
.IFCOUNTERS
);
539 case SFLOW_TAG_CTR_ETHCOUNTERS
:
540 sflowxdr_mark_unique(x
, &x
->offset
.ETHCOUNTERS
);
542 case SFLOW_TAG_CTR_LACPCOUNTERS
:
543 sflowxdr_mark_unique(x
, &x
->offset
.LACPCOUNTERS
);
545 case SFLOW_TAG_CTR_PORTNAME
:
546 sflowxdr_mark_unique(x
, &x
->offset
.PORTNAME
);
548 case SFLOW_TAG_CTR_OPENFLOWPORT
:
549 sflowxdr_mark_unique(x
, &x
->offset
.OPENFLOWPORT
);
552 /* Add others here... */
555 sflowxdr_skip(x
, ceQuads
);
556 SFLOWXDR_assert(x
, sflowxdr_mark_ok(x
, ceMark
));
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
);
564 /* Clear the offsets for the next sample. */
565 memset(&x
->offset
, 0, sizeof x
->offset
);
569 case SFLOW_FLOW_SAMPLE
:
570 case SFLOW_FLOW_SAMPLE_EXPANDED
:
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
);
579 uint32_t dsCombined
= sflowxdr_next(x
);
580 x
->dsClass
= dsCombined
>> 24;
581 x
->dsIndex
= dsCombined
& 0x00FFFFFF;
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
);
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;
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. */
611 case SFLOW_TAG_PKT_HEADER
:
612 sflowxdr_mark_unique(x
, &x
->offset
.HEADER
);
615 case SFLOW_TAG_PKT_SWITCH
:
616 sflowxdr_mark_unique(x
, &x
->offset
.SWITCH
);
619 case SFLOW_TAG_PKT_TUNNEL4_OUT
:
620 sflowxdr_mark_unique(x
, &x
->offset
.TUNNEL4_OUT
);
623 case SFLOW_TAG_PKT_TUNNEL4_IN
:
624 sflowxdr_mark_unique(x
, &x
->offset
.TUNNEL4_IN
);
627 case SFLOW_TAG_PKT_TUNNEL_VNI_OUT
:
628 sflowxdr_mark_unique(x
, &x
->offset
.TUNNEL_VNI_OUT
);
631 case SFLOW_TAG_PKT_TUNNEL_VNI_IN
:
632 sflowxdr_mark_unique(x
, &x
->offset
.TUNNEL_VNI_IN
);
635 case SFLOW_TAG_PKT_MPLS
:
636 sflowxdr_mark_unique(x
, &x
->offset
.MPLS
);
639 /* Add others here... */
642 sflowxdr_skip(x
, feQuads
);
643 SFLOWXDR_assert(x
, sflowxdr_mark_ok(x
, feMark
));
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
);
651 /* Clear the offsets for the next counter/flow sample. */
652 memset(&x
->offset
, 0, sizeof x
->offset
);
657 /* Skip other sample types. */
658 sflowxdr_skip(x
, sQuads
);
660 SFLOWXDR_assert(x
, sflowxdr_mark_ok(x
, sMark
));
665 print_sflow(struct ofpbuf
*buf
)
668 int dgram_len
= buf
->size
;
669 struct sflow_xdr xdrDatagram
;
670 struct sflow_xdr
*x
= &xdrDatagram
;
672 memset(x
, 0, sizeof *x
);
673 if (SFLOWXDR_try(x
)) {
674 SFLOWXDR_assert(x
, (dgram_buf
= ofpbuf_try_pull(buf
, buf
->size
)));
675 sflowxdr_init(x
, dgram_buf
, dgram_len
);
676 SFLOWXDR_assert(x
, dgram_len
>= SFLOW_MIN_LEN
);
680 printf("\n>>>>> ERROR in " __FILE__
" at line %d\n", x
->errline
);
685 test_sflow_main(int argc
, char *argv
[])
687 struct unixctl_server
*server
;
688 enum { MAX_RECV
= 1500 };
691 bool exiting
= false;
695 ovs_cmdl_proctitle_init(argc
, argv
);
696 set_program_name(argv
[0]);
697 service_start(&argc
, &argv
);
698 parse_options(argc
, argv
);
700 if (argc
- optind
!= 1) {
701 ovs_fatal(0, "exactly one non-option argument required "
702 "(use --help for help)");
704 target
= argv
[optind
];
706 sock
= inet_open_passive(SOCK_DGRAM
, target
, 0, NULL
, 0, true);
708 ovs_fatal(0, "%s: failed to open (%s)", target
, ovs_strerror(-sock
));
711 daemon_save_fd(STDOUT_FILENO
);
712 daemonize_start(false);
714 error
= unixctl_server_create(NULL
, &server
);
716 ovs_fatal(error
, "failed to create unixctl server");
718 unixctl_command_register("exit", "", 0, 0, test_sflow_exit
, &exiting
);
720 daemonize_complete();
722 ofpbuf_init(&buf
, MAX_RECV
);
726 unixctl_server_run(server
);
730 retval
= recv(sock
, buf
.data
, buf
.allocated
, 0);
731 } while (retval
< 0 && errno
== EINTR
);
733 ofpbuf_put_uninit(&buf
, retval
);
742 poll_fd_wait(sock
, POLLIN
);
743 unixctl_server_wait(server
);
747 unixctl_server_destroy(server
);
751 parse_options(int argc
, char *argv
[])
757 static const struct option long_options
[] = {
758 {"verbose", optional_argument
, NULL
, 'v'},
759 {"help", no_argument
, NULL
, 'h'},
764 char *short_options
= ovs_cmdl_long_options_to_short_options(long_options
);
767 int c
= getopt_long(argc
, argv
, short_options
, long_options
, NULL
);
776 DAEMON_OPTION_HANDLERS
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
);
799 printf("\nOther options:\n"
800 " -h, --help display this help message\n");
805 test_sflow_exit(struct unixctl_conn
*conn
,
806 int argc OVS_UNUSED
, const char *argv
[] OVS_UNUSED
,
809 bool *exiting
= exiting_
;
811 unixctl_command_reply(conn
, NULL
);
814 OVSTEST_REGISTER("test-sflow", test_sflow_main
);