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