LCOV - code coverage report
Current view: top level - tests/testcases/lib - test_srcdest_table.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 156 195 80.0 %
Date: 2015-11-19 Functions: 17 21 81.0 %

          Line data    Source code
       1             : /*
       2             :  * Test srcdest table for correctness.
       3             :  *
       4             :  * Copyright (C) 2014 by Christian Franke, Open Source Routing.
       5             :  *
       6             :  * This file is part of Quagga
       7             :  *
       8             :  * Quagga is free software; you can redistribute it and/or modify it
       9             :  * under the terms of the GNU General Public License as published by the
      10             :  * Free Software Foundation; either version 2, or (at your option) any
      11             :  * later version.
      12             :  *
      13             :  * Quagga is distributed in the hope that it will be useful, but
      14             :  * WITHOUT ANY WARRANTY; without even the implied warranty of
      15             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      16             :  * General Public License for more details.
      17             :  *
      18             :  * You should have received a copy of the GNU General Public License
      19             :  * along with Quagga; see the file COPYING.  If not, write to the Free
      20             :  * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
      21             :  * 02111-1307, USA.
      22             :  */
      23             : 
      24             : #include <zebra.h>
      25             : 
      26             : #include "hash.h"
      27             : #include "memory.h"
      28             : #include "prefix.h"
      29             : #include "prng.h"
      30             : #include "srcdest_table.h"
      31             : #include "table.h"
      32             : 
      33             : struct thread_master *master;
      34             : 
      35             : /* This structure is copied from lib/srcdest_table.c to which it is
      36             :  * private as far as other parts of Quagga are concerned.
      37             :  */
      38             : struct srcdest_rnode
      39             : {
      40             :   /* must be first in structure for casting to/from route_node */
      41             :   ROUTE_NODE_FIELDS;
      42             : 
      43             :   struct route_table *src_table;
      44             : };
      45             : 
      46             : struct test_state
      47             : {
      48             :   struct route_table *table;
      49             :   struct hash *log;
      50             : };
      51             : 
      52             : static char *
      53           0 : format_srcdest(const struct prefix_ipv6 *dst_p,
      54             :                const struct prefix_ipv6 *src_p)
      55             : {
      56             :   char dst_str[BUFSIZ];
      57             :   char src_str[BUFSIZ];
      58             :   char *rv;
      59             :   int ec;
      60             : 
      61           0 :   prefix2str((const struct prefix*)dst_p, dst_str, sizeof(dst_str));
      62           0 :   if (src_p && src_p->prefixlen)
      63           0 :     prefix2str((const struct prefix*)src_p, src_str, sizeof(src_str));
      64             :   else
      65           0 :     src_str[0] = '\0';
      66             : 
      67           0 :   ec = asprintf(&rv, "%s%s%s", dst_str,
      68           0 :                 (src_str[0] != '\0') ? " from " : "",
      69             :                 src_str);
      70             : 
      71           0 :   assert(ec > 0);
      72           0 :   return rv;
      73             : }
      74             : 
      75      146785 : static unsigned int log_key(void *data)
      76             : {
      77      146785 :   struct prefix *hash_entry = data;
      78      146785 :   struct prefix_ipv6 *dst_p = (struct prefix_ipv6*) &hash_entry[0];
      79      146785 :   struct prefix_ipv6 *src_p = (struct prefix_ipv6*) &hash_entry[1];
      80      146785 :   unsigned int hash = 0;
      81             :   unsigned int i;
      82             : 
      83      146785 :   hash = (hash * 33) ^ (unsigned int)dst_p->prefixlen;
      84      733925 :   for (i = 0; i < 4; i++)
      85      587140 :     hash = (hash * 33) ^ (unsigned int)dst_p->prefix.s6_addr32[i];
      86             : 
      87      146785 :   hash = (hash * 33) ^ (unsigned int)src_p->prefixlen;
      88      146785 :   if (src_p->prefixlen)
      89      493460 :     for (i = 0; i < 4; i++)
      90      394768 :       hash = (hash * 33) ^ (unsigned int)src_p->prefix.s6_addr32[i];
      91             : 
      92      146785 :   return hash;
      93             : }
      94             : 
      95             : static int
      96      145504 : log_cmp(const void *a, const void *b)
      97             : {
      98      145504 :   if (a == NULL && b != NULL)
      99           0 :     return 0;
     100      145504 :   if (b == NULL && a != NULL)
     101           0 :     return 0;
     102             : 
     103      145504 :   return !memcmp(a, b, 2 * sizeof(struct prefix));
     104             : }
     105             : 
     106             : static void
     107         281 : log_free(void *data)
     108             : {
     109         281 :   XFREE(MTYPE_TMP, data);
     110         281 : }
     111             : 
     112             : static void *
     113         541 : log_alloc(void *data)
     114             : {
     115         541 :   void *rv = XMALLOC(MTYPE_TMP, 2 * sizeof(struct prefix));
     116         541 :   memcpy(rv, data, 2 * sizeof(struct prefix));
     117         541 :   return rv;
     118             : }
     119             : 
     120             : static struct test_state *
     121           1 : test_state_new(void)
     122             : {
     123             :   struct test_state *rv;
     124             : 
     125           1 :   rv = XCALLOC(MTYPE_TMP, sizeof(*rv));
     126           1 :   assert(rv);
     127             : 
     128           1 :   rv->table = srcdest_table_init();
     129           1 :   assert(rv->table);
     130             : 
     131           1 :   rv->log = hash_create(log_key, log_cmp);
     132           1 :   return rv;
     133             : }
     134             : 
     135             : static void
     136           1 : test_state_free(struct test_state *test)
     137             : {
     138           1 :   route_table_finish(test->table);
     139           1 :   hash_clean(test->log, log_free);
     140           1 :   hash_free(test->log);
     141           1 :   XFREE(MTYPE_TMP, test);
     142           1 : }
     143             : 
     144             : static void
     145         541 : test_state_add_route(struct test_state *test,
     146             :                      struct prefix_ipv6 *dst_p,
     147             :                      struct prefix_ipv6 *src_p)
     148             : {
     149         541 :   struct route_node *rn = srcdest_rnode_get(
     150             :       test->table, (struct prefix*)dst_p,
     151             :       (struct prefix*)src_p
     152             :   );
     153             :   struct prefix hash_entry[2];
     154             : 
     155         541 :   memset(hash_entry, 0, sizeof(hash_entry));
     156         541 :   memcpy(&hash_entry[0], dst_p, sizeof(*dst_p));
     157         541 :   memcpy(&hash_entry[1], src_p, sizeof(*src_p));
     158             : 
     159         541 :   if (rn->info) {
     160           0 :     route_unlock_node(rn);
     161           0 :     assert(hash_lookup(test->log, hash_entry) != NULL);
     162           0 :     return;
     163             :   } else {
     164         541 :     assert(hash_lookup(test->log, hash_entry) == NULL);
     165             :   }
     166             : 
     167         541 :   rn->info = (void*) 0xdeadbeef;
     168         541 :   hash_get(test->log, hash_entry, log_alloc);
     169             : };
     170             : 
     171             : static void
     172         459 : test_state_del_route(struct test_state *test,
     173             :                      struct prefix_ipv6 *dst_p,
     174             :                      struct prefix_ipv6 *src_p)
     175             : {
     176         459 :   struct route_node *rn = srcdest_rnode_lookup(
     177             :       test->table, (struct prefix*)dst_p,
     178             :       (struct prefix*)src_p
     179             :   );
     180             :   struct prefix hash_entry[2];
     181             : 
     182         459 :   memset(hash_entry, 0, sizeof(hash_entry));
     183         459 :   memcpy(&hash_entry[0], dst_p, sizeof(*dst_p));
     184         459 :   memcpy(&hash_entry[1], src_p, sizeof(*src_p));
     185             : 
     186         459 :   if (!rn) {
     187         199 :     assert(!hash_lookup(test->log, hash_entry));
     188         199 :     return;
     189             :   }
     190             : 
     191         260 :   assert(rn->info == (void*)0xdeadbeef);
     192         260 :   rn->info = NULL;
     193         260 :   route_unlock_node(rn);
     194         260 :   route_unlock_node(rn);
     195             : 
     196         260 :   struct prefix *hash_entry_intern = hash_release(test->log, hash_entry);
     197         260 :   assert(hash_entry_intern != NULL);
     198         260 :   XFREE(MTYPE_TMP, hash_entry_intern);
     199             : }
     200             : 
     201             : static void
     202      145244 : verify_log(struct hash_backet* backet, void *arg)
     203             : {
     204      145244 :   struct test_state *test = arg;
     205      145244 :   struct prefix *hash_entry = backet->data;
     206      145244 :   struct prefix *dst_p = &hash_entry[0];
     207      145244 :   struct prefix *src_p = &hash_entry[1];
     208      145244 :   struct route_node *rn = srcdest_rnode_lookup(test->table, dst_p, src_p);
     209             : 
     210      145244 :   assert(rn);
     211      145244 :   assert(rn->info == (void*)0xdeadbeef);
     212             : 
     213      145244 :   route_unlock_node(rn);
     214      145244 : }
     215             : 
     216             : static void
     217           0 : dump_log(struct hash_backet* backet, void *arg)
     218             : {
     219           0 :   struct prefix *hash_entry = backet->data;
     220           0 :   struct prefix_ipv6 *dst_p = (struct prefix_ipv6*)&hash_entry[0];
     221           0 :   struct prefix_ipv6 *src_p = (struct prefix_ipv6*)&hash_entry[1];
     222           0 :   char *route_id = format_srcdest(dst_p, src_p);
     223             : 
     224           0 :   fprintf(stderr, "  %s\n", route_id);
     225           0 :   free(route_id);
     226           0 : }
     227             : 
     228             : static void
     229           0 : test_dump(struct test_state *test)
     230             : {
     231           0 :   fprintf(stderr, "Contents of hash table:\n");
     232           0 :   hash_iterate(test->log, dump_log, test);
     233           0 :   fprintf(stderr, "\n");
     234           0 : }
     235             : 
     236             : static void
     237           0 : test_failed(struct test_state *test, const char *message,
     238             :             struct prefix_ipv6 *dst_p, struct prefix_ipv6 *src_p)
     239             : {
     240           0 :   char *route_id = format_srcdest(dst_p, src_p);
     241             : 
     242           0 :   fprintf(stderr, "Test failed. Error: %s\n", message);
     243           0 :   fprintf(stderr, "Route in question: %s\n", route_id);
     244           0 :   free(route_id);
     245             : 
     246           0 :   test_dump(test);
     247           0 :   assert(3 == 4);
     248             : }
     249             : 
     250             : static void
     251        1000 : test_state_verify(struct test_state *test)
     252             : {
     253             :   struct route_node *rn;
     254             :   struct prefix hash_entry[2];
     255             : 
     256        1000 :   memset(hash_entry, 0, sizeof(hash_entry));
     257             : 
     258             :   /* Verify that there are no elements in the table which have never
     259             :    * been added */
     260      369314 :   for (rn = route_top(test->table); rn; rn = srcdest_route_next(rn))
     261             :     {
     262             :       struct prefix_ipv6 *dst_p, *src_p;
     263             : 
     264             :       /* While we are iterating, we hold a lock on the current route_node,
     265             :        * so all the lock counts we check for take that into account; in idle
     266             :        * state all the numbers will be exactly one less.
     267             :        *
     268             :        * Also this makes quite some assumptions based on the current
     269             :        * implementation details of route_table and srcdest_table - another
     270             :        * valid implementation might trigger assertions here.
     271             :        */
     272             : 
     273      368314 :       if (rnode_is_dstnode(rn))
     274             :         {
     275      268348 :           struct srcdest_rnode *srn = (struct srcdest_rnode *)rn;
     276      268348 :           unsigned int expected_lock = 1; /* We are in the loop */
     277             : 
     278      268348 :           if (rn->info != NULL) /* The route node is not internal */
     279       47559 :             expected_lock++;
     280      268348 :           if (srn->src_table != NULL) /* There's a source table associated with rn */
     281       95404 :             expected_lock++;
     282             : 
     283      268348 :           if (rn->lock != expected_lock)
     284           0 :             test_failed(test, "Dest rnode lock count doesn't match expected count!",
     285           0 :                         (struct prefix_ipv6*)&rn->p, NULL);
     286             :         }
     287             :       else
     288             :         {
     289       99966 :           unsigned int expected_lock = 1; /* We are in the loop */
     290             : 
     291       99966 :           if (rn->info != NULL) /* The route node is not internal */
     292       97685 :             expected_lock++;
     293             : 
     294       99966 :           if (rn->lock != expected_lock)
     295             :             {
     296             :               struct prefix_ipv6 *dst_p, *src_p;
     297           0 :               srcdest_rnode_prefixes(rn, (struct prefix**)&dst_p,
     298             :                                          (struct prefix**)&src_p);
     299             : 
     300           0 :               test_failed(test, "Src rnode lock count doesn't match expected count!",
     301             :                           dst_p, src_p);
     302             :             }
     303             :         }
     304             : 
     305      368314 :       if (!rn->info)
     306      223070 :         continue;
     307             : 
     308      145244 :       assert(rn->info == (void*)0xdeadbeef);
     309             : 
     310      145244 :       srcdest_rnode_prefixes(rn, (struct prefix**)&dst_p, (struct prefix**)&src_p);
     311      145244 :       memcpy(&hash_entry[0], dst_p, sizeof(*dst_p));
     312      145244 :       if (src_p)
     313       97685 :         memcpy(&hash_entry[1], src_p, sizeof(*src_p));
     314             :       else
     315       47559 :         memset(&hash_entry[1], 0, sizeof(hash_entry[1]));
     316             : 
     317      145244 :       if (hash_lookup(test->log, hash_entry) == NULL)
     318           0 :         test_failed(test, "Route is missing in hash", dst_p, src_p);
     319             :     }
     320             : 
     321             :   /* Verify that all added elements are still in the table */
     322        1000 :   hash_iterate(test->log, verify_log, test);
     323        1000 : }
     324             : 
     325             : static void
     326        1214 : get_rand_prefix(struct prng *prng, struct prefix_ipv6 *p)
     327             : {
     328             :   int i;
     329             : 
     330        1214 :   memset(p, 0, sizeof(*p));
     331             : 
     332        6070 :   for (i = 0; i < 4; i++)
     333        4856 :     p->prefix.s6_addr32[i] = prng_rand(prng);
     334        1214 :   p->prefixlen = prng_rand(prng) % 129;
     335        1214 :   p->family = AF_INET6;
     336             : 
     337        1214 :   apply_mask((struct prefix*)p);
     338        1214 : }
     339             : 
     340             : static void
     341         740 : get_rand_prefix_pair(struct prng *prng, struct prefix_ipv6 *dst_p,
     342             :                      struct prefix_ipv6 *src_p)
     343             : {
     344         740 :   get_rand_prefix(prng, dst_p);
     345         740 :   if ((prng_rand(prng) % 4) == 0)
     346             :     {
     347         474 :       get_rand_prefix(prng, src_p);
     348         474 :       if (src_p->prefixlen)
     349         468 :         return;
     350             :     }
     351             : 
     352         272 :   memset(src_p, 0, sizeof(*src_p));
     353             : }
     354             : 
     355             : static void
     356         541 : test_state_add_rand_route(struct test_state *test,
     357             :                           struct prng *prng)
     358             : {
     359             :   struct prefix_ipv6 dst_p, src_p;
     360             : 
     361         541 :   get_rand_prefix_pair(prng, &dst_p, &src_p);
     362         541 :   test_state_add_route(test, &dst_p, &src_p);
     363         541 : }
     364             : 
     365             : static void
     366         199 : test_state_del_rand_route(struct test_state *test,
     367             :                           struct prng *prng)
     368             : {
     369             :   struct prefix_ipv6 dst_p, src_p;
     370             : 
     371         199 :   get_rand_prefix_pair(prng, &dst_p, &src_p);
     372         199 :   test_state_del_route(test, &dst_p, &src_p);
     373         199 : }
     374             : 
     375             : static void
     376         260 : test_state_del_one_route(struct test_state *test,
     377             :                          struct prng *prng)
     378             : {
     379         260 :   unsigned int which_route = prng_rand(prng) % test->log->count;
     380             :   struct route_node *rn;
     381             :   struct prefix *dst_p, *src_p;
     382             :   struct prefix_ipv6 dst6_p, src6_p;
     383             : 
     384       52677 :   for (rn = route_top(test->table); rn; rn = srcdest_route_next(rn))
     385             :     {
     386       52677 :       if (!rn->info)
     387       31855 :         continue;
     388       20822 :       if (!which_route) {
     389         260 :         route_unlock_node(rn);
     390         260 :         break;
     391             :       }
     392       20562 :       which_route--;
     393             :     }
     394             : 
     395         260 :   assert(rn);
     396         260 :   srcdest_rnode_prefixes(rn, &dst_p, &src_p);
     397         260 :   memcpy(&dst6_p, dst_p, sizeof(dst6_p));
     398         260 :   if (src_p)
     399         179 :     memcpy(&src6_p, src_p, sizeof(src6_p));
     400             :   else
     401          81 :     memset(&src6_p, 0, sizeof(src6_p));
     402             : 
     403         260 :   test_state_del_route(test, &dst6_p, &src6_p);
     404         260 : }
     405             : 
     406             : static void
     407           1 : run_prng_test(void)
     408             : {
     409           1 :   struct test_state *test = test_state_new();
     410           1 :   struct prng *prng = prng_new(0);
     411             :   size_t i;
     412             : 
     413        1001 :   for (i = 0; i < 1000; i++)
     414             :     {
     415        1000 :       switch (prng_rand(prng) % 10)
     416             :         {
     417             :         case 0:
     418             :         case 1:
     419             :         case 2:
     420             :         case 3:
     421             :         case 4:
     422         541 :           test_state_add_rand_route(test, prng);
     423         541 :           break;
     424             :         case 5:
     425             :         case 6:
     426             :         case 7:
     427         260 :           test_state_del_one_route(test, prng);
     428         260 :           break;
     429             :         case 8:
     430             :         case 9:
     431         199 :           test_state_del_rand_route(test, prng);
     432         199 :           break;
     433             :         }
     434        1000 :       test_state_verify(test);
     435             :     }
     436             : 
     437           1 :   prng_free(prng);
     438           1 :   test_state_free(test);
     439           1 : }
     440             : 
     441           1 : int main(int argc, char *argv[])
     442             : {
     443           1 :   run_prng_test();
     444           1 :   printf("PRNG Test successful.\n");
     445           1 :   return 0;
     446             : }

Generated by: LCOV version 1.10