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