LCOV - code coverage report
Current view: top level - tests - test-sflow.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 329 369 89.2 %
Date: 2016-09-14 01:02:56 Functions: 23 24 95.8 %
Branches: 79 123 64.2 %

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

Generated by: LCOV version 1.12