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