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; see the file COPYING; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
31 #include "lib_errors.h"
37 #include "srcdest_table.h"
39 #include "isis_constants.h"
40 #include "isis_common.h"
41 #include "isis_flags.h"
43 #include "isis_misc.h"
44 #include "isis_adjacency.h"
45 #include "isis_circuit.h"
49 #include "isis_spf_private.h"
50 #include "isis_route.h"
51 #include "isis_zebra.h"
53 DEFINE_HOOK(isis_route_update_hook
,
54 (struct isis_area
* area
, struct prefix
*prefix
,
55 struct isis_route_info
*route_info
),
56 (area
, prefix
, route_info
))
58 static struct isis_nexthop
*nexthoplookup(struct list
*nexthops
, int family
,
59 union g_addr
*ip
, ifindex_t ifindex
);
60 static void isis_route_update(struct isis_area
*area
, struct prefix
*prefix
,
61 struct prefix_ipv6
*src_p
,
62 struct isis_route_info
*route_info
);
64 static struct isis_nexthop
*isis_nexthop_create(int family
, union g_addr
*ip
,
67 struct isis_nexthop
*nexthop
;
69 nexthop
= XCALLOC(MTYPE_ISIS_NEXTHOP
, sizeof(struct isis_nexthop
));
71 nexthop
->family
= family
;
72 nexthop
->ifindex
= ifindex
;
74 isis_sr_nexthop_reset(&nexthop
->sr
);
79 static void isis_nexthop_delete(struct isis_nexthop
*nexthop
)
81 XFREE(MTYPE_ISIS_NEXTHOP
, nexthop
);
84 static struct isis_nexthop
*nexthoplookup(struct list
*nexthops
, int family
,
85 union g_addr
*ip
, ifindex_t ifindex
)
87 struct listnode
*node
;
88 struct isis_nexthop
*nh
;
90 for (ALL_LIST_ELEMENTS_RO(nexthops
, node
, nh
)) {
91 if (nh
->family
!= family
)
93 if (nh
->ifindex
!= ifindex
)
98 if (IPV4_ADDR_CMP(&nh
->ip
.ipv4
, &ip
->ipv4
))
102 if (IPV6_ADDR_CMP(&nh
->ip
.ipv6
, &ip
->ipv6
))
106 flog_err(EC_LIB_DEVELOPMENT
,
107 "%s: unknown address family [%d]", __func__
,
118 static void adjinfo2nexthop(int family
, struct list
*nexthops
,
119 struct isis_adjacency
*adj
)
121 struct isis_nexthop
*nh
;
122 union g_addr ip
= {};
126 for (unsigned int i
= 0; i
< adj
->ipv4_address_count
; i
++) {
127 ip
.ipv4
= adj
->ipv4_addresses
[i
];
129 if (!nexthoplookup(nexthops
, AF_INET
, &ip
,
130 adj
->circuit
->interface
->ifindex
)) {
131 nh
= isis_nexthop_create(
133 adj
->circuit
->interface
->ifindex
);
134 memcpy(nh
->sysid
, adj
->sysid
, sizeof(nh
->sysid
));
135 listnode_add(nexthops
, nh
);
141 for (unsigned int i
= 0; i
< adj
->ipv6_address_count
; i
++) {
142 ip
.ipv6
= adj
->ipv6_addresses
[i
];
144 if (!nexthoplookup(nexthops
, AF_INET6
, &ip
,
145 adj
->circuit
->interface
->ifindex
)) {
146 nh
= isis_nexthop_create(
148 adj
->circuit
->interface
->ifindex
);
149 memcpy(nh
->sysid
, adj
->sysid
, sizeof(nh
->sysid
));
150 listnode_add(nexthops
, nh
);
156 flog_err(EC_LIB_DEVELOPMENT
, "%s: unknown address family [%d]",
162 static void isis_route_add_dummy_nexthops(struct isis_route_info
*rinfo
,
163 const uint8_t *sysid
)
165 struct isis_nexthop
*nh
;
167 nh
= XCALLOC(MTYPE_ISIS_NEXTHOP
, sizeof(struct isis_nexthop
));
168 memcpy(nh
->sysid
, sysid
, sizeof(nh
->sysid
));
169 isis_sr_nexthop_reset(&nh
->sr
);
170 listnode_add(rinfo
->nexthops
, nh
);
173 static struct isis_route_info
*isis_route_info_new(struct prefix
*prefix
,
174 struct prefix_ipv6
*src_p
,
177 struct list
*adjacencies
)
179 struct isis_route_info
*rinfo
;
180 struct isis_vertex_adj
*vadj
;
181 struct listnode
*node
;
183 rinfo
= XCALLOC(MTYPE_ISIS_ROUTE_INFO
, sizeof(struct isis_route_info
));
185 rinfo
->nexthops
= list_new();
186 for (ALL_LIST_ELEMENTS_RO(adjacencies
, node
, vadj
)) {
187 struct isis_spf_adj
*sadj
= vadj
->sadj
;
188 struct isis_adjacency
*adj
= sadj
->adj
;
191 * Create dummy nexthops when running SPF on a testing
194 if (CHECK_FLAG(im
->options
, F_ISIS_UNIT_TEST
)) {
195 isis_route_add_dummy_nexthops(rinfo
, sadj
->id
);
199 /* check for force resync this route */
200 if (CHECK_FLAG(adj
->circuit
->flags
,
201 ISIS_CIRCUIT_FLAPPED_AFTER_SPF
))
202 SET_FLAG(rinfo
->flag
, ISIS_ROUTE_FLAG_ZEBRA_RESYNC
);
204 /* update neighbor router address */
205 switch (prefix
->family
) {
207 if (depth
== 2 && prefix
->prefixlen
== 32)
208 adj
->router_address
= prefix
->u
.prefix4
;
211 if (depth
== 2 && prefix
->prefixlen
== 128
212 && (!src_p
|| !src_p
->prefixlen
)) {
213 adj
->router_address6
= prefix
->u
.prefix6
;
217 flog_err(EC_LIB_DEVELOPMENT
,
218 "%s: unknown address family [%d]", __func__
,
222 adjinfo2nexthop(prefix
->family
, rinfo
->nexthops
, adj
);
226 rinfo
->depth
= depth
;
231 static void isis_route_info_delete(struct isis_route_info
*route_info
)
233 if (route_info
->nexthops
) {
234 route_info
->nexthops
->del
=
235 (void (*)(void *))isis_nexthop_delete
;
236 list_delete(&route_info
->nexthops
);
239 XFREE(MTYPE_ISIS_ROUTE_INFO
, route_info
);
242 static int isis_route_info_same(struct isis_route_info
*new,
243 struct isis_route_info
*old
, char *buf
,
246 struct listnode
*node
;
247 struct isis_nexthop
*nexthop
;
249 if (new->cost
!= old
->cost
) {
251 snprintf(buf
, buf_size
, "cost (old: %u, new: %u)",
252 old
->cost
, new->cost
);
256 if (new->depth
!= old
->depth
) {
258 snprintf(buf
, buf_size
, "depth (old: %u, new: %u)",
259 old
->depth
, new->depth
);
263 if (new->nexthops
->count
!= old
->nexthops
->count
) {
265 snprintf(buf
, buf_size
, "nhops num (old: %u, new: %u)",
266 old
->nexthops
->count
, new->nexthops
->count
);
270 for (ALL_LIST_ELEMENTS_RO(new->nexthops
, node
, nexthop
)) {
271 if (!nexthoplookup(old
->nexthops
, nexthop
->family
, &nexthop
->ip
,
274 snprintf(buf
, buf_size
,
275 "new nhop"); /* TODO: print nhop */
280 /* only the resync flag needs to be checked */
281 if (CHECK_FLAG(new->flag
, ISIS_ROUTE_FLAG_ZEBRA_RESYNC
)
282 != CHECK_FLAG(old
->flag
, ISIS_ROUTE_FLAG_ZEBRA_RESYNC
)) {
284 snprintf(buf
, buf_size
, "resync flag");
291 struct isis_route_info
*isis_route_create(struct prefix
*prefix
,
292 struct prefix_ipv6
*src_p
,
295 struct list
*adjacencies
,
296 struct isis_area
*area
,
297 struct route_table
*table
)
299 struct route_node
*route_node
;
300 struct isis_route_info
*rinfo_new
, *rinfo_old
, *route_info
= NULL
;
301 char buff
[PREFIX2STR_BUFFER
];
305 prefix2str(prefix
, buff
, sizeof(buff
));
310 rinfo_new
= isis_route_info_new(prefix
, src_p
, cost
,
312 route_node
= srcdest_rnode_get(table
, prefix
, src_p
);
314 rinfo_old
= route_node
->info
;
316 if (IS_DEBUG_RTE_EVENTS
)
317 zlog_debug("ISIS-Rte (%s) route created: %s",
318 area
->area_tag
, buff
);
319 route_info
= rinfo_new
;
320 UNSET_FLAG(route_info
->flag
, ISIS_ROUTE_FLAG_ZEBRA_SYNCED
);
322 route_unlock_node(route_node
);
324 if (IS_DEBUG_RTE_EVENTS
)
325 zlog_debug("ISIS-Rte (%s) route already exists: %s",
326 area
->area_tag
, buff
);
327 #endif /* EXTREME_DEBUG */
328 if (isis_route_info_same(rinfo_new
, rinfo_old
, change_buf
,
329 sizeof(change_buf
))) {
331 if (IS_DEBUG_RTE_EVENTS
)
332 zlog_debug("ISIS-Rte (%s) route unchanged: %s",
333 area
->area_tag
, buff
);
334 #endif /* EXTREME_DEBUG */
335 isis_route_info_delete(rinfo_new
);
336 route_info
= rinfo_old
;
338 if (IS_DEBUG_RTE_EVENTS
)
340 "ISIS-Rte (%s): route changed: %s, change: %s",
341 area
->area_tag
, buff
, change_buf
);
342 isis_route_info_delete(rinfo_old
);
343 route_info
= rinfo_new
;
344 UNSET_FLAG(route_info
->flag
,
345 ISIS_ROUTE_FLAG_ZEBRA_SYNCED
);
349 SET_FLAG(route_info
->flag
, ISIS_ROUTE_FLAG_ACTIVE
);
350 route_node
->info
= route_info
;
355 static void isis_route_delete(struct isis_area
*area
, struct route_node
*rode
,
356 struct route_table
*table
)
358 struct isis_route_info
*rinfo
;
359 char buff
[SRCDEST2STR_BUFFER
];
360 struct prefix
*prefix
;
361 struct prefix_ipv6
*src_p
;
364 srcdest_rnode2str(rode
, buff
, sizeof(buff
));
366 srcdest_rnode_prefixes(rode
, (const struct prefix
**)&prefix
,
367 (const struct prefix
**)&src_p
);
371 if (IS_DEBUG_RTE_EVENTS
)
373 "ISIS-Rte: tried to delete non-existant route %s",
378 if (CHECK_FLAG(rinfo
->flag
, ISIS_ROUTE_FLAG_ZEBRA_SYNCED
)) {
379 UNSET_FLAG(rinfo
->flag
, ISIS_ROUTE_FLAG_ACTIVE
);
380 if (IS_DEBUG_RTE_EVENTS
)
381 zlog_debug("ISIS-Rte: route delete %s", buff
);
382 isis_route_update(area
, prefix
, src_p
, rinfo
);
384 isis_route_info_delete(rinfo
);
386 route_unlock_node(rode
);
389 static void isis_route_update(struct isis_area
*area
, struct prefix
*prefix
,
390 struct prefix_ipv6
*src_p
,
391 struct isis_route_info
*route_info
)
393 if (CHECK_FLAG(route_info
->flag
, ISIS_ROUTE_FLAG_ACTIVE
)) {
394 if (CHECK_FLAG(route_info
->flag
, ISIS_ROUTE_FLAG_ZEBRA_SYNCED
))
397 isis_zebra_route_add_route(area
->isis
, prefix
, src_p
, route_info
);
398 hook_call(isis_route_update_hook
, area
, prefix
, route_info
);
400 SET_FLAG(route_info
->flag
, ISIS_ROUTE_FLAG_ZEBRA_SYNCED
);
401 UNSET_FLAG(route_info
->flag
, ISIS_ROUTE_FLAG_ZEBRA_RESYNC
);
403 if (!CHECK_FLAG(route_info
->flag
, ISIS_ROUTE_FLAG_ZEBRA_SYNCED
))
406 isis_zebra_route_del_route(area
->isis
, prefix
, src_p
, route_info
);
407 hook_call(isis_route_update_hook
, area
, prefix
, route_info
);
409 UNSET_FLAG(route_info
->flag
, ISIS_ROUTE_FLAG_ZEBRA_SYNCED
);
413 static void _isis_route_verify_table(struct isis_area
*area
,
414 struct route_table
*table
,
415 struct route_table
**tables
)
417 struct route_node
*rnode
, *drnode
;
418 struct isis_route_info
*rinfo
;
420 char buff
[SRCDEST2STR_BUFFER
];
421 #endif /* EXTREME_DEBUG */
423 for (rnode
= route_top(table
); rnode
;
424 rnode
= srcdest_route_next(rnode
)) {
425 if (rnode
->info
== NULL
)
429 struct prefix
*dst_p
;
430 struct prefix_ipv6
*src_p
;
432 srcdest_rnode_prefixes(rnode
,
433 (const struct prefix
**)&dst_p
,
434 (const struct prefix
**)&src_p
);
437 if (IS_DEBUG_RTE_EVENTS
) {
438 srcdest2str(dst_p
, src_p
, buff
, sizeof(buff
));
440 "ISIS-Rte (%s): route validate: %s %s %s %s",
442 (CHECK_FLAG(rinfo
->flag
,
443 ISIS_ROUTE_FLAG_ZEBRA_SYNCED
)
446 (CHECK_FLAG(rinfo
->flag
,
447 ISIS_ROUTE_FLAG_ZEBRA_RESYNC
)
450 (CHECK_FLAG(rinfo
->flag
, ISIS_ROUTE_FLAG_ACTIVE
)
455 #endif /* EXTREME_DEBUG */
457 isis_route_update(area
, dst_p
, src_p
, rinfo
);
459 if (CHECK_FLAG(rinfo
->flag
, ISIS_ROUTE_FLAG_ACTIVE
))
462 /* Area is either L1 or L2 => we use level route tables
464 * validating => no problems with deleting routes. */
466 isis_route_delete(area
, rnode
, table
);
470 /* If area is L1L2, we work with merge table and
472 * delete node from level tables as well before deleting
474 for (int level
= ISIS_LEVEL1
; level
<= ISIS_LEVEL2
; level
++) {
475 drnode
= srcdest_rnode_lookup(tables
[level
- 1],
480 route_unlock_node(drnode
);
482 if (drnode
->info
!= rnode
->info
)
486 route_unlock_node(drnode
);
489 isis_route_delete(area
, rnode
, table
);
493 void isis_route_verify_table(struct isis_area
*area
, struct route_table
*table
)
495 _isis_route_verify_table(area
, table
, NULL
);
498 /* Function to validate route tables for L1L2 areas. In this case we can't use
499 * level route tables directly, we have to merge them at first. L1 routes are
500 * preferred over the L2 ones.
502 * Merge algorithm is trivial (at least for now). All L1 paths are copied into
503 * merge table at first, then L2 paths are added if L1 path for same prefix
504 * doesn't already exists there.
506 * FIXME: Is it right place to do it at all? Maybe we should push both levels
507 * to the RIB with different zebra route types and let RIB handle this? */
508 void isis_route_verify_merge(struct isis_area
*area
,
509 struct route_table
*level1_table
,
510 struct route_table
*level2_table
)
512 struct route_table
*tables
[] = { level1_table
, level2_table
};
513 struct route_table
*merge
;
514 struct route_node
*rnode
, *mrnode
;
516 merge
= srcdest_table_init();
518 for (int level
= ISIS_LEVEL1
; level
<= ISIS_LEVEL2
; level
++) {
519 for (rnode
= route_top(tables
[level
- 1]); rnode
;
520 rnode
= srcdest_route_next(rnode
)) {
521 struct isis_route_info
*rinfo
= rnode
->info
;
525 struct prefix
*prefix
;
526 struct prefix_ipv6
*src_p
;
528 srcdest_rnode_prefixes(rnode
,
529 (const struct prefix
**)&prefix
,
530 (const struct prefix
**)&src_p
);
531 mrnode
= srcdest_rnode_get(merge
, prefix
, src_p
);
532 struct isis_route_info
*mrinfo
= mrnode
->info
;
534 route_unlock_node(mrnode
);
535 if (CHECK_FLAG(mrinfo
->flag
,
536 ISIS_ROUTE_FLAG_ACTIVE
)) {
537 /* Clear the ZEBRA_SYNCED flag on the
538 * L2 route when L1 wins, otherwise L2
539 * won't get reinstalled when L1
544 ISIS_ROUTE_FLAG_ZEBRA_SYNCED
547 } else if (CHECK_FLAG(rinfo
->flag
,
548 ISIS_ROUTE_FLAG_ACTIVE
)) {
549 /* Clear the ZEBRA_SYNCED flag on the L1
550 * route when L2 wins, otherwise L1
551 * won't get reinstalled when it
556 ISIS_ROUTE_FLAG_ZEBRA_SYNCED
561 ISIS_ROUTE_FLAG_ZEBRA_SYNCED
)) {
565 mrnode
->info
= rnode
->info
;
569 _isis_route_verify_table(area
, merge
, tables
);
570 route_table_finish(merge
);
573 void isis_route_invalidate_table(struct isis_area
*area
,
574 struct route_table
*table
)
576 struct route_node
*rode
;
577 struct isis_route_info
*rinfo
;
578 for (rode
= route_top(table
); rode
; rode
= srcdest_route_next(rode
)) {
579 if (rode
->info
== NULL
)
583 UNSET_FLAG(rinfo
->flag
, ISIS_ROUTE_FLAG_ACTIVE
);