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