Line data Source code
1 : /*
2 : * OSPF AS external route calculation.
3 : * Copyright (C) 1999, 2000 Alex Zinin, 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 along
18 : * with this program; see the file COPYING; if not, write to the Free Software
19 : * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20 : */
21 :
22 : #include <zebra.h>
23 :
24 : #include "thread.h"
25 : #include "memory.h"
26 : #include "hash.h"
27 : #include "linklist.h"
28 : #include "prefix.h"
29 : #include "if.h"
30 : #include "table.h"
31 : #include "vty.h"
32 : #include "log.h"
33 :
34 : #include "ospfd/ospfd.h"
35 : #include "ospfd/ospf_interface.h"
36 : #include "ospfd/ospf_ism.h"
37 : #include "ospfd/ospf_asbr.h"
38 : #include "ospfd/ospf_lsa.h"
39 : #include "ospfd/ospf_lsdb.h"
40 : #include "ospfd/ospf_neighbor.h"
41 : #include "ospfd/ospf_nsm.h"
42 : #include "ospfd/ospf_spf.h"
43 : #include "ospfd/ospf_route.h"
44 : #include "ospfd/ospf_ase.h"
45 : #include "ospfd/ospf_zebra.h"
46 : #include "ospfd/ospf_dump.h"
47 :
48 53 : struct ospf_route *ospf_find_asbr_route(struct ospf *ospf,
49 : struct route_table *rtrs,
50 : struct prefix_ipv4 *asbr)
51 : {
52 53 : struct route_node *rn;
53 53 : struct ospf_route * or, *best = NULL;
54 53 : struct listnode *node;
55 53 : struct list *chosen;
56 :
57 : /* Sanity check. */
58 53 : if (rtrs == NULL)
59 : return NULL;
60 :
61 53 : rn = route_node_lookup(rtrs, (struct prefix *)asbr);
62 53 : if (!rn)
63 : return NULL;
64 :
65 21 : route_unlock_node(rn);
66 :
67 21 : chosen = list_new();
68 :
69 : /* First try to find intra-area non-bb paths. */
70 21 : if (!CHECK_FLAG(ospf->config, OSPF_RFC1583_COMPATIBLE))
71 63 : for (ALL_LIST_ELEMENTS_RO((struct list *)rn->info, node, or))
72 21 : if (or->cost < OSPF_LS_INFINITY)
73 21 : if (!OSPF_IS_AREA_ID_BACKBONE(or->u.std.area_id)
74 9 : &&
75 9 : or->path_type == OSPF_PATH_INTRA_AREA)
76 7 : listnode_add(chosen, or);
77 :
78 : /* If none is found -- look through all. */
79 21 : if (listcount(chosen) == 0) {
80 14 : list_delete(&chosen);
81 14 : chosen = rn->info;
82 : }
83 :
84 : /* Now find the route with least cost. */
85 63 : for (ALL_LIST_ELEMENTS_RO(chosen, node, or))
86 21 : if (or->cost < OSPF_LS_INFINITY) {
87 21 : if (best == NULL)
88 : best = or ;
89 0 : else if (best->cost > or->cost)
90 : best = or ;
91 0 : else if (best->cost ==
92 : or->cost
93 0 : && IPV4_ADDR_CMP(
94 : &best->u.std.area_id,
95 : & or->u.std.area_id)
96 : < 0)
97 21 : best = or ;
98 : }
99 :
100 21 : if (chosen != rn->info)
101 7 : list_delete(&chosen);
102 :
103 : return best;
104 : }
105 :
106 0 : struct ospf_route *ospf_find_asbr_route_through_area(struct route_table *rtrs,
107 : struct prefix_ipv4 *asbr,
108 : struct ospf_area *area)
109 : {
110 0 : struct route_node *rn;
111 :
112 : /* Sanity check. */
113 0 : if (rtrs == NULL)
114 : return NULL;
115 :
116 0 : rn = route_node_lookup(rtrs, (struct prefix *)asbr);
117 :
118 0 : if (rn) {
119 0 : struct listnode *node;
120 0 : struct ospf_route * or ;
121 :
122 0 : route_unlock_node(rn);
123 :
124 0 : for (ALL_LIST_ELEMENTS_RO((struct list *)rn->info, node, or))
125 0 : if (IPV4_ADDR_SAME(& or->u.std.area_id, &area->area_id))
126 0 : return or ;
127 : }
128 :
129 : return NULL;
130 : }
131 :
132 0 : static void ospf_ase_complete_direct_routes(struct ospf_route *ro,
133 : struct in_addr nexthop)
134 : {
135 0 : struct listnode *node;
136 0 : struct ospf_path *op;
137 :
138 0 : for (ALL_LIST_ELEMENTS_RO(ro->paths, node, op))
139 0 : if (op->nexthop.s_addr == INADDR_ANY)
140 0 : op->nexthop.s_addr = nexthop.s_addr;
141 0 : }
142 :
143 0 : static int ospf_ase_forward_address_check(struct ospf *ospf,
144 : struct in_addr fwd_addr)
145 : {
146 0 : struct listnode *ifn;
147 0 : struct ospf_interface *oi;
148 :
149 0 : for (ALL_LIST_ELEMENTS_RO(ospf->oiflist, ifn, oi))
150 0 : if (if_is_operative(oi->ifp))
151 0 : if (oi->type != OSPF_IFTYPE_VIRTUALLINK)
152 0 : if (IPV4_ADDR_SAME(&oi->address->u.prefix4,
153 : &fwd_addr))
154 : return 0;
155 :
156 : return 1;
157 : }
158 :
159 : static struct ospf_route *
160 16 : ospf_ase_calculate_new_route(struct ospf_lsa *lsa,
161 : struct ospf_route *asbr_route, uint32_t metric)
162 : {
163 16 : struct as_external_lsa *al;
164 16 : struct ospf_route *new;
165 :
166 16 : al = (struct as_external_lsa *)lsa->data;
167 :
168 16 : new = ospf_route_new();
169 :
170 : /* Set redistributed type -- does make sense? */
171 : /* new->type = type; */
172 16 : new->id = al->header.id;
173 16 : new->mask = al->mask;
174 :
175 16 : if (!IS_EXTERNAL_METRIC(al->e[0].tos)) {
176 0 : if (IS_DEBUG_OSPF(lsa, LSA))
177 0 : zlog_debug("Route[External]: type-1 created.");
178 0 : new->path_type = OSPF_PATH_TYPE1_EXTERNAL;
179 0 : new->cost = asbr_route->cost + metric; /* X + Y */
180 : } else {
181 16 : if (IS_DEBUG_OSPF(lsa, LSA))
182 0 : zlog_debug("Route[External]: type-2 created.");
183 16 : new->path_type = OSPF_PATH_TYPE2_EXTERNAL;
184 16 : new->cost = asbr_route->cost; /* X */
185 16 : new->u.ext.type2_cost = metric; /* Y */
186 : }
187 :
188 16 : new->type = OSPF_DESTINATION_NETWORK;
189 16 : new->u.ext.origin = lsa;
190 16 : new->u.ext.tag = ntohl(al->e[0].route_tag);
191 16 : new->u.ext.asbr = asbr_route;
192 :
193 16 : assert(new != asbr_route);
194 :
195 16 : return new;
196 : }
197 :
198 : #define OSPF_ASE_CALC_INTERVAL 1
199 :
200 68 : int ospf_ase_calculate_route(struct ospf *ospf, struct ospf_lsa *lsa)
201 : {
202 68 : uint32_t metric;
203 68 : struct as_external_lsa *al;
204 68 : struct ospf_route *asbr_route;
205 68 : struct prefix_ipv4 asbr, p;
206 68 : struct route_node *rn;
207 68 : struct ospf_route *new, * or ;
208 68 : int ret;
209 :
210 68 : assert(lsa);
211 68 : al = (struct as_external_lsa *)lsa->data;
212 :
213 68 : if (lsa->data->type == OSPF_AS_NSSA_LSA)
214 0 : if (IS_DEBUG_OSPF_NSSA)
215 0 : zlog_debug("%s: Processing Type-7", __func__);
216 :
217 : /* Stay away from any Local Translated Type-7 LSAs */
218 68 : if (CHECK_FLAG(lsa->flags, OSPF_LSA_LOCAL_XLT)) {
219 0 : if (IS_DEBUG_OSPF_NSSA)
220 0 : zlog_debug("%s: Rejecting Local Xlt'd", __func__);
221 0 : return 0;
222 : }
223 :
224 68 : if (IS_DEBUG_OSPF(lsa, LSA)) {
225 0 : zlog_debug(
226 : "Route[External]: Calculate AS-external-LSA to %pI4/%d adv_router %pI4",
227 : &al->header.id, ip_masklen(al->mask),
228 : &al->header.adv_router);
229 : }
230 :
231 : /* (1) If the cost specified by the LSA is LSInfinity, or if the
232 : LSA's LS age is equal to MaxAge, then examine the next LSA. */
233 68 : if ((metric = GET_METRIC(al->e[0].metric)) >= OSPF_LS_INFINITY) {
234 0 : if (IS_DEBUG_OSPF(lsa, LSA))
235 0 : zlog_debug(
236 : "Route[External]: Metric is OSPF_LS_INFINITY");
237 0 : return 0;
238 : }
239 68 : if (IS_LSA_MAXAGE(lsa)) {
240 2 : if (IS_DEBUG_OSPF(lsa, LSA))
241 0 : zlog_debug(
242 : "Route[External]: AS-external-LSA is MAXAGE");
243 2 : return 0;
244 : }
245 :
246 : /* (2) If the LSA was originated by the calculating router itself,
247 : examine the next LSA. */
248 66 : if (IS_LSA_SELF(lsa)) {
249 18 : if (IS_DEBUG_OSPF(lsa, LSA))
250 0 : zlog_debug(
251 : "Route[External]: AS-external-LSA is self originated");
252 18 : return 0;
253 : }
254 :
255 : /* (3) Call the destination described by the LSA N. N's address is
256 : obtained by masking the LSA's Link State ID with the
257 : network/subnet mask contained in the body of the LSA. Look
258 : up the routing table entries (potentially one per attached
259 : area) for the AS boundary router (ASBR) that originated the
260 : LSA. If no entries exist for router ASBR (i.e., ASBR is
261 : unreachable), do nothing with this LSA and consider the next
262 : in the list. */
263 :
264 48 : asbr.family = AF_INET;
265 48 : asbr.prefix = al->header.adv_router;
266 48 : asbr.prefixlen = IPV4_MAX_BITLEN;
267 48 : apply_mask_ipv4(&asbr);
268 :
269 48 : asbr_route = ospf_find_asbr_route(ospf, ospf->new_rtrs, &asbr);
270 48 : if (asbr_route == NULL) {
271 32 : if (IS_DEBUG_OSPF(lsa, LSA))
272 0 : zlog_debug(
273 : "Route[External]: Can't find originating ASBR route");
274 32 : return 0;
275 : }
276 16 : if (!(asbr_route->u.std.flags & ROUTER_LSA_EXTERNAL)) {
277 0 : if (IS_DEBUG_OSPF(lsa, LSA))
278 0 : zlog_debug(
279 : "Route[External]: Originating router is not an ASBR");
280 0 : return 0;
281 : }
282 :
283 : /* Type-5 shouldn't be calculated if it is originated from NSSA ASBR.
284 : * As per RFC 3101, expectation is to receive type-7 lsas from
285 : * NSSA ASBR. Ignore calculation, if the current LSA is type-5 and
286 : * originated ASBR's area is NSSA.
287 : */
288 16 : if ((lsa->data->type == OSPF_AS_EXTERNAL_LSA)
289 16 : && (asbr_route->u.std.external_routing != OSPF_AREA_DEFAULT)) {
290 0 : if (IS_DEBUG_OSPF(lsa, LSA))
291 0 : zlog_debug(
292 : "Route[External]: Ignore, If type-5 LSA from NSSA area.");
293 0 : return 0;
294 : }
295 :
296 : /* Else, this LSA describes an AS external path to destination
297 : N. Examine the forwarding address specified in the AS-
298 : external-LSA. This indicates the IP address to which
299 : packets for the destination should be forwarded. */
300 :
301 16 : if (al->e[0].fwd_addr.s_addr == INADDR_ANY) {
302 : /* If the forwarding address is set to 0.0.0.0, packets should
303 : be sent to the ASBR itself. Among the multiple routing table
304 : entries for the ASBR, select the preferred entry as follows.
305 : If RFC1583Compatibility is set to "disabled", prune the set
306 : of routing table entries for the ASBR as described in
307 : Section 16.4.1. In any case, among the remaining routing
308 : table entries, select the routing table entry with the least
309 : cost; when there are multiple least cost routing table
310 : entries the entry whose associated area has the largest OSPF
311 : Area ID (when considered as an unsigned 32-bit integer) is
312 : chosen. */
313 :
314 : /* asbr_route already contains the requested route */
315 : } else {
316 : /* If the forwarding address is non-zero, look up the
317 : forwarding address in the routing table.[24] The matching
318 : routing table entry must specify an intra-area or inter-area
319 : path; if no such path exists, do nothing with the LSA and
320 : consider the next in the list. */
321 0 : if (!ospf_ase_forward_address_check(ospf, al->e[0].fwd_addr)) {
322 0 : if (IS_DEBUG_OSPF(lsa, LSA))
323 0 : zlog_debug(
324 : "Route[External]: Forwarding address is our router address");
325 0 : return 0;
326 : }
327 :
328 0 : asbr.family = AF_INET;
329 0 : asbr.prefix = al->e[0].fwd_addr;
330 0 : asbr.prefixlen = IPV4_MAX_BITLEN;
331 :
332 0 : rn = route_node_match(ospf->new_table, (struct prefix *)&asbr);
333 :
334 0 : if (rn == NULL || (asbr_route = rn->info) == NULL) {
335 0 : if (IS_DEBUG_OSPF(lsa, LSA))
336 0 : zlog_debug(
337 : "Route[External]: Can't find route to forwarding address");
338 0 : if (rn)
339 0 : route_unlock_node(rn);
340 0 : return 0;
341 : }
342 :
343 0 : route_unlock_node(rn);
344 : }
345 :
346 : /* (4) Let X be the cost specified by the preferred routing table
347 : entry for the ASBR/forwarding address, and Y the cost
348 : specified in the LSA. X is in terms of the link state
349 : metric, and Y is a type 1 or 2 external metric. */
350 :
351 :
352 : /* (5) Look up the routing table entry for the destination N. If
353 : no entry exists for N, install the AS external path to N,
354 : with next hop equal to the list of next hops to the
355 : forwarding address, and advertising router equal to ASBR.
356 : If the external metric type is 1, then the path-type is set
357 : to type 1 external and the cost is equal to X+Y. If the
358 : external metric type is 2, the path-type is set to type 2
359 : external, the link state component of the route's cost is X,
360 : and the type 2 cost is Y. */
361 16 : new = ospf_ase_calculate_new_route(lsa, asbr_route, metric);
362 :
363 : /* (6) Compare the AS external path described by the LSA with the
364 : existing paths in N's routing table entry, as follows. If
365 : the new path is preferred, it replaces the present paths in
366 : N's routing table entry. If the new path is of equal
367 : preference, it is added to N's routing table entry's list of
368 : paths. */
369 :
370 : /* Set prefix. */
371 16 : p.family = AF_INET;
372 16 : p.prefix = al->header.id;
373 16 : p.prefixlen = ip_masklen(al->mask);
374 :
375 : /* if there is a Intra/Inter area route to the N
376 : do not install external route */
377 16 : if ((rn = route_node_lookup(ospf->new_table, (struct prefix *)&p))) {
378 0 : route_unlock_node(rn);
379 0 : if (rn->info == NULL)
380 0 : zlog_info("Route[External]: rn->info NULL");
381 0 : if (new)
382 0 : ospf_route_free(new);
383 0 : return 0;
384 : }
385 : /* Find a route to the same dest */
386 : /* If there is no route, create new one. */
387 16 : if ((rn = route_node_lookup(ospf->new_external_route,
388 : (struct prefix *)&p)))
389 0 : route_unlock_node(rn);
390 :
391 0 : if (!rn || (or = rn->info) == NULL) {
392 16 : if (IS_DEBUG_OSPF(lsa, LSA))
393 0 : zlog_debug("Route[External]: Adding a new route %pFX with paths %u",
394 : &p, listcount(asbr_route->paths));
395 :
396 16 : ospf_route_add(ospf->new_external_route, &p, new, asbr_route);
397 :
398 16 : if (al->e[0].fwd_addr.s_addr != INADDR_ANY)
399 0 : ospf_ase_complete_direct_routes(new, al->e[0].fwd_addr);
400 16 : return 0;
401 : } else {
402 : /* (a) Intra-area and inter-area paths are always preferred
403 : over AS external paths.
404 :
405 : (b) Type 1 external paths are always preferred over type 2
406 : external paths. When all paths are type 2 external
407 : paths, the paths with the smallest advertised type 2
408 : metric are always preferred. */
409 0 : ret = ospf_route_cmp(ospf, new, or);
410 :
411 : /* (c) If the new AS external path is still
412 : indistinguishable
413 : from the current paths in the N's routing table
414 : entry,
415 : and RFC1583Compatibility is set to "disabled", select
416 : the preferred paths based on the intra-AS paths to
417 : the
418 : ASBR/forwarding addresses, as specified in Section
419 : 16.4.1.
420 :
421 : (d) If the new AS external path is still
422 : indistinguishable
423 : from the current paths in the N's routing table
424 : entry,
425 : select the preferred path based on a least cost
426 : comparison. Type 1 external paths are compared by
427 : looking at the sum of the distance to the forwarding
428 : address and the advertised type 1 metric (X+Y). Type
429 : 2
430 : external paths advertising equal type 2 metrics are
431 : compared by looking at the distance to the forwarding
432 : addresses.
433 : */
434 : /* New route is better */
435 0 : if (ret < 0) {
436 0 : if (IS_DEBUG_OSPF(lsa, LSA))
437 0 : zlog_debug(
438 : "Route[External]: New route is better");
439 0 : ospf_route_subst(rn, new, asbr_route);
440 0 : if (al->e[0].fwd_addr.s_addr != INADDR_ANY)
441 0 : ospf_ase_complete_direct_routes(
442 : new, al->e[0].fwd_addr);
443 : or = new;
444 : new = NULL;
445 : }
446 : /* Old route is better */
447 0 : else if (ret > 0) {
448 0 : if (IS_DEBUG_OSPF(lsa, LSA))
449 0 : zlog_debug(
450 : "Route[External]: Old route is better");
451 : /* do nothing */
452 : }
453 : /* Routes are equal */
454 : else {
455 0 : if (IS_DEBUG_OSPF(lsa, LSA))
456 0 : zlog_debug("Route[External]: Routes are equal");
457 0 : ospf_route_copy_nexthops(or, asbr_route->paths);
458 0 : if (al->e[0].fwd_addr.s_addr != INADDR_ANY)
459 0 : ospf_ase_complete_direct_routes(
460 : or, al->e[0].fwd_addr);
461 : }
462 : }
463 : /* Make sure setting newly calculated ASBR route.*/
464 0 : or->u.ext.asbr = asbr_route;
465 0 : if (new)
466 0 : ospf_route_free(new);
467 :
468 0 : lsa->route = or ;
469 0 : return 0;
470 : }
471 :
472 16 : static int ospf_ase_route_match_same(struct route_table *rt,
473 : struct prefix *prefix,
474 : struct ospf_route *newor)
475 : {
476 16 : struct route_node *rn;
477 16 : struct ospf_route *or;
478 16 : struct ospf_path *op;
479 16 : struct ospf_path *newop;
480 16 : struct listnode *n1;
481 16 : struct listnode *n2;
482 :
483 16 : if (!rt || !prefix)
484 : return 0;
485 :
486 16 : rn = route_node_lookup(rt, prefix);
487 16 : if (!rn)
488 : return 0;
489 :
490 4 : route_unlock_node(rn);
491 :
492 4 : or = rn->info;
493 :
494 4 : assert(or);
495 :
496 4 : if (or->path_type != newor->path_type)
497 : return 0;
498 :
499 4 : switch (or->path_type) {
500 0 : case OSPF_PATH_TYPE1_EXTERNAL:
501 0 : if (or->cost != newor->cost)
502 : return 0;
503 : break;
504 4 : case OSPF_PATH_TYPE2_EXTERNAL:
505 4 : if ((or->cost != newor->cost)
506 4 : || (or->u.ext.type2_cost != newor->u.ext.type2_cost))
507 : return 0;
508 : break;
509 : default:
510 0 : assert(0);
511 : return 0;
512 : }
513 :
514 4 : assert(or->paths);
515 :
516 4 : if (or->paths->count != newor->paths->count)
517 : return 0;
518 :
519 : /* Check each path. */
520 8 : for (n1 = listhead(or->paths), n2 = listhead(newor->paths); n1 && n2;
521 4 : n1 = listnextnode_unchecked(n1), n2 = listnextnode_unchecked(n2)) {
522 4 : op = listgetdata(n1);
523 4 : newop = listgetdata(n2);
524 :
525 4 : if (!IPV4_ADDR_SAME(&op->nexthop, &newop->nexthop))
526 : return 0;
527 4 : if (op->ifindex != newop->ifindex)
528 : return 0;
529 : }
530 :
531 4 : if (or->u.ext.tag != newor->u.ext.tag)
532 : return 0;
533 :
534 : return 1;
535 : }
536 :
537 32 : static int ospf_ase_compare_tables(struct ospf *ospf,
538 : struct route_table *new_external_route,
539 : struct route_table *old_external_route)
540 : {
541 32 : struct route_node *rn, *new_rn;
542 32 : struct ospf_route * or ;
543 :
544 : /* Remove deleted routes */
545 54 : for (rn = route_top(old_external_route); rn; rn = route_next(rn))
546 22 : if ((or = rn->info)) {
547 14 : if (!(new_rn = route_node_lookup(new_external_route,
548 14 : &rn->p)))
549 10 : ospf_zebra_delete(
550 : ospf, (struct prefix_ipv4 *)&rn->p, or);
551 : else
552 4 : route_unlock_node(new_rn);
553 : }
554 :
555 :
556 : /* Install new routes */
557 56 : for (rn = route_top(new_external_route); rn; rn = route_next(rn))
558 24 : if ((or = rn->info) != NULL)
559 16 : if (!ospf_ase_route_match_same(old_external_route,
560 : &rn->p, or))
561 12 : ospf_zebra_add(
562 : ospf, (struct prefix_ipv4 *)&rn->p, or);
563 :
564 32 : return 0;
565 : }
566 :
567 18 : static void ospf_ase_calculate_timer(struct thread *t)
568 : {
569 18 : struct ospf *ospf;
570 18 : struct ospf_lsa *lsa;
571 18 : struct route_node *rn;
572 18 : struct listnode *node;
573 18 : struct ospf_area *area;
574 18 : struct timeval start_time, stop_time;
575 :
576 18 : ospf = THREAD_ARG(t);
577 18 : ospf->t_ase_calc = NULL;
578 :
579 18 : if (ospf->ase_calc) {
580 18 : ospf->ase_calc = 0;
581 :
582 18 : monotime(&start_time);
583 :
584 : /* Calculate external route for each AS-external-LSA */
585 108 : LSDB_LOOP (EXTERNAL_LSDB(ospf), rn, lsa)
586 54 : ospf_ase_calculate_route(ospf, lsa);
587 :
588 : /* This version simple adds to the table all NSSA areas */
589 18 : if (ospf->anyNSSA)
590 0 : for (ALL_LIST_ELEMENTS_RO(ospf->areas, node, area)) {
591 0 : if (IS_DEBUG_OSPF_NSSA)
592 0 : zlog_debug("%s: looking at area %pI4",
593 : __func__, &area->area_id);
594 :
595 0 : if (area->external_routing == OSPF_AREA_NSSA)
596 0 : LSDB_LOOP (NSSA_LSDB(area), rn, lsa)
597 0 : ospf_ase_calculate_route(ospf,
598 : lsa);
599 : }
600 : /* kevinm: And add the NSSA routes in ospf_top */
601 18 : LSDB_LOOP (NSSA_LSDB(ospf), rn, lsa)
602 0 : ospf_ase_calculate_route(ospf, lsa);
603 :
604 : /* Compare old and new external routing table and install the
605 : difference info zebra/kernel */
606 18 : ospf_ase_compare_tables(ospf, ospf->new_external_route,
607 : ospf->old_external_route);
608 :
609 : /* Delete old external routing table */
610 18 : ospf_route_table_free(ospf->old_external_route);
611 18 : ospf->old_external_route = ospf->new_external_route;
612 18 : ospf->new_external_route = route_table_init();
613 :
614 18 : monotime(&stop_time);
615 :
616 18 : if (IS_DEBUG_OSPF_EVENT)
617 18 : zlog_info(
618 : "SPF Processing Time(usecs): External Routes: %lld",
619 : (stop_time.tv_sec - start_time.tv_sec)
620 : * 1000000LL
621 : + (stop_time.tv_usec
622 : - start_time.tv_usec));
623 : }
624 :
625 : /*
626 : * Uninstall remnant routes that were installed before the restart, but
627 : * that are no longer valid.
628 : */
629 18 : if (ospf->gr_info.finishing_restart) {
630 0 : ospf_zebra_gr_disable(ospf);
631 0 : ospf->gr_info.finishing_restart = false;
632 : }
633 18 : }
634 :
635 49 : void ospf_ase_calculate_schedule(struct ospf *ospf)
636 : {
637 49 : if (ospf == NULL)
638 : return;
639 :
640 49 : ospf->ase_calc = 1;
641 : }
642 :
643 49 : void ospf_ase_calculate_timer_add(struct ospf *ospf)
644 : {
645 49 : if (ospf == NULL)
646 : return;
647 :
648 49 : thread_add_timer(master, ospf_ase_calculate_timer, ospf,
649 : OSPF_ASE_CALC_INTERVAL, &ospf->t_ase_calc);
650 : }
651 :
652 18 : void ospf_ase_register_external_lsa(struct ospf_lsa *lsa, struct ospf *top)
653 : {
654 18 : struct route_node *rn;
655 18 : struct prefix_ipv4 p;
656 18 : struct list *lst;
657 18 : struct as_external_lsa *al;
658 :
659 18 : al = (struct as_external_lsa *)lsa->data;
660 18 : p.family = AF_INET;
661 18 : p.prefix = lsa->data->id;
662 18 : p.prefixlen = ip_masklen(al->mask);
663 18 : apply_mask_ipv4(&p);
664 :
665 18 : rn = route_node_get(top->external_lsas, (struct prefix *)&p);
666 18 : if ((lst = rn->info) == NULL)
667 16 : rn->info = lst = list_new();
668 : else
669 2 : route_unlock_node(rn);
670 :
671 : /* We assume that if LSA is deleted from DB
672 : is is also deleted from this RT */
673 18 : listnode_add(lst, ospf_lsa_lock(lsa)); /* external_lsas lst */
674 18 : }
675 :
676 18 : void ospf_ase_unregister_external_lsa(struct ospf_lsa *lsa, struct ospf *top)
677 : {
678 18 : struct route_node *rn;
679 18 : struct prefix_ipv4 p;
680 18 : struct list *lst;
681 18 : struct as_external_lsa *al;
682 :
683 18 : al = (struct as_external_lsa *)lsa->data;
684 18 : p.family = AF_INET;
685 18 : p.prefix = lsa->data->id;
686 18 : p.prefixlen = ip_masklen(al->mask);
687 18 : apply_mask_ipv4(&p);
688 :
689 18 : rn = route_node_lookup(top->external_lsas, (struct prefix *)&p);
690 :
691 18 : if (rn) {
692 18 : lst = rn->info;
693 18 : struct listnode *node = listnode_lookup(lst, lsa);
694 : /* Unlock lsa only if node is present in the list */
695 18 : if (node) {
696 18 : listnode_delete(lst, lsa);
697 18 : ospf_lsa_unlock(&lsa); /* external_lsas list */
698 : }
699 :
700 18 : route_unlock_node(rn);
701 : }
702 18 : }
703 :
704 4 : void ospf_ase_external_lsas_finish(struct route_table *rt)
705 : {
706 4 : struct route_node *rn;
707 4 : struct ospf_lsa *lsa;
708 4 : struct list *lst;
709 4 : struct listnode *node, *nnode;
710 :
711 32 : for (rn = route_top(rt); rn; rn = route_next(rn))
712 28 : if ((lst = rn->info) != NULL) {
713 16 : for (ALL_LIST_ELEMENTS(lst, node, nnode, lsa))
714 0 : ospf_lsa_unlock(&lsa); /* external_lsas lst */
715 16 : list_delete(&lst);
716 : }
717 :
718 4 : route_table_finish(rt);
719 4 : }
720 :
721 14 : void ospf_ase_incremental_update(struct ospf *ospf, struct ospf_lsa *lsa)
722 : {
723 14 : struct list *lsas;
724 14 : struct listnode *node;
725 14 : struct route_node *rn, *rn2;
726 14 : struct prefix_ipv4 p;
727 14 : struct route_table *tmp_old;
728 14 : struct as_external_lsa *al;
729 :
730 14 : al = (struct as_external_lsa *)lsa->data;
731 14 : p.family = AF_INET;
732 14 : p.prefix = lsa->data->id;
733 14 : p.prefixlen = ip_masklen(al->mask);
734 14 : apply_mask_ipv4(&p);
735 :
736 : /* if new_table is NULL, there was no spf calculation, thus
737 : incremental update is unneeded */
738 14 : if (!ospf->new_table)
739 0 : return;
740 :
741 : /* If there is already an intra-area or inter-area route
742 : to the destination, no recalculation is necessary
743 : (internal routes take precedence). */
744 :
745 14 : rn = route_node_lookup(ospf->new_table, (struct prefix *)&p);
746 14 : if (rn) {
747 0 : route_unlock_node(rn);
748 0 : if (rn->info)
749 : return;
750 : }
751 :
752 14 : rn = route_node_lookup(ospf->external_lsas, (struct prefix *)&p);
753 14 : assert(rn);
754 14 : assert(rn->info);
755 14 : lsas = rn->info;
756 14 : route_unlock_node(rn);
757 :
758 42 : for (ALL_LIST_ELEMENTS_RO(lsas, node, lsa))
759 14 : ospf_ase_calculate_route(ospf, lsa);
760 :
761 : /* prepare temporary old routing table for compare */
762 14 : tmp_old = route_table_init();
763 14 : rn = route_node_lookup(ospf->old_external_route, (struct prefix *)&p);
764 14 : if (rn && rn->info) {
765 2 : rn2 = route_node_get(tmp_old, (struct prefix *)&p);
766 2 : rn2->info = rn->info;
767 2 : route_unlock_node(rn);
768 : }
769 :
770 : /* install changes to zebra */
771 14 : ospf_ase_compare_tables(ospf, ospf->new_external_route, tmp_old);
772 :
773 : /* update ospf->old_external_route table */
774 14 : if (rn && rn->info)
775 2 : ospf_route_free((struct ospf_route *)rn->info);
776 :
777 14 : rn2 = route_node_lookup(ospf->new_external_route, (struct prefix *)&p);
778 : /* if new route exists, install it to ospf->old_external_route */
779 14 : if (rn2 && rn2->info) {
780 0 : if (!rn)
781 0 : rn = route_node_get(ospf->old_external_route,
782 : (struct prefix *)&p);
783 0 : rn->info = rn2->info;
784 : } else {
785 : /* remove route node from ospf->old_external_route */
786 14 : if (rn) {
787 2 : rn->info = NULL;
788 2 : route_unlock_node(rn);
789 : }
790 : }
791 :
792 14 : if (rn2) {
793 : /* rn2->info is stored in route node of ospf->old_external_route
794 : */
795 0 : rn2->info = NULL;
796 0 : route_unlock_node(rn2);
797 0 : route_unlock_node(rn2);
798 : }
799 :
800 14 : route_table_finish(tmp_old);
801 : }
|