]>
Commit | Line | Data |
---|---|---|
acddc0ed | 1 | // SPDX-License-Identifier: GPL-2.0-or-later |
f3ccedaa CF |
2 | /* |
3 | * IS-IS Rout(e)ing protocol - isis_redist.c | |
4 | * | |
5 | * Copyright (C) 2013-2015 Christian Franke <chris@opensourcerouting.org> | |
f3ccedaa CF |
6 | */ |
7 | ||
8 | #include <zebra.h> | |
9 | ||
10 | #include "command.h" | |
11 | #include "if.h" | |
12 | #include "linklist.h" | |
13 | #include "memory.h" | |
f3ccedaa CF |
14 | #include "prefix.h" |
15 | #include "routemap.h" | |
16 | #include "stream.h" | |
17 | #include "table.h" | |
18 | #include "vty.h" | |
d43d2df5 | 19 | #include "srcdest_table.h" |
f3ccedaa | 20 | |
f3ccedaa CF |
21 | #include "isisd/isis_constants.h" |
22 | #include "isisd/isis_common.h" | |
23 | #include "isisd/isis_flags.h" | |
24 | #include "isisd/isis_misc.h" | |
25 | #include "isisd/isis_circuit.h" | |
f3ccedaa CF |
26 | #include "isisd/isisd.h" |
27 | #include "isisd/isis_lsp.h" | |
28 | #include "isisd/isis_route.h" | |
29 | #include "isisd/isis_zebra.h" | |
30 | ||
66b9a381 DL |
31 | DEFINE_MTYPE_STATIC(ISISD, ISIS_EXT_ROUTE, "ISIS redistributed route"); |
32 | DEFINE_MTYPE_STATIC(ISISD, ISIS_EXT_INFO, "ISIS redistributed route info"); | |
33 | DEFINE_MTYPE_STATIC(ISISD, ISIS_RMAP_NAME, "ISIS redistribute route-map name"); | |
34 | ||
d62a17ae | 35 | static int redist_protocol(int family) |
f3ccedaa | 36 | { |
d62a17ae | 37 | if (family == AF_INET) |
38 | return 0; | |
39 | if (family == AF_INET6) | |
40 | return 1; | |
f3ccedaa | 41 | |
d62a17ae | 42 | assert(!"Unsupported address family!"); |
43 | return 0; | |
f3ccedaa CF |
44 | } |
45 | ||
8c6482db | 46 | afi_t afi_for_redist_protocol(int protocol) |
113b1946 | 47 | { |
d62a17ae | 48 | if (protocol == 0) |
49 | return AFI_IP; | |
50 | if (protocol == 1) | |
51 | return AFI_IP6; | |
113b1946 | 52 | |
d62a17ae | 53 | assert(!"Unknown redist protocol!"); |
54 | return AFI_IP; | |
113b1946 CF |
55 | } |
56 | ||
d62a17ae | 57 | static struct route_table *get_ext_info(struct isis *i, int family) |
f3ccedaa | 58 | { |
d62a17ae | 59 | int protocol = redist_protocol(family); |
f3ccedaa | 60 | |
d62a17ae | 61 | return i->ext_info[protocol]; |
f3ccedaa CF |
62 | } |
63 | ||
d62a17ae | 64 | static struct isis_redist *get_redist_settings(struct isis_area *area, |
65 | int family, int type, int level) | |
f3ccedaa | 66 | { |
d62a17ae | 67 | int protocol = redist_protocol(family); |
f3ccedaa | 68 | |
d62a17ae | 69 | return &area->redist_settings[protocol][type][level - 1]; |
f3ccedaa CF |
70 | } |
71 | ||
d62a17ae | 72 | struct route_table *get_ext_reach(struct isis_area *area, int family, int level) |
f3ccedaa | 73 | { |
d62a17ae | 74 | int protocol = redist_protocol(family); |
f3ccedaa | 75 | |
d62a17ae | 76 | return area->ext_reach[protocol][level - 1]; |
f3ccedaa CF |
77 | } |
78 | ||
f3ccedaa CF |
79 | /* Install external reachability information into a |
80 | * specific area for a specific level. | |
81 | * Schedule an lsp regenerate if necessary */ | |
d62a17ae | 82 | static void isis_redist_install(struct isis_area *area, int level, |
d43d2df5 CF |
83 | const struct prefix *p, |
84 | const struct prefix_ipv6 *src_p, | |
85 | struct isis_ext_info *info) | |
f3ccedaa | 86 | { |
d62a17ae | 87 | int family = p->family; |
88 | struct route_table *er_table = get_ext_reach(area, family, level); | |
89 | struct route_node *er_node; | |
90 | ||
91 | if (!er_table) { | |
92 | zlog_warn( | |
3efd0893 | 93 | "%s: External reachability table of area %s is not initialized.", |
d62a17ae | 94 | __func__, area->area_tag); |
95 | return; | |
96 | } | |
97 | ||
d43d2df5 | 98 | er_node = srcdest_rnode_get(er_table, p, src_p); |
d62a17ae | 99 | if (er_node->info) { |
100 | route_unlock_node(er_node); | |
101 | ||
102 | /* Don't update/reschedule lsp generation if nothing changed. */ | |
103 | if (!memcmp(er_node->info, info, sizeof(*info))) | |
104 | return; | |
105 | } else { | |
106 | er_node->info = XMALLOC(MTYPE_ISIS_EXT_INFO, sizeof(*info)); | |
107 | } | |
108 | ||
109 | memcpy(er_node->info, info, sizeof(*info)); | |
110 | lsp_regenerate_schedule(area, level, 0); | |
f3ccedaa CF |
111 | } |
112 | ||
113 | /* Remove external reachability information from a | |
114 | * specific area for a specific level. | |
115 | * Schedule an lsp regenerate if necessary. */ | |
d62a17ae | 116 | static void isis_redist_uninstall(struct isis_area *area, int level, |
d43d2df5 CF |
117 | const struct prefix *p, |
118 | const struct prefix_ipv6 *src_p) | |
f3ccedaa | 119 | { |
d62a17ae | 120 | int family = p->family; |
121 | struct route_table *er_table = get_ext_reach(area, family, level); | |
122 | struct route_node *er_node; | |
123 | ||
124 | if (!er_table) { | |
125 | zlog_warn( | |
3efd0893 | 126 | "%s: External reachability table of area %s is not initialized.", |
d62a17ae | 127 | __func__, area->area_tag); |
128 | return; | |
129 | } | |
130 | ||
d43d2df5 | 131 | er_node = srcdest_rnode_lookup(er_table, p, src_p); |
d62a17ae | 132 | if (!er_node) |
133 | return; | |
134 | else | |
135 | route_unlock_node(er_node); | |
136 | ||
137 | if (!er_node->info) | |
138 | return; | |
139 | ||
140 | XFREE(MTYPE_ISIS_EXT_INFO, er_node->info); | |
141 | route_unlock_node(er_node); | |
142 | lsp_regenerate_schedule(area, level, 0); | |
f3ccedaa CF |
143 | } |
144 | ||
145 | /* Update external reachability info of area for a given level | |
146 | * and prefix, using the given redistribution settings. */ | |
d62a17ae | 147 | static void isis_redist_update_ext_reach(struct isis_area *area, int level, |
148 | struct isis_redist *redist, | |
d43d2df5 CF |
149 | const struct prefix *p, |
150 | const struct prefix_ipv6 *src_p, | |
d62a17ae | 151 | struct isis_ext_info *info) |
f3ccedaa | 152 | { |
d62a17ae | 153 | struct isis_ext_info area_info; |
154 | route_map_result_t map_ret; | |
155 | ||
156 | memcpy(&area_info, info, sizeof(area_info)); | |
8cfc8c5c | 157 | area_info.metric = redist->metric; |
d62a17ae | 158 | |
159 | if (redist->map_name) { | |
1782514f | 160 | map_ret = route_map_apply(redist->map, p, &area_info); |
d62a17ae | 161 | if (map_ret == RMAP_DENYMATCH) |
162 | area_info.distance = 255; | |
163 | } | |
164 | ||
165 | /* Allow synthesized default routes only on always orignate */ | |
166 | if (area_info.origin == DEFAULT_ROUTE | |
167 | && redist->redist != DEFAULT_ORIGINATE_ALWAYS) | |
168 | area_info.distance = 255; | |
169 | ||
170 | if (area_info.distance < 255) | |
d43d2df5 | 171 | isis_redist_install(area, level, p, src_p, &area_info); |
d62a17ae | 172 | else |
d43d2df5 | 173 | isis_redist_uninstall(area, level, p, src_p); |
f3ccedaa CF |
174 | } |
175 | ||
d62a17ae | 176 | static void isis_redist_ensure_default(struct isis *isis, int family) |
f3ccedaa | 177 | { |
d62a17ae | 178 | struct prefix p; |
179 | struct route_table *ei_table = get_ext_info(isis, family); | |
180 | struct route_node *ei_node; | |
181 | struct isis_ext_info *info; | |
182 | ||
183 | if (family == AF_INET) { | |
184 | p.family = AF_INET; | |
185 | p.prefixlen = 0; | |
186 | memset(&p.u.prefix4, 0, sizeof(p.u.prefix4)); | |
187 | } else if (family == AF_INET6) { | |
188 | p.family = AF_INET6; | |
189 | p.prefixlen = 0; | |
190 | memset(&p.u.prefix6, 0, sizeof(p.u.prefix6)); | |
191 | } else | |
192 | assert(!"Unknown family!"); | |
193 | ||
d43d2df5 | 194 | ei_node = srcdest_rnode_get(ei_table, &p, NULL); |
d62a17ae | 195 | if (ei_node->info) { |
196 | route_unlock_node(ei_node); | |
197 | return; | |
198 | } | |
199 | ||
200 | ei_node->info = | |
201 | XCALLOC(MTYPE_ISIS_EXT_INFO, sizeof(struct isis_ext_info)); | |
202 | ||
203 | info = ei_node->info; | |
204 | info->origin = DEFAULT_ROUTE; | |
205 | info->distance = 254; | |
206 | info->metric = MAX_WIDE_PATH_METRIC; | |
f3ccedaa CF |
207 | } |
208 | ||
209 | /* Handle notification about route being added */ | |
eab88f36 K |
210 | void isis_redist_add(struct isis *isis, int type, struct prefix *p, |
211 | struct prefix_ipv6 *src_p, uint8_t distance, | |
3b1e3aab | 212 | uint32_t metric, const route_tag_t tag) |
f3ccedaa | 213 | { |
d62a17ae | 214 | int family = p->family; |
215 | struct route_table *ei_table = get_ext_info(isis, family); | |
216 | struct route_node *ei_node; | |
217 | struct isis_ext_info *info; | |
218 | struct listnode *node; | |
219 | struct isis_area *area; | |
220 | int level; | |
221 | struct isis_redist *redist; | |
222 | ||
2dbe669b DA |
223 | zlog_debug("%s: New route %pFX from %s: distance %d.", __func__, p, |
224 | zebra_route_string(type), distance); | |
d62a17ae | 225 | |
226 | if (!ei_table) { | |
227 | zlog_warn("%s: External information table not initialized.", | |
228 | __func__); | |
229 | return; | |
230 | } | |
231 | ||
d43d2df5 | 232 | ei_node = srcdest_rnode_get(ei_table, p, src_p); |
d62a17ae | 233 | if (ei_node->info) |
234 | route_unlock_node(ei_node); | |
235 | else | |
236 | ei_node->info = XCALLOC(MTYPE_ISIS_EXT_INFO, | |
237 | sizeof(struct isis_ext_info)); | |
238 | ||
239 | info = ei_node->info; | |
240 | info->origin = type; | |
241 | info->distance = distance; | |
242 | info->metric = metric; | |
3b1e3aab | 243 | info->tag = tag; |
d62a17ae | 244 | |
d43d2df5 CF |
245 | if (is_default_prefix(p) |
246 | && (!src_p || !src_p->prefixlen)) { | |
d62a17ae | 247 | type = DEFAULT_ROUTE; |
d43d2df5 | 248 | } |
d62a17ae | 249 | |
250 | for (ALL_LIST_ELEMENTS_RO(isis->area_list, node, area)) | |
251 | for (level = 1; level <= ISIS_LEVELS; level++) { | |
252 | redist = get_redist_settings(area, family, type, level); | |
253 | if (!redist->redist) | |
254 | continue; | |
255 | ||
256 | isis_redist_update_ext_reach(area, level, redist, p, | |
d43d2df5 | 257 | src_p, info); |
d62a17ae | 258 | } |
f3ccedaa CF |
259 | } |
260 | ||
eab88f36 K |
261 | void isis_redist_delete(struct isis *isis, int type, struct prefix *p, |
262 | struct prefix_ipv6 *src_p) | |
f3ccedaa | 263 | { |
d62a17ae | 264 | int family = p->family; |
265 | struct route_table *ei_table = get_ext_info(isis, family); | |
266 | struct route_node *ei_node; | |
267 | struct listnode *node; | |
268 | struct isis_area *area; | |
269 | int level; | |
270 | struct isis_redist *redist; | |
271 | ||
2dbe669b | 272 | zlog_debug("%s: Removing route %pFX from %s.", __func__, p, |
d62a17ae | 273 | zebra_route_string(type)); |
274 | ||
d43d2df5 CF |
275 | if (is_default_prefix(p) |
276 | && (!src_p || !src_p->prefixlen)) { | |
d62a17ae | 277 | /* Don't remove default route but add synthetic route for use |
278 | * by "default-information originate always". Areas without the | |
279 | * "always" setting will ignore routes with origin | |
280 | * DEFAULT_ROUTE. */ | |
eab88f36 | 281 | isis_redist_add(isis, DEFAULT_ROUTE, p, NULL, 254, |
3b1e3aab | 282 | MAX_WIDE_PATH_METRIC, 0); |
d62a17ae | 283 | return; |
284 | } | |
285 | ||
286 | if (!ei_table) { | |
287 | zlog_warn("%s: External information table not initialized.", | |
288 | __func__); | |
289 | return; | |
290 | } | |
291 | ||
d43d2df5 | 292 | ei_node = srcdest_rnode_lookup(ei_table, p, src_p); |
d62a17ae | 293 | if (!ei_node || !ei_node->info) { |
d62a17ae | 294 | zlog_warn( |
2dbe669b DA |
295 | "%s: Got a delete for %s route %pFX, but that route was never added.", |
296 | __func__, zebra_route_string(type), p); | |
d62a17ae | 297 | if (ei_node) |
298 | route_unlock_node(ei_node); | |
299 | return; | |
300 | } | |
301 | route_unlock_node(ei_node); | |
302 | ||
303 | for (ALL_LIST_ELEMENTS_RO(isis->area_list, node, area)) | |
c30f211b | 304 | for (level = ISIS_LEVEL1; level <= ISIS_LEVEL2; level++) { |
d62a17ae | 305 | redist = get_redist_settings(area, family, type, level); |
306 | if (!redist->redist) | |
307 | continue; | |
308 | ||
d43d2df5 | 309 | isis_redist_uninstall(area, level, p, src_p); |
d62a17ae | 310 | } |
311 | ||
312 | XFREE(MTYPE_ISIS_EXT_INFO, ei_node->info); | |
313 | route_unlock_node(ei_node); | |
f3ccedaa CF |
314 | } |
315 | ||
d62a17ae | 316 | static void isis_redist_routemap_set(struct isis_redist *redist, |
317 | const char *routemap) | |
f3ccedaa | 318 | { |
d62a17ae | 319 | if (redist->map_name) { |
66b9a381 | 320 | XFREE(MTYPE_ISIS_RMAP_NAME, redist->map_name); |
5478b000 | 321 | route_map_counter_decrement(redist->map); |
d62a17ae | 322 | redist->map = NULL; |
323 | } | |
324 | ||
325 | if (routemap && strlen(routemap)) { | |
66b9a381 | 326 | redist->map_name = XSTRDUP(MTYPE_ISIS_RMAP_NAME, routemap); |
d62a17ae | 327 | redist->map = route_map_lookup_by_name(routemap); |
5478b000 | 328 | route_map_counter_increment(redist->map); |
d62a17ae | 329 | } |
f3ccedaa CF |
330 | } |
331 | ||
d62a17ae | 332 | static void isis_redist_update_zebra_subscriptions(struct isis *isis) |
f3ccedaa | 333 | { |
d62a17ae | 334 | struct listnode *node; |
335 | struct isis_area *area; | |
336 | int type; | |
337 | int level; | |
338 | int protocol; | |
339 | ||
8c6482db IR |
340 | if (isis->vrf_id == VRF_UNKNOWN) |
341 | return; | |
342 | ||
d62a17ae | 343 | char do_subscribe[REDIST_PROTOCOL_COUNT][ZEBRA_ROUTE_MAX + 1]; |
344 | ||
345 | memset(do_subscribe, 0, sizeof(do_subscribe)); | |
346 | ||
347 | for (ALL_LIST_ELEMENTS_RO(isis->area_list, node, area)) | |
348 | for (protocol = 0; protocol < REDIST_PROTOCOL_COUNT; protocol++) | |
349 | for (type = 0; type < ZEBRA_ROUTE_MAX + 1; type++) | |
350 | for (level = 0; level < ISIS_LEVELS; level++) | |
9d303b37 | 351 | if (area->redist_settings[protocol] |
a601d662 IR |
352 | [type][level] |
353 | .redist | |
354 | == 1) | |
d62a17ae | 355 | do_subscribe[protocol][type] = |
356 | 1; | |
357 | ||
358 | for (protocol = 0; protocol < REDIST_PROTOCOL_COUNT; protocol++) | |
359 | for (type = 0; type < ZEBRA_ROUTE_MAX + 1; type++) { | |
360 | /* This field is actually controlling transmission of | |
361 | * the IS-IS | |
362 | * routes to Zebra and has nothing to do with | |
363 | * redistribution, | |
364 | * so skip it. */ | |
7c0cbd0e | 365 | if (type == PROTO_TYPE) |
d62a17ae | 366 | continue; |
367 | ||
368 | afi_t afi = afi_for_redist_protocol(protocol); | |
369 | ||
370 | if (do_subscribe[protocol][type]) | |
8c6482db IR |
371 | isis_zebra_redistribute_set(afi, type, |
372 | isis->vrf_id); | |
d62a17ae | 373 | else |
8c6482db IR |
374 | isis_zebra_redistribute_unset(afi, type, |
375 | isis->vrf_id); | |
d62a17ae | 376 | } |
f3ccedaa CF |
377 | } |
378 | ||
d53e72e5 DS |
379 | void isis_redist_free(struct isis *isis) |
380 | { | |
46c9042f | 381 | struct route_node *rn; |
d53e72e5 DS |
382 | int i; |
383 | ||
384 | for (i = 0; i < REDIST_PROTOCOL_COUNT; i++) { | |
385 | if (!isis->ext_info[i]) | |
386 | continue; | |
387 | ||
46c9042f IR |
388 | for (rn = route_top(isis->ext_info[i]); rn; |
389 | rn = srcdest_route_next(rn)) { | |
390 | if (rn->info) | |
391 | XFREE(MTYPE_ISIS_EXT_INFO, rn->info); | |
392 | } | |
393 | ||
d53e72e5 DS |
394 | route_table_finish(isis->ext_info[i]); |
395 | isis->ext_info[i] = NULL; | |
396 | } | |
397 | } | |
398 | ||
8b104c10 EDP |
399 | void isis_redist_set(struct isis_area *area, int level, int family, int type, |
400 | uint32_t metric, const char *routemap, int originate_type) | |
f3ccedaa | 401 | { |
d62a17ae | 402 | int protocol = redist_protocol(family); |
403 | struct isis_redist *redist = | |
404 | get_redist_settings(area, family, type, level); | |
405 | int i; | |
406 | struct route_table *ei_table; | |
407 | struct route_node *rn; | |
408 | struct isis_ext_info *info; | |
409 | ||
410 | redist->redist = (type == DEFAULT_ROUTE) ? originate_type : 1; | |
411 | redist->metric = metric; | |
412 | isis_redist_routemap_set(redist, routemap); | |
413 | ||
414 | if (!area->ext_reach[protocol][level - 1]) { | |
d43d2df5 | 415 | area->ext_reach[protocol][level - 1] = srcdest_table_init(); |
d62a17ae | 416 | } |
417 | ||
d43d2df5 | 418 | for (i = 0; i < REDIST_PROTOCOL_COUNT; i++) { |
d62a17ae | 419 | if (!area->isis->ext_info[i]) { |
d43d2df5 | 420 | area->isis->ext_info[i] = srcdest_table_init(); |
d62a17ae | 421 | } |
d43d2df5 | 422 | } |
d62a17ae | 423 | |
424 | isis_redist_update_zebra_subscriptions(area->isis); | |
425 | ||
426 | if (type == DEFAULT_ROUTE && originate_type == DEFAULT_ORIGINATE_ALWAYS) | |
427 | isis_redist_ensure_default(area->isis, family); | |
428 | ||
429 | ei_table = get_ext_info(area->isis, family); | |
d43d2df5 | 430 | for (rn = route_top(ei_table); rn; rn = srcdest_route_next(rn)) { |
d62a17ae | 431 | if (!rn->info) |
432 | continue; | |
433 | info = rn->info; | |
434 | ||
d43d2df5 CF |
435 | const struct prefix *p, *src_p; |
436 | ||
437 | srcdest_rnode_prefixes(rn, &p, &src_p); | |
438 | ||
d62a17ae | 439 | if (type == DEFAULT_ROUTE) { |
d43d2df5 CF |
440 | if (!is_default_prefix(p) |
441 | || (src_p && src_p->prefixlen)) { | |
d62a17ae | 442 | continue; |
d43d2df5 | 443 | } |
d62a17ae | 444 | } else { |
445 | if (info->origin != type) | |
446 | continue; | |
447 | } | |
448 | ||
d43d2df5 | 449 | isis_redist_update_ext_reach(area, level, redist, p, |
36de6e0e A |
450 | (const struct prefix_ipv6 *)src_p, |
451 | info); | |
d62a17ae | 452 | } |
f3ccedaa CF |
453 | } |
454 | ||
8b104c10 | 455 | void isis_redist_unset(struct isis_area *area, int level, int family, int type) |
f3ccedaa | 456 | { |
d62a17ae | 457 | struct isis_redist *redist = |
458 | get_redist_settings(area, family, type, level); | |
459 | struct route_table *er_table = get_ext_reach(area, family, level); | |
460 | struct route_node *rn; | |
461 | struct isis_ext_info *info; | |
462 | ||
463 | if (!redist->redist) | |
464 | return; | |
465 | ||
466 | redist->redist = 0; | |
467 | if (!er_table) { | |
468 | zlog_warn("%s: External reachability table uninitialized.", | |
469 | __func__); | |
470 | return; | |
471 | } | |
472 | ||
d43d2df5 | 473 | for (rn = route_top(er_table); rn; rn = srcdest_route_next(rn)) { |
d62a17ae | 474 | if (!rn->info) |
475 | continue; | |
476 | info = rn->info; | |
477 | ||
d43d2df5 CF |
478 | const struct prefix *p, *src_p; |
479 | srcdest_rnode_prefixes(rn, &p, &src_p); | |
480 | ||
d62a17ae | 481 | if (type == DEFAULT_ROUTE) { |
d43d2df5 CF |
482 | if (!is_default_prefix(p) |
483 | || (src_p && src_p->prefixlen)) { | |
d62a17ae | 484 | continue; |
d43d2df5 | 485 | } |
d62a17ae | 486 | } else { |
487 | if (info->origin != type) | |
488 | continue; | |
489 | } | |
490 | ||
491 | XFREE(MTYPE_ISIS_EXT_INFO, rn->info); | |
492 | route_unlock_node(rn); | |
493 | } | |
494 | ||
495 | lsp_regenerate_schedule(area, level, 0); | |
496 | isis_redist_update_zebra_subscriptions(area->isis); | |
f3ccedaa CF |
497 | } |
498 | ||
d62a17ae | 499 | void isis_redist_area_finish(struct isis_area *area) |
f3ccedaa | 500 | { |
46c9042f | 501 | struct route_node *rn; |
d62a17ae | 502 | int protocol; |
503 | int level; | |
504 | int type; | |
505 | ||
506 | for (protocol = 0; protocol < REDIST_PROTOCOL_COUNT; protocol++) | |
507 | for (level = 0; level < ISIS_LEVELS; level++) { | |
508 | for (type = 0; type < ZEBRA_ROUTE_MAX + 1; type++) { | |
509 | struct isis_redist *redist; | |
510 | ||
511 | redist = &area->redist_settings[protocol][type] | |
512 | [level]; | |
513 | redist->redist = 0; | |
66b9a381 | 514 | XFREE(MTYPE_ISIS_RMAP_NAME, redist->map_name); |
d62a17ae | 515 | } |
46c9042f IR |
516 | if (!area->ext_reach[protocol][level]) |
517 | continue; | |
518 | for (rn = route_top(area->ext_reach[protocol][level]); | |
519 | rn; rn = srcdest_route_next(rn)) { | |
520 | if (rn->info) | |
521 | XFREE(MTYPE_ISIS_EXT_INFO, rn->info); | |
522 | } | |
d62a17ae | 523 | route_table_finish(area->ext_reach[protocol][level]); |
46c9042f | 524 | area->ext_reach[protocol][level] = NULL; |
d62a17ae | 525 | } |
526 | ||
527 | isis_redist_update_zebra_subscriptions(area->isis); | |
f3ccedaa CF |
528 | } |
529 | ||
a041ac8e | 530 | #ifdef FABRICD |
49d41a26 DS |
531 | DEFUN (isis_redistribute, |
532 | isis_redistribute_cmd, | |
1bfee936 | 533 | "redistribute <ipv4 " PROTO_IP_REDIST_STR "|ipv6 " PROTO_IP6_REDIST_STR ">" |
70dd370f | 534 | " [{metric (0-16777215)|route-map RMAP_NAME}]", |
49d41a26 DS |
535 | REDIST_STR |
536 | "Redistribute IPv4 routes\n" | |
1bfee936 | 537 | PROTO_IP_REDIST_HELP |
49d41a26 | 538 | "Redistribute IPv6 routes\n" |
1bfee936 | 539 | PROTO_IP6_REDIST_HELP |
49d41a26 DS |
540 | "Metric for redistributed routes\n" |
541 | "ISIS default metric\n" | |
542 | "Route map reference\n" | |
543 | "Pointer to route-map entries\n") | |
f3ccedaa | 544 | { |
d62a17ae | 545 | int idx_afi = 1; |
546 | int idx_protocol = 2; | |
ee22b196 | 547 | int idx_metric_rmap = 1; |
d62a17ae | 548 | VTY_DECLVAR_CONTEXT(isis_area, area); |
549 | int family; | |
550 | int afi; | |
551 | int type; | |
552 | int level; | |
8cfc8c5c | 553 | unsigned long metric = 0; |
d62a17ae | 554 | const char *routemap = NULL; |
555 | ||
556 | family = str2family(argv[idx_afi]->text); | |
557 | if (family < 0) | |
558 | return CMD_WARNING_CONFIG_FAILED; | |
559 | ||
560 | afi = family2afi(family); | |
561 | if (!afi) | |
562 | return CMD_WARNING_CONFIG_FAILED; | |
563 | ||
564 | type = proto_redistnum(afi, argv[idx_protocol]->text); | |
565 | if (type < 0) | |
566 | return CMD_WARNING_CONFIG_FAILED; | |
567 | ||
a041ac8e | 568 | level = 2; |
d62a17ae | 569 | |
570 | if ((area->is_type & level) != level) { | |
571 | vty_out(vty, "Node is not a level-%d IS\n", level); | |
572 | return CMD_WARNING_CONFIG_FAILED; | |
573 | } | |
574 | ||
ee22b196 DT |
575 | if (argv_find(argv, argc, "metric", &idx_metric_rmap)) { |
576 | metric = strtoul(argv[idx_metric_rmap + 1]->arg, NULL, 10); | |
577 | } | |
d62a17ae | 578 | |
ee22b196 DT |
579 | idx_metric_rmap = 1; |
580 | if (argv_find(argv, argc, "route-map", &idx_metric_rmap)) { | |
581 | routemap = argv[idx_metric_rmap + 1]->arg; | |
d62a17ae | 582 | } |
583 | ||
584 | isis_redist_set(area, level, family, type, metric, routemap, 0); | |
585 | return 0; | |
f3ccedaa CF |
586 | } |
587 | ||
49d41a26 DS |
588 | DEFUN (no_isis_redistribute, |
589 | no_isis_redistribute_cmd, | |
1bfee936 | 590 | "no redistribute <ipv4 " PROTO_IP_REDIST_STR "|ipv6 " PROTO_IP6_REDIST_STR ">", |
a041ac8e | 591 | NO_STR |
49d41a26 DS |
592 | REDIST_STR |
593 | "Redistribute IPv4 routes\n" | |
1bfee936 | 594 | PROTO_IP_REDIST_HELP |
49d41a26 | 595 | "Redistribute IPv6 routes\n" |
1bfee936 | 596 | PROTO_IP6_REDIST_HELP) |
f3ccedaa | 597 | { |
d62a17ae | 598 | int idx_afi = 2; |
599 | int idx_protocol = 3; | |
d62a17ae | 600 | VTY_DECLVAR_CONTEXT(isis_area, area); |
601 | int type; | |
602 | int level; | |
603 | int family; | |
604 | int afi; | |
605 | ||
606 | family = str2family(argv[idx_afi]->arg); | |
607 | if (family < 0) | |
608 | return CMD_WARNING_CONFIG_FAILED; | |
609 | ||
610 | afi = family2afi(family); | |
611 | if (!afi) | |
612 | return CMD_WARNING_CONFIG_FAILED; | |
613 | ||
614 | type = proto_redistnum(afi, argv[idx_protocol]->text); | |
615 | if (type < 0) | |
616 | return CMD_WARNING_CONFIG_FAILED; | |
617 | ||
a041ac8e | 618 | level = 2; |
d62a17ae | 619 | |
620 | isis_redist_unset(area, level, family, type); | |
621 | return 0; | |
f3ccedaa CF |
622 | } |
623 | ||
49d41a26 DS |
624 | DEFUN (isis_default_originate, |
625 | isis_default_originate_cmd, | |
70dd370f | 626 | "default-information originate <ipv4|ipv6> [always] [{metric (0-16777215)|route-map RMAP_NAME}]", |
49d41a26 DS |
627 | "Control distribution of default information\n" |
628 | "Distribute a default route\n" | |
629 | "Distribute default route for IPv4\n" | |
630 | "Distribute default route for IPv6\n" | |
49d41a26 DS |
631 | "Always advertise default route\n" |
632 | "Metric for default route\n" | |
633 | "ISIS default metric\n" | |
634 | "Route map reference\n" | |
635 | "Pointer to route-map entries\n") | |
f3ccedaa | 636 | { |
d62a17ae | 637 | int idx_afi = 2; |
ef020087 | 638 | int idx_always = fabricd ? 3 : 4; |
ee22b196 | 639 | int idx_metric_rmap = 1; |
d62a17ae | 640 | VTY_DECLVAR_CONTEXT(isis_area, area); |
641 | int family; | |
642 | int originate_type = DEFAULT_ORIGINATE; | |
643 | int level; | |
8cfc8c5c | 644 | unsigned long metric = 0; |
d62a17ae | 645 | const char *routemap = NULL; |
646 | ||
647 | family = str2family(argv[idx_afi]->text); | |
648 | if (family < 0) | |
649 | return CMD_WARNING_CONFIG_FAILED; | |
650 | ||
8b104c10 | 651 | level = 2; |
d62a17ae | 652 | |
653 | if ((area->is_type & level) != level) { | |
654 | vty_out(vty, "Node is not a level-%d IS\n", level); | |
655 | return CMD_WARNING_CONFIG_FAILED; | |
656 | } | |
657 | ||
658 | if (argc > idx_always && strmatch(argv[idx_always]->text, "always")) { | |
659 | originate_type = DEFAULT_ORIGINATE_ALWAYS; | |
660 | idx_metric_rmap++; | |
661 | } | |
662 | ||
ee22b196 DT |
663 | if (argv_find(argv, argc, "metric", &idx_metric_rmap)) { |
664 | metric = strtoul(argv[idx_metric_rmap + 1]->arg, NULL, 10); | |
665 | } | |
666 | ||
667 | idx_metric_rmap = 1; | |
668 | if (argv_find(argv, argc, "route-map", &idx_metric_rmap)) { | |
669 | routemap = argv[idx_metric_rmap + 1]->arg; | |
d62a17ae | 670 | } |
671 | ||
672 | if (family == AF_INET6 && originate_type != DEFAULT_ORIGINATE_ALWAYS) { | |
673 | vty_out(vty, | |
674 | "Zebra doesn't implement default-originate for IPv6 yet\n"); | |
675 | vty_out(vty, | |
676 | "so use with care or use default-originate always.\n"); | |
677 | } | |
678 | ||
679 | isis_redist_set(area, level, family, DEFAULT_ROUTE, metric, routemap, | |
680 | originate_type); | |
681 | return 0; | |
f3ccedaa CF |
682 | } |
683 | ||
49d41a26 DS |
684 | DEFUN (no_isis_default_originate, |
685 | no_isis_default_originate_cmd, | |
8b104c10 EDP |
686 | "no default-information originate <ipv4|ipv6>", |
687 | NO_STR | |
49d41a26 DS |
688 | "Control distribution of default information\n" |
689 | "Distribute a default route\n" | |
690 | "Distribute default route for IPv4\n" | |
8b104c10 | 691 | "Distribute default route for IPv6\n") |
f3ccedaa | 692 | { |
d62a17ae | 693 | int idx_afi = 3; |
d62a17ae | 694 | VTY_DECLVAR_CONTEXT(isis_area, area); |
695 | int family; | |
696 | int level; | |
697 | ||
698 | family = str2family(argv[idx_afi]->text); | |
699 | if (family < 0) | |
700 | return CMD_WARNING_CONFIG_FAILED; | |
701 | ||
8b104c10 | 702 | level = 2; |
d62a17ae | 703 | |
704 | isis_redist_unset(area, level, family, DEFAULT_ROUTE); | |
705 | return 0; | |
f3ccedaa | 706 | } |
8b104c10 | 707 | #endif /* ifdef FABRICD */ |
f3ccedaa | 708 | |
d62a17ae | 709 | int isis_redist_config_write(struct vty *vty, struct isis_area *area, |
710 | int family) | |
f3ccedaa | 711 | { |
d62a17ae | 712 | int type; |
713 | int level; | |
714 | int write = 0; | |
715 | struct isis_redist *redist; | |
716 | const char *family_str; | |
717 | ||
718 | if (family == AF_INET) | |
719 | family_str = "ipv4"; | |
720 | else if (family == AF_INET6) | |
721 | family_str = "ipv6"; | |
722 | else | |
723 | return 0; | |
724 | ||
725 | for (type = 0; type < ZEBRA_ROUTE_MAX; type++) { | |
7c0cbd0e | 726 | if (type == PROTO_TYPE) |
d62a17ae | 727 | continue; |
728 | ||
729 | for (level = 1; level <= ISIS_LEVELS; level++) { | |
730 | redist = get_redist_settings(area, family, type, level); | |
731 | if (!redist->redist) | |
732 | continue; | |
ef020087 CF |
733 | vty_out(vty, " redistribute %s %s", family_str, |
734 | zebra_route_string(type)); | |
735 | if (!fabricd) | |
736 | vty_out(vty, " level-%d", level); | |
8cfc8c5c | 737 | if (redist->metric) |
d62a17ae | 738 | vty_out(vty, " metric %u", redist->metric); |
739 | if (redist->map_name) | |
740 | vty_out(vty, " route-map %s", redist->map_name); | |
741 | vty_out(vty, "\n"); | |
742 | write++; | |
743 | } | |
744 | } | |
745 | ||
746 | for (level = 1; level <= ISIS_LEVELS; level++) { | |
747 | redist = | |
748 | get_redist_settings(area, family, DEFAULT_ROUTE, level); | |
749 | if (!redist->redist) | |
750 | continue; | |
ef020087 CF |
751 | vty_out(vty, " default-information originate %s", |
752 | family_str); | |
753 | if (!fabricd) | |
754 | vty_out(vty, " level-%d", level); | |
d62a17ae | 755 | if (redist->redist == DEFAULT_ORIGINATE_ALWAYS) |
756 | vty_out(vty, " always"); | |
8cfc8c5c | 757 | if (redist->metric) |
d62a17ae | 758 | vty_out(vty, " metric %u", redist->metric); |
759 | if (redist->map_name) | |
760 | vty_out(vty, " route-map %s", redist->map_name); | |
761 | vty_out(vty, "\n"); | |
762 | write++; | |
763 | } | |
764 | ||
765 | return write; | |
f3ccedaa CF |
766 | } |
767 | ||
d62a17ae | 768 | void isis_redist_init(void) |
f3ccedaa | 769 | { |
a041ac8e | 770 | #ifdef FABRICD |
7c0cbd0e CF |
771 | install_element(ROUTER_NODE, &isis_redistribute_cmd); |
772 | install_element(ROUTER_NODE, &no_isis_redistribute_cmd); | |
a041ac8e | 773 | |
7c0cbd0e CF |
774 | install_element(ROUTER_NODE, &isis_default_originate_cmd); |
775 | install_element(ROUTER_NODE, &no_isis_default_originate_cmd); | |
8b104c10 | 776 | #endif /* ifdef FABRICD */ |
f3ccedaa | 777 | } |