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