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