Annotation of embedaddon/quagga/isisd/isis_route.c, revision 1.1.1.1

1.1       misho       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>