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