LCOV - code coverage report
Current view: top level - lib - srcdest_table.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 88 88 100.0 %
Date: 2015-11-19 Functions: 15 15 100.0 %

          Line data    Source code
       1             : /*
       2             :  * SRC-DEST Routing Table
       3             :  *
       4             :  * Copyright (C) 2014 by David Lamparter, 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 "srcdest_table.h"
      27             : 
      28             : #include "memory.h"
      29             : #include "prefix.h"
      30             : #include "table.h"
      31             : 
      32             : /* ----- functions to manage rnodes _with_ srcdest table ----- */
      33             : struct srcdest_rnode
      34             : {
      35             :   /* must be first in structure for casting to/from route_node */
      36             :   ROUTE_NODE_FIELDS;
      37             : 
      38             :   struct route_table *src_table;
      39             : };
      40             : 
      41             : static struct srcdest_rnode *
      42      407608 : srcdest_rnode_from_rnode (struct route_node *rn)
      43             : {
      44      407608 :   assert (rnode_is_dstnode (rn));
      45      407608 :   return (struct srcdest_rnode *) rn;
      46             : }
      47             : 
      48             : static struct route_node *
      49        1524 : srcdest_rnode_to_rnode (struct srcdest_rnode *srn)
      50             : {
      51        1524 :   return (struct route_node *) srn;
      52             : }
      53             : 
      54             : static struct route_node *
      55        1345 : srcdest_rnode_create (route_table_delegate_t *delegate,
      56             :                       struct route_table *table)
      57             : {
      58             :   struct srcdest_rnode *srn;
      59        1345 :   srn = XCALLOC (MTYPE_ROUTE_NODE, sizeof (struct srcdest_rnode));
      60        1345 :   return srcdest_rnode_to_rnode(srn);
      61             : }
      62             : 
      63             : static void
      64        1130 : srcdest_rnode_destroy (route_table_delegate_t *delegate,
      65             :                        struct route_table *table, struct route_node *rn)
      66             : {
      67        1130 :   struct srcdest_rnode *srn = srcdest_rnode_from_rnode(rn);
      68             :   struct route_table *src_table;
      69             : 
      70             :   /* Clear route node's src_table here already, otherwise the
      71             :    * deletion of the last node in the src_table will trigger
      72             :    * another call to route_table_finish for the src_table.
      73             :    *
      74             :    * (Compare with srcdest_srcnode_destroy)
      75             :    */
      76        1130 :   src_table = srn->src_table;
      77        1130 :   srn->src_table = NULL;
      78        1130 :   route_table_finish(src_table);
      79        1130 :   XFREE (MTYPE_ROUTE_NODE, rn);
      80        1130 : }
      81             : 
      82             : static route_table_delegate_t srcdest_dstnode_delegate = {
      83             :   .create_node = srcdest_rnode_create,
      84             :   .destroy_node = srcdest_rnode_destroy
      85             : };
      86             : 
      87             : /* ----- functions to manage rnodes _in_ srcdest table ----- */
      88             : 
      89             : /* node creation / deletion for srcdest source prefix nodes.
      90             :  * the route_node isn't actually different from the normal route_node,
      91             :  * but the cleanup is special to free the table (and possibly the
      92             :  * destination prefix's route_node) */
      93             : 
      94             : static struct route_node *
      95         375 : srcdest_srcnode_create (route_table_delegate_t *delegate,
      96             :                    struct route_table *table)
      97             : {
      98         375 :   return XCALLOC (MTYPE_ROUTE_SRC_NODE, sizeof (struct route_node));
      99             : }
     100             : 
     101             : static void
     102         375 : srcdest_srcnode_destroy (route_table_delegate_t *delegate,
     103             :                     struct route_table *table, struct route_node *rn)
     104             : {
     105             :   struct srcdest_rnode *srn;
     106             : 
     107         375 :   XFREE (MTYPE_ROUTE_SRC_NODE, rn);
     108             : 
     109         375 :   srn = table->info;
     110         375 :   if (srn->src_table && route_table_count (srn->src_table) == 0)
     111             :     {
     112             :       /* deleting the route_table from inside destroy_node is ONLY
     113             :        * permitted IF table->count is 0!  see lib/table.c route_node_delete()
     114             :        * for details */
     115         179 :       route_table_finish (srn->src_table);
     116         179 :       srn->src_table = NULL;
     117             : 
     118             :       /* drop the ref we're holding in srcdest_node_get().  there might be
     119             :        * non-srcdest routes, so the route_node may still exist.  hence, it's
     120             :        * important to clear src_table above. */
     121         179 :       route_unlock_node (srcdest_rnode_to_rnode (srn));
     122             :     }
     123         375 : }
     124             : 
     125             : static route_table_delegate_t srcdest_srcnode_delegate = {
     126             :   .create_node = srcdest_srcnode_create,
     127             :   .destroy_node = srcdest_srcnode_destroy
     128             : };
     129             : 
     130             : /* NB: read comments in code for refcounting before using! */
     131             : static struct route_node *
     132         825 : srcdest_srcnode_get (struct route_node *rn, struct prefix *src_p)
     133             : {
     134             :   struct srcdest_rnode *srn;
     135             : 
     136         825 :   if (!src_p || src_p->prefixlen == 0)
     137         459 :     return rn;
     138             : 
     139         366 :   srn = srcdest_rnode_from_rnode (rn);
     140         366 :   if (!srn->src_table)
     141             :     {
     142             :       /* this won't use srcdest_rnode, we're already on the source here */
     143         357 :       srn->src_table = route_table_init_with_delegate (&srcdest_srcnode_delegate);
     144         357 :       srn->src_table->info = srn;
     145             : 
     146             :       /* there is no route_unlock_node on the original rn here.
     147             :        * The reference is kept for the src_table. */
     148             :     }
     149             :   else
     150             :     {
     151             :       /* only keep 1 reference for the src_table, makes the refcounting
     152             :        * more similar to the non-srcdest case.  Either way after return from
     153             :        * function, the only reference held is the one on the return value.
     154             :        *
     155             :        * We can safely drop our reference here because src_table is holding
     156             :        * another reference, so this won't free rn */
     157           9 :       route_unlock_node (rn);
     158             :     }
     159             : 
     160         366 :   return route_node_get (srn->src_table, src_p);
     161             : }
     162             : 
     163             : static struct route_node *
     164      145727 : srcdest_srcnode_lookup (struct route_node *rn, struct prefix *src_p)
     165             : {
     166             :   struct srcdest_rnode *srn;
     167             : 
     168      145727 :   if (!rn || !src_p || src_p->prefixlen == 0)
     169       47851 :     return rn;
     170             : 
     171             :   /* We got this rn from a lookup, so its refcnt was incremented. As we won't
     172             :    * return return rn from any point beyond here, we should decrement its refcnt.
     173             :    */
     174       97876 :   route_unlock_node (rn);
     175             : 
     176       97876 :   srn = srcdest_rnode_from_rnode (rn);
     177       97876 :   if (!srn->src_table)
     178           5 :     return NULL;
     179             : 
     180       97871 :   return route_node_lookup (srn->src_table, src_p);
     181             : }
     182             : 
     183             : /* ----- exported functions ----- */
     184             : 
     185             : int
     186     1622166 : rnode_is_dstnode (struct route_node *rn)
     187             : {
     188     1622166 :   return rn->table->delegate == &srcdest_dstnode_delegate;
     189             : }
     190             : 
     191             : int
     192      264071 : rnode_is_srcnode (struct route_node *rn)
     193             : {
     194      264071 :   return rn->table->delegate == &srcdest_srcnode_delegate;
     195             : }
     196             : 
     197             : struct route_table *
     198         136 : srcdest_table_init(void)
     199             : {
     200         136 :   return route_table_init_with_delegate(&srcdest_dstnode_delegate);
     201             : }
     202             : 
     203             : struct route_node *
     204      423506 : srcdest_route_next(struct route_node *rn)
     205             : {
     206             :   struct route_node *next, *parent;
     207             : 
     208             :   /* For a non src-dest node, just return route_next */
     209      423506 :   if (!(rnode_is_dstnode(rn) || rnode_is_srcnode(rn)))
     210         768 :     return route_next(rn);
     211             : 
     212      422738 :   if (rnode_is_dstnode(rn))
     213             :     {
     214             :       /* This means the route_node is part of the top hierarchy
     215             :        * and refers to a destination prefix. */
     216      308236 :       struct srcdest_rnode *srn = srcdest_rnode_from_rnode(rn);
     217             : 
     218      308236 :       if (srn->src_table)
     219      108949 :         next = route_top(srn->src_table);
     220             :       else
     221      199287 :         next = NULL;
     222             : 
     223      308236 :       if (next)
     224             :         {
     225             :           /* There is a source prefix. Return the node for it */
     226      108949 :           route_unlock_node(rn);
     227      108949 :           return next;
     228             :         }
     229             :       else
     230             :         {
     231             :           /* There is no source prefix, just continue as usual */
     232      199287 :           return route_next(rn);
     233             :         }
     234             :     }
     235             : 
     236             :   /* This part handles the case of iterating source nodes. */
     237      114502 :   parent = route_lock_node(rn->table->info);
     238      114502 :   next = route_next(rn);
     239             : 
     240      114502 :   if (next)
     241             :     {
     242             :       /* There is another source node, continue in the source table */
     243        5732 :       route_unlock_node(parent);
     244        5732 :       return next;
     245             :     }
     246             :   else
     247             :     {
     248             :       /* The source table is complete, continue in the parent table */
     249      108770 :       return route_next(parent);
     250             :     }
     251             : }
     252             : 
     253             : struct route_node *
     254         825 : srcdest_rnode_get (struct route_table *table, struct prefix *dst_p,
     255             :                   struct prefix *src_p)
     256             : {
     257             :   struct route_node *rn;
     258             : 
     259         825 :   rn = route_node_get (table, dst_p);
     260         825 :   return srcdest_srcnode_get (rn, src_p);
     261             : }
     262             : 
     263             : struct route_node *
     264      145727 : srcdest_rnode_lookup (struct route_table *table, struct prefix *dst_p,
     265             :                       struct prefix *src_p)
     266             : {
     267             :   struct route_node *rn;
     268             :   struct route_node *srn;
     269             : 
     270      145727 :   rn = route_node_lookup_maynull (table, dst_p);
     271      145727 :   srn = srcdest_srcnode_lookup (rn, src_p);
     272             : 
     273      145727 :   if (rn != NULL && rn == srn && !rn->info)
     274             :     {
     275             :       /* Match the behavior of route_node_lookup and don't return an
     276             :        * empty route-node for a dest-route */
     277           5 :       route_unlock_node(rn);
     278           5 :       return NULL;
     279             :     }
     280      145722 :   return srn;
     281             : }
     282             : 
     283             : void
     284      148730 : srcdest_rnode_prefixes (struct route_node *rn, struct prefix **p,
     285             :                     struct prefix **src_p)
     286             : {
     287      148730 :   if (rnode_is_srcnode (rn))
     288             :     {
     289       97968 :       struct route_node *dst_rn = rn->table->info;
     290       97968 :       if (p)
     291       97968 :         *p = &dst_rn->p;
     292       97968 :       if (src_p)
     293       97968 :         *src_p = &rn->p;
     294             :     }
     295             :   else
     296             :     {
     297       50762 :       if (p)
     298       50762 :         *p = &rn->p;
     299       50762 :       if (src_p)
     300       50762 :         *src_p = NULL;
     301             :     }
     302      148730 : }
     303             : 

Generated by: LCOV version 1.10