]> git.proxmox.com Git - mirror_frr.git/blame - isisd/isis_route.c
Merge pull request #5625 from qlyoung/fix-zapi-ipset-name-nullterm
[mirror_frr.git] / isisd / isis_route.c
CommitLineData
eb5d44eb 1/*
2 * IS-IS Rout(e)ing protocol - isis_route.c
3 * Copyright (C) 2001,2002 Sampo Saaristo
d62a17ae 4 * Tampere University of Technology
eb5d44eb 5 * Institute of Communications Engineering
6 *
7 * based on ../ospf6d/ospf6_route.[ch]
8 * by Yasuhiro Ohara
9 *
d62a17ae 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)
eb5d44eb 13 * any later version.
14 *
d62a17ae 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
eb5d44eb 18 * more details.
896014f4
DL
19 *
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
eb5d44eb 23 */
24
eb5d44eb 25#include <zebra.h>
eb5d44eb 26
27#include "thread.h"
28#include "linklist.h"
29#include "vty.h"
30#include "log.h"
363be4dd 31#include "lib_errors.h"
eb5d44eb 32#include "memory.h"
33#include "prefix.h"
34#include "hash.h"
35#include "if.h"
36#include "table.h"
321c1bbb 37#include "srcdest_table.h"
eb5d44eb 38
39#include "isis_constants.h"
40#include "isis_common.h"
3f045a08 41#include "isis_flags.h"
eb5d44eb 42#include "isisd.h"
43#include "isis_misc.h"
44#include "isis_adjacency.h"
45#include "isis_circuit.h"
eb5d44eb 46#include "isis_pdu.h"
47#include "isis_lsp.h"
48#include "isis_spf.h"
49#include "isis_route.h"
50#include "isis_zebra.h"
51
6cf38339
RW
52DEFINE_HOOK(isis_route_update_hook,
53 (struct isis_area * area, struct prefix *prefix,
54 struct isis_route_info *route_info),
55 (area, prefix, route_info))
56
363be4dd
RW
57static struct isis_nexthop *nexthoplookup(struct list *nexthops, int family,
58 union g_addr *ip, ifindex_t ifindex);
6cf38339
RW
59static void isis_route_update(struct isis_area *area, struct prefix *prefix,
60 struct prefix_ipv6 *src_p,
0a5f3f4f 61 struct isis_route_info *route_info);
9e1194c2 62
363be4dd 63static struct isis_nexthop *isis_nexthop_create(int family, union g_addr *ip,
d62a17ae 64 ifindex_t ifindex)
eb5d44eb 65{
d62a17ae 66 struct isis_nexthop *nexthop;
f390d2c7 67
363be4dd 68 nexthop = nexthoplookup(isis->nexthops, family, ip, ifindex);
9e1194c2 69 if (nexthop) {
d62a17ae 70 nexthop->lock++;
71 return nexthop;
72 }
f390d2c7 73
d62a17ae 74 nexthop = XCALLOC(MTYPE_ISIS_NEXTHOP, sizeof(struct isis_nexthop));
f390d2c7 75
363be4dd 76 nexthop->family = family;
d62a17ae 77 nexthop->ifindex = ifindex;
363be4dd 78 nexthop->ip = *ip;
d62a17ae 79 listnode_add(isis->nexthops, nexthop);
80 nexthop->lock++;
eb5d44eb 81
d62a17ae 82 return nexthop;
eb5d44eb 83}
84
d62a17ae 85static void isis_nexthop_delete(struct isis_nexthop *nexthop)
eb5d44eb 86{
d62a17ae 87 nexthop->lock--;
88 if (nexthop->lock == 0) {
89 listnode_delete(isis->nexthops, nexthop);
90 XFREE(MTYPE_ISIS_NEXTHOP, nexthop);
91 }
92
93 return;
eb5d44eb 94}
95
363be4dd
RW
96static struct isis_nexthop *nexthoplookup(struct list *nexthops, int family,
97 union g_addr *ip, ifindex_t ifindex)
eb5d44eb 98{
d62a17ae 99 struct listnode *node;
100 struct isis_nexthop *nh;
eb5d44eb 101
d62a17ae 102 for (ALL_LIST_ELEMENTS_RO(nexthops, node, nh)) {
363be4dd
RW
103 if (nh->family != family)
104 continue;
105 if (nh->ifindex != ifindex)
106 continue;
107
108 switch (family) {
109 case AF_INET:
110 if (IPV4_ADDR_CMP(&nh->ip.ipv4, &ip->ipv4))
111 continue;
112 break;
113 case AF_INET6:
114 if (IPV6_ADDR_CMP(&nh->ip.ipv6, &ip->ipv6))
115 continue;
116 break;
117 default:
118 flog_err(EC_LIB_DEVELOPMENT,
119 "%s: unknown address family [%d]", __func__,
120 family);
121 exit(1);
122 }
eb5d44eb 123
363be4dd 124 return nh;
d62a17ae 125 }
eb5d44eb 126
9e1194c2 127 return NULL;
eb5d44eb 128}
129
363be4dd
RW
130static void adjinfo2nexthop(int family, struct list *nexthops,
131 struct isis_adjacency *adj)
eb5d44eb 132{
d62a17ae 133 struct isis_nexthop *nh;
363be4dd
RW
134 union g_addr ip = {};
135
136 switch (family) {
137 case AF_INET:
138 for (unsigned int i = 0; i < adj->ipv4_address_count; i++) {
139 ip.ipv4 = adj->ipv4_addresses[i];
140
141 if (!nexthoplookup(nexthops, AF_INET, &ip,
142 adj->circuit->interface->ifindex)) {
143 nh = isis_nexthop_create(
144 AF_INET, &ip,
145 adj->circuit->interface->ifindex);
146 listnode_add(nexthops, nh);
147 break;
148 }
d62a17ae 149 }
363be4dd
RW
150 break;
151 case AF_INET6:
152 for (unsigned int i = 0; i < adj->ipv6_address_count; i++) {
153 ip.ipv6 = adj->ipv6_addresses[i];
154
155 if (!nexthoplookup(nexthops, AF_INET6, &ip,
156 adj->circuit->interface->ifindex)) {
157 nh = isis_nexthop_create(
158 AF_INET6, &ip,
159 adj->circuit->interface->ifindex);
160 listnode_add(nexthops, nh);
161 break;
162 }
d62a17ae 163 }
363be4dd
RW
164 break;
165 default:
166 flog_err(EC_LIB_DEVELOPMENT, "%s: unknown address family [%d]",
167 __func__, family);
168 exit(1);
f390d2c7 169 }
eb5d44eb 170}
eb5d44eb 171
d62a17ae 172static struct isis_route_info *isis_route_info_new(struct prefix *prefix,
321c1bbb 173 struct prefix_ipv6 *src_p,
d62a17ae 174 uint32_t cost,
175 uint32_t depth,
176 struct list *adjacencies)
eb5d44eb 177{
d62a17ae 178 struct isis_route_info *rinfo;
179 struct isis_adjacency *adj;
180 struct listnode *node;
181
182 rinfo = XCALLOC(MTYPE_ISIS_ROUTE_INFO, sizeof(struct isis_route_info));
183
363be4dd
RW
184 rinfo->nexthops = list_new();
185 for (ALL_LIST_ELEMENTS_RO(adjacencies, node, adj)) {
186 /* check for force resync this route */
187 if (CHECK_FLAG(adj->circuit->flags,
188 ISIS_CIRCUIT_FLAPPED_AFTER_SPF))
189 SET_FLAG(rinfo->flag, ISIS_ROUTE_FLAG_ZEBRA_RESYNC);
190
191 /* update neighbor router address */
192 switch (prefix->family) {
193 case AF_INET:
d62a17ae 194 if (depth == 2 && prefix->prefixlen == 32)
195 adj->router_address = prefix->u.prefix4;
363be4dd
RW
196 break;
197 case AF_INET6:
321c1bbb
CF
198 if (depth == 2 && prefix->prefixlen == 128
199 && (!src_p || !src_p->prefixlen)) {
d62a17ae 200 adj->router_address6 = prefix->u.prefix6;
321c1bbb 201 }
363be4dd
RW
202 break;
203 default:
204 flog_err(EC_LIB_DEVELOPMENT,
205 "%s: unknown address family [%d]", __func__,
206 prefix->family);
207 exit(1);
d62a17ae 208 }
363be4dd 209 adjinfo2nexthop(prefix->family, rinfo->nexthops, adj);
d62a17ae 210 }
211
212 rinfo->cost = cost;
213 rinfo->depth = depth;
214
215 return rinfo;
eb5d44eb 216}
217
d62a17ae 218static void isis_route_info_delete(struct isis_route_info *route_info)
eb5d44eb 219{
d62a17ae 220 if (route_info->nexthops) {
221 route_info->nexthops->del =
222 (void (*)(void *))isis_nexthop_delete;
6a154c88 223 list_delete(&route_info->nexthops);
d62a17ae 224 }
225
d62a17ae 226 XFREE(MTYPE_ISIS_ROUTE_INFO, route_info);
eb5d44eb 227}
228
d62a17ae 229static int isis_route_info_same_attrib(struct isis_route_info *new,
230 struct isis_route_info *old)
eb5d44eb 231{
d62a17ae 232 if (new->cost != old->cost)
233 return 0;
234 if (new->depth != old->depth)
235 return 0;
f390d2c7 236
d62a17ae 237 return 1;
eb5d44eb 238}
239
d62a17ae 240static int isis_route_info_same(struct isis_route_info *new,
d7c0a89a 241 struct isis_route_info *old, uint8_t family)
eb5d44eb 242{
d62a17ae 243 struct listnode *node;
244 struct isis_nexthop *nexthop;
d62a17ae 245
246 if (!CHECK_FLAG(old->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED))
247 return 0;
248
249 if (CHECK_FLAG(new->flag, ISIS_ROUTE_FLAG_ZEBRA_RESYNC))
250 return 0;
251
252 if (!isis_route_info_same_attrib(new, old))
253 return 0;
254
363be4dd
RW
255 for (ALL_LIST_ELEMENTS_RO(new->nexthops, node, nexthop))
256 if (!nexthoplookup(old->nexthops, nexthop->family, &nexthop->ip,
257 nexthop->ifindex))
258 return 0;
259
260 for (ALL_LIST_ELEMENTS_RO(old->nexthops, node, nexthop))
261 if (!nexthoplookup(new->nexthops, nexthop->family, &nexthop->ip,
262 nexthop->ifindex))
263 return 0;
d62a17ae 264
265 return 1;
eb5d44eb 266}
267
321c1bbb
CF
268struct isis_route_info *isis_route_create(struct prefix *prefix,
269 struct prefix_ipv6 *src_p,
270 uint32_t cost,
d7c0a89a 271 uint32_t depth,
d62a17ae 272 struct list *adjacencies,
3dace42d
CF
273 struct isis_area *area,
274 struct route_table *table)
eb5d44eb 275{
d62a17ae 276 struct route_node *route_node;
277 struct isis_route_info *rinfo_new, *rinfo_old, *route_info = NULL;
278 char buff[PREFIX2STR_BUFFER];
d7c0a89a 279 uint8_t family;
d62a17ae 280
281 family = prefix->family;
282 /* for debugs */
283 prefix2str(prefix, buff, sizeof(buff));
284
3dace42d 285 if (!table)
d62a17ae 286 return NULL;
3dace42d 287
321c1bbb
CF
288 rinfo_new = isis_route_info_new(prefix, src_p, cost,
289 depth, adjacencies);
290 route_node = srcdest_rnode_get(table, prefix, src_p);
d62a17ae 291
292 rinfo_old = route_node->info;
293 if (!rinfo_old) {
294 if (isis->debugs & DEBUG_RTE_EVENTS)
295 zlog_debug("ISIS-Rte (%s) route created: %s",
296 area->area_tag, buff);
297 route_info = rinfo_new;
298 UNSET_FLAG(route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED);
299 } else {
bcd9fd50 300 route_unlock_node(route_node);
d62a17ae 301 if (isis->debugs & DEBUG_RTE_EVENTS)
302 zlog_debug("ISIS-Rte (%s) route already exists: %s",
303 area->area_tag, buff);
304 if (isis_route_info_same(rinfo_new, rinfo_old, family)) {
305 if (isis->debugs & DEBUG_RTE_EVENTS)
306 zlog_debug("ISIS-Rte (%s) route unchanged: %s",
307 area->area_tag, buff);
308 isis_route_info_delete(rinfo_new);
309 route_info = rinfo_old;
310 } else {
311 if (isis->debugs & DEBUG_RTE_EVENTS)
312 zlog_debug("ISIS-Rte (%s) route changed: %s",
313 area->area_tag, buff);
314 isis_route_info_delete(rinfo_old);
315 route_info = rinfo_new;
316 UNSET_FLAG(route_info->flag,
317 ISIS_ROUTE_FLAG_ZEBRA_SYNCED);
318 }
319 }
320
321 SET_FLAG(route_info->flag, ISIS_ROUTE_FLAG_ACTIVE);
322 route_node->info = route_info;
323
324 return route_info;
eb5d44eb 325}
326
6cf38339 327static void isis_route_delete(struct isis_area *area, struct route_node *rode,
321c1bbb 328 struct route_table *table)
eb5d44eb 329{
d62a17ae 330 struct isis_route_info *rinfo;
321c1bbb 331 char buff[SRCDEST2STR_BUFFER];
bcd9fd50
CF
332 struct prefix *prefix;
333 struct prefix_ipv6 *src_p;
d62a17ae 334
335 /* for log */
bcd9fd50 336 srcdest_rnode2str(rode, buff, sizeof(buff));
d62a17ae 337
bcd9fd50
CF
338 srcdest_rnode_prefixes(rode, (const struct prefix **)&prefix,
339 (const struct prefix **)&src_p);
d62a17ae 340
bcd9fd50 341 rinfo = rode->info;
d62a17ae 342 if (rinfo == NULL) {
343 if (isis->debugs & DEBUG_RTE_EVENTS)
344 zlog_debug(
345 "ISIS-Rte: tried to delete non-existant route %s",
346 buff);
347 return;
348 }
349
350 if (CHECK_FLAG(rinfo->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED)) {
351 UNSET_FLAG(rinfo->flag, ISIS_ROUTE_FLAG_ACTIVE);
352 if (isis->debugs & DEBUG_RTE_EVENTS)
353 zlog_debug("ISIS-Rte: route delete %s", buff);
6cf38339 354 isis_route_update(area, prefix, src_p, rinfo);
d62a17ae 355 }
356 isis_route_info_delete(rinfo);
357 rode->info = NULL;
bcd9fd50 358 route_unlock_node(rode);
eb5d44eb 359}
360
6cf38339
RW
361static void isis_route_update(struct isis_area *area, struct prefix *prefix,
362 struct prefix_ipv6 *src_p,
0a5f3f4f
RW
363 struct isis_route_info *route_info)
364{
365 if (CHECK_FLAG(route_info->flag, ISIS_ROUTE_FLAG_ACTIVE)) {
366 if (CHECK_FLAG(route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED))
367 return;
368
369 isis_zebra_route_add_route(prefix, src_p, route_info);
6cf38339 370 hook_call(isis_route_update_hook, area, prefix, route_info);
0a5f3f4f
RW
371
372 SET_FLAG(route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED);
373 UNSET_FLAG(route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_RESYNC);
374 } else {
375 if (!CHECK_FLAG(route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED))
376 return;
377
378 isis_zebra_route_del_route(prefix, src_p, route_info);
6cf38339 379 hook_call(isis_route_update_hook, area, prefix, route_info);
0a5f3f4f
RW
380
381 UNSET_FLAG(route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED);
382 }
383}
384
3dace42d
CF
385static void _isis_route_verify_table(struct isis_area *area,
386 struct route_table *table,
387 struct route_table **tables)
eb5d44eb 388{
d62a17ae 389 struct route_node *rnode, *drnode;
390 struct isis_route_info *rinfo;
321c1bbb 391 char buff[SRCDEST2STR_BUFFER];
d62a17ae 392
321c1bbb
CF
393 for (rnode = route_top(table); rnode;
394 rnode = srcdest_route_next(rnode)) {
d62a17ae 395 if (rnode->info == NULL)
396 continue;
397 rinfo = rnode->info;
398
321c1bbb
CF
399 struct prefix *dst_p;
400 struct prefix_ipv6 *src_p;
401
402 srcdest_rnode_prefixes(rnode,
403 (const struct prefix **)&dst_p,
404 (const struct prefix **)&src_p);
405
d62a17ae 406 if (isis->debugs & DEBUG_RTE_EVENTS) {
321c1bbb 407 srcdest2str(dst_p, src_p, buff, sizeof(buff));
d62a17ae 408 zlog_debug(
409 "ISIS-Rte (%s): route validate: %s %s %s %s",
410 area->area_tag,
411 (CHECK_FLAG(rinfo->flag,
412 ISIS_ROUTE_FLAG_ZEBRA_SYNCED)
413 ? "synced"
414 : "not-synced"),
415 (CHECK_FLAG(rinfo->flag,
416 ISIS_ROUTE_FLAG_ZEBRA_RESYNC)
417 ? "resync"
418 : "not-resync"),
419 (CHECK_FLAG(rinfo->flag, ISIS_ROUTE_FLAG_ACTIVE)
420 ? "active"
421 : "inactive"),
422 buff);
423 }
424
6cf38339 425 isis_route_update(area, dst_p, src_p, rinfo);
bcd9fd50
CF
426
427 if (CHECK_FLAG(rinfo->flag, ISIS_ROUTE_FLAG_ACTIVE))
428 continue;
429
430 /* Area is either L1 or L2 => we use level route tables
431 * directly for
432 * validating => no problems with deleting routes. */
433 if (!tables) {
6cf38339 434 isis_route_delete(area, rnode, table);
bcd9fd50
CF
435 continue;
436 }
437
438 /* If area is L1L2, we work with merge table and
439 * therefore must
440 * delete node from level tables as well before deleting
441 * route info. */
442 for (int level = ISIS_LEVEL1; level <= ISIS_LEVEL2; level++) {
443 drnode = srcdest_rnode_lookup(tables[level - 1],
444 dst_p, src_p);
445 if (!drnode)
d62a17ae 446 continue;
3dace42d 447
bcd9fd50 448 route_unlock_node(drnode);
d62a17ae 449
bcd9fd50
CF
450 if (drnode->info != rnode->info)
451 continue;
452
453 drnode->info = NULL;
454 route_unlock_node(drnode);
d62a17ae 455 }
bcd9fd50 456
6cf38339 457 isis_route_delete(area, rnode, table);
f390d2c7 458 }
fac1f7cc 459}
460
3dace42d
CF
461void isis_route_verify_table(struct isis_area *area, struct route_table *table)
462{
d90b788e 463 _isis_route_verify_table(area, table, NULL);
3dace42d
CF
464}
465
fac1f7cc 466/* Function to validate route tables for L1L2 areas. In this case we can't use
467 * level route tables directly, we have to merge them at first. L1 routes are
468 * preferred over the L2 ones.
469 *
470 * Merge algorithm is trivial (at least for now). All L1 paths are copied into
471 * merge table at first, then L2 paths are added if L1 path for same prefix
472 * doesn't already exists there.
473 *
474 * FIXME: Is it right place to do it at all? Maybe we should push both levels
475 * to the RIB with different zebra route types and let RIB handle this? */
3dace42d
CF
476void isis_route_verify_merge(struct isis_area *area,
477 struct route_table *level1_table,
478 struct route_table *level2_table)
fac1f7cc 479{
3dace42d 480 struct route_table *tables[] = { level1_table, level2_table };
d62a17ae 481 struct route_table *merge;
482 struct route_node *rnode, *mrnode;
483
321c1bbb 484 merge = srcdest_table_init();
d62a17ae 485
3dace42d
CF
486 for (int level = ISIS_LEVEL1; level <= ISIS_LEVEL2; level++) {
487 for (rnode = route_top(tables[level - 1]); rnode;
321c1bbb 488 rnode = srcdest_route_next(rnode)) {
26b0598f
CF
489 struct isis_route_info *rinfo = rnode->info;
490 if (!rinfo)
3dace42d 491 continue;
26b0598f 492
321c1bbb
CF
493 struct prefix *prefix;
494 struct prefix_ipv6 *src_p;
495
496 srcdest_rnode_prefixes(rnode,
497 (const struct prefix **)&prefix,
498 (const struct prefix **)&src_p);
499 mrnode = srcdest_rnode_get(merge, prefix, src_p);
26b0598f
CF
500 struct isis_route_info *mrinfo = mrnode->info;
501 if (mrinfo) {
3dace42d 502 route_unlock_node(mrnode);
26b0598f
CF
503 if (CHECK_FLAG(mrinfo->flag,
504 ISIS_ROUTE_FLAG_ACTIVE)) {
505 /* Clear the ZEBRA_SYNCED flag on the
506 * L2 route when L1 wins, otherwise L2
507 * won't get reinstalled when L1
508 * disappears.
509 */
510 UNSET_FLAG(
511 rinfo->flag,
512 ISIS_ROUTE_FLAG_ZEBRA_SYNCED
513 );
514 continue;
688ea1cb
EDP
515 } else if (CHECK_FLAG(rinfo->flag,
516 ISIS_ROUTE_FLAG_ACTIVE)) {
26b0598f
CF
517 /* Clear the ZEBRA_SYNCED flag on the L1
518 * route when L2 wins, otherwise L1
519 * won't get reinstalled when it
520 * reappears.
521 */
522 UNSET_FLAG(
523 mrinfo->flag,
524 ISIS_ROUTE_FLAG_ZEBRA_SYNCED
525 );
688ea1cb
EDP
526 } else if (
527 CHECK_FLAG(
528 mrinfo->flag,
529 ISIS_ROUTE_FLAG_ZEBRA_SYNCED)) {
530 continue;
26b0598f 531 }
3dace42d
CF
532 }
533 mrnode->info = rnode->info;
534 }
d62a17ae 535 }
536
3dace42d 537 _isis_route_verify_table(area, merge, tables);
d62a17ae 538 route_table_finish(merge);
fac1f7cc 539}
540
d62a17ae 541void isis_route_invalidate_table(struct isis_area *area,
542 struct route_table *table)
3f045a08 543{
d62a17ae 544 struct route_node *rode;
545 struct isis_route_info *rinfo;
321c1bbb 546 for (rode = route_top(table); rode; rode = srcdest_route_next(rode)) {
d62a17ae 547 if (rode->info == NULL)
548 continue;
549 rinfo = rode->info;
550
551 UNSET_FLAG(rinfo->flag, ISIS_ROUTE_FLAG_ACTIVE);
552 }
3f045a08 553}