blob: c8f0aaba7b978f628259fd4b18f9527bb0506a67 [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
jardineb5d44e2003-12-23 08:09:43 +000025#include <zebra.h>
jardineb5d44e2003-12-23 08:09:43 +000026
27#include "thread.h"
28#include "linklist.h"
29#include "vty.h"
30#include "log.h"
31#include "memory.h"
32#include "prefix.h"
33#include "hash.h"
34#include "if.h"
35#include "table.h"
36
37#include "isis_constants.h"
38#include "isis_common.h"
39#include "dict.h"
40#include "isisd.h"
41#include "isis_misc.h"
42#include "isis_adjacency.h"
43#include "isis_circuit.h"
44#include "isis_tlv.h"
45#include "isis_pdu.h"
46#include "isis_lsp.h"
47#include "isis_spf.h"
48#include "isis_route.h"
49#include "isis_zebra.h"
50
51extern struct isis *isis;
52extern struct thread_master *master;
53
hasso92365882005-01-18 13:53:33 +000054static struct isis_nexthop *
jardineb5d44e2003-12-23 08:09:43 +000055isis_nexthop_create (struct in_addr *ip, unsigned int ifindex)
jardineb5d44e2003-12-23 08:09:43 +000056{
57 struct listnode *node;
58 struct isis_nexthop *nexthop;
jardineb5d44e2003-12-23 08:09:43 +000059
paul1eb8ef22005-04-07 07:30:20 +000060 for (ALL_LIST_ELEMENTS_RO (isis->nexthops, node, nexthop))
hassof390d2c2004-09-10 20:48:21 +000061 {
hassof390d2c2004-09-10 20:48:21 +000062 if (nexthop->ifindex != ifindex)
63 continue;
64 if (ip && memcmp (&nexthop->ip, ip, sizeof (struct in_addr)) != 0)
65 continue;
66
67 nexthop->lock++;
68 return nexthop;
69 }
70
hasso3fdb2dd2005-09-28 18:45:54 +000071 nexthop = XCALLOC (MTYPE_ISIS_NEXTHOP, sizeof (struct isis_nexthop));
hassof390d2c2004-09-10 20:48:21 +000072 if (!nexthop)
73 {
74 zlog_err ("ISIS-Rte: isis_nexthop_create: out of memory!");
75 }
76
jardineb5d44e2003-12-23 08:09:43 +000077 nexthop->ifindex = ifindex;
78 memcpy (&nexthop->ip, ip, sizeof (struct in_addr));
79 listnode_add (isis->nexthops, nexthop);
80 nexthop->lock++;
81
82 return nexthop;
83}
84
hasso92365882005-01-18 13:53:33 +000085static void
jardineb5d44e2003-12-23 08:09:43 +000086isis_nexthop_delete (struct isis_nexthop *nexthop)
87{
88 nexthop->lock--;
hassof390d2c2004-09-10 20:48:21 +000089 if (nexthop->lock == 0)
90 {
91 listnode_delete (isis->nexthops, nexthop);
92 XFREE (MTYPE_ISIS_NEXTHOP, nexthop);
93 }
94
jardineb5d44e2003-12-23 08:09:43 +000095 return;
96}
97
hasso92365882005-01-18 13:53:33 +000098static int
hassof390d2c2004-09-10 20:48:21 +000099nexthoplookup (struct list *nexthops, struct in_addr *ip,
100 unsigned int ifindex)
jardineb5d44e2003-12-23 08:09:43 +0000101{
102 struct listnode *node;
103 struct isis_nexthop *nh;
104
paul1eb8ef22005-04-07 07:30:20 +0000105 for (ALL_LIST_ELEMENTS_RO (nexthops, node, nh))
hassof390d2c2004-09-10 20:48:21 +0000106 {
hassof390d2c2004-09-10 20:48:21 +0000107 if (!(memcmp (ip, &nh->ip, sizeof (struct in_addr))) &&
108 ifindex == nh->ifindex)
109 return 1;
110 }
jardineb5d44e2003-12-23 08:09:43 +0000111
112 return 0;
113}
114
hasso3d549272005-09-21 18:52:14 +0000115#ifdef EXTREME_DEBUG
hasso92365882005-01-18 13:53:33 +0000116static void
jardineb5d44e2003-12-23 08:09:43 +0000117nexthop_print (struct isis_nexthop *nh)
118{
119 u_char buf[BUFSIZ];
hassof390d2c2004-09-10 20:48:21 +0000120
hassof7c43dc2004-09-26 16:24:14 +0000121 inet_ntop (AF_INET, &nh->ip, (char *) buf, BUFSIZ);
hassof390d2c2004-09-10 20:48:21 +0000122
hasso529d65b2004-12-24 00:14:50 +0000123 zlog_debug (" %s %u", buf, nh->ifindex);
jardineb5d44e2003-12-23 08:09:43 +0000124}
125
hasso92365882005-01-18 13:53:33 +0000126static void
jardineb5d44e2003-12-23 08:09:43 +0000127nexthops_print (struct list *nhs)
128{
129 struct listnode *node;
hasso13fb40a2005-10-01 06:03:04 +0000130 struct isis_nexthop *nh;
hassof390d2c2004-09-10 20:48:21 +0000131
paul1eb8ef22005-04-07 07:30:20 +0000132 for (ALL_LIST_ELEMENTS_RO (nhs, node, nh))
133 nexthop_print (nh);
jardineb5d44e2003-12-23 08:09:43 +0000134}
hasso3d549272005-09-21 18:52:14 +0000135#endif /* EXTREME_DEBUG */
jardineb5d44e2003-12-23 08:09:43 +0000136
137#ifdef HAVE_IPV6
hasso92365882005-01-18 13:53:33 +0000138static struct isis_nexthop6 *
hassof390d2c2004-09-10 20:48:21 +0000139isis_nexthop6_new (struct in6_addr *ip6, unsigned int ifindex)
jardineb5d44e2003-12-23 08:09:43 +0000140{
jardineb5d44e2003-12-23 08:09:43 +0000141 struct isis_nexthop6 *nexthop6;
hassof390d2c2004-09-10 20:48:21 +0000142
hasso3fdb2dd2005-09-28 18:45:54 +0000143 nexthop6 = XCALLOC (MTYPE_ISIS_NEXTHOP6, sizeof (struct isis_nexthop6));
hassof390d2c2004-09-10 20:48:21 +0000144 if (!nexthop6)
145 {
146 zlog_err ("ISIS-Rte: isis_nexthop_create6: out of memory!");
147 }
148
jardineb5d44e2003-12-23 08:09:43 +0000149 nexthop6->ifindex = ifindex;
150 memcpy (&nexthop6->ip6, ip6, sizeof (struct in6_addr));
151 nexthop6->lock++;
152
153 return nexthop6;
154}
155
hasso92365882005-01-18 13:53:33 +0000156static struct isis_nexthop6 *
jardineb5d44e2003-12-23 08:09:43 +0000157isis_nexthop6_create (struct in6_addr *ip6, unsigned int ifindex)
jardineb5d44e2003-12-23 08:09:43 +0000158{
159 struct listnode *node;
160 struct isis_nexthop6 *nexthop6;
jardineb5d44e2003-12-23 08:09:43 +0000161
paul1eb8ef22005-04-07 07:30:20 +0000162 for (ALL_LIST_ELEMENTS_RO (isis->nexthops6, node, nexthop6))
hassof390d2c2004-09-10 20:48:21 +0000163 {
hassof390d2c2004-09-10 20:48:21 +0000164 if (nexthop6->ifindex != ifindex)
165 continue;
166 if (ip6 && memcmp (&nexthop6->ip6, ip6, sizeof (struct in6_addr)) != 0)
167 continue;
168
169 nexthop6->lock++;
170 return nexthop6;
171 }
172
jardineb5d44e2003-12-23 08:09:43 +0000173 nexthop6 = isis_nexthop6_new (ip6, ifindex);
174
175 return nexthop6;
176}
177
hasso92365882005-01-18 13:53:33 +0000178static void
jardineb5d44e2003-12-23 08:09:43 +0000179isis_nexthop6_delete (struct isis_nexthop6 *nexthop6)
180{
181
182 nexthop6->lock--;
hassof390d2c2004-09-10 20:48:21 +0000183 if (nexthop6->lock == 0)
184 {
185 listnode_delete (isis->nexthops6, nexthop6);
186 XFREE (MTYPE_ISIS_NEXTHOP6, nexthop6);
187 }
188
jardineb5d44e2003-12-23 08:09:43 +0000189 return;
190}
191
hasso92365882005-01-18 13:53:33 +0000192static int
hassof390d2c2004-09-10 20:48:21 +0000193nexthop6lookup (struct list *nexthops6, struct in6_addr *ip6,
194 unsigned int ifindex)
jardineb5d44e2003-12-23 08:09:43 +0000195{
196 struct listnode *node;
197 struct isis_nexthop6 *nh6;
198
paul1eb8ef22005-04-07 07:30:20 +0000199 for (ALL_LIST_ELEMENTS_RO (nexthops6, node, nh6))
hassof390d2c2004-09-10 20:48:21 +0000200 {
hassof390d2c2004-09-10 20:48:21 +0000201 if (!(memcmp (ip6, &nh6->ip6, sizeof (struct in6_addr))) &&
202 ifindex == nh6->ifindex)
203 return 1;
204 }
jardineb5d44e2003-12-23 08:09:43 +0000205
206 return 0;
207}
208
hasso92365882005-01-18 13:53:33 +0000209#ifdef EXTREME_DEBUG
210static void
jardineb5d44e2003-12-23 08:09:43 +0000211nexthop6_print (struct isis_nexthop6 *nh6)
212{
213 u_char buf[BUFSIZ];
hassof390d2c2004-09-10 20:48:21 +0000214
hassof7c43dc2004-09-26 16:24:14 +0000215 inet_ntop (AF_INET6, &nh6->ip6, (char *) buf, BUFSIZ);
hassof390d2c2004-09-10 20:48:21 +0000216
hasso529d65b2004-12-24 00:14:50 +0000217 zlog_debug (" %s %u", buf, nh6->ifindex);
jardineb5d44e2003-12-23 08:09:43 +0000218}
219
hasso92365882005-01-18 13:53:33 +0000220static void
jardineb5d44e2003-12-23 08:09:43 +0000221nexthops6_print (struct list *nhs6)
222{
223 struct listnode *node;
jardin10fc9182005-10-01 00:09:39 +0000224 struct isis_nexthop6 *nh6;
hassof390d2c2004-09-10 20:48:21 +0000225
paul1eb8ef22005-04-07 07:30:20 +0000226 for (ALL_LIST_ELEMENTS_RO (nhs6, node, nh6))
227 nexthop6_print (nh6);
jardineb5d44e2003-12-23 08:09:43 +0000228}
hasso92365882005-01-18 13:53:33 +0000229#endif /* EXTREME_DEBUG */
jardineb5d44e2003-12-23 08:09:43 +0000230#endif /* HAVE_IPV6 */
231
hasso92365882005-01-18 13:53:33 +0000232static void
jardineb5d44e2003-12-23 08:09:43 +0000233adjinfo2nexthop (struct list *nexthops, struct isis_adjacency *adj)
234{
235 struct isis_nexthop *nh;
hasso3fdb2dd2005-09-28 18:45:54 +0000236 struct listnode *node;
jardineb5d44e2003-12-23 08:09:43 +0000237 struct in_addr *ipv4_addr;
238
239 if (adj->ipv4_addrs == NULL)
240 return;
paul1eb8ef22005-04-07 07:30:20 +0000241
hasso3fdb2dd2005-09-28 18:45:54 +0000242 for (ALL_LIST_ELEMENTS_RO (adj->ipv4_addrs, node, ipv4_addr))
hassof390d2c2004-09-10 20:48:21 +0000243 {
hassof390d2c2004-09-10 20:48:21 +0000244 if (!nexthoplookup (nexthops, ipv4_addr,
245 adj->circuit->interface->ifindex))
246 {
247 nh = isis_nexthop_create (ipv4_addr,
248 adj->circuit->interface->ifindex);
249 listnode_add (nexthops, nh);
250 }
jardineb5d44e2003-12-23 08:09:43 +0000251 }
jardineb5d44e2003-12-23 08:09:43 +0000252}
253
254#ifdef HAVE_IPV6
hasso92365882005-01-18 13:53:33 +0000255static void
jardineb5d44e2003-12-23 08:09:43 +0000256adjinfo2nexthop6 (struct list *nexthops6, struct isis_adjacency *adj)
257{
hasso3fdb2dd2005-09-28 18:45:54 +0000258 struct listnode *node;
jardineb5d44e2003-12-23 08:09:43 +0000259 struct in6_addr *ipv6_addr;
260 struct isis_nexthop6 *nh6;
hassof390d2c2004-09-10 20:48:21 +0000261
jardineb5d44e2003-12-23 08:09:43 +0000262 if (!adj->ipv6_addrs)
263 return;
264
hasso3fdb2dd2005-09-28 18:45:54 +0000265 for (ALL_LIST_ELEMENTS_RO (adj->ipv6_addrs, node, ipv6_addr))
hassof390d2c2004-09-10 20:48:21 +0000266 {
hassof390d2c2004-09-10 20:48:21 +0000267 if (!nexthop6lookup (nexthops6, ipv6_addr,
268 adj->circuit->interface->ifindex))
269 {
270 nh6 = isis_nexthop6_create (ipv6_addr,
271 adj->circuit->interface->ifindex);
272 listnode_add (nexthops6, nh6);
273 }
jardineb5d44e2003-12-23 08:09:43 +0000274 }
jardineb5d44e2003-12-23 08:09:43 +0000275}
276#endif /* HAVE_IPV6 */
277
hasso92365882005-01-18 13:53:33 +0000278static struct isis_route_info *
hassof390d2c2004-09-10 20:48:21 +0000279isis_route_info_new (uint32_t cost, uint32_t depth, u_char family,
280 struct list *adjacencies)
jardineb5d44e2003-12-23 08:09:43 +0000281{
282 struct isis_route_info *rinfo;
283 struct isis_adjacency *adj;
hasso3fdb2dd2005-09-28 18:45:54 +0000284 struct listnode *node;
hassof390d2c2004-09-10 20:48:21 +0000285
hasso3fdb2dd2005-09-28 18:45:54 +0000286 rinfo = XCALLOC (MTYPE_ISIS_ROUTE_INFO, sizeof (struct isis_route_info));
hassof390d2c2004-09-10 20:48:21 +0000287 if (!rinfo)
288 {
289 zlog_err ("ISIS-Rte: isis_route_info_new: out of memory!");
290 return NULL;
291 }
jardineb5d44e2003-12-23 08:09:43 +0000292
hassof390d2c2004-09-10 20:48:21 +0000293 if (family == AF_INET)
294 {
295 rinfo->nexthops = list_new ();
hasso3fdb2dd2005-09-28 18:45:54 +0000296 for (ALL_LIST_ELEMENTS_RO (adjacencies, node, adj))
paul1eb8ef22005-04-07 07:30:20 +0000297 adjinfo2nexthop (rinfo->nexthops, adj);
jardineb5d44e2003-12-23 08:09:43 +0000298 }
jardineb5d44e2003-12-23 08:09:43 +0000299#ifdef HAVE_IPV6
hassof390d2c2004-09-10 20:48:21 +0000300 if (family == AF_INET6)
301 {
302 rinfo->nexthops6 = list_new ();
hasso3fdb2dd2005-09-28 18:45:54 +0000303 for (ALL_LIST_ELEMENTS_RO (adjacencies, node, adj))
paul1eb8ef22005-04-07 07:30:20 +0000304 adjinfo2nexthop6 (rinfo->nexthops6, adj);
jardineb5d44e2003-12-23 08:09:43 +0000305 }
hassof390d2c2004-09-10 20:48:21 +0000306
jardineb5d44e2003-12-23 08:09:43 +0000307#endif /* HAVE_IPV6 */
308
309 rinfo->cost = cost;
310 rinfo->depth = depth;
hassof390d2c2004-09-10 20:48:21 +0000311
jardineb5d44e2003-12-23 08:09:43 +0000312 return rinfo;
313}
314
hasso92365882005-01-18 13:53:33 +0000315static void
jardineb5d44e2003-12-23 08:09:43 +0000316isis_route_info_delete (struct isis_route_info *route_info)
317{
hassof390d2c2004-09-10 20:48:21 +0000318 if (route_info->nexthops)
319 {
hassof7c43dc2004-09-26 16:24:14 +0000320 route_info->nexthops->del = (void (*)(void *)) isis_nexthop_delete;
hassof390d2c2004-09-10 20:48:21 +0000321 list_delete (route_info->nexthops);
322 }
323
jardineb5d44e2003-12-23 08:09:43 +0000324#ifdef HAVE_IPV6
hassof390d2c2004-09-10 20:48:21 +0000325 if (route_info->nexthops6)
326 {
hassof7c43dc2004-09-26 16:24:14 +0000327 route_info->nexthops6->del = (void (*)(void *)) isis_nexthop6_delete;
jardineb5d44e2003-12-23 08:09:43 +0000328 list_delete (route_info->nexthops6);
hassof390d2c2004-09-10 20:48:21 +0000329 }
jardineb5d44e2003-12-23 08:09:43 +0000330#endif /* HAVE_IPV6 */
hassof390d2c2004-09-10 20:48:21 +0000331
jardineb5d44e2003-12-23 08:09:43 +0000332 XFREE (MTYPE_ISIS_ROUTE_INFO, route_info);
333}
334
hasso92365882005-01-18 13:53:33 +0000335static int
hassof390d2c2004-09-10 20:48:21 +0000336isis_route_info_same_attrib (struct isis_route_info *new,
337 struct isis_route_info *old)
jardineb5d44e2003-12-23 08:09:43 +0000338{
339 if (new->cost != old->cost)
340 return 0;
341 if (new->depth != old->depth)
342 return 0;
hassof390d2c2004-09-10 20:48:21 +0000343
jardineb5d44e2003-12-23 08:09:43 +0000344 return 1;
345}
346
hasso92365882005-01-18 13:53:33 +0000347static int
hassof390d2c2004-09-10 20:48:21 +0000348isis_route_info_same (struct isis_route_info *new,
349 struct isis_route_info *old, u_char family)
jardineb5d44e2003-12-23 08:09:43 +0000350{
hasso3fdb2dd2005-09-28 18:45:54 +0000351 struct listnode *node;
jardineb5d44e2003-12-23 08:09:43 +0000352 struct isis_nexthop *nexthop;
353#ifdef HAVE_IPV6
354 struct isis_nexthop6 *nexthop6;
355#endif /* HAVE_IPV6 */
356 if (!isis_route_info_same_attrib (new, old))
357 return 0;
hassof390d2c2004-09-10 20:48:21 +0000358
359 if (family == AF_INET)
360 {
hasso3fdb2dd2005-09-28 18:45:54 +0000361 for (ALL_LIST_ELEMENTS_RO (new->nexthops, node, nexthop))
paul1eb8ef22005-04-07 07:30:20 +0000362 if (nexthoplookup (old->nexthops, &nexthop->ip, nexthop->ifindex)
363 == 0)
364 return 0;
hassof390d2c2004-09-10 20:48:21 +0000365
hasso3fdb2dd2005-09-28 18:45:54 +0000366 for (ALL_LIST_ELEMENTS_RO (old->nexthops, node, nexthop))
paul1eb8ef22005-04-07 07:30:20 +0000367 if (nexthoplookup (new->nexthops, &nexthop->ip, nexthop->ifindex)
368 == 0)
369 return 0;
jardineb5d44e2003-12-23 08:09:43 +0000370 }
jardineb5d44e2003-12-23 08:09:43 +0000371#ifdef HAVE_IPV6
hassof390d2c2004-09-10 20:48:21 +0000372 else if (family == AF_INET6)
373 {
hasso3fdb2dd2005-09-28 18:45:54 +0000374 for (ALL_LIST_ELEMENTS_RO (new->nexthops6, node, nexthop6))
paul1eb8ef22005-04-07 07:30:20 +0000375 if (nexthop6lookup (old->nexthops6, &nexthop6->ip6,
376 nexthop6->ifindex) == 0)
377 return 0;
hassof390d2c2004-09-10 20:48:21 +0000378
hasso3fdb2dd2005-09-28 18:45:54 +0000379 for (ALL_LIST_ELEMENTS_RO (old->nexthops6, node, nexthop6))
paul1eb8ef22005-04-07 07:30:20 +0000380 if (nexthop6lookup (new->nexthops6, &nexthop6->ip6,
381 nexthop6->ifindex) == 0)
382 return 0;
jardineb5d44e2003-12-23 08:09:43 +0000383 }
jardineb5d44e2003-12-23 08:09:43 +0000384#endif /* HAVE_IPV6 */
385
386 return 1;
387}
388
hasso92365882005-01-18 13:53:33 +0000389static void
jardineb5d44e2003-12-23 08:09:43 +0000390isis_nexthops_merge (struct list *new, struct list *old)
391{
hasso3fdb2dd2005-09-28 18:45:54 +0000392 struct listnode *node;
jardineb5d44e2003-12-23 08:09:43 +0000393 struct isis_nexthop *nexthop;
394
hasso3fdb2dd2005-09-28 18:45:54 +0000395 for (ALL_LIST_ELEMENTS_RO (new, node, nexthop))
hassof390d2c2004-09-10 20:48:21 +0000396 {
hassof390d2c2004-09-10 20:48:21 +0000397 if (nexthoplookup (old, &nexthop->ip, nexthop->ifindex))
398 continue;
399 listnode_add (old, nexthop);
400 nexthop->lock++;
401 }
jardineb5d44e2003-12-23 08:09:43 +0000402}
403
jardineb5d44e2003-12-23 08:09:43 +0000404#ifdef HAVE_IPV6
hasso92365882005-01-18 13:53:33 +0000405static void
jardineb5d44e2003-12-23 08:09:43 +0000406isis_nexthops6_merge (struct list *new, struct list *old)
407{
hasso3fdb2dd2005-09-28 18:45:54 +0000408 struct listnode *node;
jardineb5d44e2003-12-23 08:09:43 +0000409 struct isis_nexthop6 *nexthop6;
410
hasso3fdb2dd2005-09-28 18:45:54 +0000411 for (ALL_LIST_ELEMENTS_RO (new, node, nexthop6))
hassof390d2c2004-09-10 20:48:21 +0000412 {
hassof390d2c2004-09-10 20:48:21 +0000413 if (nexthop6lookup (old, &nexthop6->ip6, nexthop6->ifindex))
414 continue;
415 listnode_add (old, nexthop6);
416 nexthop6->lock++;
417 }
jardineb5d44e2003-12-23 08:09:43 +0000418}
419#endif /* HAVE_IPV6 */
420
hasso92365882005-01-18 13:53:33 +0000421static void
hassof390d2c2004-09-10 20:48:21 +0000422isis_route_info_merge (struct isis_route_info *new,
423 struct isis_route_info *old, u_char family)
jardineb5d44e2003-12-23 08:09:43 +0000424{
hassof390d2c2004-09-10 20:48:21 +0000425 if (family == AF_INET)
jardineb5d44e2003-12-23 08:09:43 +0000426 isis_nexthops_merge (new->nexthops, old->nexthops);
427#ifdef HAVE_IPV6
hassof390d2c2004-09-10 20:48:21 +0000428 else if (family == AF_INET6)
jardineb5d44e2003-12-23 08:09:43 +0000429 isis_nexthops6_merge (new->nexthops6, old->nexthops6);
430#endif /* HAVE_IPV6 */
hassof390d2c2004-09-10 20:48:21 +0000431
jardineb5d44e2003-12-23 08:09:43 +0000432 return;
433}
434
hasso92365882005-01-18 13:53:33 +0000435static int
hassof390d2c2004-09-10 20:48:21 +0000436isis_route_info_prefer_new (struct isis_route_info *new,
437 struct isis_route_info *old)
jardineb5d44e2003-12-23 08:09:43 +0000438{
jardineb5d44e2003-12-23 08:09:43 +0000439 if (!CHECK_FLAG (old->flag, ISIS_ROUTE_FLAG_ACTIVE))
440 return 1;
441
442 if (new->cost < old->cost)
443 return 1;
hassof390d2c2004-09-10 20:48:21 +0000444
jardineb5d44e2003-12-23 08:09:43 +0000445 return 0;
446}
447
jardineb5d44e2003-12-23 08:09:43 +0000448struct isis_route_info *
449isis_route_create (struct prefix *prefix, u_int32_t cost, u_int32_t depth,
hassofac1f7c2005-09-26 18:26:26 +0000450 struct list *adjacencies, struct isis_area *area,
451 int level)
jardineb5d44e2003-12-23 08:09:43 +0000452{
453 struct route_node *route_node;
454 struct isis_route_info *rinfo_new, *rinfo_old, *route_info = NULL;
455 u_char buff[BUFSIZ];
456 u_char family;
hassof390d2c2004-09-10 20:48:21 +0000457
jardineb5d44e2003-12-23 08:09:43 +0000458 family = prefix->family;
459 /* for debugs */
hassof7c43dc2004-09-26 16:24:14 +0000460 prefix2str (prefix, (char *) buff, BUFSIZ);
hassof390d2c2004-09-10 20:48:21 +0000461
jardineb5d44e2003-12-23 08:09:43 +0000462 rinfo_new = isis_route_info_new (cost, depth, family, adjacencies);
hassof390d2c2004-09-10 20:48:21 +0000463 if (!rinfo_new)
464 {
465 zlog_err ("ISIS-Rte (%s): isis_route_create: out of memory!",
466 area->area_tag);
467 return NULL;
468 }
469
jardineb5d44e2003-12-23 08:09:43 +0000470 if (family == AF_INET)
hassofac1f7c2005-09-26 18:26:26 +0000471 route_node = route_node_get (area->route_table[level - 1], prefix);
jardineb5d44e2003-12-23 08:09:43 +0000472#ifdef HAVE_IPV6
473 else if (family == AF_INET6)
hassofac1f7c2005-09-26 18:26:26 +0000474 route_node = route_node_get (area->route_table6[level - 1], prefix);
jardineb5d44e2003-12-23 08:09:43 +0000475#endif /* HAVE_IPV6 */
hassof390d2c2004-09-10 20:48:21 +0000476 else
jardineb5d44e2003-12-23 08:09:43 +0000477 return NULL;
hassof390d2c2004-09-10 20:48:21 +0000478 rinfo_old = route_node->info;
479 if (!rinfo_old)
480 {
481 if (isis->debugs & DEBUG_RTE_EVENTS)
hasso529d65b2004-12-24 00:14:50 +0000482 zlog_debug ("ISIS-Rte (%s) route created: %s", area->area_tag, buff);
hassof390d2c2004-09-10 20:48:21 +0000483 SET_FLAG (rinfo_new->flag, ISIS_ROUTE_FLAG_ACTIVE);
484 route_node->info = rinfo_new;
485 return rinfo_new;
486 }
487
jardineb5d44e2003-12-23 08:09:43 +0000488 if (isis->debugs & DEBUG_RTE_EVENTS)
hasso529d65b2004-12-24 00:14:50 +0000489 zlog_debug ("ISIS-Rte (%s) route already exists: %s", area->area_tag,
hassof390d2c2004-09-10 20:48:21 +0000490 buff);
491
492 if (isis_route_info_same (rinfo_new, rinfo_old, family))
493 {
jardineb5d44e2003-12-23 08:09:43 +0000494 if (isis->debugs & DEBUG_RTE_EVENTS)
hasso529d65b2004-12-24 00:14:50 +0000495 zlog_debug ("ISIS-Rte (%s) route unchanged: %s", area->area_tag, buff);
jardineb5d44e2003-12-23 08:09:43 +0000496 isis_route_info_delete (rinfo_new);
497 route_info = rinfo_old;
498 }
hassof390d2c2004-09-10 20:48:21 +0000499 else if (isis_route_info_same_attrib (rinfo_new, rinfo_old))
500 {
501 /* merge the nexthop lists */
502 if (isis->debugs & DEBUG_RTE_EVENTS)
hasso529d65b2004-12-24 00:14:50 +0000503 zlog_debug ("ISIS-Rte (%s) route changed (same attribs): %s",
hassof390d2c2004-09-10 20:48:21 +0000504 area->area_tag, buff);
505#ifdef EXTREME_DEBUG
hasso3d549272005-09-21 18:52:14 +0000506 if (family == AF_INET)
507 {
508 zlog_debug ("Old nexthops");
509 nexthops_print (rinfo_old->nexthops);
510 zlog_debug ("New nexthops");
511 nexthops_print (rinfo_new->nexthops);
512 }
513 else if (family == AF_INET6)
514 {
515 zlog_debug ("Old nexthops");
516 nexthops6_print (rinfo_old->nexthops6);
517 zlog_debug ("New nexthops");
518 nexthops6_print (rinfo_new->nexthops6);
519 }
hassof390d2c2004-09-10 20:48:21 +0000520#endif /* EXTREME_DEBUG */
521 isis_route_info_merge (rinfo_new, rinfo_old, family);
522 isis_route_info_delete (rinfo_new);
523 route_info = rinfo_old;
hasso13fb40a2005-10-01 06:03:04 +0000524 UNSET_FLAG (route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNC);
hassof390d2c2004-09-10 20:48:21 +0000525 }
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}