blob: b889d3b8abc506b46b2865e4f9f4b664686bbeb3 [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
56struct isis_nexthop *
57isis_nexthop_create (struct in_addr *ip, unsigned int ifindex)
58
59{
60 struct listnode *node;
61 struct isis_nexthop *nexthop;
62
63 for (node = listhead (isis->nexthops); node; nextnode (node)) {
64 nexthop = getdata (node);
65 if (nexthop->ifindex != ifindex)
66 continue;
67 if (ip && memcmp (&nexthop->ip, ip, sizeof (struct in_addr)) != 0)
68 continue;
69
70 nexthop->lock++;
71 return nexthop;
72 }
73
74 nexthop = XMALLOC (MTYPE_ISIS_NEXTHOP, sizeof (struct isis_nexthop));
75 if (!nexthop) {
76 zlog_err ("ISIS-Rte: isis_nexthop_create: out of memory!");
77 }
78
79 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
88
89void
90isis_nexthop_delete (struct isis_nexthop *nexthop)
91{
92 nexthop->lock--;
93 if (nexthop->lock == 0) {
94 listnode_delete (isis->nexthops, nexthop);
95 XFREE (MTYPE_ISIS_NEXTHOP, nexthop);
96 }
97
98 return;
99}
100
101int
102nexthoplookup (struct list *nexthops, struct in_addr *ip,
103 unsigned int ifindex)
104{
105 struct listnode *node;
106 struct isis_nexthop *nh;
107
108 for (node = listhead (nexthops); node; nextnode (node)) {
109 nh = getdata (node);
110 if (!(memcmp (ip, &nh->ip, sizeof (struct in_addr))) &&
111 ifindex == nh->ifindex)
112 return 1;
113 }
114
115 return 0;
116}
117
118void
119nexthop_print (struct isis_nexthop *nh)
120{
121 u_char buf[BUFSIZ];
122
123 inet_ntop (AF_INET, &nh->ip, buf, BUFSIZ);
124
125 zlog_info (" %s %u", buf, nh->ifindex);
126}
127
128void
129nexthops_print (struct list *nhs)
130{
131 struct listnode *node;
132
133 for (node = listhead(nhs); node; nextnode (node))
134 nexthop_print (getdata (node));
135}
136
137#ifdef HAVE_IPV6
138
139struct isis_nexthop6 *
140isis_nexthop6_new (struct in6_addr *ip6, unsigned int ifindex)
141{
142
143 struct isis_nexthop6 *nexthop6;
144
145 nexthop6 = XMALLOC (MTYPE_ISIS_NEXTHOP6, sizeof (struct isis_nexthop6));
146 if (!nexthop6) {
147 zlog_err ("ISIS-Rte: isis_nexthop_create6: out of memory!");
148 }
149
150 memset (nexthop6, 0, sizeof (struct isis_nexthop6));
151 nexthop6->ifindex = ifindex;
152 memcpy (&nexthop6->ip6, ip6, sizeof (struct in6_addr));
153 nexthop6->lock++;
154
155 return nexthop6;
156}
157
158struct isis_nexthop6 *
159isis_nexthop6_create (struct in6_addr *ip6, unsigned int ifindex)
160
161{
162 struct listnode *node;
163 struct isis_nexthop6 *nexthop6;
164
165 for (node = listhead (isis->nexthops6); node; nextnode (node)) {
166 nexthop6 = getdata (node);
167 if (nexthop6->ifindex != ifindex)
168 continue;
169 if (ip6 && memcmp (&nexthop6->ip6, ip6, sizeof (struct in6_addr)) != 0)
170 continue;
171
172 nexthop6->lock++;
173 return nexthop6;
174 }
175
176 nexthop6 = isis_nexthop6_new (ip6, ifindex);
177
178 return nexthop6;
179}
180
181
182void
183isis_nexthop6_delete (struct isis_nexthop6 *nexthop6)
184{
185
186 nexthop6->lock--;
187 if (nexthop6->lock == 0) {
188 listnode_delete (isis->nexthops6, nexthop6);
189 XFREE (MTYPE_ISIS_NEXTHOP6, nexthop6);
190 }
191
192 return;
193}
194
195int
196nexthop6lookup (struct list *nexthops6, struct in6_addr *ip6,
197 unsigned int ifindex)
198{
199 struct listnode *node;
200 struct isis_nexthop6 *nh6;
201
202 for (node = listhead (nexthops6); node; nextnode (node)) {
203 nh6 = getdata (node);
204 if (!(memcmp (ip6, &nh6->ip6, sizeof (struct in6_addr))) &&
205 ifindex == nh6->ifindex)
206 return 1;
207 }
208
209 return 0;
210}
211
212void
213nexthop6_print (struct isis_nexthop6 *nh6)
214{
215 u_char buf[BUFSIZ];
216
217 inet_ntop (AF_INET6, &nh6->ip6, buf, BUFSIZ);
218
219 zlog_info (" %s %u", buf, nh6->ifindex);
220}
221
222void
223nexthops6_print (struct list *nhs6)
224{
225 struct listnode *node;
226
227 for (node = listhead(nhs6); node; nextnode (node))
228 nexthop6_print (getdata (node));
229}
230
231
232#endif /* HAVE_IPV6 */
233
234void
235adjinfo2nexthop (struct list *nexthops, struct isis_adjacency *adj)
236{
237 struct isis_nexthop *nh;
238 struct listnode *node;
239 struct in_addr *ipv4_addr;
240
241 if (adj->ipv4_addrs == NULL)
242 return;
243 for (node = listhead (adj->ipv4_addrs); node; nextnode (node)) {
244 ipv4_addr = getdata (node);
245 if (!nexthoplookup (nexthops, ipv4_addr,
246 adj->circuit->interface->ifindex)) {
247 nh = isis_nexthop_create (ipv4_addr,
248 adj->circuit->interface->ifindex);
249 listnode_add (nexthops, nh);
250 }
251 }
252}
253
254#ifdef HAVE_IPV6
255void
256adjinfo2nexthop6 (struct list *nexthops6, struct isis_adjacency *adj)
257{
258 struct listnode *node;
259 struct in6_addr *ipv6_addr;
260 struct isis_nexthop6 *nh6;
261
262 if (!adj->ipv6_addrs)
263 return;
264
265 for (node = listhead (adj->ipv6_addrs); node; nextnode (node)) {
266 ipv6_addr = getdata (node);
267 if (!nexthop6lookup (nexthops6, ipv6_addr,
268 adj->circuit->interface->ifindex)) {
269 nh6 = isis_nexthop6_create (ipv6_addr,
270 adj->circuit->interface->ifindex);
271 listnode_add (nexthops6, nh6);
272 }
273 }
274}
275#endif /* HAVE_IPV6 */
276
277struct isis_route_info *
278isis_route_info_new (uint32_t cost, uint32_t depth, u_char family,
279 struct list *adjacencies)
280{
281 struct isis_route_info *rinfo;
282 struct isis_adjacency *adj;
283 struct listnode *node;
284
285 rinfo = XMALLOC (MTYPE_ISIS_ROUTE_INFO, sizeof (struct isis_route_info));
286 if (!rinfo) {
287 zlog_err ("ISIS-Rte: isis_route_info_new: out of memory!");
288 return NULL;
289 }
290 memset (rinfo, 0, sizeof (struct isis_route_info));
291
292 if (family == AF_INET) {
293 rinfo->nexthops = list_new ();
294 for (node = listhead (adjacencies); node; nextnode (node)) {
295 adj = getdata (node);
296 adjinfo2nexthop (rinfo->nexthops, adj);
297 }
298 }
299#ifdef HAVE_IPV6
300 if (family == AF_INET6) {
301 rinfo->nexthops6 = list_new ();
302 for (node = listhead (adjacencies); node; nextnode (node)) {
303 adj =getdata (node);
304 adjinfo2nexthop6 (rinfo->nexthops6, adj);
305 }
306 }
307
308#endif /* HAVE_IPV6 */
309
310 rinfo->cost = cost;
311 rinfo->depth = depth;
312
313 return rinfo;
314}
315
316
317void
318isis_route_info_delete (struct isis_route_info *route_info)
319{
320
321 if (route_info->nexthops) {
322 route_info->nexthops->del = (void *)isis_nexthop_delete;
323 list_delete (route_info->nexthops);
324 }
325
326#ifdef HAVE_IPV6
327 if (route_info->nexthops6) {
328 route_info->nexthops6->del = (void *)isis_nexthop6_delete;
329 list_delete (route_info->nexthops6);
330 }
331#endif /* HAVE_IPV6 */
332
333 XFREE (MTYPE_ISIS_ROUTE_INFO, route_info);
334}
335
336int
337isis_route_info_same_attrib (struct isis_route_info *new,
338 struct isis_route_info *old)
339{
340 if (new->cost != old->cost)
341 return 0;
342 if (new->depth != old->depth)
343 return 0;
344
345 return 1;
346}
347
348int
349isis_route_info_same (struct isis_route_info *new, struct isis_route_info *old,
350 u_char family)
351{
352 struct listnode *node;
353 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;
359
360 if (family == AF_INET) {
361 for (node = listhead (new->nexthops); node; nextnode (node)) {
362 nexthop = (struct isis_nexthop *) getdata (node);
363 if (nexthoplookup (old->nexthops, &nexthop->ip, nexthop->ifindex) == 0)
364 return 0;
365 }
366
367 for (node = listhead (old->nexthops); node; nextnode (node)) {
368 nexthop = (struct isis_nexthop *) getdata (node);
369 if (nexthoplookup (new->nexthops, &nexthop->ip, nexthop->ifindex) == 0)
370 return 0;
371 }
372 }
373#ifdef HAVE_IPV6
374 else if (family == AF_INET6) {
375 for (node = listhead (new->nexthops6); node; nextnode (node)) {
376 nexthop6 = (struct isis_nexthop6 *) getdata (node);
377 if (nexthop6lookup (old->nexthops6, &nexthop6->ip6,
378 nexthop6->ifindex) == 0)
379 return 0;
380 }
381
382 for (node = listhead (old->nexthops6); node; nextnode (node)) {
383 nexthop6 = (struct isis_nexthop6 *) getdata (node);
384 if (nexthop6lookup (new->nexthops6, &nexthop6->ip6,
385 nexthop6->ifindex) == 0)
386 return 0;
387 }
388 }
389#endif /* HAVE_IPV6 */
390
391 return 1;
392}
393
394
395void
396isis_nexthops_merge (struct list *new, struct list *old)
397{
398 struct listnode *node;
399 struct isis_nexthop *nexthop;
400
401 for (node = listhead (new); node; nextnode (node)) {
402 nexthop = (struct isis_nexthop *) getdata (node);
403 if (nexthoplookup (old, &nexthop->ip, nexthop->ifindex))
404 continue;
405 listnode_add (old, nexthop);
406 nexthop->lock++;
407 }
408}
409
410
411#ifdef HAVE_IPV6
412void
413isis_nexthops6_merge (struct list *new, struct list *old)
414{
415 struct listnode *node;
416 struct isis_nexthop6 *nexthop6;
417
418 for (node = listhead (new); node; nextnode (node)) {
419 nexthop6 = (struct isis_nexthop6 *) getdata (node);
420 if (nexthop6lookup (old, &nexthop6->ip6, nexthop6->ifindex))
421 continue;
422 listnode_add (old, nexthop6);
423 nexthop6->lock++;
424 }
425}
426#endif /* HAVE_IPV6 */
427
428void
429isis_route_info_merge (struct isis_route_info *new,
430 struct isis_route_info *old, u_char family)
431{
432
433 if (family == AF_INET)
434 isis_nexthops_merge (new->nexthops, old->nexthops);
435#ifdef HAVE_IPV6
436 else if (family == AF_INET6)
437 isis_nexthops6_merge (new->nexthops6, old->nexthops6);
438#endif /* HAVE_IPV6 */
439
440 return;
441}
442
443
444int
445isis_route_info_prefer_new (struct isis_route_info *new,
446 struct isis_route_info *old)
447{
448
449 if (!CHECK_FLAG (old->flag, ISIS_ROUTE_FLAG_ACTIVE))
450 return 1;
451
452 if (new->cost < old->cost)
453 return 1;
454
455 return 0;
456}
457
458
459struct isis_route_info *
460isis_route_create (struct prefix *prefix, u_int32_t cost, u_int32_t depth,
461 struct list *adjacencies, struct isis_area *area)
462{
463 struct route_node *route_node;
464 struct isis_route_info *rinfo_new, *rinfo_old, *route_info = NULL;
465 u_char buff[BUFSIZ];
466 u_char family;
467
468 family = prefix->family;
469 /* for debugs */
470 prefix2str (prefix, buff, BUFSIZ);
471
472 rinfo_new = isis_route_info_new (cost, depth, family, adjacencies);
473 if (!rinfo_new) {
474 zlog_err ("ISIS-Rte (%s): isis_route_create: out of memory!",
475 area->area_tag);
476 return NULL;
477 }
478
479 if (family == AF_INET)
480 route_node = route_node_get (area->route_table, prefix);
481#ifdef HAVE_IPV6
482 else if (family == AF_INET6)
483 route_node = route_node_get (area->route_table6, prefix);
484#endif /* HAVE_IPV6 */
485 else
486 return NULL;
487 rinfo_old = route_node->info;
488 if (!rinfo_old) {
489 if (isis->debugs & DEBUG_RTE_EVENTS)
490 zlog_info ("ISIS-Rte (%s) route created: %s", area->area_tag, buff);
491 SET_FLAG(rinfo_new->flag, ISIS_ROUTE_FLAG_ACTIVE);
492 route_node->info = rinfo_new;
493 return rinfo_new;
494 }
495
496 if (isis->debugs & DEBUG_RTE_EVENTS)
497 zlog_info ("ISIS-Rte (%s) route already exists: %s", area->area_tag, buff);
498
499 if (isis_route_info_same (rinfo_new, rinfo_old, family)) {
500 if (isis->debugs & DEBUG_RTE_EVENTS)
501 zlog_info ("ISIS-Rte (%s) route unchanged: %s", area->area_tag, buff);
502 isis_route_info_delete (rinfo_new);
503 route_info = rinfo_old;
504 } else if (isis_route_info_same_attrib (rinfo_new, rinfo_old)) {
505 /* merge the nexthop lists */
506 if (isis->debugs & DEBUG_RTE_EVENTS)
507 zlog_info ("ISIS-Rte (%s) route changed (same attribs): %s",
508 area->area_tag, buff);
509#ifdef EXTREME_DEBUG
510 zlog_info ("Old nexthops");
511 nexthops6_print (rinfo_old->nexthops6);
512 zlog_info ("New nexthops");
513 nexthops6_print (rinfo_new->nexthops6);
514#endif /* EXTREME_DEBUG */
515 isis_route_info_merge (rinfo_new, rinfo_old, family);
516 isis_route_info_delete (rinfo_new);
517 route_info = rinfo_old;
518 } else {
519 if (isis_route_info_prefer_new (rinfo_new, rinfo_old)) {
520 if (isis->debugs & DEBUG_RTE_EVENTS)
521 zlog_info ("ISIS-Rte (%s) route changed: %s", area->area_tag, buff);
522 isis_route_info_delete (rinfo_old);
523 route_info = rinfo_new;
524 } else {
525 if (isis->debugs & DEBUG_RTE_EVENTS)
526 zlog_info ("ISIS-Rte (%s) route rejected: %s", area->area_tag, buff);
527 isis_route_info_delete (rinfo_new);
528 route_info = rinfo_old;
529 }
530 }
531
532 SET_FLAG (route_info->flag, ISIS_ROUTE_FLAG_ACTIVE);
533 route_node->info = route_info;
534
535 return route_info;
536}
537
538void
539isis_route_delete (struct prefix *prefix, struct route_table *table)
540{
541 struct route_node *rode;
542 struct isis_route_info *rinfo;
543 char buff[BUFSIZ];
544
545 /* for log */
546 prefix2str (prefix, buff, BUFSIZ);
547
548
549 rode = route_node_get (table, prefix);
550 rinfo = rode->info;
551
552 if (rinfo == NULL) {
553 if (isis->debugs & DEBUG_RTE_EVENTS)
554 zlog_info ("ISIS-Rte: tried to delete non-existant route %s", buff);
555 return;
556 }
557
558 if (CHECK_FLAG (rinfo->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNC)) {
559 UNSET_FLAG (rinfo->flag, ISIS_ROUTE_FLAG_ACTIVE);
560 if (isis->debugs & DEBUG_RTE_EVENTS)
561 zlog_info ("ISIS-Rte: route delete %s", buff);
562 isis_zebra_route_update (prefix, rinfo);
563 }
564 isis_route_info_delete (rinfo);
565 rode->info = NULL;
566
567 return;
568}
569
570int
571isis_route_validate (struct thread *thread)
572{
573 struct isis_area *area;
574 struct route_table *table;
575 struct route_node *rode;
576 struct isis_route_info *rinfo;
577 u_char buff[BUFSIZ];
578#ifdef HAVE_IPV6
579 int v6done = 0;
580#endif
581 area = THREAD_ARG (thread);
582 table = area->route_table;
583#ifdef HAVE_IPV6
584 again:
585#endif
586 for (rode = route_top (table); rode; rode = route_next (rode)) {
587 if (rode->info == NULL)
588 continue;
589 rinfo = rode->info;
590
591 if (isis->debugs & DEBUG_RTE_EVENTS) {
592 prefix2str (&rode->p, buff, BUFSIZ);
593 zlog_info ("ISIS-Rte (%s): route validate: %s %s %s",
594 area->area_tag,
595 (CHECK_FLAG (rinfo->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNC) ?
596 "sync'ed": "nosync"),
597 (CHECK_FLAG (rinfo->flag, ISIS_ROUTE_FLAG_ACTIVE) ?
598 "active": "inactive"), buff);
599 }
600
601 isis_zebra_route_update (&rode->p, rinfo);
602 if (!CHECK_FLAG (rinfo->flag, ISIS_ROUTE_FLAG_ACTIVE))
603 isis_route_delete (&rode->p, area->route_table);
604 }
605#ifdef HAVE_IPV6
606 if (v6done)
607 return ISIS_OK;
608 table = area->route_table6;
609 v6done = 1;
610 goto again;
611#endif
612
613 return ISIS_OK;
614}