blob: e451312535b9d2253b7213a0495ae0799ffc894a [file] [log] [blame]
jardineb5d44e2003-12-23 08:09:43 +00001/*
2 * IS-IS Rout(e)ing protocol - isis_route.c
3 * Copyright (C) 2001,2002 Sampo Saaristo
4 * Tampere University of Technology
5 * Institute of Communications Engineering
6 *
7 * based on ../ospf6d/ospf6_route.[ch]
8 * by Yasuhiro Ohara
9 *
10 * This program is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU General Public Licenseas published by the Free
12 * Software Foundation; either version 2 of the License, or (at your option)
13 * any later version.
14 *
15 * This program is distributed in the hope that it will be useful,but WITHOUT
16 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
17 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
18 * more details.
19
20 * You should have received a copy of the GNU General Public License along
21 * with this program; if not, write to the Free Software Foundation, Inc.,
22 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
23 */
24
25#include <stdlib.h>
26#include <stdio.h>
27#include <zebra.h>
jardineb5d44e2003-12-23 08:09:43 +000028
29#include "thread.h"
30#include "linklist.h"
31#include "vty.h"
32#include "log.h"
33#include "memory.h"
34#include "prefix.h"
35#include "hash.h"
36#include "if.h"
37#include "table.h"
38
39#include "isis_constants.h"
40#include "isis_common.h"
41#include "dict.h"
42#include "isisd.h"
43#include "isis_misc.h"
44#include "isis_adjacency.h"
45#include "isis_circuit.h"
46#include "isis_tlv.h"
47#include "isis_pdu.h"
48#include "isis_lsp.h"
49#include "isis_spf.h"
50#include "isis_route.h"
51#include "isis_zebra.h"
52
53extern struct isis *isis;
54extern struct thread_master *master;
55
hasso92365882005-01-18 13:53:33 +000056static struct isis_nexthop *
jardineb5d44e2003-12-23 08:09:43 +000057isis_nexthop_create (struct in_addr *ip, unsigned int ifindex)
jardineb5d44e2003-12-23 08:09:43 +000058{
59 struct listnode *node;
60 struct isis_nexthop *nexthop;
jardineb5d44e2003-12-23 08:09:43 +000061
paul1eb8ef22005-04-07 07:30:20 +000062 for (ALL_LIST_ELEMENTS_RO (isis->nexthops, node, nexthop))
hassof390d2c2004-09-10 20:48:21 +000063 {
hassof390d2c2004-09-10 20:48:21 +000064 if (nexthop->ifindex != ifindex)
65 continue;
66 if (ip && memcmp (&nexthop->ip, ip, sizeof (struct in_addr)) != 0)
67 continue;
68
69 nexthop->lock++;
70 return nexthop;
71 }
72
jardineb5d44e2003-12-23 08:09:43 +000073 nexthop = XMALLOC (MTYPE_ISIS_NEXTHOP, sizeof (struct isis_nexthop));
hassof390d2c2004-09-10 20:48:21 +000074 if (!nexthop)
75 {
76 zlog_err ("ISIS-Rte: isis_nexthop_create: out of memory!");
77 }
78
jardineb5d44e2003-12-23 08:09:43 +000079 memset (nexthop, 0, sizeof (struct isis_nexthop));
80 nexthop->ifindex = ifindex;
81 memcpy (&nexthop->ip, ip, sizeof (struct in_addr));
82 listnode_add (isis->nexthops, nexthop);
83 nexthop->lock++;
84
85 return nexthop;
86}
87
hasso92365882005-01-18 13:53:33 +000088static void
jardineb5d44e2003-12-23 08:09:43 +000089isis_nexthop_delete (struct isis_nexthop *nexthop)
90{
91 nexthop->lock--;
hassof390d2c2004-09-10 20:48:21 +000092 if (nexthop->lock == 0)
93 {
94 listnode_delete (isis->nexthops, nexthop);
95 XFREE (MTYPE_ISIS_NEXTHOP, nexthop);
96 }
97
jardineb5d44e2003-12-23 08:09:43 +000098 return;
99}
100
hasso92365882005-01-18 13:53:33 +0000101static int
hassof390d2c2004-09-10 20:48:21 +0000102nexthoplookup (struct list *nexthops, struct in_addr *ip,
103 unsigned int ifindex)
jardineb5d44e2003-12-23 08:09:43 +0000104{
105 struct listnode *node;
106 struct isis_nexthop *nh;
107
paul1eb8ef22005-04-07 07:30:20 +0000108 for (ALL_LIST_ELEMENTS_RO (nexthops, node, nh))
hassof390d2c2004-09-10 20:48:21 +0000109 {
hassof390d2c2004-09-10 20:48:21 +0000110 if (!(memcmp (ip, &nh->ip, sizeof (struct in_addr))) &&
111 ifindex == nh->ifindex)
112 return 1;
113 }
jardineb5d44e2003-12-23 08:09:43 +0000114
115 return 0;
116}
117
hasso3d549272005-09-21 18:52:14 +0000118#ifdef EXTREME_DEBUG
hasso92365882005-01-18 13:53:33 +0000119static void
jardineb5d44e2003-12-23 08:09:43 +0000120nexthop_print (struct isis_nexthop *nh)
121{
122 u_char buf[BUFSIZ];
hassof390d2c2004-09-10 20:48:21 +0000123
hassof7c43dc2004-09-26 16:24:14 +0000124 inet_ntop (AF_INET, &nh->ip, (char *) buf, BUFSIZ);
hassof390d2c2004-09-10 20:48:21 +0000125
hasso529d65b2004-12-24 00:14:50 +0000126 zlog_debug (" %s %u", buf, nh->ifindex);
jardineb5d44e2003-12-23 08:09:43 +0000127}
128
hasso92365882005-01-18 13:53:33 +0000129static void
jardineb5d44e2003-12-23 08:09:43 +0000130nexthops_print (struct list *nhs)
131{
132 struct listnode *node;
hassof390d2c2004-09-10 20:48:21 +0000133
paul1eb8ef22005-04-07 07:30:20 +0000134 for (ALL_LIST_ELEMENTS_RO (nhs, node, nh))
135 nexthop_print (nh);
jardineb5d44e2003-12-23 08:09:43 +0000136}
hasso3d549272005-09-21 18:52:14 +0000137#endif /* EXTREME_DEBUG */
jardineb5d44e2003-12-23 08:09:43 +0000138
139#ifdef HAVE_IPV6
hasso92365882005-01-18 13:53:33 +0000140static struct isis_nexthop6 *
hassof390d2c2004-09-10 20:48:21 +0000141isis_nexthop6_new (struct in6_addr *ip6, unsigned int ifindex)
jardineb5d44e2003-12-23 08:09:43 +0000142{
hassof390d2c2004-09-10 20:48:21 +0000143
jardineb5d44e2003-12-23 08:09:43 +0000144 struct isis_nexthop6 *nexthop6;
hassof390d2c2004-09-10 20:48:21 +0000145
jardineb5d44e2003-12-23 08:09:43 +0000146 nexthop6 = XMALLOC (MTYPE_ISIS_NEXTHOP6, sizeof (struct isis_nexthop6));
hassof390d2c2004-09-10 20:48:21 +0000147 if (!nexthop6)
148 {
149 zlog_err ("ISIS-Rte: isis_nexthop_create6: out of memory!");
150 }
151
jardineb5d44e2003-12-23 08:09:43 +0000152 memset (nexthop6, 0, sizeof (struct isis_nexthop6));
153 nexthop6->ifindex = ifindex;
154 memcpy (&nexthop6->ip6, ip6, sizeof (struct in6_addr));
155 nexthop6->lock++;
156
157 return nexthop6;
158}
159
hasso92365882005-01-18 13:53:33 +0000160static struct isis_nexthop6 *
jardineb5d44e2003-12-23 08:09:43 +0000161isis_nexthop6_create (struct in6_addr *ip6, unsigned int ifindex)
jardineb5d44e2003-12-23 08:09:43 +0000162{
163 struct listnode *node;
164 struct isis_nexthop6 *nexthop6;
jardineb5d44e2003-12-23 08:09:43 +0000165
paul1eb8ef22005-04-07 07:30:20 +0000166 for (ALL_LIST_ELEMENTS_RO (isis->nexthops6, node, nexthop6))
hassof390d2c2004-09-10 20:48:21 +0000167 {
hassof390d2c2004-09-10 20:48:21 +0000168 if (nexthop6->ifindex != ifindex)
169 continue;
170 if (ip6 && memcmp (&nexthop6->ip6, ip6, sizeof (struct in6_addr)) != 0)
171 continue;
172
173 nexthop6->lock++;
174 return nexthop6;
175 }
176
jardineb5d44e2003-12-23 08:09:43 +0000177 nexthop6 = isis_nexthop6_new (ip6, ifindex);
178
179 return nexthop6;
180}
181
hasso92365882005-01-18 13:53:33 +0000182static void
jardineb5d44e2003-12-23 08:09:43 +0000183isis_nexthop6_delete (struct isis_nexthop6 *nexthop6)
184{
185
186 nexthop6->lock--;
hassof390d2c2004-09-10 20:48:21 +0000187 if (nexthop6->lock == 0)
188 {
189 listnode_delete (isis->nexthops6, nexthop6);
190 XFREE (MTYPE_ISIS_NEXTHOP6, nexthop6);
191 }
192
jardineb5d44e2003-12-23 08:09:43 +0000193 return;
194}
195
hasso92365882005-01-18 13:53:33 +0000196static int
hassof390d2c2004-09-10 20:48:21 +0000197nexthop6lookup (struct list *nexthops6, struct in6_addr *ip6,
198 unsigned int ifindex)
jardineb5d44e2003-12-23 08:09:43 +0000199{
200 struct listnode *node;
201 struct isis_nexthop6 *nh6;
202
paul1eb8ef22005-04-07 07:30:20 +0000203 for (ALL_LIST_ELEMENTS_RO (nexthops6, node, nh6))
hassof390d2c2004-09-10 20:48:21 +0000204 {
hassof390d2c2004-09-10 20:48:21 +0000205 if (!(memcmp (ip6, &nh6->ip6, sizeof (struct in6_addr))) &&
206 ifindex == nh6->ifindex)
207 return 1;
208 }
jardineb5d44e2003-12-23 08:09:43 +0000209
210 return 0;
211}
212
hasso92365882005-01-18 13:53:33 +0000213#ifdef EXTREME_DEBUG
214static void
jardineb5d44e2003-12-23 08:09:43 +0000215nexthop6_print (struct isis_nexthop6 *nh6)
216{
217 u_char buf[BUFSIZ];
hassof390d2c2004-09-10 20:48:21 +0000218
hassof7c43dc2004-09-26 16:24:14 +0000219 inet_ntop (AF_INET6, &nh6->ip6, (char *) buf, BUFSIZ);
hassof390d2c2004-09-10 20:48:21 +0000220
hasso529d65b2004-12-24 00:14:50 +0000221 zlog_debug (" %s %u", buf, nh6->ifindex);
jardineb5d44e2003-12-23 08:09:43 +0000222}
223
hasso92365882005-01-18 13:53:33 +0000224static void
jardineb5d44e2003-12-23 08:09:43 +0000225nexthops6_print (struct list *nhs6)
226{
227 struct listnode *node;
hassof390d2c2004-09-10 20:48:21 +0000228
paul1eb8ef22005-04-07 07:30:20 +0000229 for (ALL_LIST_ELEMENTS_RO (nhs6, node, nh6))
230 nexthop6_print (nh6);
jardineb5d44e2003-12-23 08:09:43 +0000231}
hasso92365882005-01-18 13:53:33 +0000232#endif /* EXTREME_DEBUG */
jardineb5d44e2003-12-23 08:09:43 +0000233#endif /* HAVE_IPV6 */
234
hasso92365882005-01-18 13:53:33 +0000235static void
jardineb5d44e2003-12-23 08:09:43 +0000236adjinfo2nexthop (struct list *nexthops, struct isis_adjacency *adj)
237{
238 struct isis_nexthop *nh;
paul1eb8ef22005-04-07 07:30:20 +0000239 struct listnode *node, *nnode;
jardineb5d44e2003-12-23 08:09:43 +0000240 struct in_addr *ipv4_addr;
241
242 if (adj->ipv4_addrs == NULL)
243 return;
paul1eb8ef22005-04-07 07:30:20 +0000244
245 for (ALL_LIST_ELEMENTS (adj->ipv4_addrs, node, nnode, ipv4_addr))
hassof390d2c2004-09-10 20:48:21 +0000246 {
hassof390d2c2004-09-10 20:48:21 +0000247 if (!nexthoplookup (nexthops, ipv4_addr,
248 adj->circuit->interface->ifindex))
249 {
250 nh = isis_nexthop_create (ipv4_addr,
251 adj->circuit->interface->ifindex);
252 listnode_add (nexthops, nh);
253 }
jardineb5d44e2003-12-23 08:09:43 +0000254 }
jardineb5d44e2003-12-23 08:09:43 +0000255}
256
257#ifdef HAVE_IPV6
hasso92365882005-01-18 13:53:33 +0000258static void
jardineb5d44e2003-12-23 08:09:43 +0000259adjinfo2nexthop6 (struct list *nexthops6, struct isis_adjacency *adj)
260{
paul1eb8ef22005-04-07 07:30:20 +0000261 struct listnode *node, *nnode;
jardineb5d44e2003-12-23 08:09:43 +0000262 struct in6_addr *ipv6_addr;
263 struct isis_nexthop6 *nh6;
hassof390d2c2004-09-10 20:48:21 +0000264
jardineb5d44e2003-12-23 08:09:43 +0000265 if (!adj->ipv6_addrs)
266 return;
267
paul1eb8ef22005-04-07 07:30:20 +0000268 for (ALL_LIST_ELEMENTS (adj->ipv6_addrs, node, nnode, ipv6_addr))
hassof390d2c2004-09-10 20:48:21 +0000269 {
hassof390d2c2004-09-10 20:48:21 +0000270 if (!nexthop6lookup (nexthops6, ipv6_addr,
271 adj->circuit->interface->ifindex))
272 {
273 nh6 = isis_nexthop6_create (ipv6_addr,
274 adj->circuit->interface->ifindex);
275 listnode_add (nexthops6, nh6);
276 }
jardineb5d44e2003-12-23 08:09:43 +0000277 }
jardineb5d44e2003-12-23 08:09:43 +0000278}
279#endif /* HAVE_IPV6 */
280
hasso92365882005-01-18 13:53:33 +0000281static struct isis_route_info *
hassof390d2c2004-09-10 20:48:21 +0000282isis_route_info_new (uint32_t cost, uint32_t depth, u_char family,
283 struct list *adjacencies)
jardineb5d44e2003-12-23 08:09:43 +0000284{
285 struct isis_route_info *rinfo;
286 struct isis_adjacency *adj;
paul1eb8ef22005-04-07 07:30:20 +0000287 struct listnode *node, *nnode;
hassof390d2c2004-09-10 20:48:21 +0000288
jardineb5d44e2003-12-23 08:09:43 +0000289 rinfo = XMALLOC (MTYPE_ISIS_ROUTE_INFO, sizeof (struct isis_route_info));
hassof390d2c2004-09-10 20:48:21 +0000290 if (!rinfo)
291 {
292 zlog_err ("ISIS-Rte: isis_route_info_new: out of memory!");
293 return NULL;
294 }
jardineb5d44e2003-12-23 08:09:43 +0000295 memset (rinfo, 0, sizeof (struct isis_route_info));
296
hassof390d2c2004-09-10 20:48:21 +0000297 if (family == AF_INET)
298 {
299 rinfo->nexthops = list_new ();
paul1eb8ef22005-04-07 07:30:20 +0000300 for (ALL_LIST_ELEMENTS (adjacencies, node, nnode, adj))
301 adjinfo2nexthop (rinfo->nexthops, adj);
jardineb5d44e2003-12-23 08:09:43 +0000302 }
jardineb5d44e2003-12-23 08:09:43 +0000303#ifdef HAVE_IPV6
hassof390d2c2004-09-10 20:48:21 +0000304 if (family == AF_INET6)
305 {
306 rinfo->nexthops6 = list_new ();
paul1eb8ef22005-04-07 07:30:20 +0000307 for (ALL_LIST_ELEMENTS (adjacencies, node, nnode, adj))
308 adjinfo2nexthop6 (rinfo->nexthops6, adj);
jardineb5d44e2003-12-23 08:09:43 +0000309 }
hassof390d2c2004-09-10 20:48:21 +0000310
jardineb5d44e2003-12-23 08:09:43 +0000311#endif /* HAVE_IPV6 */
312
313 rinfo->cost = cost;
314 rinfo->depth = depth;
hassof390d2c2004-09-10 20:48:21 +0000315
jardineb5d44e2003-12-23 08:09:43 +0000316 return rinfo;
317}
318
hasso92365882005-01-18 13:53:33 +0000319static void
jardineb5d44e2003-12-23 08:09:43 +0000320isis_route_info_delete (struct isis_route_info *route_info)
321{
hassof390d2c2004-09-10 20:48:21 +0000322 if (route_info->nexthops)
323 {
hassof7c43dc2004-09-26 16:24:14 +0000324 route_info->nexthops->del = (void (*)(void *)) isis_nexthop_delete;
hassof390d2c2004-09-10 20:48:21 +0000325 list_delete (route_info->nexthops);
326 }
327
jardineb5d44e2003-12-23 08:09:43 +0000328#ifdef HAVE_IPV6
hassof390d2c2004-09-10 20:48:21 +0000329 if (route_info->nexthops6)
330 {
hassof7c43dc2004-09-26 16:24:14 +0000331 route_info->nexthops6->del = (void (*)(void *)) isis_nexthop6_delete;
jardineb5d44e2003-12-23 08:09:43 +0000332 list_delete (route_info->nexthops6);
hassof390d2c2004-09-10 20:48:21 +0000333 }
jardineb5d44e2003-12-23 08:09:43 +0000334#endif /* HAVE_IPV6 */
hassof390d2c2004-09-10 20:48:21 +0000335
jardineb5d44e2003-12-23 08:09:43 +0000336 XFREE (MTYPE_ISIS_ROUTE_INFO, route_info);
337}
338
hasso92365882005-01-18 13:53:33 +0000339static int
hassof390d2c2004-09-10 20:48:21 +0000340isis_route_info_same_attrib (struct isis_route_info *new,
341 struct isis_route_info *old)
jardineb5d44e2003-12-23 08:09:43 +0000342{
343 if (new->cost != old->cost)
344 return 0;
345 if (new->depth != old->depth)
346 return 0;
hassof390d2c2004-09-10 20:48:21 +0000347
jardineb5d44e2003-12-23 08:09:43 +0000348 return 1;
349}
350
hasso92365882005-01-18 13:53:33 +0000351static int
hassof390d2c2004-09-10 20:48:21 +0000352isis_route_info_same (struct isis_route_info *new,
353 struct isis_route_info *old, u_char family)
jardineb5d44e2003-12-23 08:09:43 +0000354{
paul1eb8ef22005-04-07 07:30:20 +0000355 struct listnode *node, *nnode;
jardineb5d44e2003-12-23 08:09:43 +0000356 struct isis_nexthop *nexthop;
357#ifdef HAVE_IPV6
358 struct isis_nexthop6 *nexthop6;
359#endif /* HAVE_IPV6 */
360 if (!isis_route_info_same_attrib (new, old))
361 return 0;
hassof390d2c2004-09-10 20:48:21 +0000362
363 if (family == AF_INET)
364 {
paul1eb8ef22005-04-07 07:30:20 +0000365 for (ALL_LIST_ELEMENTS (new->nexthops, node, nnode, nexthop))
366 if (nexthoplookup (old->nexthops, &nexthop->ip, nexthop->ifindex)
367 == 0)
368 return 0;
hassof390d2c2004-09-10 20:48:21 +0000369
paul1eb8ef22005-04-07 07:30:20 +0000370 for (ALL_LIST_ELEMENTS (old->nexthops, node, nnode, nexthop))
371 if (nexthoplookup (new->nexthops, &nexthop->ip, nexthop->ifindex)
372 == 0)
373 return 0;
jardineb5d44e2003-12-23 08:09:43 +0000374 }
jardineb5d44e2003-12-23 08:09:43 +0000375#ifdef HAVE_IPV6
hassof390d2c2004-09-10 20:48:21 +0000376 else if (family == AF_INET6)
377 {
paul1eb8ef22005-04-07 07:30:20 +0000378 for (ALL_LIST_ELEMENTS (new->nexthops6, node, nnode, nexthop6))
379 if (nexthop6lookup (old->nexthops6, &nexthop6->ip6,
380 nexthop6->ifindex) == 0)
381 return 0;
hassof390d2c2004-09-10 20:48:21 +0000382
paul1eb8ef22005-04-07 07:30:20 +0000383 for (ALL_LIST_ELEMENTS (old->nexthops6, node, nnode, nexthop6))
384 if (nexthop6lookup (new->nexthops6, &nexthop6->ip6,
385 nexthop6->ifindex) == 0)
386 return 0;
jardineb5d44e2003-12-23 08:09:43 +0000387 }
jardineb5d44e2003-12-23 08:09:43 +0000388#endif /* HAVE_IPV6 */
389
390 return 1;
391}
392
hasso92365882005-01-18 13:53:33 +0000393static void
jardineb5d44e2003-12-23 08:09:43 +0000394isis_nexthops_merge (struct list *new, struct list *old)
395{
paul1eb8ef22005-04-07 07:30:20 +0000396 struct listnode *node, *nnode;
jardineb5d44e2003-12-23 08:09:43 +0000397 struct isis_nexthop *nexthop;
398
paul1eb8ef22005-04-07 07:30:20 +0000399 for (ALL_LIST_ELEMENTS (new, node, nnode, nexthop))
hassof390d2c2004-09-10 20:48:21 +0000400 {
hassof390d2c2004-09-10 20:48:21 +0000401 if (nexthoplookup (old, &nexthop->ip, nexthop->ifindex))
402 continue;
403 listnode_add (old, nexthop);
404 nexthop->lock++;
405 }
jardineb5d44e2003-12-23 08:09:43 +0000406}
407
jardineb5d44e2003-12-23 08:09:43 +0000408#ifdef HAVE_IPV6
hasso92365882005-01-18 13:53:33 +0000409static void
jardineb5d44e2003-12-23 08:09:43 +0000410isis_nexthops6_merge (struct list *new, struct list *old)
411{
paul1eb8ef22005-04-07 07:30:20 +0000412 struct listnode *node, *nnode;
jardineb5d44e2003-12-23 08:09:43 +0000413 struct isis_nexthop6 *nexthop6;
414
paul1eb8ef22005-04-07 07:30:20 +0000415 for (ALL_LIST_ELEMENTS (new, node, nnode, nexthop6))
hassof390d2c2004-09-10 20:48:21 +0000416 {
hassof390d2c2004-09-10 20:48:21 +0000417 if (nexthop6lookup (old, &nexthop6->ip6, nexthop6->ifindex))
418 continue;
419 listnode_add (old, nexthop6);
420 nexthop6->lock++;
421 }
jardineb5d44e2003-12-23 08:09:43 +0000422}
423#endif /* HAVE_IPV6 */
424
hasso92365882005-01-18 13:53:33 +0000425static void
hassof390d2c2004-09-10 20:48:21 +0000426isis_route_info_merge (struct isis_route_info *new,
427 struct isis_route_info *old, u_char family)
jardineb5d44e2003-12-23 08:09:43 +0000428{
hassof390d2c2004-09-10 20:48:21 +0000429 if (family == AF_INET)
jardineb5d44e2003-12-23 08:09:43 +0000430 isis_nexthops_merge (new->nexthops, old->nexthops);
431#ifdef HAVE_IPV6
hassof390d2c2004-09-10 20:48:21 +0000432 else if (family == AF_INET6)
jardineb5d44e2003-12-23 08:09:43 +0000433 isis_nexthops6_merge (new->nexthops6, old->nexthops6);
434#endif /* HAVE_IPV6 */
hassof390d2c2004-09-10 20:48:21 +0000435
jardineb5d44e2003-12-23 08:09:43 +0000436 return;
437}
438
hasso92365882005-01-18 13:53:33 +0000439static int
hassof390d2c2004-09-10 20:48:21 +0000440isis_route_info_prefer_new (struct isis_route_info *new,
441 struct isis_route_info *old)
jardineb5d44e2003-12-23 08:09:43 +0000442{
jardineb5d44e2003-12-23 08:09:43 +0000443 if (!CHECK_FLAG (old->flag, ISIS_ROUTE_FLAG_ACTIVE))
444 return 1;
445
446 if (new->cost < old->cost)
447 return 1;
hassof390d2c2004-09-10 20:48:21 +0000448
jardineb5d44e2003-12-23 08:09:43 +0000449 return 0;
450}
451
jardineb5d44e2003-12-23 08:09:43 +0000452struct isis_route_info *
453isis_route_create (struct prefix *prefix, u_int32_t cost, u_int32_t depth,
hassofac1f7c2005-09-26 18:26:26 +0000454 struct list *adjacencies, struct isis_area *area,
455 int level)
jardineb5d44e2003-12-23 08:09:43 +0000456{
457 struct route_node *route_node;
458 struct isis_route_info *rinfo_new, *rinfo_old, *route_info = NULL;
459 u_char buff[BUFSIZ];
460 u_char family;
hassof390d2c2004-09-10 20:48:21 +0000461
jardineb5d44e2003-12-23 08:09:43 +0000462 family = prefix->family;
463 /* for debugs */
hassof7c43dc2004-09-26 16:24:14 +0000464 prefix2str (prefix, (char *) buff, BUFSIZ);
hassof390d2c2004-09-10 20:48:21 +0000465
jardineb5d44e2003-12-23 08:09:43 +0000466 rinfo_new = isis_route_info_new (cost, depth, family, adjacencies);
hassof390d2c2004-09-10 20:48:21 +0000467 if (!rinfo_new)
468 {
469 zlog_err ("ISIS-Rte (%s): isis_route_create: out of memory!",
470 area->area_tag);
471 return NULL;
472 }
473
jardineb5d44e2003-12-23 08:09:43 +0000474 if (family == AF_INET)
hassofac1f7c2005-09-26 18:26:26 +0000475 route_node = route_node_get (area->route_table[level - 1], prefix);
jardineb5d44e2003-12-23 08:09:43 +0000476#ifdef HAVE_IPV6
477 else if (family == AF_INET6)
hassofac1f7c2005-09-26 18:26:26 +0000478 route_node = route_node_get (area->route_table6[level - 1], prefix);
jardineb5d44e2003-12-23 08:09:43 +0000479#endif /* HAVE_IPV6 */
hassof390d2c2004-09-10 20:48:21 +0000480 else
jardineb5d44e2003-12-23 08:09:43 +0000481 return NULL;
hassof390d2c2004-09-10 20:48:21 +0000482 rinfo_old = route_node->info;
483 if (!rinfo_old)
484 {
485 if (isis->debugs & DEBUG_RTE_EVENTS)
hasso529d65b2004-12-24 00:14:50 +0000486 zlog_debug ("ISIS-Rte (%s) route created: %s", area->area_tag, buff);
hassof390d2c2004-09-10 20:48:21 +0000487 SET_FLAG (rinfo_new->flag, ISIS_ROUTE_FLAG_ACTIVE);
488 route_node->info = rinfo_new;
489 return rinfo_new;
490 }
491
jardineb5d44e2003-12-23 08:09:43 +0000492 if (isis->debugs & DEBUG_RTE_EVENTS)
hasso529d65b2004-12-24 00:14:50 +0000493 zlog_debug ("ISIS-Rte (%s) route already exists: %s", area->area_tag,
hassof390d2c2004-09-10 20:48:21 +0000494 buff);
495
496 if (isis_route_info_same (rinfo_new, rinfo_old, family))
497 {
jardineb5d44e2003-12-23 08:09:43 +0000498 if (isis->debugs & DEBUG_RTE_EVENTS)
hasso529d65b2004-12-24 00:14:50 +0000499 zlog_debug ("ISIS-Rte (%s) route unchanged: %s", area->area_tag, buff);
jardineb5d44e2003-12-23 08:09:43 +0000500 isis_route_info_delete (rinfo_new);
501 route_info = rinfo_old;
502 }
hassof390d2c2004-09-10 20:48:21 +0000503 else if (isis_route_info_same_attrib (rinfo_new, rinfo_old))
504 {
505 /* merge the nexthop lists */
506 if (isis->debugs & DEBUG_RTE_EVENTS)
hasso529d65b2004-12-24 00:14:50 +0000507 zlog_debug ("ISIS-Rte (%s) route changed (same attribs): %s",
hassof390d2c2004-09-10 20:48:21 +0000508 area->area_tag, buff);
509#ifdef EXTREME_DEBUG
hasso3d549272005-09-21 18:52:14 +0000510 if (family == AF_INET)
511 {
512 zlog_debug ("Old nexthops");
513 nexthops_print (rinfo_old->nexthops);
514 zlog_debug ("New nexthops");
515 nexthops_print (rinfo_new->nexthops);
516 }
517 else if (family == AF_INET6)
518 {
519 zlog_debug ("Old nexthops");
520 nexthops6_print (rinfo_old->nexthops6);
521 zlog_debug ("New nexthops");
522 nexthops6_print (rinfo_new->nexthops6);
523 }
hassof390d2c2004-09-10 20:48:21 +0000524#endif /* EXTREME_DEBUG */
525 isis_route_info_merge (rinfo_new, rinfo_old, family);
526 isis_route_info_delete (rinfo_new);
527 route_info = rinfo_old;
528 }
529 else
530 {
531 if (isis_route_info_prefer_new (rinfo_new, rinfo_old))
532 {
533 if (isis->debugs & DEBUG_RTE_EVENTS)
hasso529d65b2004-12-24 00:14:50 +0000534 zlog_debug ("ISIS-Rte (%s) route changed: %s", area->area_tag,
535 buff);
hassof390d2c2004-09-10 20:48:21 +0000536 isis_route_info_delete (rinfo_old);
537 route_info = rinfo_new;
538 }
539 else
540 {
541 if (isis->debugs & DEBUG_RTE_EVENTS)
hasso529d65b2004-12-24 00:14:50 +0000542 zlog_debug ("ISIS-Rte (%s) route rejected: %s", area->area_tag,
543 buff);
hassof390d2c2004-09-10 20:48:21 +0000544 isis_route_info_delete (rinfo_new);
545 route_info = rinfo_old;
546 }
547 }
548
jardineb5d44e2003-12-23 08:09:43 +0000549 SET_FLAG (route_info->flag, ISIS_ROUTE_FLAG_ACTIVE);
550 route_node->info = route_info;
hassof390d2c2004-09-10 20:48:21 +0000551
jardineb5d44e2003-12-23 08:09:43 +0000552 return route_info;
553}
554
hasso92365882005-01-18 13:53:33 +0000555static void
jardineb5d44e2003-12-23 08:09:43 +0000556isis_route_delete (struct prefix *prefix, struct route_table *table)
557{
558 struct route_node *rode;
559 struct isis_route_info *rinfo;
560 char buff[BUFSIZ];
561
562 /* for log */
563 prefix2str (prefix, buff, BUFSIZ);
564
565
566 rode = route_node_get (table, prefix);
567 rinfo = rode->info;
568
hassof390d2c2004-09-10 20:48:21 +0000569 if (rinfo == NULL)
570 {
571 if (isis->debugs & DEBUG_RTE_EVENTS)
hasso529d65b2004-12-24 00:14:50 +0000572 zlog_debug ("ISIS-Rte: tried to delete non-existant route %s", buff);
hassof390d2c2004-09-10 20:48:21 +0000573 return;
574 }
jardineb5d44e2003-12-23 08:09:43 +0000575
hassof390d2c2004-09-10 20:48:21 +0000576 if (CHECK_FLAG (rinfo->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNC))
577 {
578 UNSET_FLAG (rinfo->flag, ISIS_ROUTE_FLAG_ACTIVE);
579 if (isis->debugs & DEBUG_RTE_EVENTS)
hasso529d65b2004-12-24 00:14:50 +0000580 zlog_debug ("ISIS-Rte: route delete %s", buff);
hassof390d2c2004-09-10 20:48:21 +0000581 isis_zebra_route_update (prefix, rinfo);
582 }
jardineb5d44e2003-12-23 08:09:43 +0000583 isis_route_info_delete (rinfo);
584 rode->info = NULL;
hassof390d2c2004-09-10 20:48:21 +0000585
jardineb5d44e2003-12-23 08:09:43 +0000586 return;
587}
588
hassofac1f7c2005-09-26 18:26:26 +0000589/* Validating routes in particular table. */
590static void
591isis_route_validate_table (struct isis_area *area, struct route_table *table)
jardineb5d44e2003-12-23 08:09:43 +0000592{
hassofac1f7c2005-09-26 18:26:26 +0000593 struct route_node *rnode, *drnode;
jardineb5d44e2003-12-23 08:09:43 +0000594 struct isis_route_info *rinfo;
595 u_char buff[BUFSIZ];
hassofac1f7c2005-09-26 18:26:26 +0000596
597 for (rnode = route_top (table); rnode; rnode = route_next (rnode))
hassof390d2c2004-09-10 20:48:21 +0000598 {
hassofac1f7c2005-09-26 18:26:26 +0000599 if (rnode->info == NULL)
hassof390d2c2004-09-10 20:48:21 +0000600 continue;
hassofac1f7c2005-09-26 18:26:26 +0000601 rinfo = rnode->info;
hassof390d2c2004-09-10 20:48:21 +0000602
603 if (isis->debugs & DEBUG_RTE_EVENTS)
604 {
hassofac1f7c2005-09-26 18:26:26 +0000605 prefix2str (&rnode->p, (char *) buff, BUFSIZ);
hasso529d65b2004-12-24 00:14:50 +0000606 zlog_debug ("ISIS-Rte (%s): route validate: %s %s %s",
607 area->area_tag,
608 (CHECK_FLAG (rinfo->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNC) ?
hassof390d2c2004-09-10 20:48:21 +0000609 "sync'ed" : "nosync"),
hasso529d65b2004-12-24 00:14:50 +0000610 (CHECK_FLAG (rinfo->flag, ISIS_ROUTE_FLAG_ACTIVE) ?
hassof390d2c2004-09-10 20:48:21 +0000611 "active" : "inactive"), buff);
612 }
613
hassofac1f7c2005-09-26 18:26:26 +0000614 isis_zebra_route_update (&rnode->p, rinfo);
hassof390d2c2004-09-10 20:48:21 +0000615 if (!CHECK_FLAG (rinfo->flag, ISIS_ROUTE_FLAG_ACTIVE))
hassofac1f7c2005-09-26 18:26:26 +0000616 {
617 /* Area is either L1 or L2 => we use level route tables directly for
618 * validating => no problems with deleting routes. */
619 if (area->is_type != IS_LEVEL_1_AND_2)
620 {
621 isis_route_delete (&rnode->p, table);
622 continue;
623 }
624 /* If area is L1L2, we work with merge table and therefore must
625 * delete node from level tables as well before deleting route info.
626 * FIXME: Is it performance problem? There has to be the better way.
627 * Like not to deal with it here at all (see the next comment)? */
628 if (rnode->p.family == AF_INET)
629 {
630 drnode = route_node_get (area->route_table[0], &rnode->p);
631 if (drnode->info == rnode->info)
632 drnode->info = NULL;
633 drnode = route_node_get (area->route_table[1], &rnode->p);
634 if (drnode->info == rnode->info)
635 drnode->info = NULL;
636 }
637 if (rnode->p.family == AF_INET6)
638 {
639 drnode = route_node_get (area->route_table6[0], &rnode->p);
640 if (drnode->info == rnode->info)
641 drnode->info = NULL;
642 drnode = route_node_get (area->route_table6[1], &rnode->p);
643 if (drnode->info == rnode->info)
644 drnode->info = NULL;
645 }
646
647 isis_route_delete (&rnode->p, table);
648 }
jardineb5d44e2003-12-23 08:09:43 +0000649 }
hassofac1f7c2005-09-26 18:26:26 +0000650}
651
652/* Function to validate route tables for L1L2 areas. In this case we can't use
653 * level route tables directly, we have to merge them at first. L1 routes are
654 * preferred over the L2 ones.
655 *
656 * Merge algorithm is trivial (at least for now). All L1 paths are copied into
657 * merge table at first, then L2 paths are added if L1 path for same prefix
658 * doesn't already exists there.
659 *
660 * FIXME: Is it right place to do it at all? Maybe we should push both levels
661 * to the RIB with different zebra route types and let RIB handle this? */
662static void
663isis_route_validate_merge (struct isis_area *area, int family)
664{
665 struct route_table *table = NULL;
666 struct route_table *merge;
667 struct route_node *rnode, *mrnode;
668
669 merge = route_table_init ();
670
671 if (family == AF_INET)
672 table = area->route_table[0];
673 else if (family == AF_INET6)
674 table = area->route_table6[0];
675
676 for (rnode = route_top (table); rnode; rnode = route_next (rnode))
677 {
678 if (rnode->info == NULL)
679 continue;
680 mrnode = route_node_get (merge, &rnode->p);
681 mrnode->info = rnode->info;
682 }
683
684 if (family == AF_INET)
685 table = area->route_table[1];
686 else if (family == AF_INET6)
687 table = area->route_table6[1];
688
689 for (rnode = route_top (table); rnode; rnode = route_next (rnode))
690 {
691 if (rnode->info == NULL)
692 continue;
693 mrnode = route_node_get (merge, &rnode->p);
694 if (mrnode->info != NULL)
695 continue;
696 mrnode->info = rnode->info;
697 }
698
699 isis_route_validate_table (area, merge);
700 route_table_finish (merge);
701}
702
703/* Walk through route tables and propagate necessary changes into RIB. In case
704 * of L1L2 area, level tables have to be merged at first. */
705int
706isis_route_validate (struct thread *thread)
707{
708 struct isis_area *area;
709
710 area = THREAD_ARG (thread);
711
712 if (area->is_type == IS_LEVEL_1)
713 {
714 isis_route_validate_table (area, area->route_table[0]);
715 goto validate_ipv6;
716 }
717 if (area->is_type == IS_LEVEL_2)
718 {
719 isis_route_validate_table (area, area->route_table[1]);
720 goto validate_ipv6;
721 }
722
723 isis_route_validate_merge (area, AF_INET);
724
jardineb5d44e2003-12-23 08:09:43 +0000725#ifdef HAVE_IPV6
hassofac1f7c2005-09-26 18:26:26 +0000726validate_ipv6:
727 if (area->is_type == IS_LEVEL_1)
728 {
729 isis_route_validate_table (area, area->route_table6[0]);
730 return ISIS_OK;
731 }
732 if (area->is_type == IS_LEVEL_2)
733 {
734 isis_route_validate_table (area, area->route_table6[1]);
735 return ISIS_OK;
736 }
737
738 isis_route_validate_merge (area, AF_INET6);
jardineb5d44e2003-12-23 08:09:43 +0000739#endif
740
741 return ISIS_OK;
742}