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_route.h"
50 #include "isis_zebra.h"
52 static struct isis_nexthop
*nexthoplookup(struct list
*nexthops
, int family
,
53 union g_addr
*ip
, ifindex_t ifindex
);
55 static struct isis_nexthop
*isis_nexthop_create(int family
, union g_addr
*ip
,
58 struct isis_nexthop
*nexthop
;
60 nexthop
= nexthoplookup(isis
->nexthops
, family
, ip
, ifindex
);
66 nexthop
= XCALLOC(MTYPE_ISIS_NEXTHOP
, sizeof(struct isis_nexthop
));
68 nexthop
->family
= family
;
69 nexthop
->ifindex
= ifindex
;
71 listnode_add(isis
->nexthops
, nexthop
);
77 static void isis_nexthop_delete(struct isis_nexthop
*nexthop
)
80 if (nexthop
->lock
== 0) {
81 listnode_delete(isis
->nexthops
, nexthop
);
82 XFREE(MTYPE_ISIS_NEXTHOP
, nexthop
);
88 static struct isis_nexthop
*nexthoplookup(struct list
*nexthops
, int family
,
89 union g_addr
*ip
, ifindex_t ifindex
)
91 struct listnode
*node
;
92 struct isis_nexthop
*nh
;
94 for (ALL_LIST_ELEMENTS_RO(nexthops
, node
, nh
)) {
95 if (nh
->family
!= family
)
97 if (nh
->ifindex
!= ifindex
)
102 if (IPV4_ADDR_CMP(&nh
->ip
.ipv4
, &ip
->ipv4
))
106 if (IPV6_ADDR_CMP(&nh
->ip
.ipv6
, &ip
->ipv6
))
110 flog_err(EC_LIB_DEVELOPMENT
,
111 "%s: unknown address family [%d]", __func__
,
122 static void adjinfo2nexthop(int family
, struct list
*nexthops
,
123 struct isis_adjacency
*adj
)
125 struct isis_nexthop
*nh
;
126 union g_addr ip
= {};
130 for (unsigned int i
= 0; i
< adj
->ipv4_address_count
; i
++) {
131 ip
.ipv4
= adj
->ipv4_addresses
[i
];
133 if (!nexthoplookup(nexthops
, AF_INET
, &ip
,
134 adj
->circuit
->interface
->ifindex
)) {
135 nh
= isis_nexthop_create(
137 adj
->circuit
->interface
->ifindex
);
138 listnode_add(nexthops
, nh
);
144 for (unsigned int i
= 0; i
< adj
->ipv6_address_count
; i
++) {
145 ip
.ipv6
= adj
->ipv6_addresses
[i
];
147 if (!nexthoplookup(nexthops
, AF_INET6
, &ip
,
148 adj
->circuit
->interface
->ifindex
)) {
149 nh
= isis_nexthop_create(
151 adj
->circuit
->interface
->ifindex
);
152 listnode_add(nexthops
, nh
);
158 flog_err(EC_LIB_DEVELOPMENT
, "%s: unknown address family [%d]",
164 static struct isis_route_info
*isis_route_info_new(struct prefix
*prefix
,
165 struct prefix_ipv6
*src_p
,
168 struct list
*adjacencies
)
170 struct isis_route_info
*rinfo
;
171 struct isis_adjacency
*adj
;
172 struct listnode
*node
;
174 rinfo
= XCALLOC(MTYPE_ISIS_ROUTE_INFO
, sizeof(struct isis_route_info
));
176 rinfo
->nexthops
= list_new();
177 for (ALL_LIST_ELEMENTS_RO(adjacencies
, node
, adj
)) {
178 /* check for force resync this route */
179 if (CHECK_FLAG(adj
->circuit
->flags
,
180 ISIS_CIRCUIT_FLAPPED_AFTER_SPF
))
181 SET_FLAG(rinfo
->flag
, ISIS_ROUTE_FLAG_ZEBRA_RESYNC
);
183 /* update neighbor router address */
184 switch (prefix
->family
) {
186 if (depth
== 2 && prefix
->prefixlen
== 32)
187 adj
->router_address
= prefix
->u
.prefix4
;
190 if (depth
== 2 && prefix
->prefixlen
== 128
191 && (!src_p
|| !src_p
->prefixlen
)) {
192 adj
->router_address6
= prefix
->u
.prefix6
;
196 flog_err(EC_LIB_DEVELOPMENT
,
197 "%s: unknown address family [%d]", __func__
,
201 adjinfo2nexthop(prefix
->family
, rinfo
->nexthops
, adj
);
205 rinfo
->depth
= depth
;
210 static void isis_route_info_delete(struct isis_route_info
*route_info
)
212 if (route_info
->nexthops
) {
213 route_info
->nexthops
->del
=
214 (void (*)(void *))isis_nexthop_delete
;
215 list_delete(&route_info
->nexthops
);
218 XFREE(MTYPE_ISIS_ROUTE_INFO
, route_info
);
221 static int isis_route_info_same_attrib(struct isis_route_info
*new,
222 struct isis_route_info
*old
)
224 if (new->cost
!= old
->cost
)
226 if (new->depth
!= old
->depth
)
232 static int isis_route_info_same(struct isis_route_info
*new,
233 struct isis_route_info
*old
, uint8_t family
)
235 struct listnode
*node
;
236 struct isis_nexthop
*nexthop
;
238 if (!CHECK_FLAG(old
->flag
, ISIS_ROUTE_FLAG_ZEBRA_SYNCED
))
241 if (CHECK_FLAG(new->flag
, ISIS_ROUTE_FLAG_ZEBRA_RESYNC
))
244 if (!isis_route_info_same_attrib(new, old
))
247 for (ALL_LIST_ELEMENTS_RO(new->nexthops
, node
, nexthop
))
248 if (!nexthoplookup(old
->nexthops
, nexthop
->family
, &nexthop
->ip
,
252 for (ALL_LIST_ELEMENTS_RO(old
->nexthops
, node
, nexthop
))
253 if (!nexthoplookup(new->nexthops
, nexthop
->family
, &nexthop
->ip
,
260 struct isis_route_info
*isis_route_create(struct prefix
*prefix
,
261 struct prefix_ipv6
*src_p
,
264 struct list
*adjacencies
,
265 struct isis_area
*area
,
266 struct route_table
*table
)
268 struct route_node
*route_node
;
269 struct isis_route_info
*rinfo_new
, *rinfo_old
, *route_info
= NULL
;
270 char buff
[PREFIX2STR_BUFFER
];
273 family
= prefix
->family
;
275 prefix2str(prefix
, buff
, sizeof(buff
));
280 rinfo_new
= isis_route_info_new(prefix
, src_p
, cost
,
282 route_node
= srcdest_rnode_get(table
, prefix
, src_p
);
284 rinfo_old
= route_node
->info
;
286 if (isis
->debugs
& DEBUG_RTE_EVENTS
)
287 zlog_debug("ISIS-Rte (%s) route created: %s",
288 area
->area_tag
, buff
);
289 route_info
= rinfo_new
;
290 UNSET_FLAG(route_info
->flag
, ISIS_ROUTE_FLAG_ZEBRA_SYNCED
);
292 route_unlock_node(route_node
);
293 if (isis
->debugs
& DEBUG_RTE_EVENTS
)
294 zlog_debug("ISIS-Rte (%s) route already exists: %s",
295 area
->area_tag
, buff
);
296 if (isis_route_info_same(rinfo_new
, rinfo_old
, family
)) {
297 if (isis
->debugs
& DEBUG_RTE_EVENTS
)
298 zlog_debug("ISIS-Rte (%s) route unchanged: %s",
299 area
->area_tag
, buff
);
300 isis_route_info_delete(rinfo_new
);
301 route_info
= rinfo_old
;
303 if (isis
->debugs
& DEBUG_RTE_EVENTS
)
304 zlog_debug("ISIS-Rte (%s) route changed: %s",
305 area
->area_tag
, buff
);
306 isis_route_info_delete(rinfo_old
);
307 route_info
= rinfo_new
;
308 UNSET_FLAG(route_info
->flag
,
309 ISIS_ROUTE_FLAG_ZEBRA_SYNCED
);
313 SET_FLAG(route_info
->flag
, ISIS_ROUTE_FLAG_ACTIVE
);
314 route_node
->info
= route_info
;
319 static void isis_route_delete(struct route_node
*rode
,
320 struct route_table
*table
)
322 struct isis_route_info
*rinfo
;
323 char buff
[SRCDEST2STR_BUFFER
];
324 struct prefix
*prefix
;
325 struct prefix_ipv6
*src_p
;
328 srcdest_rnode2str(rode
, buff
, sizeof(buff
));
330 srcdest_rnode_prefixes(rode
, (const struct prefix
**)&prefix
,
331 (const struct prefix
**)&src_p
);
335 if (isis
->debugs
& DEBUG_RTE_EVENTS
)
337 "ISIS-Rte: tried to delete non-existant route %s",
342 if (CHECK_FLAG(rinfo
->flag
, ISIS_ROUTE_FLAG_ZEBRA_SYNCED
)) {
343 UNSET_FLAG(rinfo
->flag
, ISIS_ROUTE_FLAG_ACTIVE
);
344 if (isis
->debugs
& DEBUG_RTE_EVENTS
)
345 zlog_debug("ISIS-Rte: route delete %s", buff
);
346 isis_zebra_route_update(prefix
, src_p
, rinfo
);
348 isis_route_info_delete(rinfo
);
350 route_unlock_node(rode
);
353 static void _isis_route_verify_table(struct isis_area
*area
,
354 struct route_table
*table
,
355 struct route_table
**tables
)
357 struct route_node
*rnode
, *drnode
;
358 struct isis_route_info
*rinfo
;
359 char buff
[SRCDEST2STR_BUFFER
];
361 for (rnode
= route_top(table
); rnode
;
362 rnode
= srcdest_route_next(rnode
)) {
363 if (rnode
->info
== NULL
)
367 struct prefix
*dst_p
;
368 struct prefix_ipv6
*src_p
;
370 srcdest_rnode_prefixes(rnode
,
371 (const struct prefix
**)&dst_p
,
372 (const struct prefix
**)&src_p
);
374 if (isis
->debugs
& DEBUG_RTE_EVENTS
) {
375 srcdest2str(dst_p
, src_p
, buff
, sizeof(buff
));
377 "ISIS-Rte (%s): route validate: %s %s %s %s",
379 (CHECK_FLAG(rinfo
->flag
,
380 ISIS_ROUTE_FLAG_ZEBRA_SYNCED
)
383 (CHECK_FLAG(rinfo
->flag
,
384 ISIS_ROUTE_FLAG_ZEBRA_RESYNC
)
387 (CHECK_FLAG(rinfo
->flag
, ISIS_ROUTE_FLAG_ACTIVE
)
393 isis_zebra_route_update(dst_p
, src_p
, rinfo
);
395 if (CHECK_FLAG(rinfo
->flag
, ISIS_ROUTE_FLAG_ACTIVE
))
398 /* Area is either L1 or L2 => we use level route tables
400 * validating => no problems with deleting routes. */
402 isis_route_delete(rnode
, table
);
406 /* If area is L1L2, we work with merge table and
408 * delete node from level tables as well before deleting
410 for (int level
= ISIS_LEVEL1
; level
<= ISIS_LEVEL2
; level
++) {
411 drnode
= srcdest_rnode_lookup(tables
[level
- 1],
416 route_unlock_node(drnode
);
418 if (drnode
->info
!= rnode
->info
)
422 route_unlock_node(drnode
);
425 isis_route_delete(rnode
, table
);
429 void isis_route_verify_table(struct isis_area
*area
, struct route_table
*table
)
431 _isis_route_verify_table(area
, table
, NULL
);
434 /* Function to validate route tables for L1L2 areas. In this case we can't use
435 * level route tables directly, we have to merge them at first. L1 routes are
436 * preferred over the L2 ones.
438 * Merge algorithm is trivial (at least for now). All L1 paths are copied into
439 * merge table at first, then L2 paths are added if L1 path for same prefix
440 * doesn't already exists there.
442 * FIXME: Is it right place to do it at all? Maybe we should push both levels
443 * to the RIB with different zebra route types and let RIB handle this? */
444 void isis_route_verify_merge(struct isis_area
*area
,
445 struct route_table
*level1_table
,
446 struct route_table
*level2_table
)
448 struct route_table
*tables
[] = { level1_table
, level2_table
};
449 struct route_table
*merge
;
450 struct route_node
*rnode
, *mrnode
;
452 merge
= srcdest_table_init();
454 for (int level
= ISIS_LEVEL1
; level
<= ISIS_LEVEL2
; level
++) {
455 for (rnode
= route_top(tables
[level
- 1]); rnode
;
456 rnode
= srcdest_route_next(rnode
)) {
457 struct isis_route_info
*rinfo
= rnode
->info
;
461 struct prefix
*prefix
;
462 struct prefix_ipv6
*src_p
;
464 srcdest_rnode_prefixes(rnode
,
465 (const struct prefix
**)&prefix
,
466 (const struct prefix
**)&src_p
);
467 mrnode
= srcdest_rnode_get(merge
, prefix
, src_p
);
468 struct isis_route_info
*mrinfo
= mrnode
->info
;
470 route_unlock_node(mrnode
);
471 if (CHECK_FLAG(mrinfo
->flag
,
472 ISIS_ROUTE_FLAG_ACTIVE
)) {
473 /* Clear the ZEBRA_SYNCED flag on the
474 * L2 route when L1 wins, otherwise L2
475 * won't get reinstalled when L1
480 ISIS_ROUTE_FLAG_ZEBRA_SYNCED
483 } else if (CHECK_FLAG(rinfo
->flag
,
484 ISIS_ROUTE_FLAG_ACTIVE
)) {
485 /* Clear the ZEBRA_SYNCED flag on the L1
486 * route when L2 wins, otherwise L1
487 * won't get reinstalled when it
492 ISIS_ROUTE_FLAG_ZEBRA_SYNCED
497 ISIS_ROUTE_FLAG_ZEBRA_SYNCED
)) {
501 mrnode
->info
= rnode
->info
;
505 _isis_route_verify_table(area
, merge
, tables
);
506 route_table_finish(merge
);
509 void isis_route_invalidate_table(struct isis_area
*area
,
510 struct route_table
*table
)
512 struct route_node
*rode
;
513 struct isis_route_info
*rinfo
;
514 for (rode
= route_top(table
); rode
; rode
= srcdest_route_next(rode
)) {
515 if (rode
->info
== NULL
)
519 UNSET_FLAG(rinfo
->flag
, ISIS_ROUTE_FLAG_ACTIVE
);