LCOV - code coverage report
Current view: top level - tests - test-netflow.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 94 137 68.6 %
Date: 2016-09-14 01:02:56 Functions: 6 7 85.7 %
Branches: 45 85 52.9 %

           Branch data     Line data    Source code
       1                 :            : /*
       2                 :            :  * Copyright (c) 2011, 2012, 2013, 2014, 2015 Nicira, Inc.
       3                 :            :  *
       4                 :            :  * Licensed under the Apache License, Version 2.0 (the "License");
       5                 :            :  * you may not use this file except in compliance with the License.
       6                 :            :  * You may obtain a copy of the License at:
       7                 :            :  *
       8                 :            :  *     http://www.apache.org/licenses/LICENSE-2.0
       9                 :            :  *
      10                 :            :  * Unless required by applicable law or agreed to in writing, software
      11                 :            :  * distributed under the License is distributed on an "AS IS" BASIS,
      12                 :            :  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      13                 :            :  * See the License for the specific language governing permissions and
      14                 :            :  * limitations under the License.
      15                 :            :  */
      16                 :            : 
      17                 :            : #include <config.h>
      18                 :            : #undef NDEBUG
      19                 :            : #include "netflow.h"
      20                 :            : #include <errno.h>
      21                 :            : #include <getopt.h>
      22                 :            : #include <signal.h>
      23                 :            : #include <stdlib.h>
      24                 :            : #include <unistd.h>
      25                 :            : #include "command-line.h"
      26                 :            : #include "daemon.h"
      27                 :            : #include "openvswitch/dynamic-string.h"
      28                 :            : #include "openvswitch/ofpbuf.h"
      29                 :            : #include "ovstest.h"
      30                 :            : #include "packets.h"
      31                 :            : #include "poll-loop.h"
      32                 :            : #include "socket-util.h"
      33                 :            : #include "unixctl.h"
      34                 :            : #include "util.h"
      35                 :            : #include "openvswitch/vlog.h"
      36                 :            : 
      37                 :            : OVS_NO_RETURN static void usage(void);
      38                 :            : static void parse_options(int argc, char *argv[]);
      39                 :            : 
      40                 :            : static unixctl_cb_func test_netflow_exit;
      41                 :            : 
      42                 :            : static void
      43                 :         18 : print_netflow(struct ofpbuf *buf)
      44                 :            : {
      45                 :            :     const struct netflow_v5_header *hdr;
      46                 :            :     int i;
      47                 :            : 
      48                 :         18 :     hdr = ofpbuf_try_pull(buf, sizeof *hdr);
      49         [ -  + ]:         18 :     if (!hdr) {
      50                 :          0 :         printf("truncated NetFlow packet header\n");
      51                 :          0 :         return;
      52                 :            :     }
      53                 :         36 :     printf("header: v%"PRIu16", "
      54                 :            :            "uptime %"PRIu32", "
      55                 :            :            "now %"PRIu32".%09"PRIu32", "
      56                 :            :            "seq %"PRIu32", "
      57                 :            :            "engine %"PRIu8",%"PRIu8,
      58                 :         18 :            ntohs(hdr->version),
      59                 :            :            ntohl(hdr->sysuptime),
      60                 :            :            ntohl(hdr->unix_secs), ntohl(hdr->unix_nsecs),
      61                 :            :            ntohl(hdr->flow_seq),
      62                 :         36 :            hdr->engine_type, hdr->engine_id);
      63         [ -  + ]:         18 :     if (hdr->sampling_interval != htons(0)) {
      64                 :          0 :         printf(", interval %"PRIu16, ntohs(hdr->sampling_interval));
      65                 :            :     }
      66                 :         18 :     putchar('\n');
      67                 :            : 
      68         [ +  + ]:         48 :     for (i = 0; i < ntohs(hdr->count); i++) {
      69                 :            :         struct netflow_v5_record *rec;
      70                 :            : 
      71                 :         30 :         rec = ofpbuf_try_pull(buf, sizeof *rec);
      72         [ -  + ]:         30 :         if (!rec) {
      73                 :          0 :             printf("truncated NetFlow records\n");
      74                 :          0 :             return;
      75                 :            :         }
      76                 :            : 
      77                 :         30 :         printf("seq %"PRIu32": "IP_FMT" > "IP_FMT, ntohl(hdr->flow_seq),
      78                 :         30 :                IP_ARGS(rec->src_addr), IP_ARGS(rec->dst_addr));
      79                 :            : 
      80                 :         30 :         printf(", if %"PRIu16" > %"PRIu16,
      81                 :         30 :                ntohs(rec->input), ntohs(rec->output));
      82                 :            : 
      83                 :         30 :         printf(", %"PRIu32" pkts, %"PRIu32" bytes",
      84                 :            :                ntohl(rec->packet_count), ntohl(rec->byte_count));
      85                 :            : 
      86   [ +  -  -  +  :         30 :         switch (rec->ip_proto) {
                      - ]
      87                 :            :         case IPPROTO_TCP:
      88                 :         24 :             printf(", TCP %"PRIu16" > %"PRIu16,
      89                 :         24 :                    ntohs(rec->src_port), ntohs(rec->dst_port));
      90         [ -  + ]:         24 :             if (rec->tcp_flags) {
      91                 :          0 :                 struct ds s = DS_EMPTY_INITIALIZER;
      92                 :          0 :                 packet_format_tcp_flags(&s, rec->tcp_flags);
      93                 :          0 :                 printf(" %s", ds_cstr(&s));
      94                 :          0 :                 ds_destroy(&s);
      95                 :            :             }
      96                 :         24 :             break;
      97                 :            : 
      98                 :            :         case IPPROTO_UDP:
      99                 :          0 :             printf(", UDP %"PRIu16" > %"PRIu16,
     100                 :          0 :                    ntohs(rec->src_port), ntohs(rec->dst_port));
     101                 :          0 :             break;
     102                 :            : 
     103                 :            :         case IPPROTO_SCTP:
     104                 :          0 :             printf(", SCTP %"PRIu16" > %"PRIu16,
     105                 :          0 :                    ntohs(rec->src_port), ntohs(rec->dst_port));
     106                 :          0 :             break;
     107                 :            : 
     108                 :            :         case IPPROTO_ICMP:
     109                 :          6 :             printf(", ICMP %"PRIu16":%"PRIu16,
     110                 :          6 :                    ntohs(rec->dst_port) >> 8,
     111                 :          6 :                    ntohs(rec->dst_port) & 0xff);
     112         [ -  + ]:          6 :             if (rec->src_port != htons(0)) {
     113                 :          0 :                 printf(", src_port=%"PRIu16, ntohs(rec->src_port));
     114                 :            :             }
     115                 :          6 :             break;
     116                 :            : 
     117                 :            :         default:
     118                 :          0 :             printf(", proto %"PRIu8, rec->ip_proto);
     119                 :          0 :             break;
     120                 :            :         }
     121                 :            : 
     122 [ +  + ][ -  + ]:         30 :         if (rec->ip_proto != IPPROTO_TCP && rec->tcp_flags != 0) {
     123                 :          0 :             printf(", flags %"PRIx8, rec->tcp_flags);
     124                 :            :         }
     125                 :            : 
     126 [ +  + ][ +  - ]:         30 :         if (rec->ip_proto != IPPROTO_TCP &&
     127         [ +  - ]:          6 :             rec->ip_proto != IPPROTO_UDP &&
     128         [ -  + ]:          6 :             rec->ip_proto != IPPROTO_SCTP &&
     129                 :          6 :             rec->ip_proto != IPPROTO_ICMP) {
     130         [ #  # ]:          0 :             if (rec->src_port != htons(0)) {
     131                 :          0 :                 printf(", src_port %"PRIu16, ntohs(rec->src_port));
     132                 :            :             }
     133         [ #  # ]:          0 :             if (rec->dst_port != htons(0)) {
     134                 :          0 :                 printf(", dst_port %"PRIu16, ntohs(rec->dst_port));
     135                 :            :             }
     136                 :            :         }
     137                 :            : 
     138         [ -  + ]:         30 :         if (rec->ip_tos) {
     139                 :          0 :             printf(", TOS %"PRIx8, rec->ip_tos);
     140                 :            :         }
     141                 :            : 
     142                 :         30 :         printf(", time %"PRIu32"...%"PRIu32,
     143                 :            :                ntohl(rec->init_time), ntohl(rec->used_time));
     144                 :            : 
     145         [ -  + ]:         30 :         if (rec->nexthop != htonl(0)) {
     146                 :          0 :             printf(", nexthop "IP_FMT, IP_ARGS(rec->nexthop));
     147                 :            :         }
     148 [ +  - ][ -  + ]:         30 :         if (rec->src_as != htons(0) || rec->dst_as != htons(0)) {
     149                 :          0 :             printf(", AS %"PRIu16" > %"PRIu16,
     150                 :          0 :                    ntohs(rec->src_as), ntohs(rec->dst_as));
     151                 :            :         }
     152 [ +  - ][ -  + ]:         30 :         if (rec->src_mask != 0 || rec->dst_mask != 0) {
     153                 :          0 :             printf(", mask %"PRIu8" > %"PRIu8, rec->src_mask, rec->dst_mask);
     154                 :            :         }
     155         [ -  + ]:         30 :         if (rec->pad1) {
     156                 :          0 :             printf(", pad1 %"PRIu8, rec->pad1);
     157                 :            :         }
     158 [ +  - ][ -  + ]:         30 :         if (rec->pad[0] || rec->pad[1]) {
     159                 :          0 :             printf(", pad %"PRIu8", %"PRIu8, rec->pad[0], rec->pad[1]);
     160                 :            :         }
     161                 :         30 :         putchar('\n');
     162                 :            :     }
     163                 :            : 
     164         [ -  + ]:         18 :     if (buf->size) {
     165                 :          0 :         printf("%"PRIu32" extra bytes after last record\n", buf->size);
     166                 :            :     }
     167                 :            : }
     168                 :            : 
     169                 :            : static void
     170                 :          6 : test_netflow_main(int argc, char *argv[])
     171                 :            : {
     172                 :            :     struct unixctl_server *server;
     173                 :            :     enum { MAX_RECV = 1500 };
     174                 :            :     const char *target;
     175                 :            :     struct ofpbuf buf;
     176                 :          6 :     bool exiting = false;
     177                 :            :     int error;
     178                 :            :     int sock;
     179                 :            :     int n;
     180                 :            : 
     181                 :          6 :     ovs_cmdl_proctitle_init(argc, argv);
     182                 :          6 :     set_program_name(argv[0]);
     183                 :          6 :     service_start(&argc, &argv);
     184                 :          6 :     parse_options(argc, argv);
     185                 :            : 
     186         [ -  + ]:          6 :     if (argc - optind != 1) {
     187                 :          0 :         ovs_fatal(0, "exactly one non-option argument required "
     188                 :            :                   "(use --help for help)");
     189                 :            :     }
     190                 :          6 :     target = argv[optind];
     191                 :            : 
     192                 :          6 :     sock = inet_open_passive(SOCK_DGRAM, target, 0, NULL, 0, true);
     193         [ -  + ]:          6 :     if (sock < 0) {
     194                 :          0 :         ovs_fatal(0, "%s: failed to open (%s)", argv[1], ovs_strerror(-sock));
     195                 :            :     }
     196                 :            : 
     197                 :          6 :     daemon_save_fd(STDOUT_FILENO);
     198                 :          6 :     daemonize_start(false);
     199                 :            : 
     200                 :          6 :     error = unixctl_server_create(NULL, &server);
     201         [ -  + ]:          6 :     if (error) {
     202                 :          0 :         ovs_fatal(error, "failed to create unixctl server");
     203                 :            :     }
     204                 :          6 :     unixctl_command_register("exit", "", 0, 0, test_netflow_exit, &exiting);
     205                 :            : 
     206                 :          6 :     daemonize_complete();
     207                 :            : 
     208                 :          6 :     ofpbuf_init(&buf, MAX_RECV);
     209                 :          6 :     n = 0;
     210                 :            :     for (;;) {
     211                 :            :         int retval;
     212                 :            : 
     213                 :         41 :         unixctl_server_run(server);
     214                 :            : 
     215                 :         41 :         ofpbuf_clear(&buf);
     216                 :            :         do {
     217                 :         41 :             retval = recv(sock, buf.data, buf.allocated, 0);
     218 [ +  + ][ -  + ]:         41 :         } while (retval < 0 && errno == EINTR);
     219         [ +  + ]:         41 :         if (retval > 0) {
     220                 :         18 :             ofpbuf_put_uninit(&buf, retval);
     221         [ +  + ]:         18 :             if (n++ > 0) {
     222                 :         14 :                 putchar('\n');
     223                 :            :             }
     224                 :         18 :             print_netflow(&buf);
     225                 :         18 :             fflush(stdout);
     226                 :            :         }
     227                 :            : 
     228         [ +  + ]:         41 :         if (exiting) {
     229                 :          6 :             break;
     230                 :            :         }
     231                 :            : 
     232                 :         35 :         poll_fd_wait(sock, POLLIN);
     233                 :         35 :         unixctl_server_wait(server);
     234                 :         35 :         poll_block();
     235                 :         35 :     }
     236                 :            : 
     237                 :          6 :     ofpbuf_uninit(&buf);
     238                 :          6 :     unixctl_server_destroy(server);
     239                 :          6 : }
     240                 :            : 
     241                 :            : static void
     242                 :          6 : parse_options(int argc, char *argv[])
     243                 :            : {
     244                 :            :     enum {
     245                 :            :         DAEMON_OPTION_ENUMS,
     246                 :            :         VLOG_OPTION_ENUMS
     247                 :            :     };
     248                 :            :     static const struct option long_options[] = {
     249                 :            :         {"help", no_argument, NULL, 'h'},
     250                 :            :         DAEMON_LONG_OPTIONS,
     251                 :            :         VLOG_LONG_OPTIONS,
     252                 :            :         {NULL, 0, NULL, 0},
     253                 :            :     };
     254                 :          6 :     char *short_options = ovs_cmdl_long_options_to_short_options(long_options);
     255                 :            : 
     256                 :            :     for (;;) {
     257                 :         30 :         int c = getopt_long(argc, argv, short_options, long_options, NULL);
     258         [ +  + ]:         30 :         if (c == -1) {
     259                 :          6 :             break;
     260                 :            :         }
     261                 :            : 
     262   [ -  +  -  +  :         24 :         switch (c) {
          +  -  -  -  -  
             +  -  -  -  
                      - ]
     263                 :            :         case 'h':
     264                 :          0 :             usage();
     265                 :            : 
     266                 :         18 :         DAEMON_OPTION_HANDLERS
     267                 :          6 :         VLOG_OPTION_HANDLERS
     268                 :            : 
     269                 :            :         case '?':
     270                 :          0 :             exit(EXIT_FAILURE);
     271                 :            : 
     272                 :            :         default:
     273                 :          0 :             abort();
     274                 :            :         }
     275                 :         24 :     }
     276                 :          6 :     free(short_options);
     277                 :          6 : }
     278                 :            : 
     279                 :            : static void
     280                 :          0 : usage(void)
     281                 :            : {
     282                 :          0 :     printf("%s: netflow collector test utility\n"
     283                 :            :            "usage: %s [OPTIONS] PORT[:IP]\n"
     284                 :            :            "where PORT is the UDP port to listen on and IP is optionally\n"
     285                 :            :            "the IP address to listen on.\n",
     286                 :            :            program_name, program_name);
     287                 :          0 :     daemon_usage();
     288                 :          0 :     vlog_usage();
     289                 :          0 :     printf("\nOther options:\n"
     290                 :            :            "  -h, --help                  display this help message\n");
     291                 :          0 :     exit(EXIT_SUCCESS);
     292                 :            : }
     293                 :            : 
     294                 :            : static void
     295                 :          6 : test_netflow_exit(struct unixctl_conn *conn,
     296                 :            :                   int argc OVS_UNUSED, const char *argv[] OVS_UNUSED,
     297                 :            :                   void *exiting_)
     298                 :            : {
     299                 :          6 :     bool *exiting = exiting_;
     300                 :          6 :     *exiting = true;
     301                 :          6 :     unixctl_command_reply(conn, NULL);
     302                 :          6 : }
     303                 :            : 
     304                 :       1186 : OVSTEST_REGISTER("test-netflow", test_netflow_main);

Generated by: LCOV version 1.12