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