blob: 7d0239ca9cb982f7d3923845c9317178695910c8 [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
hasso3fdb2dd2005-09-28 18:45:54 +000073 nexthop = XCALLOC (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 nexthop->ifindex = ifindex;
80 memcpy (&nexthop->ip, ip, sizeof (struct in_addr));
81 listnode_add (isis->nexthops, nexthop);
82 nexthop->lock++;
83
84 return nexthop;
85}
86
hasso92365882005-01-18 13:53:33 +000087static void
jardineb5d44e2003-12-23 08:09:43 +000088isis_nexthop_delete (struct isis_nexthop *nexthop)
89{
90 nexthop->lock--;
hassof390d2c2004-09-10 20:48:21 +000091 if (nexthop->lock == 0)
92 {
93 listnode_delete (isis->nexthops, nexthop);
94 XFREE (MTYPE_ISIS_NEXTHOP, nexthop);
95 }
96
jardineb5d44e2003-12-23 08:09:43 +000097 return;
98}
99
hasso92365882005-01-18 13:53:33 +0000100static int
hassof390d2c2004-09-10 20:48:21 +0000101nexthoplookup (struct list *nexthops, struct in_addr *ip,
102 unsigned int ifindex)
jardineb5d44e2003-12-23 08:09:43 +0000103{
104 struct listnode *node;
105 struct isis_nexthop *nh;
106
paul1eb8ef22005-04-07 07:30:20 +0000107 for (ALL_LIST_ELEMENTS_RO (nexthops, node, nh))
hassof390d2c2004-09-10 20:48:21 +0000108 {
hassof390d2c2004-09-10 20:48:21 +0000109 if (!(memcmp (ip, &nh->ip, sizeof (struct in_addr))) &&
110 ifindex == nh->ifindex)
111 return 1;
112 }
jardineb5d44e2003-12-23 08:09:43 +0000113
114 return 0;
115}
116
hasso3d549272005-09-21 18:52:14 +0000117#ifdef EXTREME_DEBUG
hasso92365882005-01-18 13:53:33 +0000118static void
jardineb5d44e2003-12-23 08:09:43 +0000119nexthop_print (struct isis_nexthop *nh)
120{
121 u_char buf[BUFSIZ];
hassof390d2c2004-09-10 20:48:21 +0000122
hassof7c43dc2004-09-26 16:24:14 +0000123 inet_ntop (AF_INET, &nh->ip, (char *) buf, BUFSIZ);
hassof390d2c2004-09-10 20:48:21 +0000124
hasso529d65b2004-12-24 00:14:50 +0000125 zlog_debug (" %s %u", buf, nh->ifindex);
jardineb5d44e2003-12-23 08:09:43 +0000126}
127
hasso92365882005-01-18 13:53:33 +0000128static void
jardineb5d44e2003-12-23 08:09:43 +0000129nexthops_print (struct list *nhs)
130{
131 struct listnode *node;
hasso13fb40a2005-10-01 06:03:04 +0000132 struct isis_nexthop *nh;
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{
jardineb5d44e2003-12-23 08:09:43 +0000143 struct isis_nexthop6 *nexthop6;
hassof390d2c2004-09-10 20:48:21 +0000144
hasso3fdb2dd2005-09-28 18:45:54 +0000145 nexthop6 = XCALLOC (MTYPE_ISIS_NEXTHOP6, sizeof (struct isis_nexthop6));
hassof390d2c2004-09-10 20:48:21 +0000146 if (!nexthop6)
147 {
148 zlog_err ("ISIS-Rte: isis_nexthop_create6: out of memory!");
149 }
150
jardineb5d44e2003-12-23 08:09:43 +0000151 nexthop6->ifindex = ifindex;
152 memcpy (&nexthop6->ip6, ip6, sizeof (struct in6_addr));
153 nexthop6->lock++;
154
155 return nexthop6;
156}
157
hasso92365882005-01-18 13:53:33 +0000158static struct isis_nexthop6 *
jardineb5d44e2003-12-23 08:09:43 +0000159isis_nexthop6_create (struct in6_addr *ip6, unsigned int ifindex)
jardineb5d44e2003-12-23 08:09:43 +0000160{
161 struct listnode *node;
162 struct isis_nexthop6 *nexthop6;
jardineb5d44e2003-12-23 08:09:43 +0000163
paul1eb8ef22005-04-07 07:30:20 +0000164 for (ALL_LIST_ELEMENTS_RO (isis->nexthops6, node, nexthop6))
hassof390d2c2004-09-10 20:48:21 +0000165 {
hassof390d2c2004-09-10 20:48:21 +0000166 if (nexthop6->ifindex != ifindex)
167 continue;
168 if (ip6 && memcmp (&nexthop6->ip6, ip6, sizeof (struct in6_addr)) != 0)
169 continue;
170
171 nexthop6->lock++;
172 return nexthop6;
173 }
174
jardineb5d44e2003-12-23 08:09:43 +0000175 nexthop6 = isis_nexthop6_new (ip6, ifindex);
176
177 return nexthop6;
178}
179
hasso92365882005-01-18 13:53:33 +0000180static void
jardineb5d44e2003-12-23 08:09:43 +0000181isis_nexthop6_delete (struct isis_nexthop6 *nexthop6)
182{
183
184 nexthop6->lock--;
hassof390d2c2004-09-10 20:48:21 +0000185 if (nexthop6->lock == 0)
186 {
187 listnode_delete (isis->nexthops6, nexthop6);
188 XFREE (MTYPE_ISIS_NEXTHOP6, nexthop6);
189 }
190
jardineb5d44e2003-12-23 08:09:43 +0000191 return;
192}
193
hasso92365882005-01-18 13:53:33 +0000194static int
hassof390d2c2004-09-10 20:48:21 +0000195nexthop6lookup (struct list *nexthops6, struct in6_addr *ip6,
196 unsigned int ifindex)
jardineb5d44e2003-12-23 08:09:43 +0000197{
198 struct listnode *node;
199 struct isis_nexthop6 *nh6;
200
paul1eb8ef22005-04-07 07:30:20 +0000201 for (ALL_LIST_ELEMENTS_RO (nexthops6, node, nh6))
hassof390d2c2004-09-10 20:48:21 +0000202 {
hassof390d2c2004-09-10 20:48:21 +0000203 if (!(memcmp (ip6, &nh6->ip6, sizeof (struct in6_addr))) &&
204 ifindex == nh6->ifindex)
205 return 1;
206 }
jardineb5d44e2003-12-23 08:09:43 +0000207
208 return 0;
209}
210
hasso92365882005-01-18 13:53:33 +0000211#ifdef EXTREME_DEBUG
212static void
jardineb5d44e2003-12-23 08:09:43 +0000213nexthop6_print (struct isis_nexthop6 *nh6)
214{
215 u_char buf[BUFSIZ];
hassof390d2c2004-09-10 20:48:21 +0000216
hassof7c43dc2004-09-26 16:24:14 +0000217 inet_ntop (AF_INET6, &nh6->ip6, (char *) buf, BUFSIZ);
hassof390d2c2004-09-10 20:48:21 +0000218
hasso529d65b2004-12-24 00:14:50 +0000219 zlog_debug (" %s %u", buf, nh6->ifindex);
jardineb5d44e2003-12-23 08:09:43 +0000220}
221
hasso92365882005-01-18 13:53:33 +0000222static void
jardineb5d44e2003-12-23 08:09:43 +0000223nexthops6_print (struct list *nhs6)
224{
225 struct listnode *node;
jardin10fc9182005-10-01 00:09:39 +0000226 struct isis_nexthop6 *nh6;
hassof390d2c2004-09-10 20:48:21 +0000227
paul1eb8ef22005-04-07 07:30:20 +0000228 for (ALL_LIST_ELEMENTS_RO (nhs6, node, nh6))
229 nexthop6_print (nh6);
jardineb5d44e2003-12-23 08:09:43 +0000230}
hasso92365882005-01-18 13:53:33 +0000231#endif /* EXTREME_DEBUG */
jardineb5d44e2003-12-23 08:09:43 +0000232#endif /* HAVE_IPV6 */
233
hasso92365882005-01-18 13:53:33 +0000234static void
jardineb5d44e2003-12-23 08:09:43 +0000235adjinfo2nexthop (struct list *nexthops, struct isis_adjacency *adj)
236{
237 struct isis_nexthop *nh;
hasso3fdb2dd2005-09-28 18:45:54 +0000238 struct listnode *node;
jardineb5d44e2003-12-23 08:09:43 +0000239 struct in_addr *ipv4_addr;
240
241 if (adj->ipv4_addrs == NULL)
242 return;
paul1eb8ef22005-04-07 07:30:20 +0000243
hasso3fdb2dd2005-09-28 18:45:54 +0000244 for (ALL_LIST_ELEMENTS_RO (adj->ipv4_addrs, node, ipv4_addr))
hassof390d2c2004-09-10 20:48:21 +0000245 {
hassof390d2c2004-09-10 20:48:21 +0000246 if (!nexthoplookup (nexthops, ipv4_addr,
247 adj->circuit->interface->ifindex))
248 {
249 nh = isis_nexthop_create (ipv4_addr,
250 adj->circuit->interface->ifindex);
251 listnode_add (nexthops, nh);
252 }
jardineb5d44e2003-12-23 08:09:43 +0000253 }
jardineb5d44e2003-12-23 08:09:43 +0000254}
255
256#ifdef HAVE_IPV6
hasso92365882005-01-18 13:53:33 +0000257static void
jardineb5d44e2003-12-23 08:09:43 +0000258adjinfo2nexthop6 (struct list *nexthops6, struct isis_adjacency *adj)
259{
hasso3fdb2dd2005-09-28 18:45:54 +0000260 struct listnode *node;
jardineb5d44e2003-12-23 08:09:43 +0000261 struct in6_addr *ipv6_addr;
262 struct isis_nexthop6 *nh6;
hassof390d2c2004-09-10 20:48:21 +0000263
jardineb5d44e2003-12-23 08:09:43 +0000264 if (!adj->ipv6_addrs)
265 return;
266
hasso3fdb2dd2005-09-28 18:45:54 +0000267 for (ALL_LIST_ELEMENTS_RO (adj->ipv6_addrs, node, ipv6_addr))
hassof390d2c2004-09-10 20:48:21 +0000268 {
hassof390d2c2004-09-10 20:48:21 +0000269 if (!nexthop6lookup (nexthops6, ipv6_addr,
270 adj->circuit->interface->ifindex))
271 {
272 nh6 = isis_nexthop6_create (ipv6_addr,
273 adj->circuit->interface->ifindex);
274 listnode_add (nexthops6, nh6);
275 }
jardineb5d44e2003-12-23 08:09:43 +0000276 }
jardineb5d44e2003-12-23 08:09:43 +0000277}
278#endif /* HAVE_IPV6 */
279
hasso92365882005-01-18 13:53:33 +0000280static struct isis_route_info *
hassof390d2c2004-09-10 20:48:21 +0000281isis_route_info_new (uint32_t cost, uint32_t depth, u_char family,
282 struct list *adjacencies)
jardineb5d44e2003-12-23 08:09:43 +0000283{
284 struct isis_route_info *rinfo;
285 struct isis_adjacency *adj;
hasso3fdb2dd2005-09-28 18:45:54 +0000286 struct listnode *node;
hassof390d2c2004-09-10 20:48:21 +0000287
hasso3fdb2dd2005-09-28 18:45:54 +0000288 rinfo = XCALLOC (MTYPE_ISIS_ROUTE_INFO, sizeof (struct isis_route_info));
hassof390d2c2004-09-10 20:48:21 +0000289 if (!rinfo)
290 {
291 zlog_err ("ISIS-Rte: isis_route_info_new: out of memory!");
292 return NULL;
293 }
jardineb5d44e2003-12-23 08:09:43 +0000294
hassof390d2c2004-09-10 20:48:21 +0000295 if (family == AF_INET)
296 {
297 rinfo->nexthops = list_new ();
hasso3fdb2dd2005-09-28 18:45:54 +0000298 for (ALL_LIST_ELEMENTS_RO (adjacencies, node, adj))
paul1eb8ef22005-04-07 07:30:20 +0000299 adjinfo2nexthop (rinfo->nexthops, adj);
jardineb5d44e2003-12-23 08:09:43 +0000300 }
jardineb5d44e2003-12-23 08:09:43 +0000301#ifdef HAVE_IPV6
hassof390d2c2004-09-10 20:48:21 +0000302 if (family == AF_INET6)
303 {
304 rinfo->nexthops6 = list_new ();
hasso3fdb2dd2005-09-28 18:45:54 +0000305 for (ALL_LIST_ELEMENTS_RO (adjacencies, node, adj))
paul1eb8ef22005-04-07 07:30:20 +0000306 adjinfo2nexthop6 (rinfo->nexthops6, adj);
jardineb5d44e2003-12-23 08:09:43 +0000307 }
hassof390d2c2004-09-10 20:48:21 +0000308
jardineb5d44e2003-12-23 08:09:43 +0000309#endif /* HAVE_IPV6 */
310
311 rinfo->cost = cost;
312 rinfo->depth = depth;
hassof390d2c2004-09-10 20:48:21 +0000313
jardineb5d44e2003-12-23 08:09:43 +0000314 return rinfo;
315}
316
hasso92365882005-01-18 13:53:33 +0000317static void
jardineb5d44e2003-12-23 08:09:43 +0000318isis_route_info_delete (struct isis_route_info *route_info)
319{
hassof390d2c2004-09-10 20:48:21 +0000320 if (route_info->nexthops)
321 {
hassof7c43dc2004-09-26 16:24:14 +0000322 route_info->nexthops->del = (void (*)(void *)) isis_nexthop_delete;
hassof390d2c2004-09-10 20:48:21 +0000323 list_delete (route_info->nexthops);
324 }
325
jardineb5d44e2003-12-23 08:09:43 +0000326#ifdef HAVE_IPV6
hassof390d2c2004-09-10 20:48:21 +0000327 if (route_info->nexthops6)
328 {
hassof7c43dc2004-09-26 16:24:14 +0000329 route_info->nexthops6->del = (void (*)(void *)) isis_nexthop6_delete;
jardineb5d44e2003-12-23 08:09:43 +0000330 list_delete (route_info->nexthops6);
hassof390d2c2004-09-10 20:48:21 +0000331 }
jardineb5d44e2003-12-23 08:09:43 +0000332#endif /* HAVE_IPV6 */
hassof390d2c2004-09-10 20:48:21 +0000333
jardineb5d44e2003-12-23 08:09:43 +0000334 XFREE (MTYPE_ISIS_ROUTE_INFO, route_info);
335}
336
hasso92365882005-01-18 13:53:33 +0000337static int
hassof390d2c2004-09-10 20:48:21 +0000338isis_route_info_same_attrib (struct isis_route_info *new,
339 struct isis_route_info *old)
jardineb5d44e2003-12-23 08:09:43 +0000340{
341 if (new->cost != old->cost)
342 return 0;
343 if (new->depth != old->depth)
344 return 0;
hassof390d2c2004-09-10 20:48:21 +0000345
jardineb5d44e2003-12-23 08:09:43 +0000346 return 1;
347}
348
hasso92365882005-01-18 13:53:33 +0000349static int
hassof390d2c2004-09-10 20:48:21 +0000350isis_route_info_same (struct isis_route_info *new,
351 struct isis_route_info *old, u_char family)
jardineb5d44e2003-12-23 08:09:43 +0000352{
hasso3fdb2dd2005-09-28 18:45:54 +0000353 struct listnode *node;
jardineb5d44e2003-12-23 08:09:43 +0000354 struct isis_nexthop *nexthop;
355#ifdef HAVE_IPV6
356 struct isis_nexthop6 *nexthop6;
357#endif /* HAVE_IPV6 */
358 if (!isis_route_info_same_attrib (new, old))
359 return 0;
hassof390d2c2004-09-10 20:48:21 +0000360
361 if (family == AF_INET)
362 {
hasso3fdb2dd2005-09-28 18:45:54 +0000363 for (ALL_LIST_ELEMENTS_RO (new->nexthops, node, nexthop))
paul1eb8ef22005-04-07 07:30:20 +0000364 if (nexthoplookup (old->nexthops, &nexthop->ip, nexthop->ifindex)
365 == 0)
366 return 0;
hassof390d2c2004-09-10 20:48:21 +0000367
hasso3fdb2dd2005-09-28 18:45:54 +0000368 for (ALL_LIST_ELEMENTS_RO (old->nexthops, node, nexthop))
paul1eb8ef22005-04-07 07:30:20 +0000369 if (nexthoplookup (new->nexthops, &nexthop->ip, nexthop->ifindex)
370 == 0)
371 return 0;
jardineb5d44e2003-12-23 08:09:43 +0000372 }
jardineb5d44e2003-12-23 08:09:43 +0000373#ifdef HAVE_IPV6
hassof390d2c2004-09-10 20:48:21 +0000374 else if (family == AF_INET6)
375 {
hasso3fdb2dd2005-09-28 18:45:54 +0000376 for (ALL_LIST_ELEMENTS_RO (new->nexthops6, node, nexthop6))
paul1eb8ef22005-04-07 07:30:20 +0000377 if (nexthop6lookup (old->nexthops6, &nexthop6->ip6,
378 nexthop6->ifindex) == 0)
379 return 0;
hassof390d2c2004-09-10 20:48:21 +0000380
hasso3fdb2dd2005-09-28 18:45:54 +0000381 for (ALL_LIST_ELEMENTS_RO (old->nexthops6, node, nexthop6))
paul1eb8ef22005-04-07 07:30:20 +0000382 if (nexthop6lookup (new->nexthops6, &nexthop6->ip6,
383 nexthop6->ifindex) == 0)
384 return 0;
jardineb5d44e2003-12-23 08:09:43 +0000385 }
jardineb5d44e2003-12-23 08:09:43 +0000386#endif /* HAVE_IPV6 */
387
388 return 1;
389}
390
hasso92365882005-01-18 13:53:33 +0000391static void
jardineb5d44e2003-12-23 08:09:43 +0000392isis_nexthops_merge (struct list *new, struct list *old)
393{
hasso3fdb2dd2005-09-28 18:45:54 +0000394 struct listnode *node;
jardineb5d44e2003-12-23 08:09:43 +0000395 struct isis_nexthop *nexthop;
396
hasso3fdb2dd2005-09-28 18:45:54 +0000397 for (ALL_LIST_ELEMENTS_RO (new, node, nexthop))
hassof390d2c2004-09-10 20:48:21 +0000398 {
hassof390d2c2004-09-10 20:48:21 +0000399 if (nexthoplookup (old, &nexthop->ip, nexthop->ifindex))
400 continue;
401 listnode_add (old, nexthop);
402 nexthop->lock++;
403 }
jardineb5d44e2003-12-23 08:09:43 +0000404}
405
jardineb5d44e2003-12-23 08:09:43 +0000406#ifdef HAVE_IPV6
hasso92365882005-01-18 13:53:33 +0000407static void
jardineb5d44e2003-12-23 08:09:43 +0000408isis_nexthops6_merge (struct list *new, struct list *old)
409{
hasso3fdb2dd2005-09-28 18:45:54 +0000410 struct listnode *node;
jardineb5d44e2003-12-23 08:09:43 +0000411 struct isis_nexthop6 *nexthop6;
412
hasso3fdb2dd2005-09-28 18:45:54 +0000413 for (ALL_LIST_ELEMENTS_RO (new, node, nexthop6))
hassof390d2c2004-09-10 20:48:21 +0000414 {
hassof390d2c2004-09-10 20:48:21 +0000415 if (nexthop6lookup (old, &nexthop6->ip6, nexthop6->ifindex))
416 continue;
417 listnode_add (old, nexthop6);
418 nexthop6->lock++;
419 }
jardineb5d44e2003-12-23 08:09:43 +0000420}
421#endif /* HAVE_IPV6 */
422
hasso92365882005-01-18 13:53:33 +0000423static void
hassof390d2c2004-09-10 20:48:21 +0000424isis_route_info_merge (struct isis_route_info *new,
425 struct isis_route_info *old, u_char family)
jardineb5d44e2003-12-23 08:09:43 +0000426{
hassof390d2c2004-09-10 20:48:21 +0000427 if (family == AF_INET)
jardineb5d44e2003-12-23 08:09:43 +0000428 isis_nexthops_merge (new->nexthops, old->nexthops);
429#ifdef HAVE_IPV6
hassof390d2c2004-09-10 20:48:21 +0000430 else if (family == AF_INET6)
jardineb5d44e2003-12-23 08:09:43 +0000431 isis_nexthops6_merge (new->nexthops6, old->nexthops6);
432#endif /* HAVE_IPV6 */
hassof390d2c2004-09-10 20:48:21 +0000433
jardineb5d44e2003-12-23 08:09:43 +0000434 return;
435}
436
hasso92365882005-01-18 13:53:33 +0000437static int
hassof390d2c2004-09-10 20:48:21 +0000438isis_route_info_prefer_new (struct isis_route_info *new,
439 struct isis_route_info *old)
jardineb5d44e2003-12-23 08:09:43 +0000440{
jardineb5d44e2003-12-23 08:09:43 +0000441 if (!CHECK_FLAG (old->flag, ISIS_ROUTE_FLAG_ACTIVE))
442 return 1;
443
444 if (new->cost < old->cost)
445 return 1;
hassof390d2c2004-09-10 20:48:21 +0000446
jardineb5d44e2003-12-23 08:09:43 +0000447 return 0;
448}
449
jardineb5d44e2003-12-23 08:09:43 +0000450struct isis_route_info *
451isis_route_create (struct prefix *prefix, u_int32_t cost, u_int32_t depth,
hassofac1f7c2005-09-26 18:26:26 +0000452 struct list *adjacencies, struct isis_area *area,
453 int level)
jardineb5d44e2003-12-23 08:09:43 +0000454{
455 struct route_node *route_node;
456 struct isis_route_info *rinfo_new, *rinfo_old, *route_info = NULL;
457 u_char buff[BUFSIZ];
458 u_char family;
hassof390d2c2004-09-10 20:48:21 +0000459
jardineb5d44e2003-12-23 08:09:43 +0000460 family = prefix->family;
461 /* for debugs */
hassof7c43dc2004-09-26 16:24:14 +0000462 prefix2str (prefix, (char *) buff, BUFSIZ);
hassof390d2c2004-09-10 20:48:21 +0000463
jardineb5d44e2003-12-23 08:09:43 +0000464 rinfo_new = isis_route_info_new (cost, depth, family, adjacencies);
hassof390d2c2004-09-10 20:48:21 +0000465 if (!rinfo_new)
466 {
467 zlog_err ("ISIS-Rte (%s): isis_route_create: out of memory!",
468 area->area_tag);
469 return NULL;
470 }
471
jardineb5d44e2003-12-23 08:09:43 +0000472 if (family == AF_INET)
hassofac1f7c2005-09-26 18:26:26 +0000473 route_node = route_node_get (area->route_table[level - 1], prefix);
jardineb5d44e2003-12-23 08:09:43 +0000474#ifdef HAVE_IPV6
475 else if (family == AF_INET6)
hassofac1f7c2005-09-26 18:26:26 +0000476 route_node = route_node_get (area->route_table6[level - 1], prefix);
jardineb5d44e2003-12-23 08:09:43 +0000477#endif /* HAVE_IPV6 */
hassof390d2c2004-09-10 20:48:21 +0000478 else
jardineb5d44e2003-12-23 08:09:43 +0000479 return NULL;
hassof390d2c2004-09-10 20:48:21 +0000480 rinfo_old = route_node->info;
481 if (!rinfo_old)
482 {
483 if (isis->debugs & DEBUG_RTE_EVENTS)
hasso529d65b2004-12-24 00:14:50 +0000484 zlog_debug ("ISIS-Rte (%s) route created: %s", area->area_tag, buff);
hassof390d2c2004-09-10 20:48:21 +0000485 SET_FLAG (rinfo_new->flag, ISIS_ROUTE_FLAG_ACTIVE);
486 route_node->info = rinfo_new;
487 return rinfo_new;
488 }
489
jardineb5d44e2003-12-23 08:09:43 +0000490 if (isis->debugs & DEBUG_RTE_EVENTS)
hasso529d65b2004-12-24 00:14:50 +0000491 zlog_debug ("ISIS-Rte (%s) route already exists: %s", area->area_tag,
hassof390d2c2004-09-10 20:48:21 +0000492 buff);
493
494 if (isis_route_info_same (rinfo_new, rinfo_old, family))
495 {
jardineb5d44e2003-12-23 08:09:43 +0000496 if (isis->debugs & DEBUG_RTE_EVENTS)
hasso529d65b2004-12-24 00:14:50 +0000497 zlog_debug ("ISIS-Rte (%s) route unchanged: %s", area->area_tag, buff);
jardineb5d44e2003-12-23 08:09:43 +0000498 isis_route_info_delete (rinfo_new);
499 route_info = rinfo_old;
500 }
hassof390d2c2004-09-10 20:48:21 +0000501 else if (isis_route_info_same_attrib (rinfo_new, rinfo_old))
502 {
503 /* merge the nexthop lists */
504 if (isis->debugs & DEBUG_RTE_EVENTS)
hasso529d65b2004-12-24 00:14:50 +0000505 zlog_debug ("ISIS-Rte (%s) route changed (same attribs): %s",
hassof390d2c2004-09-10 20:48:21 +0000506 area->area_tag, buff);
507#ifdef EXTREME_DEBUG
hasso3d549272005-09-21 18:52:14 +0000508 if (family == AF_INET)
509 {
510 zlog_debug ("Old nexthops");
511 nexthops_print (rinfo_old->nexthops);
512 zlog_debug ("New nexthops");
513 nexthops_print (rinfo_new->nexthops);
514 }
515 else if (family == AF_INET6)
516 {
517 zlog_debug ("Old nexthops");
518 nexthops6_print (rinfo_old->nexthops6);
519 zlog_debug ("New nexthops");
520 nexthops6_print (rinfo_new->nexthops6);
521 }
hassof390d2c2004-09-10 20:48:21 +0000522#endif /* EXTREME_DEBUG */
523 isis_route_info_merge (rinfo_new, rinfo_old, family);
524 isis_route_info_delete (rinfo_new);
525 route_info = rinfo_old;
hasso13fb40a2005-10-01 06:03:04 +0000526 UNSET_FLAG (route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNC);
hassof390d2c2004-09-10 20:48:21 +0000527 }
528 else
529 {
530 if (isis_route_info_prefer_new (rinfo_new, rinfo_old))
531 {
532 if (isis->debugs & DEBUG_RTE_EVENTS)
hasso529d65b2004-12-24 00:14:50 +0000533 zlog_debug ("ISIS-Rte (%s) route changed: %s", area->area_tag,
534 buff);
hassof390d2c2004-09-10 20:48:21 +0000535 isis_route_info_delete (rinfo_old);
536 route_info = rinfo_new;
537 }
538 else
539 {
540 if (isis->debugs & DEBUG_RTE_EVENTS)
hasso529d65b2004-12-24 00:14:50 +0000541 zlog_debug ("ISIS-Rte (%s) route rejected: %s", area->area_tag,
542 buff);
hassof390d2c2004-09-10 20:48:21 +0000543 isis_route_info_delete (rinfo_new);
544 route_info = rinfo_old;
545 }
546 }
547
jardineb5d44e2003-12-23 08:09:43 +0000548 SET_FLAG (route_info->flag, ISIS_ROUTE_FLAG_ACTIVE);
549 route_node->info = route_info;
hassof390d2c2004-09-10 20:48:21 +0000550
jardineb5d44e2003-12-23 08:09:43 +0000551 return route_info;
552}
553
hasso92365882005-01-18 13:53:33 +0000554static void
jardineb5d44e2003-12-23 08:09:43 +0000555isis_route_delete (struct prefix *prefix, struct route_table *table)
556{
557 struct route_node *rode;
558 struct isis_route_info *rinfo;
559 char buff[BUFSIZ];
560
561 /* for log */
562 prefix2str (prefix, buff, BUFSIZ);
563
564
565 rode = route_node_get (table, prefix);
566 rinfo = rode->info;
567
hassof390d2c2004-09-10 20:48:21 +0000568 if (rinfo == NULL)
569 {
570 if (isis->debugs & DEBUG_RTE_EVENTS)
hasso529d65b2004-12-24 00:14:50 +0000571 zlog_debug ("ISIS-Rte: tried to delete non-existant route %s", buff);
hassof390d2c2004-09-10 20:48:21 +0000572 return;
573 }
jardineb5d44e2003-12-23 08:09:43 +0000574
hassof390d2c2004-09-10 20:48:21 +0000575 if (CHECK_FLAG (rinfo->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNC))
576 {
577 UNSET_FLAG (rinfo->flag, ISIS_ROUTE_FLAG_ACTIVE);
578 if (isis->debugs & DEBUG_RTE_EVENTS)
hasso529d65b2004-12-24 00:14:50 +0000579 zlog_debug ("ISIS-Rte: route delete %s", buff);
hassof390d2c2004-09-10 20:48:21 +0000580 isis_zebra_route_update (prefix, rinfo);
581 }
jardineb5d44e2003-12-23 08:09:43 +0000582 isis_route_info_delete (rinfo);
583 rode->info = NULL;
hassof390d2c2004-09-10 20:48:21 +0000584
jardineb5d44e2003-12-23 08:09:43 +0000585 return;
586}
587
hassofac1f7c2005-09-26 18:26:26 +0000588/* Validating routes in particular table. */
589static void
590isis_route_validate_table (struct isis_area *area, struct route_table *table)
jardineb5d44e2003-12-23 08:09:43 +0000591{
hassofac1f7c2005-09-26 18:26:26 +0000592 struct route_node *rnode, *drnode;
jardineb5d44e2003-12-23 08:09:43 +0000593 struct isis_route_info *rinfo;
594 u_char buff[BUFSIZ];
hassofac1f7c2005-09-26 18:26:26 +0000595
596 for (rnode = route_top (table); rnode; rnode = route_next (rnode))
hassof390d2c2004-09-10 20:48:21 +0000597 {
hassofac1f7c2005-09-26 18:26:26 +0000598 if (rnode->info == NULL)
hassof390d2c2004-09-10 20:48:21 +0000599 continue;
hassofac1f7c2005-09-26 18:26:26 +0000600 rinfo = rnode->info;
hassof390d2c2004-09-10 20:48:21 +0000601
602 if (isis->debugs & DEBUG_RTE_EVENTS)
603 {
hassofac1f7c2005-09-26 18:26:26 +0000604 prefix2str (&rnode->p, (char *) buff, BUFSIZ);
hasso529d65b2004-12-24 00:14:50 +0000605 zlog_debug ("ISIS-Rte (%s): route validate: %s %s %s",
606 area->area_tag,
607 (CHECK_FLAG (rinfo->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNC) ?
hassof390d2c2004-09-10 20:48:21 +0000608 "sync'ed" : "nosync"),
hasso529d65b2004-12-24 00:14:50 +0000609 (CHECK_FLAG (rinfo->flag, ISIS_ROUTE_FLAG_ACTIVE) ?
hassof390d2c2004-09-10 20:48:21 +0000610 "active" : "inactive"), buff);
611 }
612
hassofac1f7c2005-09-26 18:26:26 +0000613 isis_zebra_route_update (&rnode->p, rinfo);
hassof390d2c2004-09-10 20:48:21 +0000614 if (!CHECK_FLAG (rinfo->flag, ISIS_ROUTE_FLAG_ACTIVE))
hassofac1f7c2005-09-26 18:26:26 +0000615 {
616 /* Area is either L1 or L2 => we use level route tables directly for
617 * validating => no problems with deleting routes. */
618 if (area->is_type != IS_LEVEL_1_AND_2)
619 {
620 isis_route_delete (&rnode->p, table);
621 continue;
622 }
623 /* If area is L1L2, we work with merge table and therefore must
624 * delete node from level tables as well before deleting route info.
625 * FIXME: Is it performance problem? There has to be the better way.
626 * Like not to deal with it here at all (see the next comment)? */
627 if (rnode->p.family == AF_INET)
628 {
629 drnode = route_node_get (area->route_table[0], &rnode->p);
630 if (drnode->info == rnode->info)
631 drnode->info = NULL;
632 drnode = route_node_get (area->route_table[1], &rnode->p);
633 if (drnode->info == rnode->info)
634 drnode->info = NULL;
635 }
636 if (rnode->p.family == AF_INET6)
637 {
638 drnode = route_node_get (area->route_table6[0], &rnode->p);
639 if (drnode->info == rnode->info)
640 drnode->info = NULL;
641 drnode = route_node_get (area->route_table6[1], &rnode->p);
642 if (drnode->info == rnode->info)
643 drnode->info = NULL;
644 }
645
646 isis_route_delete (&rnode->p, table);
647 }
jardineb5d44e2003-12-23 08:09:43 +0000648 }
hassofac1f7c2005-09-26 18:26:26 +0000649}
650
651/* Function to validate route tables for L1L2 areas. In this case we can't use
652 * level route tables directly, we have to merge them at first. L1 routes are
653 * preferred over the L2 ones.
654 *
655 * Merge algorithm is trivial (at least for now). All L1 paths are copied into
656 * merge table at first, then L2 paths are added if L1 path for same prefix
657 * doesn't already exists there.
658 *
659 * FIXME: Is it right place to do it at all? Maybe we should push both levels
660 * to the RIB with different zebra route types and let RIB handle this? */
661static void
662isis_route_validate_merge (struct isis_area *area, int family)
663{
664 struct route_table *table = NULL;
665 struct route_table *merge;
666 struct route_node *rnode, *mrnode;
667
668 merge = route_table_init ();
669
670 if (family == AF_INET)
671 table = area->route_table[0];
672 else if (family == AF_INET6)
673 table = area->route_table6[0];
674
675 for (rnode = route_top (table); rnode; rnode = route_next (rnode))
676 {
677 if (rnode->info == NULL)
678 continue;
679 mrnode = route_node_get (merge, &rnode->p);
680 mrnode->info = rnode->info;
681 }
682
683 if (family == AF_INET)
684 table = area->route_table[1];
685 else if (family == AF_INET6)
686 table = area->route_table6[1];
687
688 for (rnode = route_top (table); rnode; rnode = route_next (rnode))
689 {
690 if (rnode->info == NULL)
691 continue;
692 mrnode = route_node_get (merge, &rnode->p);
693 if (mrnode->info != NULL)
694 continue;
695 mrnode->info = rnode->info;
696 }
697
698 isis_route_validate_table (area, merge);
699 route_table_finish (merge);
700}
701
702/* Walk through route tables and propagate necessary changes into RIB. In case
703 * of L1L2 area, level tables have to be merged at first. */
704int
705isis_route_validate (struct thread *thread)
706{
707 struct isis_area *area;
708
709 area = THREAD_ARG (thread);
710
711 if (area->is_type == IS_LEVEL_1)
712 {
713 isis_route_validate_table (area, area->route_table[0]);
714 goto validate_ipv6;
715 }
716 if (area->is_type == IS_LEVEL_2)
717 {
718 isis_route_validate_table (area, area->route_table[1]);
719 goto validate_ipv6;
720 }
721
722 isis_route_validate_merge (area, AF_INET);
723
jardineb5d44e2003-12-23 08:09:43 +0000724#ifdef HAVE_IPV6
hassofac1f7c2005-09-26 18:26:26 +0000725validate_ipv6:
726 if (area->is_type == IS_LEVEL_1)
727 {
728 isis_route_validate_table (area, area->route_table6[0]);
729 return ISIS_OK;
730 }
731 if (area->is_type == IS_LEVEL_2)
732 {
733 isis_route_validate_table (area, area->route_table6[1]);
734 return ISIS_OK;
735 }
736
737 isis_route_validate_merge (area, AF_INET6);
jardineb5d44e2003-12-23 08:09:43 +0000738#endif
739
740 return ISIS_OK;
741}