File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / quagga / isisd / isis_route.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue Feb 21 17:26:11 2012 UTC (12 years, 4 months ago) by misho
Branches: quagga, MAIN
CVS tags: v0_99_20_1, v0_99_20, HEAD
quagga

    1: /*
    2:  * IS-IS Rout(e)ing protocol               - isis_route.c
    3:  * Copyright (C) 2001,2002   Sampo Saaristo
    4:  *                           Tampere University of Technology      
    5:  *                           Institute of Communications Engineering
    6:  *
    7:  *                                         based on ../ospf6d/ospf6_route.[ch]
    8:  *                                         by Yasuhiro Ohara
    9:  *
   10:  * This program is free software; you can redistribute it and/or modify it 
   11:  * under the terms of the GNU General Public Licenseas published by the Free 
   12:  * Software Foundation; either version 2 of the License, or (at your option) 
   13:  * any later version.
   14:  *
   15:  * This program is distributed in the hope that it will be useful,but WITHOUT 
   16:  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
   17:  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for 
   18:  * more details.
   19: 
   20:  * You should have received a copy of the GNU General Public License along 
   21:  * with this program; if not, write to the Free Software Foundation, Inc., 
   22:  * 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
   23:  */
   24: 
   25: #include <zebra.h>
   26: 
   27: #include "thread.h"
   28: #include "linklist.h"
   29: #include "vty.h"
   30: #include "log.h"
   31: #include "memory.h"
   32: #include "prefix.h"
   33: #include "hash.h"
   34: #include "if.h"
   35: #include "table.h"
   36: 
   37: #include "isis_constants.h"
   38: #include "isis_common.h"
   39: #include "dict.h"
   40: #include "isisd.h"
   41: #include "isis_misc.h"
   42: #include "isis_adjacency.h"
   43: #include "isis_circuit.h"
   44: #include "isis_tlv.h"
   45: #include "isis_pdu.h"
   46: #include "isis_lsp.h"
   47: #include "isis_spf.h"
   48: #include "isis_route.h"
   49: #include "isis_zebra.h"
   50: 
   51: extern struct isis *isis;
   52: extern struct thread_master *master;
   53: 
   54: static struct isis_nexthop *
   55: isis_nexthop_create (struct in_addr *ip, unsigned int ifindex)
   56: {
   57:   struct listnode *node;
   58:   struct isis_nexthop *nexthop;
   59: 
   60:   for (ALL_LIST_ELEMENTS_RO (isis->nexthops, node, nexthop))
   61:     {
   62:       if (nexthop->ifindex != ifindex)
   63: 	continue;
   64:       if (ip && memcmp (&nexthop->ip, ip, sizeof (struct in_addr)) != 0)
   65: 	continue;
   66: 
   67:       nexthop->lock++;
   68:       return nexthop;
   69:     }
   70: 
   71:   nexthop = XCALLOC (MTYPE_ISIS_NEXTHOP, sizeof (struct isis_nexthop));
   72:   if (!nexthop)
   73:     {
   74:       zlog_err ("ISIS-Rte: isis_nexthop_create: out of memory!");
   75:     }
   76: 
   77:   nexthop->ifindex = ifindex;
   78:   memcpy (&nexthop->ip, ip, sizeof (struct in_addr));
   79:   listnode_add (isis->nexthops, nexthop);
   80:   nexthop->lock++;
   81: 
   82:   return nexthop;
   83: }
   84: 
   85: static void
   86: isis_nexthop_delete (struct isis_nexthop *nexthop)
   87: {
   88:   nexthop->lock--;
   89:   if (nexthop->lock == 0)
   90:     {
   91:       listnode_delete (isis->nexthops, nexthop);
   92:       XFREE (MTYPE_ISIS_NEXTHOP, nexthop);
   93:     }
   94: 
   95:   return;
   96: }
   97: 
   98: static int
   99: nexthoplookup (struct list *nexthops, struct in_addr *ip,
  100: 	       unsigned int ifindex)
  101: {
  102:   struct listnode *node;
  103:   struct isis_nexthop *nh;
  104: 
  105:   for (ALL_LIST_ELEMENTS_RO (nexthops, node, nh))
  106:     {
  107:       if (!(memcmp (ip, &nh->ip, sizeof (struct in_addr))) &&
  108: 	  ifindex == nh->ifindex)
  109: 	return 1;
  110:     }
  111: 
  112:   return 0;
  113: }
  114: 
  115: #ifdef EXTREME_DEBUG
  116: static void
  117: nexthop_print (struct isis_nexthop *nh)
  118: {
  119:   u_char buf[BUFSIZ];
  120: 
  121:   inet_ntop (AF_INET, &nh->ip, (char *) buf, BUFSIZ);
  122: 
  123:   zlog_debug ("      %s %u", buf, nh->ifindex);
  124: }
  125: 
  126: static void
  127: nexthops_print (struct list *nhs)
  128: {
  129:   struct listnode *node;
  130:   struct isis_nexthop *nh;
  131: 
  132:   for (ALL_LIST_ELEMENTS_RO (nhs, node, nh))
  133:     nexthop_print (nh);
  134: }
  135: #endif /* EXTREME_DEBUG */
  136: 
  137: #ifdef HAVE_IPV6
  138: static struct isis_nexthop6 *
  139: isis_nexthop6_new (struct in6_addr *ip6, unsigned int ifindex)
  140: {
  141:   struct isis_nexthop6 *nexthop6;
  142: 
  143:   nexthop6 = XCALLOC (MTYPE_ISIS_NEXTHOP6, sizeof (struct isis_nexthop6));
  144:   if (!nexthop6)
  145:     {
  146:       zlog_err ("ISIS-Rte: isis_nexthop_create6: out of memory!");
  147:     }
  148: 
  149:   nexthop6->ifindex = ifindex;
  150:   memcpy (&nexthop6->ip6, ip6, sizeof (struct in6_addr));
  151:   nexthop6->lock++;
  152: 
  153:   return nexthop6;
  154: }
  155: 
  156: static struct isis_nexthop6 *
  157: isis_nexthop6_create (struct in6_addr *ip6, unsigned int ifindex)
  158: {
  159:   struct listnode *node;
  160:   struct isis_nexthop6 *nexthop6;
  161: 
  162:   for (ALL_LIST_ELEMENTS_RO (isis->nexthops6, node, nexthop6))
  163:     {
  164:       if (nexthop6->ifindex != ifindex)
  165: 	continue;
  166:       if (ip6 && memcmp (&nexthop6->ip6, ip6, sizeof (struct in6_addr)) != 0)
  167: 	continue;
  168: 
  169:       nexthop6->lock++;
  170:       return nexthop6;
  171:     }
  172: 
  173:   nexthop6 = isis_nexthop6_new (ip6, ifindex);
  174: 
  175:   return nexthop6;
  176: }
  177: 
  178: static void
  179: isis_nexthop6_delete (struct isis_nexthop6 *nexthop6)
  180: {
  181: 
  182:   nexthop6->lock--;
  183:   if (nexthop6->lock == 0)
  184:     {
  185:       listnode_delete (isis->nexthops6, nexthop6);
  186:       XFREE (MTYPE_ISIS_NEXTHOP6, nexthop6);
  187:     }
  188: 
  189:   return;
  190: }
  191: 
  192: static int
  193: nexthop6lookup (struct list *nexthops6, struct in6_addr *ip6,
  194: 		unsigned int ifindex)
  195: {
  196:   struct listnode *node;
  197:   struct isis_nexthop6 *nh6;
  198: 
  199:   for (ALL_LIST_ELEMENTS_RO (nexthops6, node, nh6))
  200:     {
  201:       if (!(memcmp (ip6, &nh6->ip6, sizeof (struct in6_addr))) &&
  202: 	  ifindex == nh6->ifindex)
  203: 	return 1;
  204:     }
  205: 
  206:   return 0;
  207: }
  208: 
  209: #ifdef EXTREME_DEBUG
  210: static void
  211: nexthop6_print (struct isis_nexthop6 *nh6)
  212: {
  213:   u_char buf[BUFSIZ];
  214: 
  215:   inet_ntop (AF_INET6, &nh6->ip6, (char *) buf, BUFSIZ);
  216: 
  217:   zlog_debug ("      %s %u", buf, nh6->ifindex);
  218: }
  219: 
  220: static void
  221: nexthops6_print (struct list *nhs6)
  222: {
  223:   struct listnode *node;
  224:   struct isis_nexthop6 *nh6;
  225: 
  226:   for (ALL_LIST_ELEMENTS_RO (nhs6, node, nh6))
  227:     nexthop6_print (nh6);
  228: }
  229: #endif /* EXTREME_DEBUG */
  230: #endif /* HAVE_IPV6 */
  231: 
  232: static void
  233: adjinfo2nexthop (struct list *nexthops, struct isis_adjacency *adj)
  234: {
  235:   struct isis_nexthop *nh;
  236:   struct listnode *node;
  237:   struct in_addr *ipv4_addr;
  238: 
  239:   if (adj->ipv4_addrs == NULL)
  240:     return;
  241: 
  242:   for (ALL_LIST_ELEMENTS_RO (adj->ipv4_addrs, node, ipv4_addr))
  243:     {
  244:       if (!nexthoplookup (nexthops, ipv4_addr,
  245: 			  adj->circuit->interface->ifindex))
  246: 	{
  247: 	  nh = isis_nexthop_create (ipv4_addr,
  248: 				    adj->circuit->interface->ifindex);
  249: 	  listnode_add (nexthops, nh);
  250: 	}
  251:     }
  252: }
  253: 
  254: #ifdef HAVE_IPV6
  255: static void
  256: adjinfo2nexthop6 (struct list *nexthops6, struct isis_adjacency *adj)
  257: {
  258:   struct listnode *node;
  259:   struct in6_addr *ipv6_addr;
  260:   struct isis_nexthop6 *nh6;
  261: 
  262:   if (!adj->ipv6_addrs)
  263:     return;
  264: 
  265:   for (ALL_LIST_ELEMENTS_RO (adj->ipv6_addrs, node, ipv6_addr))
  266:     {
  267:       if (!nexthop6lookup (nexthops6, ipv6_addr,
  268: 			   adj->circuit->interface->ifindex))
  269: 	{
  270: 	  nh6 = isis_nexthop6_create (ipv6_addr,
  271: 				      adj->circuit->interface->ifindex);
  272: 	  listnode_add (nexthops6, nh6);
  273: 	}
  274:     }
  275: }
  276: #endif /* HAVE_IPV6 */
  277: 
  278: static struct isis_route_info *
  279: isis_route_info_new (uint32_t cost, uint32_t depth, u_char family,
  280: 		     struct list *adjacencies)
  281: {
  282:   struct isis_route_info *rinfo;
  283:   struct isis_adjacency *adj;
  284:   struct listnode *node;
  285: 
  286:   rinfo = XCALLOC (MTYPE_ISIS_ROUTE_INFO, sizeof (struct isis_route_info));
  287:   if (!rinfo)
  288:     {
  289:       zlog_err ("ISIS-Rte: isis_route_info_new: out of memory!");
  290:       return NULL;
  291:     }
  292: 
  293:   if (family == AF_INET)
  294:     {
  295:       rinfo->nexthops = list_new ();
  296:       for (ALL_LIST_ELEMENTS_RO (adjacencies, node, adj))
  297:         adjinfo2nexthop (rinfo->nexthops, adj);
  298:     }
  299: #ifdef HAVE_IPV6
  300:   if (family == AF_INET6)
  301:     {
  302:       rinfo->nexthops6 = list_new ();
  303:       for (ALL_LIST_ELEMENTS_RO (adjacencies, node, adj))
  304:         adjinfo2nexthop6 (rinfo->nexthops6, adj);
  305:     }
  306: 
  307: #endif /* HAVE_IPV6 */
  308: 
  309:   rinfo->cost = cost;
  310:   rinfo->depth = depth;
  311: 
  312:   return rinfo;
  313: }
  314: 
  315: static void
  316: isis_route_info_delete (struct isis_route_info *route_info)
  317: {
  318:   if (route_info->nexthops)
  319:     {
  320:       route_info->nexthops->del = (void (*)(void *)) isis_nexthop_delete;
  321:       list_delete (route_info->nexthops);
  322:     }
  323: 
  324: #ifdef HAVE_IPV6
  325:   if (route_info->nexthops6)
  326:     {
  327:       route_info->nexthops6->del = (void (*)(void *)) isis_nexthop6_delete;
  328:       list_delete (route_info->nexthops6);
  329:     }
  330: #endif /* HAVE_IPV6 */
  331: 
  332:   XFREE (MTYPE_ISIS_ROUTE_INFO, route_info);
  333: }
  334: 
  335: static int
  336: isis_route_info_same_attrib (struct isis_route_info *new,
  337: 			     struct isis_route_info *old)
  338: {
  339:   if (new->cost != old->cost)
  340:     return 0;
  341:   if (new->depth != old->depth)
  342:     return 0;
  343: 
  344:   return 1;
  345: }
  346: 
  347: static int
  348: isis_route_info_same (struct isis_route_info *new,
  349: 		      struct isis_route_info *old, u_char family)
  350: {
  351:   struct listnode *node;
  352:   struct isis_nexthop *nexthop;
  353: #ifdef HAVE_IPV6
  354:   struct isis_nexthop6 *nexthop6;
  355: #endif /* HAVE_IPV6 */
  356:   if (!isis_route_info_same_attrib (new, old))
  357:     return 0;
  358: 
  359:   if (family == AF_INET)
  360:     {
  361:       for (ALL_LIST_ELEMENTS_RO (new->nexthops, node, nexthop))
  362:         if (nexthoplookup (old->nexthops, &nexthop->ip, nexthop->ifindex) 
  363:               == 0)
  364:           return 0;
  365: 
  366:       for (ALL_LIST_ELEMENTS_RO (old->nexthops, node, nexthop))
  367:         if (nexthoplookup (new->nexthops, &nexthop->ip, nexthop->ifindex) 
  368:              == 0)
  369:           return 0;
  370:     }
  371: #ifdef HAVE_IPV6
  372:   else if (family == AF_INET6)
  373:     {
  374:       for (ALL_LIST_ELEMENTS_RO (new->nexthops6, node, nexthop6))
  375:         if (nexthop6lookup (old->nexthops6, &nexthop6->ip6,
  376:                             nexthop6->ifindex) == 0)
  377:           return 0;
  378: 
  379:       for (ALL_LIST_ELEMENTS_RO (old->nexthops6, node, nexthop6))
  380:         if (nexthop6lookup (new->nexthops6, &nexthop6->ip6,
  381:                             nexthop6->ifindex) == 0)
  382:           return 0;
  383:     }
  384: #endif /* HAVE_IPV6 */
  385: 
  386:   return 1;
  387: }
  388: 
  389: static void
  390: isis_nexthops_merge (struct list *new, struct list *old)
  391: {
  392:   struct listnode *node;
  393:   struct isis_nexthop *nexthop;
  394: 
  395:   for (ALL_LIST_ELEMENTS_RO (new, node, nexthop))
  396:     {
  397:       if (nexthoplookup (old, &nexthop->ip, nexthop->ifindex))
  398: 	continue;
  399:       listnode_add (old, nexthop);
  400:       nexthop->lock++;
  401:     }
  402: }
  403: 
  404: #ifdef HAVE_IPV6
  405: static void
  406: isis_nexthops6_merge (struct list *new, struct list *old)
  407: {
  408:   struct listnode *node;
  409:   struct isis_nexthop6 *nexthop6;
  410: 
  411:   for (ALL_LIST_ELEMENTS_RO (new, node, nexthop6))
  412:     {
  413:       if (nexthop6lookup (old, &nexthop6->ip6, nexthop6->ifindex))
  414: 	continue;
  415:       listnode_add (old, nexthop6);
  416:       nexthop6->lock++;
  417:     }
  418: }
  419: #endif /* HAVE_IPV6 */
  420: 
  421: static void
  422: isis_route_info_merge (struct isis_route_info *new,
  423: 		       struct isis_route_info *old, u_char family)
  424: {
  425:   if (family == AF_INET)
  426:     isis_nexthops_merge (new->nexthops, old->nexthops);
  427: #ifdef HAVE_IPV6
  428:   else if (family == AF_INET6)
  429:     isis_nexthops6_merge (new->nexthops6, old->nexthops6);
  430: #endif /* HAVE_IPV6 */
  431: 
  432:   return;
  433: }
  434: 
  435: static int
  436: isis_route_info_prefer_new (struct isis_route_info *new,
  437: 			    struct isis_route_info *old)
  438: {
  439:   if (!CHECK_FLAG (old->flag, ISIS_ROUTE_FLAG_ACTIVE))
  440:     return 1;
  441: 
  442:   if (new->cost < old->cost)
  443:     return 1;
  444: 
  445:   return 0;
  446: }
  447: 
  448: struct isis_route_info *
  449: isis_route_create (struct prefix *prefix, u_int32_t cost, u_int32_t depth,
  450: 		   struct list *adjacencies, struct isis_area *area,
  451: 		   int level)
  452: {
  453:   struct route_node *route_node;
  454:   struct isis_route_info *rinfo_new, *rinfo_old, *route_info = NULL;
  455:   u_char buff[BUFSIZ];
  456:   u_char family;
  457: 
  458:   family = prefix->family;
  459:   /* for debugs */
  460:   prefix2str (prefix, (char *) buff, BUFSIZ);
  461: 
  462:   rinfo_new = isis_route_info_new (cost, depth, family, adjacencies);
  463:   if (!rinfo_new)
  464:     {
  465:       zlog_err ("ISIS-Rte (%s): isis_route_create: out of memory!",
  466: 		area->area_tag);
  467:       return NULL;
  468:     }
  469: 
  470:   if (family == AF_INET)
  471:     route_node = route_node_get (area->route_table[level - 1], prefix);
  472: #ifdef HAVE_IPV6
  473:   else if (family == AF_INET6)
  474:     route_node = route_node_get (area->route_table6[level - 1], prefix);
  475: #endif /* HAVE_IPV6 */
  476:   else
  477:     return NULL;
  478:   rinfo_old = route_node->info;
  479:   if (!rinfo_old)
  480:     {
  481:       if (isis->debugs & DEBUG_RTE_EVENTS)
  482: 	zlog_debug ("ISIS-Rte (%s) route created: %s", area->area_tag, buff);
  483:       SET_FLAG (rinfo_new->flag, ISIS_ROUTE_FLAG_ACTIVE);
  484:       route_node->info = rinfo_new;
  485:       return rinfo_new;
  486:     }
  487: 
  488:   if (isis->debugs & DEBUG_RTE_EVENTS)
  489:     zlog_debug ("ISIS-Rte (%s) route already exists: %s", area->area_tag,
  490: 	       buff);
  491: 
  492:   if (isis_route_info_same (rinfo_new, rinfo_old, family))
  493:     {
  494:       if (isis->debugs & DEBUG_RTE_EVENTS)
  495: 	zlog_debug ("ISIS-Rte (%s) route unchanged: %s", area->area_tag, buff);
  496:       isis_route_info_delete (rinfo_new);
  497:       route_info = rinfo_old;
  498:     }
  499:   else if (isis_route_info_same_attrib (rinfo_new, rinfo_old))
  500:     {
  501:       /* merge the nexthop lists */
  502:       if (isis->debugs & DEBUG_RTE_EVENTS)
  503: 	zlog_debug ("ISIS-Rte (%s) route changed (same attribs): %s",
  504: 		   area->area_tag, buff);
  505: #ifdef EXTREME_DEBUG
  506:       if (family == AF_INET)
  507: 	{
  508: 	  zlog_debug ("Old nexthops");
  509: 	  nexthops_print (rinfo_old->nexthops);
  510: 	  zlog_debug ("New nexthops");
  511: 	  nexthops_print (rinfo_new->nexthops);
  512: 	}
  513:       else if (family == AF_INET6)
  514: 	{
  515: 	  zlog_debug ("Old nexthops");
  516: 	  nexthops6_print (rinfo_old->nexthops6);
  517: 	  zlog_debug ("New nexthops");
  518: 	  nexthops6_print (rinfo_new->nexthops6);
  519: 	}
  520: #endif /* EXTREME_DEBUG */
  521:       isis_route_info_merge (rinfo_new, rinfo_old, family);
  522:       isis_route_info_delete (rinfo_new);
  523:       route_info = rinfo_old;
  524:       UNSET_FLAG (route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNC);
  525:     }
  526:   else
  527:     {
  528:       if (isis_route_info_prefer_new (rinfo_new, rinfo_old))
  529: 	{
  530: 	  if (isis->debugs & DEBUG_RTE_EVENTS)
  531: 	    zlog_debug ("ISIS-Rte (%s) route changed: %s", area->area_tag,
  532: 			buff);
  533: 	  isis_route_info_delete (rinfo_old);
  534: 	  route_info = rinfo_new;
  535: 	}
  536:       else
  537: 	{
  538: 	  if (isis->debugs & DEBUG_RTE_EVENTS)
  539: 	    zlog_debug ("ISIS-Rte (%s) route rejected: %s", area->area_tag,
  540: 			buff);
  541: 	  isis_route_info_delete (rinfo_new);
  542: 	  route_info = rinfo_old;
  543: 	}
  544:     }
  545: 
  546:   SET_FLAG (route_info->flag, ISIS_ROUTE_FLAG_ACTIVE);
  547:   route_node->info = route_info;
  548: 
  549:   return route_info;
  550: }
  551: 
  552: static void
  553: isis_route_delete (struct prefix *prefix, struct route_table *table)
  554: {
  555:   struct route_node *rode;
  556:   struct isis_route_info *rinfo;
  557:   char buff[BUFSIZ];
  558: 
  559:   /* for log */
  560:   prefix2str (prefix, buff, BUFSIZ);
  561: 
  562: 
  563:   rode = route_node_get (table, prefix);
  564:   rinfo = rode->info;
  565: 
  566:   if (rinfo == NULL)
  567:     {
  568:       if (isis->debugs & DEBUG_RTE_EVENTS)
  569: 	zlog_debug ("ISIS-Rte: tried to delete non-existant route %s", buff);
  570:       return;
  571:     }
  572: 
  573:   if (CHECK_FLAG (rinfo->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNC))
  574:     {
  575:       UNSET_FLAG (rinfo->flag, ISIS_ROUTE_FLAG_ACTIVE);
  576:       if (isis->debugs & DEBUG_RTE_EVENTS)
  577: 	zlog_debug ("ISIS-Rte: route delete  %s", buff);
  578:       isis_zebra_route_update (prefix, rinfo);
  579:     }
  580:   isis_route_info_delete (rinfo);
  581:   rode->info = NULL;
  582: 
  583:   return;
  584: }
  585: 
  586: /* Validating routes in particular table. */
  587: static void
  588: isis_route_validate_table (struct isis_area *area, struct route_table *table)
  589: {
  590:   struct route_node *rnode, *drnode;
  591:   struct isis_route_info *rinfo;
  592:   u_char buff[BUFSIZ];
  593: 
  594:   for (rnode = route_top (table); rnode; rnode = route_next (rnode))
  595:     {
  596:       if (rnode->info == NULL)
  597: 	continue;
  598:       rinfo = rnode->info;
  599: 
  600:       if (isis->debugs & DEBUG_RTE_EVENTS)
  601: 	{
  602: 	  prefix2str (&rnode->p, (char *) buff, BUFSIZ);
  603: 	  zlog_debug ("ISIS-Rte (%s): route validate: %s %s %s",
  604: 		      area->area_tag,
  605: 		      (CHECK_FLAG (rinfo->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNC) ?
  606: 		      "sync'ed" : "nosync"),
  607: 		      (CHECK_FLAG (rinfo->flag, ISIS_ROUTE_FLAG_ACTIVE) ?
  608: 		      "active" : "inactive"), buff);
  609: 	}
  610: 
  611:       isis_zebra_route_update (&rnode->p, rinfo);
  612:       if (!CHECK_FLAG (rinfo->flag, ISIS_ROUTE_FLAG_ACTIVE))
  613: 	{
  614: 	  /* Area is either L1 or L2 => we use level route tables directly for
  615: 	   * validating => no problems with deleting routes. */
  616: 	  if (area->is_type != IS_LEVEL_1_AND_2)
  617: 	    {
  618: 	      isis_route_delete (&rnode->p, table);
  619: 	      continue;
  620: 	    }
  621: 	  /* If area is L1L2, we work with merge table and therefore must
  622: 	   * delete node from level tables as well before deleting route info.
  623: 	   * FIXME: Is it performance problem? There has to be the better way.
  624: 	   * Like not to deal with it here at all (see the next comment)? */
  625: 	  if (rnode->p.family == AF_INET)
  626: 	    {
  627: 	      drnode = route_node_get (area->route_table[0], &rnode->p);
  628: 	      if (drnode->info == rnode->info)
  629: 		drnode->info = NULL;
  630: 	      drnode = route_node_get (area->route_table[1], &rnode->p);
  631: 	      if (drnode->info == rnode->info)
  632: 		drnode->info = NULL;
  633: 	    }
  634: 
  635: #ifdef HAVE_IPV6
  636: 	  if (rnode->p.family == AF_INET6)
  637: 	    {
  638: 	      drnode = route_node_get (area->route_table6[0], &rnode->p);
  639: 	      if (drnode->info == rnode->info)
  640: 		drnode->info = NULL;
  641: 	      drnode = route_node_get (area->route_table6[1], &rnode->p);
  642: 	      if (drnode->info == rnode->info)
  643: 		drnode->info = NULL;
  644: 	    }
  645: #endif
  646: 	      
  647: 	  isis_route_delete (&rnode->p, table);
  648: 	}
  649:     }
  650: }
  651: 
  652: /* Function to validate route tables for L1L2 areas. In this case we can't use
  653:  * level route tables directly, we have to merge them at first. L1 routes are
  654:  * preferred over the L2 ones.
  655:  *
  656:  * Merge algorithm is trivial (at least for now). All L1 paths are copied into
  657:  * merge table at first, then L2 paths are added if L1 path for same prefix
  658:  * doesn't already exists there.
  659:  *
  660:  * FIXME: Is it right place to do it at all? Maybe we should push both levels
  661:  * to the RIB with different zebra route types and let RIB handle this? */
  662: static void
  663: isis_route_validate_merge (struct isis_area *area, int family)
  664: {
  665:   struct route_table *table = NULL;
  666:   struct route_table *merge;
  667:   struct route_node *rnode, *mrnode;
  668: 
  669:   merge = route_table_init ();
  670: 
  671:   if (family == AF_INET)
  672:     table = area->route_table[0];
  673: #ifdef HAVE_IPV6
  674:   else if (family == AF_INET6)
  675:     table = area->route_table6[0];
  676: #endif
  677: 
  678:   for (rnode = route_top (table); rnode; rnode = route_next (rnode))
  679:     {
  680:       if (rnode->info == NULL)
  681:         continue;
  682:       mrnode = route_node_get (merge, &rnode->p);
  683:       mrnode->info = rnode->info;
  684:     }
  685: 
  686:   if (family == AF_INET)
  687:     table = area->route_table[1];
  688: #ifdef HAVE_IPV6
  689:   else if (family == AF_INET6)
  690:     table = area->route_table6[1];
  691: #endif
  692: 
  693:   for (rnode = route_top (table); rnode; rnode = route_next (rnode))
  694:     {
  695:       if (rnode->info == NULL)
  696:         continue;
  697:       mrnode = route_node_get (merge, &rnode->p);
  698:       if (mrnode->info != NULL)
  699:         continue;
  700:       mrnode->info = rnode->info;
  701:     }
  702: 
  703:   isis_route_validate_table (area, merge);
  704:   route_table_finish (merge);
  705: }
  706: 
  707: /* Walk through route tables and propagate necessary changes into RIB. In case
  708:  * of L1L2 area, level tables have to be merged at first. */
  709: int
  710: isis_route_validate (struct thread *thread)
  711: {
  712:   struct isis_area *area;
  713: 
  714:   area = THREAD_ARG (thread);
  715: 
  716:   if (area->is_type == IS_LEVEL_1)
  717:     { 
  718:       isis_route_validate_table (area, area->route_table[0]);
  719:       goto validate_ipv6;
  720:     }
  721:   if (area->is_type == IS_LEVEL_2)
  722:     {
  723:       isis_route_validate_table (area, area->route_table[1]);
  724:       goto validate_ipv6;
  725:     }
  726: 
  727:   isis_route_validate_merge (area, AF_INET);
  728: 
  729: validate_ipv6:
  730: #ifdef HAVE_IPV6
  731:   if (area->is_type == IS_LEVEL_1)
  732:     {
  733:       isis_route_validate_table (area, area->route_table6[0]);
  734:       return ISIS_OK;
  735:     }
  736:   if (area->is_type == IS_LEVEL_2)
  737:     {
  738:       isis_route_validate_table (area, area->route_table6[1]);
  739:       return ISIS_OK;
  740:     }
  741: 
  742:   isis_route_validate_merge (area, AF_INET6);
  743: #endif
  744: 
  745:   return ISIS_OK;
  746: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>