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