]> git.proxmox.com Git - mirror_frr.git/blame - isisd/isis_route.c
isisd: remove leftover from old dict code
[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
363be4dd
RW
52static struct isis_nexthop *nexthoplookup(struct list *nexthops, int family,
53 union g_addr *ip, ifindex_t ifindex);
9e1194c2 54
363be4dd 55static struct isis_nexthop *isis_nexthop_create(int family, union g_addr *ip,
d62a17ae 56 ifindex_t ifindex)
eb5d44eb 57{
d62a17ae 58 struct isis_nexthop *nexthop;
f390d2c7 59
363be4dd 60 nexthop = nexthoplookup(isis->nexthops, family, ip, ifindex);
9e1194c2 61 if (nexthop) {
d62a17ae 62 nexthop->lock++;
63 return nexthop;
64 }
f390d2c7 65
d62a17ae 66 nexthop = XCALLOC(MTYPE_ISIS_NEXTHOP, sizeof(struct isis_nexthop));
f390d2c7 67
363be4dd 68 nexthop->family = family;
d62a17ae 69 nexthop->ifindex = ifindex;
363be4dd 70 nexthop->ip = *ip;
d62a17ae 71 listnode_add(isis->nexthops, nexthop);
72 nexthop->lock++;
eb5d44eb 73
d62a17ae 74 return nexthop;
eb5d44eb 75}
76
d62a17ae 77static void isis_nexthop_delete(struct isis_nexthop *nexthop)
eb5d44eb 78{
d62a17ae 79 nexthop->lock--;
80 if (nexthop->lock == 0) {
81 listnode_delete(isis->nexthops, nexthop);
82 XFREE(MTYPE_ISIS_NEXTHOP, nexthop);
83 }
84
85 return;
eb5d44eb 86}
87
363be4dd
RW
88static struct isis_nexthop *nexthoplookup(struct list *nexthops, int family,
89 union g_addr *ip, ifindex_t ifindex)
eb5d44eb 90{
d62a17ae 91 struct listnode *node;
92 struct isis_nexthop *nh;
eb5d44eb 93
d62a17ae 94 for (ALL_LIST_ELEMENTS_RO(nexthops, node, nh)) {
363be4dd
RW
95 if (nh->family != family)
96 continue;
97 if (nh->ifindex != ifindex)
98 continue;
99
100 switch (family) {
101 case AF_INET:
102 if (IPV4_ADDR_CMP(&nh->ip.ipv4, &ip->ipv4))
103 continue;
104 break;
105 case AF_INET6:
106 if (IPV6_ADDR_CMP(&nh->ip.ipv6, &ip->ipv6))
107 continue;
108 break;
109 default:
110 flog_err(EC_LIB_DEVELOPMENT,
111 "%s: unknown address family [%d]", __func__,
112 family);
113 exit(1);
114 }
eb5d44eb 115
363be4dd 116 return nh;
d62a17ae 117 }
eb5d44eb 118
9e1194c2 119 return NULL;
eb5d44eb 120}
121
363be4dd
RW
122static void adjinfo2nexthop(int family, struct list *nexthops,
123 struct isis_adjacency *adj)
eb5d44eb 124{
d62a17ae 125 struct isis_nexthop *nh;
363be4dd
RW
126 union g_addr ip = {};
127
128 switch (family) {
129 case AF_INET:
130 for (unsigned int i = 0; i < adj->ipv4_address_count; i++) {
131 ip.ipv4 = adj->ipv4_addresses[i];
132
133 if (!nexthoplookup(nexthops, AF_INET, &ip,
134 adj->circuit->interface->ifindex)) {
135 nh = isis_nexthop_create(
136 AF_INET, &ip,
137 adj->circuit->interface->ifindex);
138 listnode_add(nexthops, nh);
139 break;
140 }
d62a17ae 141 }
363be4dd
RW
142 break;
143 case AF_INET6:
144 for (unsigned int i = 0; i < adj->ipv6_address_count; i++) {
145 ip.ipv6 = adj->ipv6_addresses[i];
146
147 if (!nexthoplookup(nexthops, AF_INET6, &ip,
148 adj->circuit->interface->ifindex)) {
149 nh = isis_nexthop_create(
150 AF_INET6, &ip,
151 adj->circuit->interface->ifindex);
152 listnode_add(nexthops, nh);
153 break;
154 }
d62a17ae 155 }
363be4dd
RW
156 break;
157 default:
158 flog_err(EC_LIB_DEVELOPMENT, "%s: unknown address family [%d]",
159 __func__, family);
160 exit(1);
f390d2c7 161 }
eb5d44eb 162}
eb5d44eb 163
d62a17ae 164static struct isis_route_info *isis_route_info_new(struct prefix *prefix,
321c1bbb 165 struct prefix_ipv6 *src_p,
d62a17ae 166 uint32_t cost,
167 uint32_t depth,
168 struct list *adjacencies)
eb5d44eb 169{
d62a17ae 170 struct isis_route_info *rinfo;
171 struct isis_adjacency *adj;
172 struct listnode *node;
173
174 rinfo = XCALLOC(MTYPE_ISIS_ROUTE_INFO, sizeof(struct isis_route_info));
175
363be4dd
RW
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);
182
183 /* update neighbor router address */
184 switch (prefix->family) {
185 case AF_INET:
d62a17ae 186 if (depth == 2 && prefix->prefixlen == 32)
187 adj->router_address = prefix->u.prefix4;
363be4dd
RW
188 break;
189 case AF_INET6:
321c1bbb
CF
190 if (depth == 2 && prefix->prefixlen == 128
191 && (!src_p || !src_p->prefixlen)) {
d62a17ae 192 adj->router_address6 = prefix->u.prefix6;
321c1bbb 193 }
363be4dd
RW
194 break;
195 default:
196 flog_err(EC_LIB_DEVELOPMENT,
197 "%s: unknown address family [%d]", __func__,
198 prefix->family);
199 exit(1);
d62a17ae 200 }
363be4dd 201 adjinfo2nexthop(prefix->family, rinfo->nexthops, adj);
d62a17ae 202 }
203
204 rinfo->cost = cost;
205 rinfo->depth = depth;
206
207 return rinfo;
eb5d44eb 208}
209
d62a17ae 210static void isis_route_info_delete(struct isis_route_info *route_info)
eb5d44eb 211{
d62a17ae 212 if (route_info->nexthops) {
213 route_info->nexthops->del =
214 (void (*)(void *))isis_nexthop_delete;
6a154c88 215 list_delete(&route_info->nexthops);
d62a17ae 216 }
217
d62a17ae 218 XFREE(MTYPE_ISIS_ROUTE_INFO, route_info);
eb5d44eb 219}
220
d62a17ae 221static int isis_route_info_same_attrib(struct isis_route_info *new,
222 struct isis_route_info *old)
eb5d44eb 223{
d62a17ae 224 if (new->cost != old->cost)
225 return 0;
226 if (new->depth != old->depth)
227 return 0;
f390d2c7 228
d62a17ae 229 return 1;
eb5d44eb 230}
231
d62a17ae 232static int isis_route_info_same(struct isis_route_info *new,
d7c0a89a 233 struct isis_route_info *old, uint8_t family)
eb5d44eb 234{
d62a17ae 235 struct listnode *node;
236 struct isis_nexthop *nexthop;
d62a17ae 237
238 if (!CHECK_FLAG(old->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED))
239 return 0;
240
241 if (CHECK_FLAG(new->flag, ISIS_ROUTE_FLAG_ZEBRA_RESYNC))
242 return 0;
243
244 if (!isis_route_info_same_attrib(new, old))
245 return 0;
246
363be4dd
RW
247 for (ALL_LIST_ELEMENTS_RO(new->nexthops, node, nexthop))
248 if (!nexthoplookup(old->nexthops, nexthop->family, &nexthop->ip,
249 nexthop->ifindex))
250 return 0;
251
252 for (ALL_LIST_ELEMENTS_RO(old->nexthops, node, nexthop))
253 if (!nexthoplookup(new->nexthops, nexthop->family, &nexthop->ip,
254 nexthop->ifindex))
255 return 0;
d62a17ae 256
257 return 1;
eb5d44eb 258}
259
321c1bbb
CF
260struct isis_route_info *isis_route_create(struct prefix *prefix,
261 struct prefix_ipv6 *src_p,
262 uint32_t cost,
d7c0a89a 263 uint32_t depth,
d62a17ae 264 struct list *adjacencies,
3dace42d
CF
265 struct isis_area *area,
266 struct route_table *table)
eb5d44eb 267{
d62a17ae 268 struct route_node *route_node;
269 struct isis_route_info *rinfo_new, *rinfo_old, *route_info = NULL;
270 char buff[PREFIX2STR_BUFFER];
d7c0a89a 271 uint8_t family;
d62a17ae 272
273 family = prefix->family;
274 /* for debugs */
275 prefix2str(prefix, buff, sizeof(buff));
276
3dace42d 277 if (!table)
d62a17ae 278 return NULL;
3dace42d 279
321c1bbb
CF
280 rinfo_new = isis_route_info_new(prefix, src_p, cost,
281 depth, adjacencies);
282 route_node = srcdest_rnode_get(table, prefix, src_p);
d62a17ae 283
284 rinfo_old = route_node->info;
285 if (!rinfo_old) {
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);
291 } else {
bcd9fd50 292 route_unlock_node(route_node);
d62a17ae 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;
302 } else {
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);
310 }
311 }
312
313 SET_FLAG(route_info->flag, ISIS_ROUTE_FLAG_ACTIVE);
314 route_node->info = route_info;
315
316 return route_info;
eb5d44eb 317}
318
bcd9fd50 319static void isis_route_delete(struct route_node *rode,
321c1bbb 320 struct route_table *table)
eb5d44eb 321{
d62a17ae 322 struct isis_route_info *rinfo;
321c1bbb 323 char buff[SRCDEST2STR_BUFFER];
bcd9fd50
CF
324 struct prefix *prefix;
325 struct prefix_ipv6 *src_p;
d62a17ae 326
327 /* for log */
bcd9fd50 328 srcdest_rnode2str(rode, buff, sizeof(buff));
d62a17ae 329
bcd9fd50
CF
330 srcdest_rnode_prefixes(rode, (const struct prefix **)&prefix,
331 (const struct prefix **)&src_p);
d62a17ae 332
bcd9fd50 333 rinfo = rode->info;
d62a17ae 334 if (rinfo == NULL) {
335 if (isis->debugs & DEBUG_RTE_EVENTS)
336 zlog_debug(
337 "ISIS-Rte: tried to delete non-existant route %s",
338 buff);
339 return;
340 }
341
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);
321c1bbb 346 isis_zebra_route_update(prefix, src_p, rinfo);
d62a17ae 347 }
348 isis_route_info_delete(rinfo);
349 rode->info = NULL;
bcd9fd50 350 route_unlock_node(rode);
eb5d44eb 351}
352
3dace42d
CF
353static void _isis_route_verify_table(struct isis_area *area,
354 struct route_table *table,
355 struct route_table **tables)
eb5d44eb 356{
d62a17ae 357 struct route_node *rnode, *drnode;
358 struct isis_route_info *rinfo;
321c1bbb 359 char buff[SRCDEST2STR_BUFFER];
d62a17ae 360
321c1bbb
CF
361 for (rnode = route_top(table); rnode;
362 rnode = srcdest_route_next(rnode)) {
d62a17ae 363 if (rnode->info == NULL)
364 continue;
365 rinfo = rnode->info;
366
321c1bbb
CF
367 struct prefix *dst_p;
368 struct prefix_ipv6 *src_p;
369
370 srcdest_rnode_prefixes(rnode,
371 (const struct prefix **)&dst_p,
372 (const struct prefix **)&src_p);
373
d62a17ae 374 if (isis->debugs & DEBUG_RTE_EVENTS) {
321c1bbb 375 srcdest2str(dst_p, src_p, buff, sizeof(buff));
d62a17ae 376 zlog_debug(
377 "ISIS-Rte (%s): route validate: %s %s %s %s",
378 area->area_tag,
379 (CHECK_FLAG(rinfo->flag,
380 ISIS_ROUTE_FLAG_ZEBRA_SYNCED)
381 ? "synced"
382 : "not-synced"),
383 (CHECK_FLAG(rinfo->flag,
384 ISIS_ROUTE_FLAG_ZEBRA_RESYNC)
385 ? "resync"
386 : "not-resync"),
387 (CHECK_FLAG(rinfo->flag, ISIS_ROUTE_FLAG_ACTIVE)
388 ? "active"
389 : "inactive"),
390 buff);
391 }
392
321c1bbb 393 isis_zebra_route_update(dst_p, src_p, rinfo);
bcd9fd50
CF
394
395 if (CHECK_FLAG(rinfo->flag, ISIS_ROUTE_FLAG_ACTIVE))
396 continue;
397
398 /* Area is either L1 or L2 => we use level route tables
399 * directly for
400 * validating => no problems with deleting routes. */
401 if (!tables) {
402 isis_route_delete(rnode, table);
403 continue;
404 }
405
406 /* If area is L1L2, we work with merge table and
407 * therefore must
408 * delete node from level tables as well before deleting
409 * route info. */
410 for (int level = ISIS_LEVEL1; level <= ISIS_LEVEL2; level++) {
411 drnode = srcdest_rnode_lookup(tables[level - 1],
412 dst_p, src_p);
413 if (!drnode)
d62a17ae 414 continue;
3dace42d 415
bcd9fd50 416 route_unlock_node(drnode);
d62a17ae 417
bcd9fd50
CF
418 if (drnode->info != rnode->info)
419 continue;
420
421 drnode->info = NULL;
422 route_unlock_node(drnode);
d62a17ae 423 }
bcd9fd50
CF
424
425 isis_route_delete(rnode, table);
f390d2c7 426 }
fac1f7cc 427}
428
3dace42d
CF
429void isis_route_verify_table(struct isis_area *area, struct route_table *table)
430{
d90b788e 431 _isis_route_verify_table(area, table, NULL);
3dace42d
CF
432}
433
fac1f7cc 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.
437 *
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.
441 *
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? */
3dace42d
CF
444void isis_route_verify_merge(struct isis_area *area,
445 struct route_table *level1_table,
446 struct route_table *level2_table)
fac1f7cc 447{
3dace42d 448 struct route_table *tables[] = { level1_table, level2_table };
d62a17ae 449 struct route_table *merge;
450 struct route_node *rnode, *mrnode;
451
321c1bbb 452 merge = srcdest_table_init();
d62a17ae 453
3dace42d
CF
454 for (int level = ISIS_LEVEL1; level <= ISIS_LEVEL2; level++) {
455 for (rnode = route_top(tables[level - 1]); rnode;
321c1bbb 456 rnode = srcdest_route_next(rnode)) {
26b0598f
CF
457 struct isis_route_info *rinfo = rnode->info;
458 if (!rinfo)
3dace42d 459 continue;
26b0598f 460
321c1bbb
CF
461 struct prefix *prefix;
462 struct prefix_ipv6 *src_p;
463
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);
26b0598f
CF
468 struct isis_route_info *mrinfo = mrnode->info;
469 if (mrinfo) {
3dace42d 470 route_unlock_node(mrnode);
26b0598f
CF
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
476 * disappears.
477 */
478 UNSET_FLAG(
479 rinfo->flag,
480 ISIS_ROUTE_FLAG_ZEBRA_SYNCED
481 );
482 continue;
688ea1cb
EDP
483 } else if (CHECK_FLAG(rinfo->flag,
484 ISIS_ROUTE_FLAG_ACTIVE)) {
26b0598f
CF
485 /* Clear the ZEBRA_SYNCED flag on the L1
486 * route when L2 wins, otherwise L1
487 * won't get reinstalled when it
488 * reappears.
489 */
490 UNSET_FLAG(
491 mrinfo->flag,
492 ISIS_ROUTE_FLAG_ZEBRA_SYNCED
493 );
688ea1cb
EDP
494 } else if (
495 CHECK_FLAG(
496 mrinfo->flag,
497 ISIS_ROUTE_FLAG_ZEBRA_SYNCED)) {
498 continue;
26b0598f 499 }
3dace42d
CF
500 }
501 mrnode->info = rnode->info;
502 }
d62a17ae 503 }
504
3dace42d 505 _isis_route_verify_table(area, merge, tables);
d62a17ae 506 route_table_finish(merge);
fac1f7cc 507}
508
d62a17ae 509void isis_route_invalidate_table(struct isis_area *area,
510 struct route_table *table)
3f045a08 511{
d62a17ae 512 struct route_node *rode;
513 struct isis_route_info *rinfo;
321c1bbb 514 for (rode = route_top(table); rode; rode = srcdest_route_next(rode)) {
d62a17ae 515 if (rode->info == NULL)
516 continue;
517 rinfo = rode->info;
518
519 UNSET_FLAG(rinfo->flag, ISIS_ROUTE_FLAG_ACTIVE);
520 }
3f045a08 521}