Annotation of embedaddon/quagga/ospfd/ospf_route.c, revision 1.1.1.1
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:
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>