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
7 * based on ../ospf6d/ospf6_route.[ch]
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)
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
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.
37 #include "isis_constants.h"
38 #include "isis_common.h"
39 #include "isis_flags.h"
42 #include "isis_misc.h"
43 #include "isis_adjacency.h"
44 #include "isis_circuit.h"
49 #include "isis_route.h"
50 #include "isis_zebra.h"
52 static struct isis_nexthop
*
53 isis_nexthop_create (struct in_addr
*ip
, unsigned int ifindex
)
55 struct listnode
*node
;
56 struct isis_nexthop
*nexthop
;
58 for (ALL_LIST_ELEMENTS_RO (isis
->nexthops
, node
, nexthop
))
60 if (nexthop
->ifindex
!= ifindex
)
62 if (ip
&& memcmp (&nexthop
->ip
, ip
, sizeof (struct in_addr
)) != 0)
69 nexthop
= XCALLOC (MTYPE_ISIS_NEXTHOP
, sizeof (struct isis_nexthop
));
72 zlog_err ("ISIS-Rte: isis_nexthop_create: out of memory!");
75 nexthop
->ifindex
= ifindex
;
76 memcpy (&nexthop
->ip
, ip
, sizeof (struct in_addr
));
77 listnode_add (isis
->nexthops
, nexthop
);
84 isis_nexthop_delete (struct isis_nexthop
*nexthop
)
87 if (nexthop
->lock
== 0)
89 listnode_delete (isis
->nexthops
, nexthop
);
90 XFREE (MTYPE_ISIS_NEXTHOP
, nexthop
);
97 nexthoplookup (struct list
*nexthops
, struct in_addr
*ip
,
100 struct listnode
*node
;
101 struct isis_nexthop
*nh
;
103 for (ALL_LIST_ELEMENTS_RO (nexthops
, node
, nh
))
105 if (!(memcmp (ip
, &nh
->ip
, sizeof (struct in_addr
))) &&
106 ifindex
== nh
->ifindex
)
115 nexthop_print (struct isis_nexthop
*nh
)
119 inet_ntop (AF_INET
, &nh
->ip
, (char *) buf
, BUFSIZ
);
121 zlog_debug (" %s %u", buf
, nh
->ifindex
);
125 nexthops_print (struct list
*nhs
)
127 struct listnode
*node
;
128 struct isis_nexthop
*nh
;
130 for (ALL_LIST_ELEMENTS_RO (nhs
, node
, nh
))
133 #endif /* EXTREME_DEBUG */
136 static struct isis_nexthop6
*
137 isis_nexthop6_new (struct in6_addr
*ip6
, unsigned int ifindex
)
139 struct isis_nexthop6
*nexthop6
;
141 nexthop6
= XCALLOC (MTYPE_ISIS_NEXTHOP6
, sizeof (struct isis_nexthop6
));
144 zlog_err ("ISIS-Rte: isis_nexthop_create6: out of memory!");
147 nexthop6
->ifindex
= ifindex
;
148 memcpy (&nexthop6
->ip6
, ip6
, sizeof (struct in6_addr
));
154 static struct isis_nexthop6
*
155 isis_nexthop6_create (struct in6_addr
*ip6
, unsigned int ifindex
)
157 struct listnode
*node
;
158 struct isis_nexthop6
*nexthop6
;
160 for (ALL_LIST_ELEMENTS_RO (isis
->nexthops6
, node
, nexthop6
))
162 if (nexthop6
->ifindex
!= ifindex
)
164 if (ip6
&& memcmp (&nexthop6
->ip6
, ip6
, sizeof (struct in6_addr
)) != 0)
171 nexthop6
= isis_nexthop6_new (ip6
, ifindex
);
177 isis_nexthop6_delete (struct isis_nexthop6
*nexthop6
)
181 if (nexthop6
->lock
== 0)
183 listnode_delete (isis
->nexthops6
, nexthop6
);
184 XFREE (MTYPE_ISIS_NEXTHOP6
, nexthop6
);
191 nexthop6lookup (struct list
*nexthops6
, struct in6_addr
*ip6
,
192 unsigned int ifindex
)
194 struct listnode
*node
;
195 struct isis_nexthop6
*nh6
;
197 for (ALL_LIST_ELEMENTS_RO (nexthops6
, node
, nh6
))
199 if (!(memcmp (ip6
, &nh6
->ip6
, sizeof (struct in6_addr
))) &&
200 ifindex
== nh6
->ifindex
)
209 nexthop6_print (struct isis_nexthop6
*nh6
)
213 inet_ntop (AF_INET6
, &nh6
->ip6
, (char *) buf
, BUFSIZ
);
215 zlog_debug (" %s %u", buf
, nh6
->ifindex
);
219 nexthops6_print (struct list
*nhs6
)
221 struct listnode
*node
;
222 struct isis_nexthop6
*nh6
;
224 for (ALL_LIST_ELEMENTS_RO (nhs6
, node
, nh6
))
225 nexthop6_print (nh6
);
227 #endif /* EXTREME_DEBUG */
228 #endif /* HAVE_IPV6 */
231 adjinfo2nexthop (struct list
*nexthops
, struct isis_adjacency
*adj
)
233 struct isis_nexthop
*nh
;
234 struct listnode
*node
;
235 struct in_addr
*ipv4_addr
;
237 if (adj
->ipv4_addrs
== NULL
)
240 for (ALL_LIST_ELEMENTS_RO (adj
->ipv4_addrs
, node
, ipv4_addr
))
242 if (!nexthoplookup (nexthops
, ipv4_addr
,
243 adj
->circuit
->interface
->ifindex
))
245 nh
= isis_nexthop_create (ipv4_addr
,
246 adj
->circuit
->interface
->ifindex
);
247 nh
->router_address
= adj
->router_address
;
248 listnode_add (nexthops
, nh
);
255 adjinfo2nexthop6 (struct list
*nexthops6
, struct isis_adjacency
*adj
)
257 struct listnode
*node
;
258 struct in6_addr
*ipv6_addr
;
259 struct isis_nexthop6
*nh6
;
261 if (!adj
->ipv6_addrs
)
264 for (ALL_LIST_ELEMENTS_RO (adj
->ipv6_addrs
, node
, ipv6_addr
))
266 if (!nexthop6lookup (nexthops6
, ipv6_addr
,
267 adj
->circuit
->interface
->ifindex
))
269 nh6
= isis_nexthop6_create (ipv6_addr
,
270 adj
->circuit
->interface
->ifindex
);
271 nh6
->router_address6
= adj
->router_address6
;
272 listnode_add (nexthops6
, nh6
);
276 #endif /* HAVE_IPV6 */
278 static struct isis_route_info
*
279 isis_route_info_new (struct prefix
*prefix
, uint32_t cost
, uint32_t depth
,
280 struct list
*adjacencies
)
282 struct isis_route_info
*rinfo
;
283 struct isis_adjacency
*adj
;
284 struct listnode
*node
;
286 rinfo
= XCALLOC (MTYPE_ISIS_ROUTE_INFO
, sizeof (struct isis_route_info
));
289 zlog_err ("ISIS-Rte: isis_route_info_new: out of memory!");
293 if (prefix
->family
== AF_INET
)
295 rinfo
->nexthops
= list_new ();
296 for (ALL_LIST_ELEMENTS_RO (adjacencies
, node
, adj
))
298 /* check for force resync this route */
299 if (CHECK_FLAG (adj
->circuit
->flags
, ISIS_CIRCUIT_FLAPPED_AFTER_SPF
))
300 SET_FLAG (rinfo
->flag
, ISIS_ROUTE_FLAG_ZEBRA_RESYNC
);
301 /* update neighbor router address */
302 if (depth
== 2 && prefix
->prefixlen
== 32)
303 adj
->router_address
= prefix
->u
.prefix4
;
304 adjinfo2nexthop (rinfo
->nexthops
, adj
);
308 if (prefix
->family
== AF_INET6
)
310 rinfo
->nexthops6
= list_new ();
311 for (ALL_LIST_ELEMENTS_RO (adjacencies
, node
, adj
))
313 /* check for force resync this route */
314 if (CHECK_FLAG (adj
->circuit
->flags
, ISIS_CIRCUIT_FLAPPED_AFTER_SPF
))
315 SET_FLAG (rinfo
->flag
, ISIS_ROUTE_FLAG_ZEBRA_RESYNC
);
316 /* update neighbor router address */
317 if (depth
== 2 && prefix
->prefixlen
== 128)
318 adj
->router_address6
= prefix
->u
.prefix6
;
319 adjinfo2nexthop6 (rinfo
->nexthops6
, adj
);
323 #endif /* HAVE_IPV6 */
326 rinfo
->depth
= depth
;
332 isis_route_info_delete (struct isis_route_info
*route_info
)
334 if (route_info
->nexthops
)
336 route_info
->nexthops
->del
= (void (*)(void *)) isis_nexthop_delete
;
337 list_delete (route_info
->nexthops
);
341 if (route_info
->nexthops6
)
343 route_info
->nexthops6
->del
= (void (*)(void *)) isis_nexthop6_delete
;
344 list_delete (route_info
->nexthops6
);
346 #endif /* HAVE_IPV6 */
348 XFREE (MTYPE_ISIS_ROUTE_INFO
, route_info
);
352 isis_route_info_same_attrib (struct isis_route_info
*new,
353 struct isis_route_info
*old
)
355 if (new->cost
!= old
->cost
)
357 if (new->depth
!= old
->depth
)
364 isis_route_info_same (struct isis_route_info
*new,
365 struct isis_route_info
*old
, u_char family
)
367 struct listnode
*node
;
368 struct isis_nexthop
*nexthop
;
370 struct isis_nexthop6
*nexthop6
;
371 #endif /* HAVE_IPV6 */
373 if (!CHECK_FLAG (old
->flag
, ISIS_ROUTE_FLAG_ZEBRA_SYNCED
))
376 if (CHECK_FLAG (new->flag
, ISIS_ROUTE_FLAG_ZEBRA_RESYNC
))
379 if (!isis_route_info_same_attrib (new, old
))
382 if (family
== AF_INET
)
384 for (ALL_LIST_ELEMENTS_RO (new->nexthops
, node
, nexthop
))
385 if (nexthoplookup (old
->nexthops
, &nexthop
->ip
, nexthop
->ifindex
)
389 for (ALL_LIST_ELEMENTS_RO (old
->nexthops
, node
, nexthop
))
390 if (nexthoplookup (new->nexthops
, &nexthop
->ip
, nexthop
->ifindex
)
395 else if (family
== AF_INET6
)
397 for (ALL_LIST_ELEMENTS_RO (new->nexthops6
, node
, nexthop6
))
398 if (nexthop6lookup (old
->nexthops6
, &nexthop6
->ip6
,
399 nexthop6
->ifindex
) == 0)
402 for (ALL_LIST_ELEMENTS_RO (old
->nexthops6
, node
, nexthop6
))
403 if (nexthop6lookup (new->nexthops6
, &nexthop6
->ip6
,
404 nexthop6
->ifindex
) == 0)
407 #endif /* HAVE_IPV6 */
412 struct isis_route_info
*
413 isis_route_create (struct prefix
*prefix
, u_int32_t cost
, u_int32_t depth
,
414 struct list
*adjacencies
, struct isis_area
*area
,
417 struct route_node
*route_node
;
418 struct isis_route_info
*rinfo_new
, *rinfo_old
, *route_info
= NULL
;
419 char buff
[PREFIX2STR_BUFFER
];
422 family
= prefix
->family
;
424 prefix2str (prefix
, buff
, sizeof (buff
));
426 rinfo_new
= isis_route_info_new (prefix
, cost
, depth
, adjacencies
);
429 zlog_err ("ISIS-Rte (%s): isis_route_create: out of memory!",
434 if (family
== AF_INET
)
435 route_node
= route_node_get (area
->route_table
[level
- 1], prefix
);
437 else if (family
== AF_INET6
)
438 route_node
= route_node_get (area
->route_table6
[level
- 1], prefix
);
439 #endif /* HAVE_IPV6 */
442 isis_route_info_delete (rinfo_new
);
446 rinfo_old
= route_node
->info
;
449 if (isis
->debugs
& DEBUG_RTE_EVENTS
)
450 zlog_debug ("ISIS-Rte (%s) route created: %s", area
->area_tag
, buff
);
451 route_info
= rinfo_new
;
452 UNSET_FLAG (route_info
->flag
, ISIS_ROUTE_FLAG_ZEBRA_SYNCED
);
456 if (isis
->debugs
& DEBUG_RTE_EVENTS
)
457 zlog_debug ("ISIS-Rte (%s) route already exists: %s", area
->area_tag
,
459 if (isis_route_info_same (rinfo_new
, rinfo_old
, family
))
461 if (isis
->debugs
& DEBUG_RTE_EVENTS
)
462 zlog_debug ("ISIS-Rte (%s) route unchanged: %s", area
->area_tag
,
464 isis_route_info_delete (rinfo_new
);
465 route_info
= rinfo_old
;
469 if (isis
->debugs
& DEBUG_RTE_EVENTS
)
470 zlog_debug ("ISIS-Rte (%s) route changed: %s", area
->area_tag
,
472 isis_route_info_delete (rinfo_old
);
473 route_info
= rinfo_new
;
474 UNSET_FLAG (route_info
->flag
, ISIS_ROUTE_FLAG_ZEBRA_SYNCED
);
478 SET_FLAG (route_info
->flag
, ISIS_ROUTE_FLAG_ACTIVE
);
479 route_node
->info
= route_info
;
485 isis_route_delete (struct prefix
*prefix
, struct route_table
*table
)
487 struct route_node
*rode
;
488 struct isis_route_info
*rinfo
;
489 char buff
[PREFIX2STR_BUFFER
];
492 prefix2str (prefix
, buff
, sizeof (buff
));
495 rode
= route_node_get (table
, prefix
);
500 if (isis
->debugs
& DEBUG_RTE_EVENTS
)
501 zlog_debug ("ISIS-Rte: tried to delete non-existant route %s", buff
);
505 if (CHECK_FLAG (rinfo
->flag
, ISIS_ROUTE_FLAG_ZEBRA_SYNCED
))
507 UNSET_FLAG (rinfo
->flag
, ISIS_ROUTE_FLAG_ACTIVE
);
508 if (isis
->debugs
& DEBUG_RTE_EVENTS
)
509 zlog_debug ("ISIS-Rte: route delete %s", buff
);
510 isis_zebra_route_update (prefix
, rinfo
);
512 isis_route_info_delete (rinfo
);
518 /* Validating routes in particular table. */
520 isis_route_validate_table (struct isis_area
*area
, struct route_table
*table
)
522 struct route_node
*rnode
, *drnode
;
523 struct isis_route_info
*rinfo
;
524 char buff
[PREFIX2STR_BUFFER
];
526 for (rnode
= route_top (table
); rnode
; rnode
= route_next (rnode
))
528 if (rnode
->info
== NULL
)
532 if (isis
->debugs
& DEBUG_RTE_EVENTS
)
534 prefix2str (&rnode
->p
, buff
, sizeof (buff
));
535 zlog_debug ("ISIS-Rte (%s): route validate: %s %s %s %s",
537 (CHECK_FLAG (rinfo
->flag
, ISIS_ROUTE_FLAG_ZEBRA_SYNCED
) ?
538 "synced" : "not-synced"),
539 (CHECK_FLAG (rinfo
->flag
, ISIS_ROUTE_FLAG_ZEBRA_RESYNC
) ?
540 "resync" : "not-resync"),
541 (CHECK_FLAG (rinfo
->flag
, ISIS_ROUTE_FLAG_ACTIVE
) ?
542 "active" : "inactive"), buff
);
545 isis_zebra_route_update (&rnode
->p
, rinfo
);
546 if (!CHECK_FLAG (rinfo
->flag
, ISIS_ROUTE_FLAG_ACTIVE
))
548 /* Area is either L1 or L2 => we use level route tables directly for
549 * validating => no problems with deleting routes. */
550 if (area
->is_type
!= IS_LEVEL_1_AND_2
)
552 isis_route_delete (&rnode
->p
, table
);
555 /* If area is L1L2, we work with merge table and therefore must
556 * delete node from level tables as well before deleting route info.
557 * FIXME: Is it performance problem? There has to be the better way.
558 * Like not to deal with it here at all (see the next comment)? */
559 if (rnode
->p
.family
== AF_INET
)
561 drnode
= route_node_get (area
->route_table
[0], &rnode
->p
);
562 if (drnode
->info
== rnode
->info
)
564 drnode
= route_node_get (area
->route_table
[1], &rnode
->p
);
565 if (drnode
->info
== rnode
->info
)
570 if (rnode
->p
.family
== AF_INET6
)
572 drnode
= route_node_get (area
->route_table6
[0], &rnode
->p
);
573 if (drnode
->info
== rnode
->info
)
575 drnode
= route_node_get (area
->route_table6
[1], &rnode
->p
);
576 if (drnode
->info
== rnode
->info
)
581 isis_route_delete (&rnode
->p
, table
);
586 /* Function to validate route tables for L1L2 areas. In this case we can't use
587 * level route tables directly, we have to merge them at first. L1 routes are
588 * preferred over the L2 ones.
590 * Merge algorithm is trivial (at least for now). All L1 paths are copied into
591 * merge table at first, then L2 paths are added if L1 path for same prefix
592 * doesn't already exists there.
594 * FIXME: Is it right place to do it at all? Maybe we should push both levels
595 * to the RIB with different zebra route types and let RIB handle this? */
597 isis_route_validate_merge (struct isis_area
*area
, int family
)
599 struct route_table
*table
= NULL
;
600 struct route_table
*merge
;
601 struct route_node
*rnode
, *mrnode
;
603 merge
= route_table_init ();
605 if (family
== AF_INET
)
606 table
= area
->route_table
[0];
608 else if (family
== AF_INET6
)
609 table
= area
->route_table6
[0];
612 for (rnode
= route_top (table
); rnode
; rnode
= route_next (rnode
))
614 if (rnode
->info
== NULL
)
616 mrnode
= route_node_get (merge
, &rnode
->p
);
617 mrnode
->info
= rnode
->info
;
620 if (family
== AF_INET
)
621 table
= area
->route_table
[1];
623 else if (family
== AF_INET6
)
624 table
= area
->route_table6
[1];
627 for (rnode
= route_top (table
); rnode
; rnode
= route_next (rnode
))
629 if (rnode
->info
== NULL
)
631 mrnode
= route_node_get (merge
, &rnode
->p
);
632 if (mrnode
->info
!= NULL
)
634 mrnode
->info
= rnode
->info
;
637 isis_route_validate_table (area
, merge
);
638 route_table_finish (merge
);
641 /* Walk through route tables and propagate necessary changes into RIB. In case
642 * of L1L2 area, level tables have to be merged at first. */
644 isis_route_validate (struct isis_area
*area
)
646 struct listnode
*node
;
647 struct isis_circuit
*circuit
;
649 if (area
->is_type
== IS_LEVEL_1
)
650 isis_route_validate_table (area
, area
->route_table
[0]);
651 else if (area
->is_type
== IS_LEVEL_2
)
652 isis_route_validate_table (area
, area
->route_table
[1]);
654 isis_route_validate_merge (area
, AF_INET
);
657 if (area
->is_type
== IS_LEVEL_1
)
658 isis_route_validate_table (area
, area
->route_table6
[0]);
659 else if (area
->is_type
== IS_LEVEL_2
)
660 isis_route_validate_table (area
, area
->route_table6
[1]);
662 isis_route_validate_merge (area
, AF_INET6
);
665 /* walk all circuits and reset any spf specific flags */
666 for (ALL_LIST_ELEMENTS_RO (area
->circuit_list
, node
, circuit
))
667 UNSET_FLAG(circuit
->flags
, ISIS_CIRCUIT_FLAPPED_AFTER_SPF
);
673 isis_route_invalidate_table (struct isis_area
*area
, struct route_table
*table
)
675 struct route_node
*rode
;
676 struct isis_route_info
*rinfo
;
677 for (rode
= route_top (table
); rode
; rode
= route_next (rode
))
679 if (rode
->info
== NULL
)
683 UNSET_FLAG (rinfo
->flag
, ISIS_ROUTE_FLAG_ACTIVE
);
688 isis_route_invalidate (struct isis_area
*area
)
690 if (area
->is_type
& IS_LEVEL_1
)
691 isis_route_invalidate_table (area
, area
->route_table
[0]);
692 if (area
->is_type
& IS_LEVEL_2
)
693 isis_route_invalidate_table (area
, area
->route_table
[1]);