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