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