LCOV - code coverage report
Current view: top level - tests - test-conntrack.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 1 113 0.9 %
Date: 2016-09-14 01:02:56 Functions: 1 9 11.1 %
Branches: 0 46 0.0 %

           Branch data     Line data    Source code
       1                 :            : /*
       2                 :            :  * Copyright (c) 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                 :            : #include "conntrack.h"
      19                 :            : 
      20                 :            : #include "dp-packet.h"
      21                 :            : #include "fatal-signal.h"
      22                 :            : #include "flow.h"
      23                 :            : #include "netdev.h"
      24                 :            : #include "ovs-thread.h"
      25                 :            : #include "ovstest.h"
      26                 :            : #include "pcap-file.h"
      27                 :            : #include "timeval.h"
      28                 :            : 
      29                 :            : static const char payload[] = "50540000000a50540000000908004500001c0000000000"
      30                 :            :                               "11a4cd0a0101010a0101020001000200080000";
      31                 :            : 
      32                 :            : static struct dp_packet_batch *
      33                 :          0 : prepare_packets(size_t n, bool change, unsigned tid, ovs_be16 *dl_type)
      34                 :            : {
      35                 :          0 :     struct dp_packet_batch *pkt_batch = xzalloc(sizeof *pkt_batch);
      36                 :            :     struct flow flow;
      37                 :            :     size_t i;
      38                 :            : 
      39         [ #  # ]:          0 :     ovs_assert(n <= ARRAY_SIZE(pkt_batch->packets));
      40                 :            : 
      41                 :          0 :     dp_packet_batch_init(pkt_batch);
      42                 :          0 :     pkt_batch->count = n;
      43                 :            : 
      44         [ #  # ]:          0 :     for (i = 0; i < n; i++) {
      45                 :            :         struct udp_header *udp;
      46                 :          0 :         struct dp_packet *pkt = dp_packet_new(sizeof payload/2);
      47                 :            : 
      48                 :          0 :         dp_packet_put_hex(pkt, payload, NULL);
      49                 :          0 :         flow_extract(pkt, &flow);
      50                 :            : 
      51                 :          0 :         udp = dp_packet_l4(pkt);
      52                 :          0 :         udp->udp_src = htons(ntohs(udp->udp_src) + tid);
      53                 :            : 
      54         [ #  # ]:          0 :         if (change) {
      55                 :          0 :             udp->udp_dst = htons(ntohs(udp->udp_dst) + i);
      56                 :            :         }
      57                 :            : 
      58                 :          0 :         pkt_batch->packets[i] = pkt;
      59                 :          0 :         *dl_type = flow.dl_type;
      60                 :            :     }
      61                 :            : 
      62                 :            : 
      63                 :          0 :     return pkt_batch;
      64                 :            : }
      65                 :            : 
      66                 :            : static void
      67                 :          0 : destroy_packets(struct dp_packet_batch *pkt_batch)
      68                 :            : {
      69                 :          0 :     dp_packet_delete_batch(pkt_batch, true);
      70                 :          0 :     free(pkt_batch);
      71                 :          0 : }
      72                 :            : 
      73                 :            : struct thread_aux {
      74                 :            :     pthread_t thread;
      75                 :            :     unsigned tid;
      76                 :            : };
      77                 :            : 
      78                 :            : static struct conntrack ct;
      79                 :            : static unsigned long n_threads, n_pkts, batch_size;
      80                 :            : static bool change_conn = false;
      81                 :            : static struct ovs_barrier barrier;
      82                 :            : 
      83                 :            : static void *
      84                 :          0 : ct_thread_main(void *aux_)
      85                 :            : {
      86                 :          0 :     struct thread_aux *aux = aux_;
      87                 :            :     struct dp_packet_batch *pkt_batch;
      88                 :            :     ovs_be16 dl_type;
      89                 :            :     size_t i;
      90                 :            : 
      91                 :          0 :     pkt_batch = prepare_packets(batch_size, change_conn, aux->tid, &dl_type);
      92                 :          0 :     ovs_barrier_block(&barrier);
      93         [ #  # ]:          0 :     for (i = 0; i < n_pkts; i += batch_size) {
      94                 :          0 :         conntrack_execute(&ct, pkt_batch, dl_type, true, 0, NULL, NULL, NULL);
      95                 :            :     }
      96                 :          0 :     ovs_barrier_block(&barrier);
      97                 :          0 :     destroy_packets(pkt_batch);
      98                 :            : 
      99                 :          0 :     return NULL;
     100                 :            : }
     101                 :            : 
     102                 :            : static void
     103                 :          0 : test_benchmark(struct ovs_cmdl_context *ctx)
     104                 :            : {
     105                 :            :     struct thread_aux *threads;
     106                 :            :     long long start;
     107                 :            :     unsigned i;
     108                 :            : 
     109                 :          0 :     fatal_signal_init();
     110                 :            : 
     111                 :            :     /* Parse arguments */
     112                 :          0 :     n_threads = strtoul(ctx->argv[1], NULL, 0);
     113         [ #  # ]:          0 :     if (!n_threads) {
     114                 :          0 :         ovs_fatal(0, "n_threads must be at least one");
     115                 :            :     }
     116                 :          0 :     n_pkts = strtoul(ctx->argv[2], NULL, 0);
     117                 :          0 :     batch_size = strtoul(ctx->argv[3], NULL, 0);
     118 [ #  # ][ #  # ]:          0 :     if (batch_size == 0 || batch_size > NETDEV_MAX_BURST) {
     119                 :          0 :         ovs_fatal(0, "batch_size must be between 1 and NETDEV_MAX_BURST(%u)",
     120                 :            :                   NETDEV_MAX_BURST);
     121                 :            :     }
     122         [ #  # ]:          0 :     if (ctx->argc > 4) {
     123                 :          0 :         change_conn = strtoul(ctx->argv[4], NULL, 0);
     124                 :            :     }
     125                 :            : 
     126                 :          0 :     threads = xcalloc(n_threads, sizeof *threads);
     127                 :          0 :     ovs_barrier_init(&barrier, n_threads + 1);
     128                 :          0 :     conntrack_init(&ct);
     129                 :            : 
     130                 :            :     /* Create threads */
     131         [ #  # ]:          0 :     for (i = 0; i < n_threads; i++) {
     132                 :          0 :         threads[i].tid = i;
     133                 :          0 :         threads[i].thread = ovs_thread_create("ct_thread", ct_thread_main,
     134                 :          0 :                                               &threads[i]);
     135                 :            :     }
     136                 :            :     /* Starts the work inside the threads */
     137                 :          0 :     ovs_barrier_block(&barrier);
     138                 :          0 :     start = time_msec();
     139                 :            : 
     140                 :            :     /* Wait for the threads to finish the work */
     141                 :          0 :     ovs_barrier_block(&barrier);
     142                 :          0 :     printf("conntrack:  %5lld ms\n", time_msec() - start);
     143                 :            : 
     144         [ #  # ]:          0 :     for (i = 0; i < n_threads; i++) {
     145                 :          0 :         xpthread_join(threads[i].thread, NULL);
     146                 :            :     }
     147                 :            : 
     148                 :          0 :     conntrack_destroy(&ct);
     149                 :          0 :     ovs_barrier_destroy(&barrier);
     150                 :          0 :     free(threads);
     151                 :          0 : }
     152                 :            : 
     153                 :            : static void
     154                 :          0 : pcap_batch_execute_conntrack(struct conntrack *ct,
     155                 :            :                              struct dp_packet_batch *pkt_batch)
     156                 :            : {
     157                 :            :     size_t i;
     158                 :            :     struct dp_packet_batch new_batch;
     159                 :          0 :     ovs_be16 dl_type = htons(0);
     160                 :            : 
     161                 :          0 :     dp_packet_batch_init(&new_batch);
     162                 :            : 
     163                 :            :     /* pkt_batch contains packets with different 'dl_type'. We have to
     164                 :            :      * call conntrack_execute() on packets with the same 'dl_type'. */
     165                 :            : 
     166         [ #  # ]:          0 :     for (i = 0; i < pkt_batch->count; i++) {
     167                 :          0 :         struct dp_packet *pkt = pkt_batch->packets[i];
     168                 :            :         struct flow flow;
     169                 :            : 
     170                 :            :         /* This also initializes the l3 and l4 pointers. */
     171                 :          0 :         flow_extract(pkt, &flow);
     172                 :            : 
     173         [ #  # ]:          0 :         if (!new_batch.count) {
     174                 :          0 :             dl_type = flow.dl_type;
     175                 :            :         }
     176                 :            : 
     177         [ #  # ]:          0 :         if (flow.dl_type != dl_type) {
     178                 :          0 :             conntrack_execute(ct, &new_batch, dl_type, true, 0, NULL, NULL,
     179                 :            :                               NULL);
     180                 :          0 :             dp_packet_batch_init(&new_batch);
     181                 :            :         }
     182                 :          0 :         new_batch.packets[new_batch.count++] = pkt;
     183                 :            :     }
     184                 :            : 
     185         [ #  # ]:          0 :     if (new_batch.count) {
     186                 :          0 :         conntrack_execute(ct, &new_batch, dl_type, true, 0, NULL, NULL, NULL);
     187                 :            :     }
     188                 :            : 
     189                 :          0 : }
     190                 :            : 
     191                 :            : static void
     192                 :          0 : test_pcap(struct ovs_cmdl_context *ctx)
     193                 :            : {
     194                 :            :     size_t total_count, i, batch_size;
     195                 :            :     FILE *pcap;
     196                 :            :     int err;
     197                 :            : 
     198                 :          0 :     pcap = ovs_pcap_open(ctx->argv[1], "rb");
     199         [ #  # ]:          0 :     if (!pcap) {
     200                 :          0 :         return;
     201                 :            :     }
     202                 :            : 
     203                 :          0 :     batch_size = 1;
     204         [ #  # ]:          0 :     if (ctx->argc > 2) {
     205                 :          0 :         batch_size = strtoul(ctx->argv[2], NULL, 0);
     206 [ #  # ][ #  # ]:          0 :         if (batch_size == 0 || batch_size > NETDEV_MAX_BURST) {
     207                 :          0 :             ovs_fatal(0,
     208                 :            :                       "batch_size must be between 1 and NETDEV_MAX_BURST(%u)",
     209                 :            :                       NETDEV_MAX_BURST);
     210                 :            :         }
     211                 :            :     }
     212                 :            : 
     213                 :          0 :     fatal_signal_init();
     214                 :            : 
     215                 :          0 :     conntrack_init(&ct);
     216                 :          0 :     total_count = 0;
     217                 :            :     for (;;) {
     218                 :            :         struct dp_packet_batch pkt_batch;
     219                 :            : 
     220                 :          0 :         dp_packet_batch_init(&pkt_batch);
     221                 :            : 
     222         [ #  # ]:          0 :         for (i = 0; i < batch_size; i++) {
     223                 :          0 :             err = ovs_pcap_read(pcap, &pkt_batch.packets[i], NULL);
     224         [ #  # ]:          0 :             if (err) {
     225                 :          0 :                 break;
     226                 :            :             }
     227                 :            :         }
     228                 :            : 
     229                 :          0 :         pkt_batch.count = i;
     230         [ #  # ]:          0 :         if (pkt_batch.count == 0) {
     231                 :          0 :             break;
     232                 :            :         }
     233                 :            : 
     234                 :          0 :         pcap_batch_execute_conntrack(&ct, &pkt_batch);
     235                 :            : 
     236         [ #  # ]:          0 :         for (i = 0; i < pkt_batch.count; i++) {
     237                 :          0 :             struct ds ds = DS_EMPTY_INITIALIZER;
     238                 :          0 :             struct dp_packet *pkt = pkt_batch.packets[i];
     239                 :            : 
     240                 :          0 :             total_count++;
     241                 :            : 
     242                 :          0 :             format_flags(&ds, ct_state_to_string, pkt->md.ct_state, '|');
     243                 :          0 :             printf("%"PRIuSIZE": %s\n", total_count, ds_cstr(&ds));
     244                 :            : 
     245                 :          0 :             ds_destroy(&ds);
     246                 :            :         }
     247                 :            : 
     248                 :          0 :         dp_packet_delete_batch(&pkt_batch, true);
     249         [ #  # ]:          0 :         if (err) {
     250                 :          0 :             break;
     251                 :            :         }
     252                 :          0 :     }
     253                 :          0 :     conntrack_destroy(&ct);
     254                 :            : }
     255                 :            : 
     256                 :            : static const struct ovs_cmdl_command commands[] = {
     257                 :            :     /* Connection tracker tests. */
     258                 :            :     /* Starts 'n_threads' threads. Each thread will send 'n_pkts' packets to
     259                 :            :      * the connection tracker, 'batch_size' per call. If 'change_connection'
     260                 :            :      * is '1', each packet in a batch will have a different source and
     261                 :            :      * destination port */
     262                 :            :     {"benchmark", "n_threads n_pkts batch_size [change_connection]", 3, 4,
     263                 :            :      test_benchmark, OVS_RO},
     264                 :            :     /* Reads packets from 'file' and sends them to the connection tracker,
     265                 :            :      * 'batch_size' (1 by default) per call, with the commit flag set.
     266                 :            :      * Prints the ct_state of each packet. */
     267                 :            :     {"pcap", "file [batch_size]", 1, 2, test_pcap, OVS_RO},
     268                 :            : 
     269                 :            :     {NULL, NULL, 0, 0, NULL, OVS_RO},
     270                 :            : };
     271                 :            : 
     272                 :            : static void
     273                 :          0 : test_conntrack_main(int argc, char *argv[])
     274                 :            : {
     275                 :          0 :     struct ovs_cmdl_context ctx = {
     276                 :          0 :         .argc = argc - 1,
     277                 :          0 :         .argv = argv + 1,
     278                 :            :     };
     279                 :          0 :     set_program_name(argv[0]);
     280                 :          0 :     ovs_cmdl_run_command(&ctx, commands);
     281                 :          0 : }
     282                 :            : 
     283                 :       1174 : OVSTEST_REGISTER("test-conntrack", test_conntrack_main);

Generated by: LCOV version 1.12