File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / quagga / ospfd / ospf_route.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue Feb 21 17:26:12 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:  * OSPF routing table.
    3:  * Copyright (C) 1999, 2000 Toshiaki Takada
    4:  *
    5:  * This file is part of GNU Zebra.
    6:  *
    7:  * GNU Zebra is free software; you can redistribute it and/or modify it
    8:  * under the terms of the GNU General Public License as published by the
    9:  * Free Software Foundation; either version 2, or (at your option) any
   10:  * later version.
   11:  *
   12:  * GNU Zebra is distributed in the hope that it will be useful, but
   13:  * WITHOUT ANY WARRANTY; without even the implied warranty of
   14:  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   15:  * General Public License for more details.
   16:  *
   17:  * You should have received a copy of the GNU General Public License
   18:  * along with GNU Zebra; see the file COPYING.  If not, write to the Free
   19:  * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
   20:  * 02111-1307, USA.
   21:  */
   22: 
   23: #include <zebra.h>
   24: 
   25: #include "prefix.h"
   26: #include "table.h"
   27: #include "memory.h"
   28: #include "linklist.h"
   29: #include "log.h"
   30: #include "if.h"
   31: #include "command.h"
   32: #include "sockunion.h"
   33: 
   34: #include "ospfd/ospfd.h"
   35: #include "ospfd/ospf_interface.h"
   36: #include "ospfd/ospf_asbr.h"
   37: #include "ospfd/ospf_lsa.h"
   38: #include "ospfd/ospf_route.h"
   39: #include "ospfd/ospf_spf.h"
   40: #include "ospfd/ospf_zebra.h"
   41: #include "ospfd/ospf_dump.h"
   42: 
   43: struct ospf_route *
   44: ospf_route_new ()
   45: {
   46:   struct ospf_route *new;
   47: 
   48:   new = XCALLOC (MTYPE_OSPF_ROUTE, sizeof (struct ospf_route));
   49: 
   50:   new->ctime = quagga_time (NULL);
   51:   new->mtime = new->ctime;
   52:   new->paths = list_new ();
   53:   new->paths->del = (void (*) (void *))ospf_path_free;
   54: 
   55:   return new;
   56: }
   57: 
   58: void
   59: ospf_route_free (struct ospf_route *or)
   60: {
   61:   if (or->paths)
   62:       list_delete (or->paths);
   63: 
   64:   XFREE (MTYPE_OSPF_ROUTE, or);
   65: }
   66: 
   67: struct ospf_path *
   68: ospf_path_new ()
   69: {
   70:   struct ospf_path *new;
   71: 
   72:   new = XCALLOC (MTYPE_OSPF_PATH, sizeof (struct ospf_path));
   73: 
   74:   return new;
   75: }
   76: 
   77: static struct ospf_path *
   78: ospf_path_dup (struct ospf_path *path)
   79: {
   80:   struct ospf_path *new;
   81: 
   82:   new = ospf_path_new ();
   83:   memcpy (new, path, sizeof (struct ospf_path));
   84: 
   85:   return new;
   86: }
   87: 
   88: void
   89: ospf_path_free (struct ospf_path *op)
   90: {
   91:   XFREE (MTYPE_OSPF_PATH, op);
   92: }
   93: 
   94: void
   95: ospf_route_delete (struct route_table *rt)
   96: {
   97:   struct route_node *rn;
   98:   struct ospf_route *or;
   99: 
  100:   for (rn = route_top (rt); rn; rn = route_next (rn))
  101:     if ((or = rn->info) != NULL)
  102:       {
  103: 	if (or->type == OSPF_DESTINATION_NETWORK)
  104: 	  ospf_zebra_delete ((struct prefix_ipv4 *) &rn->p,
  105: 				       or);
  106: 	else if (or->type == OSPF_DESTINATION_DISCARD)
  107: 	  ospf_zebra_delete_discard ((struct prefix_ipv4 *) &rn->p);
  108:       }
  109: }
  110: 
  111: void
  112: ospf_route_table_free (struct route_table *rt)
  113: {
  114:   struct route_node *rn;
  115:   struct ospf_route *or;
  116: 
  117:   for (rn = route_top (rt); rn; rn = route_next (rn))
  118:     if ((or = rn->info) != NULL)
  119:       {
  120: 	ospf_route_free (or);
  121: 
  122: 	rn->info = NULL;
  123: 	route_unlock_node (rn);
  124:       }
  125: 
  126:    route_table_finish (rt);
  127: }
  128: 
  129: /* If a prefix and a nexthop match any route in the routing table,
  130:    then return 1, otherwise return 0. */
  131: int
  132: ospf_route_match_same (struct route_table *rt, struct prefix_ipv4 *prefix,
  133: 		       struct ospf_route *newor)
  134: {
  135:   struct route_node *rn;
  136:   struct ospf_route *or;
  137:   struct ospf_path *op;
  138:   struct ospf_path *newop;
  139:   struct listnode *n1;
  140:   struct listnode *n2;
  141: 
  142:   if (! rt || ! prefix)
  143:     return 0;
  144: 
  145:    rn = route_node_lookup (rt, (struct prefix *) prefix);
  146:    if (! rn || ! rn->info)
  147:      return 0;
  148:  
  149:    route_unlock_node (rn);
  150: 
  151:    or = rn->info;
  152:    if (or->type == newor->type && or->cost == newor->cost)
  153:      {
  154:        if (or->type == OSPF_DESTINATION_NETWORK)
  155: 	 {
  156: 	   if (or->paths->count != newor->paths->count)
  157: 	     return 0;
  158: 
  159: 	   /* Check each path. */
  160: 	   for (n1 = listhead (or->paths), n2 = listhead (newor->paths);
  161: 		n1 && n2; n1 = listnextnode (n1), n2 = listnextnode (n2))
  162: 	     { 
  163: 	       op = listgetdata (n1);
  164: 	       newop = listgetdata (n2);
  165: 
  166: 	       if (! IPV4_ADDR_SAME (&op->nexthop, &newop->nexthop))
  167: 		 return 0;
  168: 	       if (op->ifindex != newop->ifindex)
  169: 		 return 0;
  170: 	     }
  171: 	   return 1;
  172: 	 }
  173:        else if (prefix_same (&rn->p, (struct prefix *) prefix))
  174: 	 return 1;
  175:      }
  176:   return 0;
  177: }
  178: 
  179: /* delete routes generated from AS-External routes if there is a inter/intra
  180:  * area route
  181:  */
  182: static void 
  183: ospf_route_delete_same_ext(struct route_table *external_routes,
  184:                      struct route_table *routes)
  185: {
  186:   struct route_node *rn,
  187:                     *ext_rn;
  188:   
  189:   if ( (external_routes == NULL) || (routes == NULL) )
  190:     return;
  191:   
  192:   /* Remove deleted routes */
  193:   for ( rn = route_top (routes); rn; rn = route_next (rn) )
  194:     {
  195:       if (rn && rn->info)
  196:         {
  197:           struct prefix_ipv4 *p = (struct prefix_ipv4 *)(&rn->p);
  198:           if ( (ext_rn = route_node_lookup (external_routes, (struct prefix *)p)) )
  199:             {
  200:               if (ext_rn->info)
  201:                 {
  202:                   ospf_zebra_delete (p, ext_rn->info);
  203:                   ospf_route_free( ext_rn->info);
  204:                   ext_rn->info = NULL;
  205:                 }
  206:               route_unlock_node (ext_rn);
  207:             }
  208:         }
  209:     }
  210: }
  211: 
  212: /* rt: Old, cmprt: New */
  213: static void
  214: ospf_route_delete_uniq (struct route_table *rt, struct route_table *cmprt)
  215: {
  216:   struct route_node *rn;
  217:   struct ospf_route *or;
  218: 
  219:   for (rn = route_top (rt); rn; rn = route_next (rn))
  220:     if ((or = rn->info) != NULL) 
  221:       if (or->path_type == OSPF_PATH_INTRA_AREA ||
  222: 	  or->path_type == OSPF_PATH_INTER_AREA)
  223: 	{
  224: 	  if (or->type == OSPF_DESTINATION_NETWORK)
  225: 	    {
  226: 	      if (! ospf_route_match_same (cmprt, 
  227: 					   (struct prefix_ipv4 *) &rn->p, or))
  228: 		ospf_zebra_delete ((struct prefix_ipv4 *) &rn->p, or);
  229: 	    }
  230: 	  else if (or->type == OSPF_DESTINATION_DISCARD)
  231: 	    if (! ospf_route_match_same (cmprt,
  232: 					 (struct prefix_ipv4 *) &rn->p, or))
  233: 	      ospf_zebra_delete_discard ((struct prefix_ipv4 *) &rn->p);
  234: 	}
  235: }
  236: 
  237: /* Install routes to table. */
  238: void
  239: ospf_route_install (struct ospf *ospf, struct route_table *rt)
  240: {
  241:   struct route_node *rn;
  242:   struct ospf_route *or;
  243: 
  244:   /* rt contains new routing table, new_table contains an old one.
  245:      updating pointers */
  246:   if (ospf->old_table)
  247:     ospf_route_table_free (ospf->old_table);
  248: 
  249:   ospf->old_table = ospf->new_table;
  250:   ospf->new_table = rt;
  251: 
  252:   /* Delete old routes. */
  253:   if (ospf->old_table)
  254:     ospf_route_delete_uniq (ospf->old_table, rt);
  255:   if (ospf->old_external_route)
  256:     ospf_route_delete_same_ext (ospf->old_external_route, rt);
  257: 
  258:   /* Install new routes. */
  259:   for (rn = route_top (rt); rn; rn = route_next (rn))
  260:     if ((or = rn->info) != NULL)
  261:       {
  262: 	if (or->type == OSPF_DESTINATION_NETWORK)
  263: 	  {
  264: 	    if (! ospf_route_match_same (ospf->old_table,
  265: 					 (struct prefix_ipv4 *)&rn->p, or))
  266: 	      ospf_zebra_add ((struct prefix_ipv4 *) &rn->p, or);
  267: 	  }
  268: 	else if (or->type == OSPF_DESTINATION_DISCARD)
  269: 	  if (! ospf_route_match_same (ospf->old_table,
  270: 				       (struct prefix_ipv4 *) &rn->p, or))
  271: 	    ospf_zebra_add_discard ((struct prefix_ipv4 *) &rn->p);
  272:       }
  273: }
  274: 
  275: static void
  276: ospf_intra_route_add (struct route_table *rt, struct vertex *v,
  277: 		      struct ospf_area *area)
  278: {
  279:   struct route_node *rn;
  280:   struct ospf_route *or;
  281:   struct prefix_ipv4 p;
  282:   struct ospf_path *path;
  283:   struct vertex_parent *parent;
  284:   struct listnode *node, *nnode;
  285: 
  286:   p.family = AF_INET;
  287:   p.prefix = v->id;
  288:   if (v->type == OSPF_VERTEX_ROUTER)
  289:     p.prefixlen = IPV4_MAX_BITLEN;
  290:   else
  291:     {
  292:       struct network_lsa *lsa = (struct network_lsa *) v->lsa;
  293:       p.prefixlen = ip_masklen (lsa->mask);
  294:     }
  295:   apply_mask_ipv4 (&p);
  296: 
  297:   rn = route_node_get (rt, (struct prefix *) &p);
  298:   if (rn->info)
  299:     {
  300:       zlog_warn ("Same routing information exists for %s", inet_ntoa (v->id));
  301:       route_unlock_node (rn);
  302:       return;
  303:     }
  304: 
  305:   or = ospf_route_new ();
  306: 
  307:   if (v->type == OSPF_VERTEX_NETWORK)
  308:     {
  309:       or->type = OSPF_DESTINATION_NETWORK;
  310: 
  311:       for (ALL_LIST_ELEMENTS (v->parents, node, nnode, parent))
  312:         {
  313:           path = ospf_path_new ();
  314:           path->nexthop = parent->nexthop->router;
  315:           listnode_add (or->paths, path);
  316:         }
  317:     }
  318:   else
  319:     or->type = OSPF_DESTINATION_ROUTER;
  320: 
  321:   or->id = v->id;
  322:   or->u.std.area_id = area->area_id;
  323:   or->u.std.external_routing= area->external_routing;
  324:   or->path_type = OSPF_PATH_INTRA_AREA;
  325:   or->cost = v->distance;
  326: 
  327:   rn->info = or;
  328: }
  329: 
  330: /* RFC2328 16.1. (4). For "router". */
  331: void
  332: ospf_intra_add_router (struct route_table *rt, struct vertex *v,
  333: 		       struct ospf_area *area)
  334: {
  335:   struct route_node *rn;
  336:   struct ospf_route *or;
  337:   struct prefix_ipv4 p;
  338:   struct router_lsa *lsa;
  339: 
  340:   if (IS_DEBUG_OSPF_EVENT)
  341:     zlog_debug ("ospf_intra_add_router: Start");
  342: 
  343:   lsa = (struct router_lsa *) v->lsa;
  344: 
  345:   if (IS_DEBUG_OSPF_EVENT)
  346:     zlog_debug ("ospf_intra_add_router: LS ID: %s",
  347: 	       inet_ntoa (lsa->header.id));
  348:   
  349:   if (!OSPF_IS_AREA_BACKBONE(area))
  350:     ospf_vl_up_check (area, lsa->header.id, v);
  351: 
  352:   if (!CHECK_FLAG (lsa->flags, ROUTER_LSA_SHORTCUT))
  353:     area->shortcut_capability = 0;
  354: 
  355:   /* If the newly added vertex is an area border router or AS boundary
  356:      router, a routing table entry is added whose destination type is
  357:      "router". */
  358:   if (! IS_ROUTER_LSA_BORDER (lsa) && ! IS_ROUTER_LSA_EXTERNAL (lsa))
  359:     {
  360:       if (IS_DEBUG_OSPF_EVENT)
  361: 	zlog_debug ("ospf_intra_add_router: "
  362: 		   "this router is neither ASBR nor ABR, skipping it");
  363:       return;
  364:     }
  365: 
  366:   /* Update ABR and ASBR count in this area. */
  367:   if (IS_ROUTER_LSA_BORDER (lsa))
  368:     area->abr_count++;
  369:   if (IS_ROUTER_LSA_EXTERNAL (lsa))
  370:     area->asbr_count++;
  371: 
  372:   /* The Options field found in the associated router-LSA is copied
  373:      into the routing table entry's Optional capabilities field. Call
  374:      the newly added vertex Router X. */
  375:   or = ospf_route_new ();
  376: 
  377:   or->id = v->id;
  378:   or->u.std.area_id = area->area_id;
  379:   or->u.std.external_routing = area->external_routing;
  380:   or->path_type = OSPF_PATH_INTRA_AREA;
  381:   or->cost = v->distance;
  382:   or->type = OSPF_DESTINATION_ROUTER;
  383:   or->u.std.origin = (struct lsa_header *) lsa;
  384:   or->u.std.options = lsa->header.options;
  385:   or->u.std.flags = lsa->flags;
  386: 
  387:   /* If Router X is the endpoint of one of the calculating router's
  388:      virtual links, and the virtual link uses Area A as Transit area:
  389:      the virtual link is declared up, the IP address of the virtual
  390:      interface is set to the IP address of the outgoing interface
  391:      calculated above for Router X, and the virtual neighbor's IP
  392:      address is set to Router X's interface address (contained in
  393:      Router X's router-LSA) that points back to the root of the
  394:      shortest- path tree; equivalently, this is the interface that
  395:      points back to Router X's parent vertex on the shortest-path tree
  396:      (similar to the calculation in Section 16.1.1). */
  397: 
  398:   p.family = AF_INET;
  399:   p.prefix = v->id;
  400:   p.prefixlen = IPV4_MAX_BITLEN;
  401: 
  402:   if (IS_DEBUG_OSPF_EVENT)
  403:     zlog_debug ("ospf_intra_add_router: talking about %s/%d",
  404: 	       inet_ntoa (p.prefix), p.prefixlen);
  405: 
  406:   rn = route_node_get (rt, (struct prefix *) &p);
  407: 
  408:   /* Note that we keep all routes to ABRs and ASBRs, not only the best */
  409:   if (rn->info == NULL)
  410:     rn->info = list_new ();
  411:   else
  412:     route_unlock_node (rn);
  413: 
  414:   ospf_route_copy_nexthops_from_vertex (or, v);
  415: 
  416:   listnode_add (rn->info, or);
  417: 
  418:   if (IS_DEBUG_OSPF_EVENT)
  419:     zlog_debug ("ospf_intra_add_router: Stop");
  420: }
  421: 
  422: /* RFC2328 16.1. (4).  For transit network. */
  423: void
  424: ospf_intra_add_transit (struct route_table *rt, struct vertex *v,
  425: 			struct ospf_area *area)
  426: {
  427:   struct route_node *rn;
  428:   struct ospf_route *or;
  429:   struct prefix_ipv4 p;
  430:   struct network_lsa *lsa;
  431: 
  432:   lsa = (struct network_lsa*) v->lsa;
  433: 
  434:   /* If the newly added vertex is a transit network, the routing table
  435:      entry for the network is located.  The entry's Destination ID is
  436:      the IP network number, which can be obtained by masking the
  437:      Vertex ID (Link State ID) with its associated subnet mask (found
  438:      in the body of the associated network-LSA). */
  439:   p.family = AF_INET;
  440:   p.prefix = v->id;
  441:   p.prefixlen = ip_masklen (lsa->mask);
  442:   apply_mask_ipv4 (&p);
  443: 
  444:   rn = route_node_get (rt, (struct prefix *) &p);
  445: 
  446:   /* If the routing table entry already exists (i.e., there is already
  447:      an intra-area route to the destination installed in the routing
  448:      table), multiple vertices have mapped to the same IP network.
  449:      For example, this can occur when a new Designated Router is being
  450:      established.  In this case, the current routing table entry
  451:      should be overwritten if and only if the newly found path is just
  452:      as short and the current routing table entry's Link State Origin
  453:      has a smaller Link State ID than the newly added vertex' LSA. */
  454:   if (rn->info)
  455:     {
  456:       struct ospf_route *cur_or;
  457: 
  458:       route_unlock_node (rn);
  459:       cur_or = rn->info;
  460: 
  461:       if (v->distance > cur_or->cost ||
  462:           IPV4_ADDR_CMP (&cur_or->u.std.origin->id, &lsa->header.id) > 0)
  463: 	return;
  464:       
  465:       ospf_route_free (rn->info);
  466:     }
  467: 
  468:   or = ospf_route_new ();
  469: 
  470:   or->id = v->id;
  471:   or->u.std.area_id = area->area_id;
  472:   or->u.std.external_routing = area->external_routing;
  473:   or->path_type = OSPF_PATH_INTRA_AREA;
  474:   or->cost = v->distance;
  475:   or->type = OSPF_DESTINATION_NETWORK;
  476:   or->u.std.origin = (struct lsa_header *) lsa;
  477: 
  478:   ospf_route_copy_nexthops_from_vertex (or, v);
  479:   
  480:   rn->info = or;
  481: }
  482: 
  483: /* RFC2328 16.1. second stage. */
  484: void
  485: ospf_intra_add_stub (struct route_table *rt, struct router_lsa_link *link,
  486: 		     struct vertex *v, struct ospf_area *area,
  487: 		     int parent_is_root)
  488: {
  489:   u_int32_t cost;
  490:   struct route_node *rn;
  491:   struct ospf_route *or;
  492:   struct prefix_ipv4 p;
  493:   struct router_lsa *lsa;
  494:   struct ospf_interface *oi;
  495:   struct ospf_path *path;
  496: 
  497:   if (IS_DEBUG_OSPF_EVENT)
  498:     zlog_debug ("ospf_intra_add_stub(): Start");
  499: 
  500:   lsa = (struct router_lsa *) v->lsa;
  501: 
  502:   p.family = AF_INET;
  503:   p.prefix = link->link_id;
  504:   p.prefixlen = ip_masklen (link->link_data);
  505:   apply_mask_ipv4 (&p);
  506: 
  507:   if (IS_DEBUG_OSPF_EVENT)
  508:     zlog_debug ("ospf_intra_add_stub(): processing route to %s/%d",  
  509: 	       inet_ntoa (p.prefix), p.prefixlen);
  510: 
  511:   /* (1) Calculate the distance D of stub network from the root.  D is
  512:      equal to the distance from the root to the router vertex
  513:      (calculated in stage 1), plus the stub network link's advertised
  514:      cost. */
  515:   cost = v->distance + ntohs (link->m[0].metric);
  516: 
  517:   if (IS_DEBUG_OSPF_EVENT)
  518:     zlog_debug ("ospf_intra_add_stub(): calculated cost is %d + %d = %d", 
  519: 	       v->distance, ntohs(link->m[0].metric), cost);
  520:   
  521:   /* PtP links with /32 masks adds host routes to remote, directly
  522:    * connected hosts, see RFC 2328, 12.4.1.1, Option 1.
  523:    * Such routes can just be ignored for the sake of tidyness.
  524:    */
  525:   if (parent_is_root && link->link_data.s_addr == 0xffffffff &&
  526:       ospf_if_lookup_by_local_addr (area->ospf, NULL, link->link_id))
  527:     {
  528:       if (IS_DEBUG_OSPF_EVENT)
  529:         zlog_debug ("%s: ignoring host route %s/32 to self.",
  530:                     __func__, inet_ntoa (link->link_id));
  531:       return;
  532:     }
  533:   
  534:   rn = route_node_get (rt, (struct prefix *) &p);
  535: 
  536:   /* Lookup current routing table. */
  537:   if (rn->info)
  538:     {
  539:       struct ospf_route *cur_or;
  540: 
  541:       route_unlock_node (rn);
  542: 
  543:       cur_or = rn->info;
  544: 
  545:       if (IS_DEBUG_OSPF_EVENT)
  546: 	zlog_debug ("ospf_intra_add_stub(): "
  547: 		   "another route to the same prefix found with cost %u",
  548: 		   cur_or->cost);
  549: 
  550:       /* Compare this distance to the current best cost to the stub
  551: 	 network.  This is done by looking up the stub network's
  552: 	 current routing table entry.  If the calculated distance D is
  553: 	 larger, go on to examine the next stub network link in the
  554: 	 LSA. */
  555:       if (cost > cur_or->cost)
  556: 	{
  557: 	  if (IS_DEBUG_OSPF_EVENT)
  558: 	    zlog_debug ("ospf_intra_add_stub(): old route is better, exit");
  559: 	  return;
  560: 	}
  561: 
  562:       /* (2) If this step is reached, the stub network's routing table
  563: 	 entry must be updated.  Calculate the set of next hops that
  564: 	 would result from using the stub network link.  This
  565: 	 calculation is shown in Section 16.1.1; input to this
  566: 	 calculation is the destination (the stub network) and the
  567: 	 parent vertex (the router vertex). If the distance D is the
  568: 	 same as the current routing table cost, simply add this set
  569: 	 of next hops to the routing table entry's list of next hops.
  570: 	 In this case, the routing table already has a Link State
  571: 	 Origin.  If this Link State Origin is a router-LSA whose Link
  572: 	 State ID is smaller than V's Router ID, reset the Link State
  573: 	 Origin to V's router-LSA. */
  574: 
  575:       if (cost == cur_or->cost)
  576: 	{
  577: 	  if (IS_DEBUG_OSPF_EVENT)
  578: 	    zlog_debug ("ospf_intra_add_stub(): routes are equal, merge");
  579: 
  580: 	  ospf_route_copy_nexthops_from_vertex (cur_or, v);
  581: 
  582: 	  if (IPV4_ADDR_CMP (&cur_or->u.std.origin->id, &lsa->header.id) < 0)
  583: 	    cur_or->u.std.origin = (struct lsa_header *) lsa;
  584: 	  return;
  585: 	}
  586: 
  587:       /* Otherwise D is smaller than the routing table cost.
  588: 	 Overwrite the current routing table entry by setting the
  589: 	 routing table entry's cost to D, and by setting the entry's
  590: 	 list of next hops to the newly calculated set.  Set the
  591: 	 routing table entry's Link State Origin to V's router-LSA.
  592: 	 Then go on to examine the next stub network link. */
  593: 
  594:       if (cost < cur_or->cost)
  595: 	{
  596: 	  if (IS_DEBUG_OSPF_EVENT)
  597: 	    zlog_debug ("ospf_intra_add_stub(): new route is better, set it");
  598: 
  599: 	  cur_or->cost = cost;
  600: 
  601: 	  list_delete_all_node (cur_or->paths);
  602: 
  603: 	  ospf_route_copy_nexthops_from_vertex (cur_or, v);
  604: 
  605: 	  cur_or->u.std.origin = (struct lsa_header *) lsa;
  606: 	  return;
  607: 	}
  608:     }
  609: 
  610:   if (IS_DEBUG_OSPF_EVENT)
  611:     zlog_debug ("ospf_intra_add_stub(): installing new route");
  612: 
  613:   or = ospf_route_new ();
  614: 
  615:   or->id = v->id;
  616:   or->u.std.area_id = area->area_id;
  617:   or->u.std.external_routing = area->external_routing;
  618:   or->path_type = OSPF_PATH_INTRA_AREA;
  619:   or->cost = cost;
  620:   or->type = OSPF_DESTINATION_NETWORK;
  621:   or->u.std.origin = (struct lsa_header *) lsa;
  622: 
  623:   /* Nexthop is depend on connection type. */
  624:   if (v != area->spf)
  625:     {
  626:       if (IS_DEBUG_OSPF_EVENT)
  627: 	zlog_debug ("ospf_intra_add_stub(): this network is on remote router");
  628:       ospf_route_copy_nexthops_from_vertex (or, v);
  629:     }
  630:   else
  631:     {
  632:       if (IS_DEBUG_OSPF_EVENT)
  633: 	zlog_debug ("ospf_intra_add_stub(): this network is on this router");
  634: 
  635:       if ((oi = ospf_if_lookup_by_prefix (area->ospf, &p)))
  636: 	{
  637: 	  if (IS_DEBUG_OSPF_EVENT)
  638: 	    zlog_debug ("ospf_intra_add_stub(): the interface is %s",
  639: 		       IF_NAME (oi));
  640: 
  641: 	  path = ospf_path_new ();
  642: 	  path->nexthop.s_addr = 0;
  643: 	  path->ifindex = oi->ifp->ifindex;
  644: 	  listnode_add (or->paths, path);
  645: 	}
  646:       else
  647: 	{
  648: 	  if (IS_DEBUG_OSPF_EVENT)
  649: 	    zlog_debug ("ospf_intra_add_stub(): where's the interface ?");
  650: 	}
  651:     }
  652: 
  653:   rn->info = or;
  654: 
  655:   if (IS_DEBUG_OSPF_EVENT)
  656:     zlog_debug("ospf_intra_add_stub(): Stop");
  657: }
  658: 
  659: const char *ospf_path_type_str[] =
  660: {
  661:   "unknown-type",
  662:   "intra-area",
  663:   "inter-area",
  664:   "type1-external",
  665:   "type2-external"
  666: };
  667: 
  668: void
  669: ospf_route_table_dump (struct route_table *rt)
  670: {
  671:   struct route_node *rn;
  672:   struct ospf_route *or;
  673:   char buf1[BUFSIZ];
  674:   char buf2[BUFSIZ];
  675:   struct listnode *pnode;
  676:   struct ospf_path *path;
  677: 
  678: #if 0
  679:   zlog_debug ("Type   Dest   Area   Path	 Type	 Cost	Next	 Adv.");
  680:   zlog_debug ("					Hop(s)	 Router(s)");
  681: #endif /* 0 */
  682: 
  683:   zlog_debug ("========== OSPF routing table ==========");
  684:   for (rn = route_top (rt); rn; rn = route_next (rn))
  685:     if ((or = rn->info) != NULL)
  686:       {
  687:         if (or->type == OSPF_DESTINATION_NETWORK)
  688: 	  {
  689: 	    zlog_debug ("N %s/%d\t%s\t%s\t%d", 
  690: 		       inet_ntop (AF_INET, &rn->p.u.prefix4, buf1, BUFSIZ),
  691: 		       rn->p.prefixlen,
  692: 		       inet_ntop (AF_INET, &or->u.std.area_id, buf2,
  693: 				  BUFSIZ),
  694: 		       ospf_path_type_str[or->path_type],
  695: 		       or->cost);
  696: 	    for (ALL_LIST_ELEMENTS_RO (or->paths, pnode, path))
  697:               zlog_debug ("  -> %s", inet_ntoa (path->nexthop));
  698: 	  }
  699:         else
  700: 	  zlog_debug ("R %s\t%s\t%s\t%d", 
  701: 		     inet_ntop (AF_INET, &rn->p.u.prefix4, buf1, BUFSIZ),
  702: 		     inet_ntop (AF_INET, &or->u.std.area_id, buf2,
  703: 				BUFSIZ),
  704: 		     ospf_path_type_str[or->path_type],
  705: 		     or->cost);
  706:       }
  707:   zlog_debug ("========================================");
  708: }
  709: 
  710: /* This is 16.4.1 implementation.
  711:    o Intra-area paths using non-backbone areas are always the most preferred.
  712:    o The other paths, intra-area backbone paths and inter-area paths,
  713:      are of equal preference. */
  714: static int
  715: ospf_asbr_route_cmp (struct ospf *ospf, struct ospf_route *r1,
  716: 		     struct ospf_route *r2)
  717: {
  718:   u_char r1_type, r2_type;
  719: 
  720:   r1_type = r1->path_type;
  721:   r2_type = r2->path_type;
  722: 
  723:   /* r1/r2 itself is backbone, and it's Inter-area path. */
  724:   if (OSPF_IS_AREA_ID_BACKBONE (r1->u.std.area_id))
  725:     r1_type = OSPF_PATH_INTER_AREA;
  726:   if (OSPF_IS_AREA_ID_BACKBONE (r2->u.std.area_id))
  727:     r2_type = OSPF_PATH_INTER_AREA;
  728: 
  729:   return (r1_type - r2_type);
  730: }
  731: 
  732: /* Compare two routes.
  733:  ret <  0 -- r1 is better.
  734:  ret == 0 -- r1 and r2 are the same.
  735:  ret >  0 -- r2 is better. */
  736: int
  737: ospf_route_cmp (struct ospf *ospf, struct ospf_route *r1,
  738: 		struct ospf_route *r2)
  739: {
  740:   int ret = 0;
  741: 
  742:   /* Path types of r1 and r2 are not the same. */
  743:   if ((ret = (r1->path_type - r2->path_type)))
  744:     return ret;
  745: 
  746:   if (IS_DEBUG_OSPF_EVENT)
  747:     zlog_debug ("Route[Compare]: Path types are the same.");
  748:   /* Path types are the same, compare any cost. */
  749:   switch (r1->path_type)
  750:     {
  751:     case OSPF_PATH_INTRA_AREA:
  752:     case OSPF_PATH_INTER_AREA:
  753:       break;
  754:     case OSPF_PATH_TYPE1_EXTERNAL:
  755:       if (!CHECK_FLAG (ospf->config, OSPF_RFC1583_COMPATIBLE))
  756: 	{
  757: 	  ret = ospf_asbr_route_cmp (ospf, r1->u.ext.asbr, r2->u.ext.asbr);
  758: 	  if (ret != 0)
  759: 	    return ret;
  760: 	}
  761:       break;
  762:     case OSPF_PATH_TYPE2_EXTERNAL:
  763:       if ((ret = (r1->u.ext.type2_cost - r2->u.ext.type2_cost)))
  764: 	return ret;
  765: 
  766:       if (!CHECK_FLAG (ospf->config, OSPF_RFC1583_COMPATIBLE))
  767: 	{
  768: 	  ret = ospf_asbr_route_cmp (ospf, r1->u.ext.asbr, r2->u.ext.asbr);
  769: 	  if (ret != 0)
  770: 	    return ret;
  771: 	}
  772:       break;
  773:     }      
  774: 
  775:   /* Anyway, compare the costs. */
  776:   return (r1->cost - r2->cost);
  777: }
  778: 
  779: static int
  780: ospf_path_exist (struct list *plist, struct in_addr nexthop,
  781: 		 struct ospf_interface *oi)
  782: {
  783:   struct listnode *node, *nnode;
  784:   struct ospf_path *path;
  785: 
  786:   for (ALL_LIST_ELEMENTS (plist, node, nnode, path))
  787:     if (IPV4_ADDR_SAME (&path->nexthop, &nexthop) &&
  788: 	path->ifindex == oi->ifp->ifindex)
  789:       return 1;
  790: 
  791:   return 0;
  792: }
  793: 
  794: void
  795: ospf_route_copy_nexthops_from_vertex (struct ospf_route *to,
  796: 				      struct vertex *v)
  797: {
  798:   struct listnode *node;
  799:   struct ospf_path *path;
  800:   struct vertex_nexthop *nexthop;
  801:   struct vertex_parent *vp;
  802: 
  803:   assert (to->paths);
  804: 
  805:   for (ALL_LIST_ELEMENTS_RO (v->parents, node, vp))
  806:     {
  807:       nexthop = vp->nexthop;
  808:       
  809:       if (nexthop->oi != NULL) 
  810: 	{
  811: 	  if (! ospf_path_exist (to->paths, nexthop->router, nexthop->oi))
  812: 	    {
  813: 	      path = ospf_path_new ();
  814: 	      path->nexthop = nexthop->router;
  815: 	      path->ifindex = nexthop->oi->ifp->ifindex;
  816: 	      listnode_add (to->paths, path);
  817: 	    }
  818: 	}
  819:     }
  820: }
  821: 
  822: struct ospf_path *
  823: ospf_path_lookup (struct list *plist, struct ospf_path *path)
  824: {
  825:   struct listnode *node;
  826:   struct ospf_path *op;
  827: 
  828:   for (ALL_LIST_ELEMENTS_RO (plist, node, op))
  829:   {
  830:     if (!IPV4_ADDR_SAME (&op->nexthop, &path->nexthop))
  831:       continue;
  832:     if (!IPV4_ADDR_SAME (&op->adv_router, &path->adv_router))
  833:       continue;
  834:     if (op->ifindex != path->ifindex)
  835:       continue;
  836:     return op;
  837:   }
  838:   return NULL;
  839: }
  840: 
  841: void
  842: ospf_route_copy_nexthops (struct ospf_route *to, struct list *from)
  843: {
  844:   struct listnode *node, *nnode;
  845:   struct ospf_path *path;
  846: 
  847:   assert (to->paths);
  848: 
  849:   for (ALL_LIST_ELEMENTS (from, node, nnode, path))
  850:     /* The same routes are just discarded. */
  851:     if (!ospf_path_lookup (to->paths, path))
  852:       listnode_add (to->paths, ospf_path_dup (path));
  853: }
  854: 
  855: void
  856: ospf_route_subst_nexthops (struct ospf_route *to, struct list *from)
  857: {
  858: 
  859:   list_delete_all_node (to->paths);
  860:   ospf_route_copy_nexthops (to, from);
  861: }
  862: 
  863: void
  864: ospf_route_subst (struct route_node *rn, struct ospf_route *new_or,
  865: 		  struct ospf_route *over)
  866: {
  867:   route_lock_node (rn);
  868:   ospf_route_free (rn->info);
  869: 
  870:   ospf_route_copy_nexthops (new_or, over->paths);
  871:   rn->info = new_or;
  872:   route_unlock_node (rn);
  873: }
  874: 
  875: void
  876: ospf_route_add (struct route_table *rt, struct prefix_ipv4 *p,
  877: 		struct ospf_route *new_or, struct ospf_route *over)
  878: {
  879:   struct route_node *rn;
  880: 
  881:   rn = route_node_get (rt, (struct prefix *) p);
  882: 
  883:   ospf_route_copy_nexthops (new_or, over->paths);
  884: 
  885:   if (rn->info)
  886:     {
  887:       if (IS_DEBUG_OSPF_EVENT)
  888: 	zlog_debug ("ospf_route_add(): something's wrong !");
  889:       route_unlock_node (rn);
  890:       return;
  891:     }
  892: 
  893:   rn->info = new_or;
  894: }
  895: 
  896: void
  897: ospf_prune_unreachable_networks (struct route_table *rt)
  898: {
  899:   struct route_node *rn, *next;
  900:   struct ospf_route *or;
  901: 
  902:   if (IS_DEBUG_OSPF_EVENT)
  903:     zlog_debug ("Pruning unreachable networks");
  904: 
  905:   for (rn = route_top (rt); rn; rn = next)
  906:     {
  907:       next = route_next (rn);
  908:       if (rn->info != NULL)
  909: 	{
  910: 	  or = rn->info;
  911: 	  if (listcount (or->paths) == 0)
  912: 	    {
  913: 	      if (IS_DEBUG_OSPF_EVENT)
  914: 		zlog_debug ("Pruning route to %s/%d",
  915: 			   inet_ntoa (rn->p.u.prefix4), rn->p.prefixlen);
  916: 
  917: 	      ospf_route_free (or);
  918: 	      rn->info = NULL;
  919: 	      route_unlock_node (rn);
  920: 	    }
  921: 	}
  922:     }
  923: }
  924: 
  925: void
  926: ospf_prune_unreachable_routers (struct route_table *rtrs)
  927: {
  928:   struct route_node *rn, *next;
  929:   struct ospf_route *or;
  930:   struct listnode *node, *nnode;
  931:   struct list *paths;
  932: 
  933:   if (IS_DEBUG_OSPF_EVENT)
  934:     zlog_debug ("Pruning unreachable routers");
  935: 
  936:   for (rn = route_top (rtrs); rn; rn = next)
  937:     {
  938:       next = route_next (rn);
  939:       if ((paths = rn->info) == NULL)
  940: 	continue;
  941: 
  942:       for (ALL_LIST_ELEMENTS (paths, node, nnode, or))
  943: 	{
  944: 	  if (listcount (or->paths) == 0)
  945: 	    {
  946: 	      if (IS_DEBUG_OSPF_EVENT)
  947: 		{
  948: 		  zlog_debug ("Pruning route to rtr %s",
  949: 			     inet_ntoa (rn->p.u.prefix4));
  950: 		  zlog_debug ("               via area %s",
  951: 			     inet_ntoa (or->u.std.area_id));
  952: 		}
  953: 
  954: 	      listnode_delete (paths, or);
  955: 	      ospf_route_free (or);
  956: 	    }
  957: 	}
  958: 
  959:       if (listcount (paths) == 0)
  960: 	{
  961: 	  if (IS_DEBUG_OSPF_EVENT)
  962: 	    zlog_debug ("Pruning router node %s", inet_ntoa (rn->p.u.prefix4));
  963: 
  964: 	  list_delete (paths);
  965: 	  rn->info = NULL;
  966: 	  route_unlock_node (rn);
  967: 	}
  968:     }
  969: }
  970: 
  971: int
  972: ospf_add_discard_route (struct route_table *rt, struct ospf_area *area,
  973: 			struct prefix_ipv4 *p)
  974: {
  975:   struct route_node *rn;
  976:   struct ospf_route *or, *new_or;
  977: 
  978:   rn = route_node_get (rt, (struct prefix *) p);
  979: 
  980:   if (rn == NULL)
  981:     {
  982:       if (IS_DEBUG_OSPF_EVENT)
  983: 	zlog_debug ("ospf_add_discard_route(): router installation error");
  984:       return 0;
  985:     }
  986: 
  987:   if (rn->info) /* If the route to the same destination is found */
  988:     {
  989:       route_unlock_node (rn);
  990: 
  991:       or = rn->info;
  992: 
  993:       if (or->path_type == OSPF_PATH_INTRA_AREA)
  994: 	{
  995: 	  if (IS_DEBUG_OSPF_EVENT)
  996: 	    zlog_debug ("ospf_add_discard_route(): "
  997: 		       "an intra-area route exists");
  998: 	  return 0;
  999: 	}
 1000: 
 1001:       if (or->type == OSPF_DESTINATION_DISCARD)
 1002: 	{
 1003: 	  if (IS_DEBUG_OSPF_EVENT)
 1004: 	    zlog_debug ("ospf_add_discard_route(): "
 1005: 		       "discard entry already installed");
 1006: 	  return 0;
 1007: 	}
 1008: 
 1009:       ospf_route_free (rn->info);
 1010:   }
 1011: 
 1012:   new_or = ospf_route_new ();
 1013:   new_or->type = OSPF_DESTINATION_DISCARD;
 1014:   new_or->id.s_addr = 0;
 1015:   new_or->cost = 0;
 1016:   new_or->u.std.area_id = area->area_id;
 1017:   new_or->u.std.external_routing = area->external_routing;
 1018:   new_or->path_type = OSPF_PATH_INTER_AREA;
 1019:   rn->info = new_or;
 1020: 
 1021:   ospf_zebra_add_discard (p);
 1022: 
 1023:   return 1;
 1024: }
 1025: 
 1026: void
 1027: ospf_delete_discard_route (struct prefix_ipv4 *p)
 1028: {
 1029:   ospf_zebra_delete_discard(p);
 1030: }
 1031: 

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