blob: b9b25e2c98fd9dfc9f53d692642810457608dd01 [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;
hassof390d2c2004-09-10 20:48:21 +0000132
paul1eb8ef22005-04-07 07:30:20 +0000133 for (ALL_LIST_ELEMENTS_RO (nhs, node, nh))
134 nexthop_print (nh);
jardineb5d44e2003-12-23 08:09:43 +0000135}
hasso3d549272005-09-21 18:52:14 +0000136#endif /* EXTREME_DEBUG */
jardineb5d44e2003-12-23 08:09:43 +0000137
138#ifdef HAVE_IPV6
hasso92365882005-01-18 13:53:33 +0000139static struct isis_nexthop6 *
hassof390d2c2004-09-10 20:48:21 +0000140isis_nexthop6_new (struct in6_addr *ip6, unsigned int ifindex)
jardineb5d44e2003-12-23 08:09:43 +0000141{
hassof390d2c2004-09-10 20:48:21 +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;
hassof390d2c2004-09-10 20:48:21 +0000226
paul1eb8ef22005-04-07 07:30:20 +0000227 for (ALL_LIST_ELEMENTS_RO (nhs6, node, nh6))
228 nexthop6_print (nh6);
jardineb5d44e2003-12-23 08:09:43 +0000229}
hasso92365882005-01-18 13:53:33 +0000230#endif /* EXTREME_DEBUG */
jardineb5d44e2003-12-23 08:09:43 +0000231#endif /* HAVE_IPV6 */
232
hasso92365882005-01-18 13:53:33 +0000233static void
jardineb5d44e2003-12-23 08:09:43 +0000234adjinfo2nexthop (struct list *nexthops, struct isis_adjacency *adj)
235{
236 struct isis_nexthop *nh;
hasso3fdb2dd2005-09-28 18:45:54 +0000237 struct listnode *node;
jardineb5d44e2003-12-23 08:09:43 +0000238 struct in_addr *ipv4_addr;
239
240 if (adj->ipv4_addrs == NULL)
241 return;
paul1eb8ef22005-04-07 07:30:20 +0000242
hasso3fdb2dd2005-09-28 18:45:54 +0000243 for (ALL_LIST_ELEMENTS_RO (adj->ipv4_addrs, node, ipv4_addr))
hassof390d2c2004-09-10 20:48:21 +0000244 {
hassof390d2c2004-09-10 20:48:21 +0000245 if (!nexthoplookup (nexthops, ipv4_addr,
246 adj->circuit->interface->ifindex))
247 {
248 nh = isis_nexthop_create (ipv4_addr,
249 adj->circuit->interface->ifindex);
250 listnode_add (nexthops, nh);
251 }
jardineb5d44e2003-12-23 08:09:43 +0000252 }
jardineb5d44e2003-12-23 08:09:43 +0000253}
254
255#ifdef HAVE_IPV6
hasso92365882005-01-18 13:53:33 +0000256static void
jardineb5d44e2003-12-23 08:09:43 +0000257adjinfo2nexthop6 (struct list *nexthops6, struct isis_adjacency *adj)
258{
hasso3fdb2dd2005-09-28 18:45:54 +0000259 struct listnode *node;
jardineb5d44e2003-12-23 08:09:43 +0000260 struct in6_addr *ipv6_addr;
261 struct isis_nexthop6 *nh6;
hassof390d2c2004-09-10 20:48:21 +0000262
jardineb5d44e2003-12-23 08:09:43 +0000263 if (!adj->ipv6_addrs)
264 return;
265
hasso3fdb2dd2005-09-28 18:45:54 +0000266 for (ALL_LIST_ELEMENTS_RO (adj->ipv6_addrs, node, ipv6_addr))
hassof390d2c2004-09-10 20:48:21 +0000267 {
hassof390d2c2004-09-10 20:48:21 +0000268 if (!nexthop6lookup (nexthops6, ipv6_addr,
269 adj->circuit->interface->ifindex))
270 {
271 nh6 = isis_nexthop6_create (ipv6_addr,
272 adj->circuit->interface->ifindex);
273 listnode_add (nexthops6, nh6);
274 }
jardineb5d44e2003-12-23 08:09:43 +0000275 }
jardineb5d44e2003-12-23 08:09:43 +0000276}
277#endif /* HAVE_IPV6 */
278
hasso92365882005-01-18 13:53:33 +0000279static struct isis_route_info *
hassof390d2c2004-09-10 20:48:21 +0000280isis_route_info_new (uint32_t cost, uint32_t depth, u_char family,
281 struct list *adjacencies)
jardineb5d44e2003-12-23 08:09:43 +0000282{
283 struct isis_route_info *rinfo;
284 struct isis_adjacency *adj;
hasso3fdb2dd2005-09-28 18:45:54 +0000285 struct listnode *node;
hassof390d2c2004-09-10 20:48:21 +0000286
hasso3fdb2dd2005-09-28 18:45:54 +0000287 rinfo = XCALLOC (MTYPE_ISIS_ROUTE_INFO, sizeof (struct isis_route_info));
hassof390d2c2004-09-10 20:48:21 +0000288 if (!rinfo)
289 {
290 zlog_err ("ISIS-Rte: isis_route_info_new: out of memory!");
291 return NULL;
292 }
jardineb5d44e2003-12-23 08:09:43 +0000293
hassof390d2c2004-09-10 20:48:21 +0000294 if (family == AF_INET)
295 {
296 rinfo->nexthops = list_new ();
hasso3fdb2dd2005-09-28 18:45:54 +0000297 for (ALL_LIST_ELEMENTS_RO (adjacencies, node, adj))
paul1eb8ef22005-04-07 07:30:20 +0000298 adjinfo2nexthop (rinfo->nexthops, adj);
jardineb5d44e2003-12-23 08:09:43 +0000299 }
jardineb5d44e2003-12-23 08:09:43 +0000300#ifdef HAVE_IPV6
hassof390d2c2004-09-10 20:48:21 +0000301 if (family == AF_INET6)
302 {
303 rinfo->nexthops6 = list_new ();
hasso3fdb2dd2005-09-28 18:45:54 +0000304 for (ALL_LIST_ELEMENTS_RO (adjacencies, node, adj))
paul1eb8ef22005-04-07 07:30:20 +0000305 adjinfo2nexthop6 (rinfo->nexthops6, adj);
jardineb5d44e2003-12-23 08:09:43 +0000306 }
hassof390d2c2004-09-10 20:48:21 +0000307
jardineb5d44e2003-12-23 08:09:43 +0000308#endif /* HAVE_IPV6 */
309
310 rinfo->cost = cost;
311 rinfo->depth = depth;
hassof390d2c2004-09-10 20:48:21 +0000312
jardineb5d44e2003-12-23 08:09:43 +0000313 return rinfo;
314}
315
hasso92365882005-01-18 13:53:33 +0000316static void
jardineb5d44e2003-12-23 08:09:43 +0000317isis_route_info_delete (struct isis_route_info *route_info)
318{
hassof390d2c2004-09-10 20:48:21 +0000319 if (route_info->nexthops)
320 {
hassof7c43dc2004-09-26 16:24:14 +0000321 route_info->nexthops->del = (void (*)(void *)) isis_nexthop_delete;
hassof390d2c2004-09-10 20:48:21 +0000322 list_delete (route_info->nexthops);
323 }
324
jardineb5d44e2003-12-23 08:09:43 +0000325#ifdef HAVE_IPV6
hassof390d2c2004-09-10 20:48:21 +0000326 if (route_info->nexthops6)
327 {
hassof7c43dc2004-09-26 16:24:14 +0000328 route_info->nexthops6->del = (void (*)(void *)) isis_nexthop6_delete;
jardineb5d44e2003-12-23 08:09:43 +0000329 list_delete (route_info->nexthops6);
hassof390d2c2004-09-10 20:48:21 +0000330 }
jardineb5d44e2003-12-23 08:09:43 +0000331#endif /* HAVE_IPV6 */
hassof390d2c2004-09-10 20:48:21 +0000332
jardineb5d44e2003-12-23 08:09:43 +0000333 XFREE (MTYPE_ISIS_ROUTE_INFO, route_info);
334}
335
hasso92365882005-01-18 13:53:33 +0000336static int
hassof390d2c2004-09-10 20:48:21 +0000337isis_route_info_same_attrib (struct isis_route_info *new,
338 struct isis_route_info *old)
jardineb5d44e2003-12-23 08:09:43 +0000339{
340 if (new->cost != old->cost)
341 return 0;
342 if (new->depth != old->depth)
343 return 0;
hassof390d2c2004-09-10 20:48:21 +0000344
jardineb5d44e2003-12-23 08:09:43 +0000345 return 1;
346}
347
hasso92365882005-01-18 13:53:33 +0000348static int
hassof390d2c2004-09-10 20:48:21 +0000349isis_route_info_same (struct isis_route_info *new,
350 struct isis_route_info *old, u_char family)
jardineb5d44e2003-12-23 08:09:43 +0000351{
hasso3fdb2dd2005-09-28 18:45:54 +0000352 struct listnode *node;
jardineb5d44e2003-12-23 08:09:43 +0000353 struct isis_nexthop *nexthop;
354#ifdef HAVE_IPV6
355 struct isis_nexthop6 *nexthop6;
356#endif /* HAVE_IPV6 */
357 if (!isis_route_info_same_attrib (new, old))
358 return 0;
hassof390d2c2004-09-10 20:48:21 +0000359
360 if (family == AF_INET)
361 {
hasso3fdb2dd2005-09-28 18:45:54 +0000362 for (ALL_LIST_ELEMENTS_RO (new->nexthops, node, nexthop))
paul1eb8ef22005-04-07 07:30:20 +0000363 if (nexthoplookup (old->nexthops, &nexthop->ip, nexthop->ifindex)
364 == 0)
365 return 0;
hassof390d2c2004-09-10 20:48:21 +0000366
hasso3fdb2dd2005-09-28 18:45:54 +0000367 for (ALL_LIST_ELEMENTS_RO (old->nexthops, node, nexthop))
paul1eb8ef22005-04-07 07:30:20 +0000368 if (nexthoplookup (new->nexthops, &nexthop->ip, nexthop->ifindex)
369 == 0)
370 return 0;
jardineb5d44e2003-12-23 08:09:43 +0000371 }
jardineb5d44e2003-12-23 08:09:43 +0000372#ifdef HAVE_IPV6
hassof390d2c2004-09-10 20:48:21 +0000373 else if (family == AF_INET6)
374 {
hasso3fdb2dd2005-09-28 18:45:54 +0000375 for (ALL_LIST_ELEMENTS_RO (new->nexthops6, node, nexthop6))
paul1eb8ef22005-04-07 07:30:20 +0000376 if (nexthop6lookup (old->nexthops6, &nexthop6->ip6,
377 nexthop6->ifindex) == 0)
378 return 0;
hassof390d2c2004-09-10 20:48:21 +0000379
hasso3fdb2dd2005-09-28 18:45:54 +0000380 for (ALL_LIST_ELEMENTS_RO (old->nexthops6, node, nexthop6))
paul1eb8ef22005-04-07 07:30:20 +0000381 if (nexthop6lookup (new->nexthops6, &nexthop6->ip6,
382 nexthop6->ifindex) == 0)
383 return 0;
jardineb5d44e2003-12-23 08:09:43 +0000384 }
jardineb5d44e2003-12-23 08:09:43 +0000385#endif /* HAVE_IPV6 */
386
387 return 1;
388}
389
hasso92365882005-01-18 13:53:33 +0000390static void
jardineb5d44e2003-12-23 08:09:43 +0000391isis_nexthops_merge (struct list *new, struct list *old)
392{
hasso3fdb2dd2005-09-28 18:45:54 +0000393 struct listnode *node;
jardineb5d44e2003-12-23 08:09:43 +0000394 struct isis_nexthop *nexthop;
395
hasso3fdb2dd2005-09-28 18:45:54 +0000396 for (ALL_LIST_ELEMENTS_RO (new, node, nexthop))
hassof390d2c2004-09-10 20:48:21 +0000397 {
hassof390d2c2004-09-10 20:48:21 +0000398 if (nexthoplookup (old, &nexthop->ip, nexthop->ifindex))
399 continue;
400 listnode_add (old, nexthop);
401 nexthop->lock++;
402 }
jardineb5d44e2003-12-23 08:09:43 +0000403}
404
jardineb5d44e2003-12-23 08:09:43 +0000405#ifdef HAVE_IPV6
hasso92365882005-01-18 13:53:33 +0000406static void
jardineb5d44e2003-12-23 08:09:43 +0000407isis_nexthops6_merge (struct list *new, struct list *old)
408{
hasso3fdb2dd2005-09-28 18:45:54 +0000409 struct listnode *node;
jardineb5d44e2003-12-23 08:09:43 +0000410 struct isis_nexthop6 *nexthop6;
411
hasso3fdb2dd2005-09-28 18:45:54 +0000412 for (ALL_LIST_ELEMENTS_RO (new, node, nexthop6))
hassof390d2c2004-09-10 20:48:21 +0000413 {
hassof390d2c2004-09-10 20:48:21 +0000414 if (nexthop6lookup (old, &nexthop6->ip6, nexthop6->ifindex))
415 continue;
416 listnode_add (old, nexthop6);
417 nexthop6->lock++;
418 }
jardineb5d44e2003-12-23 08:09:43 +0000419}
420#endif /* HAVE_IPV6 */
421
hasso92365882005-01-18 13:53:33 +0000422static void
hassof390d2c2004-09-10 20:48:21 +0000423isis_route_info_merge (struct isis_route_info *new,
424 struct isis_route_info *old, u_char family)
jardineb5d44e2003-12-23 08:09:43 +0000425{
hassof390d2c2004-09-10 20:48:21 +0000426 if (family == AF_INET)
jardineb5d44e2003-12-23 08:09:43 +0000427 isis_nexthops_merge (new->nexthops, old->nexthops);
428#ifdef HAVE_IPV6
hassof390d2c2004-09-10 20:48:21 +0000429 else if (family == AF_INET6)
jardineb5d44e2003-12-23 08:09:43 +0000430 isis_nexthops6_merge (new->nexthops6, old->nexthops6);
431#endif /* HAVE_IPV6 */
hassof390d2c2004-09-10 20:48:21 +0000432
jardineb5d44e2003-12-23 08:09:43 +0000433 return;
434}
435
hasso92365882005-01-18 13:53:33 +0000436static int
hassof390d2c2004-09-10 20:48:21 +0000437isis_route_info_prefer_new (struct isis_route_info *new,
438 struct isis_route_info *old)
jardineb5d44e2003-12-23 08:09:43 +0000439{
jardineb5d44e2003-12-23 08:09:43 +0000440 if (!CHECK_FLAG (old->flag, ISIS_ROUTE_FLAG_ACTIVE))
441 return 1;
442
443 if (new->cost < old->cost)
444 return 1;
hassof390d2c2004-09-10 20:48:21 +0000445
jardineb5d44e2003-12-23 08:09:43 +0000446 return 0;
447}
448
jardineb5d44e2003-12-23 08:09:43 +0000449struct isis_route_info *
450isis_route_create (struct prefix *prefix, u_int32_t cost, u_int32_t depth,
hassofac1f7c2005-09-26 18:26:26 +0000451 struct list *adjacencies, struct isis_area *area,
452 int level)
jardineb5d44e2003-12-23 08:09:43 +0000453{
454 struct route_node *route_node;
455 struct isis_route_info *rinfo_new, *rinfo_old, *route_info = NULL;
456 u_char buff[BUFSIZ];
457 u_char family;
hassof390d2c2004-09-10 20:48:21 +0000458
jardineb5d44e2003-12-23 08:09:43 +0000459 family = prefix->family;
460 /* for debugs */
hassof7c43dc2004-09-26 16:24:14 +0000461 prefix2str (prefix, (char *) buff, BUFSIZ);
hassof390d2c2004-09-10 20:48:21 +0000462
jardineb5d44e2003-12-23 08:09:43 +0000463 rinfo_new = isis_route_info_new (cost, depth, family, adjacencies);
hassof390d2c2004-09-10 20:48:21 +0000464 if (!rinfo_new)
465 {
466 zlog_err ("ISIS-Rte (%s): isis_route_create: out of memory!",
467 area->area_tag);
468 return NULL;
469 }
470
jardineb5d44e2003-12-23 08:09:43 +0000471 if (family == AF_INET)
hassofac1f7c2005-09-26 18:26:26 +0000472 route_node = route_node_get (area->route_table[level - 1], prefix);
jardineb5d44e2003-12-23 08:09:43 +0000473#ifdef HAVE_IPV6
474 else if (family == AF_INET6)
hassofac1f7c2005-09-26 18:26:26 +0000475 route_node = route_node_get (area->route_table6[level - 1], prefix);
jardineb5d44e2003-12-23 08:09:43 +0000476#endif /* HAVE_IPV6 */
hassof390d2c2004-09-10 20:48:21 +0000477 else
jardineb5d44e2003-12-23 08:09:43 +0000478 return NULL;
hassof390d2c2004-09-10 20:48:21 +0000479 rinfo_old = route_node->info;
480 if (!rinfo_old)
481 {
482 if (isis->debugs & DEBUG_RTE_EVENTS)
hasso529d65b2004-12-24 00:14:50 +0000483 zlog_debug ("ISIS-Rte (%s) route created: %s", area->area_tag, buff);
hassof390d2c2004-09-10 20:48:21 +0000484 SET_FLAG (rinfo_new->flag, ISIS_ROUTE_FLAG_ACTIVE);
485 route_node->info = rinfo_new;
486 return rinfo_new;
487 }
488
jardineb5d44e2003-12-23 08:09:43 +0000489 if (isis->debugs & DEBUG_RTE_EVENTS)
hasso529d65b2004-12-24 00:14:50 +0000490 zlog_debug ("ISIS-Rte (%s) route already exists: %s", area->area_tag,
hassof390d2c2004-09-10 20:48:21 +0000491 buff);
492
493 if (isis_route_info_same (rinfo_new, rinfo_old, family))
494 {
jardineb5d44e2003-12-23 08:09:43 +0000495 if (isis->debugs & DEBUG_RTE_EVENTS)
hasso529d65b2004-12-24 00:14:50 +0000496 zlog_debug ("ISIS-Rte (%s) route unchanged: %s", area->area_tag, buff);
jardineb5d44e2003-12-23 08:09:43 +0000497 isis_route_info_delete (rinfo_new);
498 route_info = rinfo_old;
499 }
hassof390d2c2004-09-10 20:48:21 +0000500 else if (isis_route_info_same_attrib (rinfo_new, rinfo_old))
501 {
502 /* merge the nexthop lists */
503 if (isis->debugs & DEBUG_RTE_EVENTS)
hasso529d65b2004-12-24 00:14:50 +0000504 zlog_debug ("ISIS-Rte (%s) route changed (same attribs): %s",
hassof390d2c2004-09-10 20:48:21 +0000505 area->area_tag, buff);
506#ifdef EXTREME_DEBUG
hasso3d549272005-09-21 18:52:14 +0000507 if (family == AF_INET)
508 {
509 zlog_debug ("Old nexthops");
510 nexthops_print (rinfo_old->nexthops);
511 zlog_debug ("New nexthops");
512 nexthops_print (rinfo_new->nexthops);
513 }
514 else if (family == AF_INET6)
515 {
516 zlog_debug ("Old nexthops");
517 nexthops6_print (rinfo_old->nexthops6);
518 zlog_debug ("New nexthops");
519 nexthops6_print (rinfo_new->nexthops6);
520 }
hassof390d2c2004-09-10 20:48:21 +0000521#endif /* EXTREME_DEBUG */
522 isis_route_info_merge (rinfo_new, rinfo_old, family);
523 isis_route_info_delete (rinfo_new);
524 route_info = rinfo_old;
525 }
526 else
527 {
528 if (isis_route_info_prefer_new (rinfo_new, rinfo_old))
529 {
530 if (isis->debugs & DEBUG_RTE_EVENTS)
hasso529d65b2004-12-24 00:14:50 +0000531 zlog_debug ("ISIS-Rte (%s) route changed: %s", area->area_tag,
532 buff);
hassof390d2c2004-09-10 20:48:21 +0000533 isis_route_info_delete (rinfo_old);
534 route_info = rinfo_new;
535 }
536 else
537 {
538 if (isis->debugs & DEBUG_RTE_EVENTS)
hasso529d65b2004-12-24 00:14:50 +0000539 zlog_debug ("ISIS-Rte (%s) route rejected: %s", area->area_tag,
540 buff);
hassof390d2c2004-09-10 20:48:21 +0000541 isis_route_info_delete (rinfo_new);
542 route_info = rinfo_old;
543 }
544 }
545
jardineb5d44e2003-12-23 08:09:43 +0000546 SET_FLAG (route_info->flag, ISIS_ROUTE_FLAG_ACTIVE);
547 route_node->info = route_info;
hassof390d2c2004-09-10 20:48:21 +0000548
jardineb5d44e2003-12-23 08:09:43 +0000549 return route_info;
550}
551
hasso92365882005-01-18 13:53:33 +0000552static void
jardineb5d44e2003-12-23 08:09:43 +0000553isis_route_delete (struct prefix *prefix, struct route_table *table)
554{
555 struct route_node *rode;
556 struct isis_route_info *rinfo;
557 char buff[BUFSIZ];
558
559 /* for log */
560 prefix2str (prefix, buff, BUFSIZ);
561
562
563 rode = route_node_get (table, prefix);
564 rinfo = rode->info;
565
hassof390d2c2004-09-10 20:48:21 +0000566 if (rinfo == NULL)
567 {
568 if (isis->debugs & DEBUG_RTE_EVENTS)
hasso529d65b2004-12-24 00:14:50 +0000569 zlog_debug ("ISIS-Rte: tried to delete non-existant route %s", buff);
hassof390d2c2004-09-10 20:48:21 +0000570 return;
571 }
jardineb5d44e2003-12-23 08:09:43 +0000572
hassof390d2c2004-09-10 20:48:21 +0000573 if (CHECK_FLAG (rinfo->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNC))
574 {
575 UNSET_FLAG (rinfo->flag, ISIS_ROUTE_FLAG_ACTIVE);
576 if (isis->debugs & DEBUG_RTE_EVENTS)
hasso529d65b2004-12-24 00:14:50 +0000577 zlog_debug ("ISIS-Rte: route delete %s", buff);
hassof390d2c2004-09-10 20:48:21 +0000578 isis_zebra_route_update (prefix, rinfo);
579 }
jardineb5d44e2003-12-23 08:09:43 +0000580 isis_route_info_delete (rinfo);
581 rode->info = NULL;
hassof390d2c2004-09-10 20:48:21 +0000582
jardineb5d44e2003-12-23 08:09:43 +0000583 return;
584}
585
hassofac1f7c2005-09-26 18:26:26 +0000586/* Validating routes in particular table. */
587static void
588isis_route_validate_table (struct isis_area *area, struct route_table *table)
jardineb5d44e2003-12-23 08:09:43 +0000589{
hassofac1f7c2005-09-26 18:26:26 +0000590 struct route_node *rnode, *drnode;
jardineb5d44e2003-12-23 08:09:43 +0000591 struct isis_route_info *rinfo;
592 u_char buff[BUFSIZ];
hassofac1f7c2005-09-26 18:26:26 +0000593
594 for (rnode = route_top (table); rnode; rnode = route_next (rnode))
hassof390d2c2004-09-10 20:48:21 +0000595 {
hassofac1f7c2005-09-26 18:26:26 +0000596 if (rnode->info == NULL)
hassof390d2c2004-09-10 20:48:21 +0000597 continue;
hassofac1f7c2005-09-26 18:26:26 +0000598 rinfo = rnode->info;
hassof390d2c2004-09-10 20:48:21 +0000599
600 if (isis->debugs & DEBUG_RTE_EVENTS)
601 {
hassofac1f7c2005-09-26 18:26:26 +0000602 prefix2str (&rnode->p, (char *) buff, BUFSIZ);
hasso529d65b2004-12-24 00:14:50 +0000603 zlog_debug ("ISIS-Rte (%s): route validate: %s %s %s",
604 area->area_tag,
605 (CHECK_FLAG (rinfo->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNC) ?
hassof390d2c2004-09-10 20:48:21 +0000606 "sync'ed" : "nosync"),
hasso529d65b2004-12-24 00:14:50 +0000607 (CHECK_FLAG (rinfo->flag, ISIS_ROUTE_FLAG_ACTIVE) ?
hassof390d2c2004-09-10 20:48:21 +0000608 "active" : "inactive"), buff);
609 }
610
hassofac1f7c2005-09-26 18:26:26 +0000611 isis_zebra_route_update (&rnode->p, rinfo);
hassof390d2c2004-09-10 20:48:21 +0000612 if (!CHECK_FLAG (rinfo->flag, ISIS_ROUTE_FLAG_ACTIVE))
hassofac1f7c2005-09-26 18:26:26 +0000613 {
614 /* Area is either L1 or L2 => we use level route tables directly for
615 * validating => no problems with deleting routes. */
616 if (area->is_type != IS_LEVEL_1_AND_2)
617 {
618 isis_route_delete (&rnode->p, table);
619 continue;
620 }
621 /* If area is L1L2, we work with merge table and therefore must
622 * delete node from level tables as well before deleting route info.
623 * FIXME: Is it performance problem? There has to be the better way.
624 * Like not to deal with it here at all (see the next comment)? */
625 if (rnode->p.family == AF_INET)
626 {
627 drnode = route_node_get (area->route_table[0], &rnode->p);
628 if (drnode->info == rnode->info)
629 drnode->info = NULL;
630 drnode = route_node_get (area->route_table[1], &rnode->p);
631 if (drnode->info == rnode->info)
632 drnode->info = NULL;
633 }
634 if (rnode->p.family == AF_INET6)
635 {
636 drnode = route_node_get (area->route_table6[0], &rnode->p);
637 if (drnode->info == rnode->info)
638 drnode->info = NULL;
639 drnode = route_node_get (area->route_table6[1], &rnode->p);
640 if (drnode->info == rnode->info)
641 drnode->info = NULL;
642 }
643
644 isis_route_delete (&rnode->p, table);
645 }
jardineb5d44e2003-12-23 08:09:43 +0000646 }
hassofac1f7c2005-09-26 18:26:26 +0000647}
648
649/* Function to validate route tables for L1L2 areas. In this case we can't use
650 * level route tables directly, we have to merge them at first. L1 routes are
651 * preferred over the L2 ones.
652 *
653 * Merge algorithm is trivial (at least for now). All L1 paths are copied into
654 * merge table at first, then L2 paths are added if L1 path for same prefix
655 * doesn't already exists there.
656 *
657 * FIXME: Is it right place to do it at all? Maybe we should push both levels
658 * to the RIB with different zebra route types and let RIB handle this? */
659static void
660isis_route_validate_merge (struct isis_area *area, int family)
661{
662 struct route_table *table = NULL;
663 struct route_table *merge;
664 struct route_node *rnode, *mrnode;
665
666 merge = route_table_init ();
667
668 if (family == AF_INET)
669 table = area->route_table[0];
670 else if (family == AF_INET6)
671 table = area->route_table6[0];
672
673 for (rnode = route_top (table); rnode; rnode = route_next (rnode))
674 {
675 if (rnode->info == NULL)
676 continue;
677 mrnode = route_node_get (merge, &rnode->p);
678 mrnode->info = rnode->info;
679 }
680
681 if (family == AF_INET)
682 table = area->route_table[1];
683 else if (family == AF_INET6)
684 table = area->route_table6[1];
685
686 for (rnode = route_top (table); rnode; rnode = route_next (rnode))
687 {
688 if (rnode->info == NULL)
689 continue;
690 mrnode = route_node_get (merge, &rnode->p);
691 if (mrnode->info != NULL)
692 continue;
693 mrnode->info = rnode->info;
694 }
695
696 isis_route_validate_table (area, merge);
697 route_table_finish (merge);
698}
699
700/* Walk through route tables and propagate necessary changes into RIB. In case
701 * of L1L2 area, level tables have to be merged at first. */
702int
703isis_route_validate (struct thread *thread)
704{
705 struct isis_area *area;
706
707 area = THREAD_ARG (thread);
708
709 if (area->is_type == IS_LEVEL_1)
710 {
711 isis_route_validate_table (area, area->route_table[0]);
712 goto validate_ipv6;
713 }
714 if (area->is_type == IS_LEVEL_2)
715 {
716 isis_route_validate_table (area, area->route_table[1]);
717 goto validate_ipv6;
718 }
719
720 isis_route_validate_merge (area, AF_INET);
721
jardineb5d44e2003-12-23 08:09:43 +0000722#ifdef HAVE_IPV6
hassofac1f7c2005-09-26 18:26:26 +0000723validate_ipv6:
724 if (area->is_type == IS_LEVEL_1)
725 {
726 isis_route_validate_table (area, area->route_table6[0]);
727 return ISIS_OK;
728 }
729 if (area->is_type == IS_LEVEL_2)
730 {
731 isis_route_validate_table (area, area->route_table6[1]);
732 return ISIS_OK;
733 }
734
735 isis_route_validate_merge (area, AF_INET6);
jardineb5d44e2003-12-23 08:09:43 +0000736#endif
737
738 return ISIS_OK;
739}