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"
31 #include "openvswitch/ofpbuf.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_ETHCOUNTERS 2
58 #define SFLOW_TAG_CTR_LACPCOUNTERS 7
59 #define SFLOW_TAG_CTR_OPENFLOWPORT 1004
60 #define SFLOW_TAG_CTR_PORTNAME 1005
61 #define SFLOW_TAG_PKT_HEADER 1
62 #define SFLOW_TAG_PKT_SWITCH 1001
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
67 #define SFLOW_TAG_PKT_MPLS 1006
70 #define SFL_MAX_PORTNAME_LEN 255
74 SFLOW_ADDRTYPE_undefined
= 0,
96 struct sflow_addr agentAddr
;
97 char agentIPStr
[INET6_ADDRSTRLEN
+ 2];
105 /* Sequence numbers. */
110 /* Structure offsets. */
114 uint32_t TUNNEL4_OUT
;
116 uint32_t TUNNEL_VNI_OUT
;
117 uint32_t TUNNEL_VNI_IN
;
120 uint32_t ETHCOUNTERS
;
121 uint32_t LACPCOUNTERS
;
122 uint32_t OPENFLOWPORT
;
126 /* Flow sample fields. */
127 uint32_t meanSkipCount
;
130 uint32_t inputPortFormat
;
132 uint32_t outputPortFormat
;
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)
141 sflowxdr_init(struct sflow_xdr
*x
, void *buf
, size_t len
)
148 sflowxdr_next(struct sflow_xdr
*x
)
150 return ntohl(x
->datap
[x
->i
++]);
154 sflowxdr_next_n(struct sflow_xdr
*x
)
156 return x
->datap
[x
->i
++];
160 sflowxdr_more(const struct sflow_xdr
*x
, uint32_t q
)
162 return q
+ x
->i
<= x
->quads
;
166 sflowxdr_skip(struct sflow_xdr
*x
, uint32_t q
)
172 sflowxdr_mark(const struct sflow_xdr
*x
, uint32_t q
)
178 sflowxdr_mark_ok(const struct sflow_xdr
*x
, uint32_t m
)
184 sflowxdr_mark_unique(struct sflow_xdr
*x
, uint32_t *pi
)
193 sflowxdr_setc(struct sflow_xdr
*x
, uint32_t j
)
199 sflowxdr_str(const struct sflow_xdr
*x
)
201 return (const char *) (x
->datap
+ x
->i
);
205 sflowxdr_next_int64(struct sflow_xdr
*x
)
208 scratch
= sflowxdr_next(x
);
210 scratch
+= sflowxdr_next(x
);
215 process_counter_sample(struct sflow_xdr
*x
)
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
));
245 if (x
->offset
.LACPCOUNTERS
) {
246 struct eth_addr
*mac
;
252 uint8_t partnerAdmin
;
257 sflowxdr_setc(x
, x
->offset
.LACPCOUNTERS
);
258 printf("LACPCOUNTERS");
259 mac
= (void *)sflowxdr_str(x
);
260 printf(" sysID="ETH_ADDR_FMT
, ETH_ADDR_ARGS(*mac
));
262 mac
= (void *)sflowxdr_str(x
);
263 printf(" partnerID="ETH_ADDR_FMT
, ETH_ADDR_ARGS(*mac
));
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
);
271 printf(" LACPDUsRx=%"PRIu32
, sflowxdr_next(x
));
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
));
276 printf(" LACPDUsTx=%"PRIu32
, sflowxdr_next(x
));
277 printf(" markerPDUsTx=%"PRIu32
, sflowxdr_next(x
));
278 printf(" markerRespPDUsTx=%"PRIu32
, sflowxdr_next(x
));
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
));
288 if (x
->offset
.PORTNAME
) {
291 char portName
[SFL_MAX_PORTNAME_LEN
+ 1];
292 sflowxdr_setc(x
, x
->offset
.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
);
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
,
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
));
324 bin_to_hex(int hexit
)
326 return "0123456789ABCDEF"[hexit
];
330 print_hex(const char *a
, int len
, char *buf
, int bufLen
)
332 unsigned char nextByte
;
336 for (i
= 0; i
< len
; i
++) {
337 if (b
> bufLen
- 10) {
341 buf
[b
++] = bin_to_hex(nextByte
>> 4);
342 buf
[b
++] = bin_to_hex(nextByte
& 0x0f);
352 print_struct_ipv4(struct sflow_xdr
*x
, const char *prefix
)
356 printf(" %s_length=%"PRIu32
, prefix
, sflowxdr_next(x
));
357 printf(" %s_protocol=%"PRIu32
, prefix
, sflowxdr_next(x
));
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
));
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
));
370 #define SFLOW_HEX_SCRATCH 1024
373 process_flow_sample(struct sflow_xdr
*x
)
375 if (x
->offset
.HEADER
) {
377 char scratch
[SFLOW_HEX_SCRATCH
];
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
);
385 if (x
->offset
.TUNNEL4_IN
) {
386 sflowxdr_setc(x
, x
->offset
.TUNNEL4_IN
);
387 print_struct_ipv4(x
, "tunnel4_in");
390 if (x
->offset
.TUNNEL4_OUT
) {
391 sflowxdr_setc(x
, x
->offset
.TUNNEL4_OUT
);
392 print_struct_ipv4(x
, "tunnel4_out");
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
));
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
));
405 if (x
->offset
.MPLS
) {
406 uint32_t addr_type
, stack_depth
, ii
;
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);
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
));
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
));
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
);
459 process_datagram(struct sflow_xdr
*x
)
463 SFLOWXDR_assert(x
, (sflowxdr_next(x
) == SFLOW_VERSION_5
));
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
);
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
);
479 case SFLOW_ADDRTYPE_undefined
:
484 x
->subAgentId
= sflowxdr_next(x
);
485 x
->dgramSeqNo
= sflowxdr_next(x
);
486 x
->uptime_mS
= sflowxdr_next(x
);
488 /* Store the agent address as a string. */
489 if (x
->agentAddr
.type
== SFLOW_ADDRTYPE_IP6
) {
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
);
495 snprintf(x
->agentIPStr
, sizeof x
->agentIPStr
,
496 IP_FMT
, IP_ARGS(x
->agentAddr
.a
.ip4
));
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
));
508 case SFLOW_COUNTERS_SAMPLE_EXPANDED
:
509 case SFLOW_COUNTERS_SAMPLE
:
511 uint32_t csElements
, e
;
512 uint32_t ceTag
, ceQuads
, ceMark
, csEnd
;
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
);
519 uint32_t dsCombined
= sflowxdr_next(x
);
520 x
->dsClass
= dsCombined
>> 24;
521 x
->dsIndex
= dsCombined
& 0x00FFFFFF;
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. */
534 case SFLOW_TAG_CTR_IFCOUNTERS
:
535 sflowxdr_mark_unique(x
, &x
->offset
.IFCOUNTERS
);
537 case SFLOW_TAG_CTR_ETHCOUNTERS
:
538 sflowxdr_mark_unique(x
, &x
->offset
.ETHCOUNTERS
);
540 case SFLOW_TAG_CTR_LACPCOUNTERS
:
541 sflowxdr_mark_unique(x
, &x
->offset
.LACPCOUNTERS
);
543 case SFLOW_TAG_CTR_PORTNAME
:
544 sflowxdr_mark_unique(x
, &x
->offset
.PORTNAME
);
546 case SFLOW_TAG_CTR_OPENFLOWPORT
:
547 sflowxdr_mark_unique(x
, &x
->offset
.OPENFLOWPORT
);
550 /* Add others here... */
553 sflowxdr_skip(x
, ceQuads
);
554 SFLOWXDR_assert(x
, sflowxdr_mark_ok(x
, ceMark
));
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
);
562 /* Clear the offsets for the next sample. */
563 memset(&x
->offset
, 0, sizeof x
->offset
);
567 case SFLOW_FLOW_SAMPLE
:
568 case SFLOW_FLOW_SAMPLE_EXPANDED
:
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
);
577 uint32_t dsCombined
= sflowxdr_next(x
);
578 x
->dsClass
= dsCombined
>> 24;
579 x
->dsIndex
= dsCombined
& 0x00FFFFFF;
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
);
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;
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. */
609 case SFLOW_TAG_PKT_HEADER
:
610 sflowxdr_mark_unique(x
, &x
->offset
.HEADER
);
613 case SFLOW_TAG_PKT_SWITCH
:
614 sflowxdr_mark_unique(x
, &x
->offset
.SWITCH
);
617 case SFLOW_TAG_PKT_TUNNEL4_OUT
:
618 sflowxdr_mark_unique(x
, &x
->offset
.TUNNEL4_OUT
);
621 case SFLOW_TAG_PKT_TUNNEL4_IN
:
622 sflowxdr_mark_unique(x
, &x
->offset
.TUNNEL4_IN
);
625 case SFLOW_TAG_PKT_TUNNEL_VNI_OUT
:
626 sflowxdr_mark_unique(x
, &x
->offset
.TUNNEL_VNI_OUT
);
629 case SFLOW_TAG_PKT_TUNNEL_VNI_IN
:
630 sflowxdr_mark_unique(x
, &x
->offset
.TUNNEL_VNI_IN
);
633 case SFLOW_TAG_PKT_MPLS
:
634 sflowxdr_mark_unique(x
, &x
->offset
.MPLS
);
637 /* Add others here... */
640 sflowxdr_skip(x
, feQuads
);
641 SFLOWXDR_assert(x
, sflowxdr_mark_ok(x
, feMark
));
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
);
649 /* Clear the offsets for the next counter/flow sample. */
650 memset(&x
->offset
, 0, sizeof x
->offset
);
655 /* Skip other sample types. */
656 sflowxdr_skip(x
, sQuads
);
658 SFLOWXDR_assert(x
, sflowxdr_mark_ok(x
, sMark
));
663 print_sflow(struct ofpbuf
*buf
)
666 int dgram_len
= buf
->size
;
667 struct sflow_xdr xdrDatagram
;
668 struct sflow_xdr
*x
= &xdrDatagram
;
670 memset(x
, 0, sizeof *x
);
671 if (SFLOWXDR_try(x
)) {
672 SFLOWXDR_assert(x
, (dgram_buf
= ofpbuf_try_pull(buf
, buf
->size
)));
673 sflowxdr_init(x
, dgram_buf
, dgram_len
);
674 SFLOWXDR_assert(x
, dgram_len
>= SFLOW_MIN_LEN
);
678 printf("\n>>>>> ERROR in " __FILE__
" at line %d\n", x
->errline
);
683 test_sflow_main(int argc
, char *argv
[])
685 struct unixctl_server
*server
;
686 enum { MAX_RECV
= 1500 };
689 bool exiting
= false;
693 ovs_cmdl_proctitle_init(argc
, argv
);
694 set_program_name(argv
[0]);
695 service_start(&argc
, &argv
);
696 parse_options(argc
, argv
);
698 if (argc
- optind
!= 1) {
699 ovs_fatal(0, "exactly one non-option argument required "
700 "(use --help for help)");
702 target
= argv
[optind
];
704 sock
= inet_open_passive(SOCK_DGRAM
, target
, 0, NULL
, 0, true);
706 ovs_fatal(0, "%s: failed to open (%s)", target
, ovs_strerror(-sock
));
709 daemon_save_fd(STDOUT_FILENO
);
710 daemonize_start(false);
712 error
= unixctl_server_create(NULL
, &server
);
714 ovs_fatal(error
, "failed to create unixctl server");
716 unixctl_command_register("exit", "", 0, 0, test_sflow_exit
, &exiting
);
718 daemonize_complete();
720 ofpbuf_init(&buf
, MAX_RECV
);
724 unixctl_server_run(server
);
728 retval
= recv(sock
, buf
.data
, buf
.allocated
, 0);
729 } while (retval
< 0 && errno
== EINTR
);
731 ofpbuf_put_uninit(&buf
, retval
);
740 poll_fd_wait(sock
, POLLIN
);
741 unixctl_server_wait(server
);
745 unixctl_server_destroy(server
);
749 parse_options(int argc
, char *argv
[])
755 static const struct option long_options
[] = {
756 {"verbose", optional_argument
, NULL
, 'v'},
757 {"help", no_argument
, NULL
, 'h'},
762 char *short_options
= ovs_cmdl_long_options_to_short_options(long_options
);
765 int c
= getopt_long(argc
, argv
, short_options
, long_options
, NULL
);
774 DAEMON_OPTION_HANDLERS
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
);
797 printf("\nOther options:\n"
798 " -h, --help display this help message\n");
803 test_sflow_exit(struct unixctl_conn
*conn
,
804 int argc OVS_UNUSED
, const char *argv
[] OVS_UNUSED
,
807 bool *exiting
= exiting_
;
809 unixctl_command_reply(conn
, NULL
);
812 OVSTEST_REGISTER("test-sflow", test_sflow_main
);