]> git.proxmox.com Git - mirror_frr.git/blob - isisd/isis_redist.c
Merge pull request #4096 from donaldsharp/pim_nht_cleanup
[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/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"
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 redist_protocol(int family)
47 {
48 if (family == AF_INET)
49 return 0;
50 if (family == AF_INET6)
51 return 1;
52
53 assert(!"Unsupported address family!");
54 return 0;
55 }
56
57 static afi_t afi_for_redist_protocol(int protocol)
58 {
59 if (protocol == 0)
60 return AFI_IP;
61 if (protocol == 1)
62 return AFI_IP6;
63
64 assert(!"Unknown redist protocol!");
65 return AFI_IP;
66 }
67
68 static struct route_table *get_ext_info(struct isis *i, int family)
69 {
70 int protocol = redist_protocol(family);
71
72 return i->ext_info[protocol];
73 }
74
75 static struct isis_redist *get_redist_settings(struct isis_area *area,
76 int family, int type, int level)
77 {
78 int protocol = redist_protocol(family);
79
80 return &area->redist_settings[protocol][type][level - 1];
81 }
82
83 struct route_table *get_ext_reach(struct isis_area *area, int family, int level)
84 {
85 int protocol = redist_protocol(family);
86
87 return area->ext_reach[protocol][level - 1];
88 }
89
90 /* Install external reachability information into a
91 * specific area for a specific level.
92 * Schedule an lsp regenerate if necessary */
93 static void isis_redist_install(struct isis_area *area, int level,
94 const struct prefix *p,
95 const struct prefix_ipv6 *src_p,
96 struct isis_ext_info *info)
97 {
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
110 er_node = srcdest_rnode_get(er_table, p, src_p);
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);
123 }
124
125 /* Remove external reachability information from a
126 * specific area for a specific level.
127 * Schedule an lsp regenerate if necessary. */
128 static void isis_redist_uninstall(struct isis_area *area, int level,
129 const struct prefix *p,
130 const struct prefix_ipv6 *src_p)
131 {
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
144 er_node = srcdest_rnode_lookup(er_table, p, src_p);
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);
156 }
157
158 /* Update external reachability info of area for a given level
159 * and prefix, using the given redistribution settings. */
160 static void isis_redist_update_ext_reach(struct isis_area *area, int level,
161 struct isis_redist *redist,
162 const struct prefix *p,
163 const struct prefix_ipv6 *src_p,
164 struct isis_ext_info *info)
165 {
166 struct isis_ext_info area_info;
167 route_map_result_t map_ret;
168
169 memcpy(&area_info, info, sizeof(area_info));
170 area_info.metric = redist->metric;
171
172 if (redist->map_name) {
173 map_ret =
174 route_map_apply(redist->map, p, RMAP_ISIS, &area_info);
175 if (map_ret == RMAP_DENYMATCH)
176 area_info.distance = 255;
177 }
178
179 /* Allow synthesized default routes only on always orignate */
180 if (area_info.origin == DEFAULT_ROUTE
181 && redist->redist != DEFAULT_ORIGINATE_ALWAYS)
182 area_info.distance = 255;
183
184 if (area_info.distance < 255)
185 isis_redist_install(area, level, p, src_p, &area_info);
186 else
187 isis_redist_uninstall(area, level, p, src_p);
188 }
189
190 static void isis_redist_ensure_default(struct isis *isis, int family)
191 {
192 struct prefix p;
193 struct route_table *ei_table = get_ext_info(isis, family);
194 struct route_node *ei_node;
195 struct isis_ext_info *info;
196
197 if (family == AF_INET) {
198 p.family = AF_INET;
199 p.prefixlen = 0;
200 memset(&p.u.prefix4, 0, sizeof(p.u.prefix4));
201 } else if (family == AF_INET6) {
202 p.family = AF_INET6;
203 p.prefixlen = 0;
204 memset(&p.u.prefix6, 0, sizeof(p.u.prefix6));
205 } else
206 assert(!"Unknown family!");
207
208 ei_node = srcdest_rnode_get(ei_table, &p, NULL);
209 if (ei_node->info) {
210 route_unlock_node(ei_node);
211 return;
212 }
213
214 ei_node->info =
215 XCALLOC(MTYPE_ISIS_EXT_INFO, sizeof(struct isis_ext_info));
216
217 info = ei_node->info;
218 info->origin = DEFAULT_ROUTE;
219 info->distance = 254;
220 info->metric = MAX_WIDE_PATH_METRIC;
221 }
222
223 /* Handle notification about route being added */
224 void isis_redist_add(int type, struct prefix *p, struct prefix_ipv6 *src_p,
225 uint8_t distance, uint32_t metric)
226 {
227 int family = p->family;
228 struct route_table *ei_table = get_ext_info(isis, family);
229 struct route_node *ei_node;
230 struct isis_ext_info *info;
231 struct listnode *node;
232 struct isis_area *area;
233 int level;
234 struct isis_redist *redist;
235
236 char debug_buf[BUFSIZ];
237 prefix2str(p, debug_buf, sizeof(debug_buf));
238
239 zlog_debug("%s: New route %s from %s: distance %d.", __func__,
240 debug_buf, zebra_route_string(type), distance);
241
242 if (!ei_table) {
243 zlog_warn("%s: External information table not initialized.",
244 __func__);
245 return;
246 }
247
248 ei_node = srcdest_rnode_get(ei_table, p, src_p);
249 if (ei_node->info)
250 route_unlock_node(ei_node);
251 else
252 ei_node->info = XCALLOC(MTYPE_ISIS_EXT_INFO,
253 sizeof(struct isis_ext_info));
254
255 info = ei_node->info;
256 info->origin = type;
257 info->distance = distance;
258 info->metric = metric;
259
260 if (is_default_prefix(p)
261 && (!src_p || !src_p->prefixlen)) {
262 type = DEFAULT_ROUTE;
263 }
264
265 for (ALL_LIST_ELEMENTS_RO(isis->area_list, node, area))
266 for (level = 1; level <= ISIS_LEVELS; level++) {
267 redist = get_redist_settings(area, family, type, level);
268 if (!redist->redist)
269 continue;
270
271 isis_redist_update_ext_reach(area, level, redist, p,
272 src_p, info);
273 }
274 }
275
276 void isis_redist_delete(int type, struct prefix *p, struct prefix_ipv6 *src_p)
277 {
278 int family = p->family;
279 struct route_table *ei_table = get_ext_info(isis, family);
280 struct route_node *ei_node;
281 struct listnode *node;
282 struct isis_area *area;
283 int level;
284 struct isis_redist *redist;
285
286 char debug_buf[BUFSIZ];
287 prefix2str(p, debug_buf, sizeof(debug_buf));
288
289 zlog_debug("%s: Removing route %s from %s.", __func__, debug_buf,
290 zebra_route_string(type));
291
292 if (is_default_prefix(p)
293 && (!src_p || !src_p->prefixlen)) {
294 /* Don't remove default route but add synthetic route for use
295 * by "default-information originate always". Areas without the
296 * "always" setting will ignore routes with origin
297 * DEFAULT_ROUTE. */
298 isis_redist_add(DEFAULT_ROUTE, p, NULL,
299 254, MAX_WIDE_PATH_METRIC);
300 return;
301 }
302
303 if (!ei_table) {
304 zlog_warn("%s: External information table not initialized.",
305 __func__);
306 return;
307 }
308
309 ei_node = srcdest_rnode_lookup(ei_table, p, src_p);
310 if (!ei_node || !ei_node->info) {
311 char buf[BUFSIZ];
312 prefix2str(p, buf, sizeof(buf));
313 zlog_warn(
314 "%s: Got a delete for %s route %s, but that route"
315 " was never added.",
316 __func__, zebra_route_string(type), buf);
317 if (ei_node)
318 route_unlock_node(ei_node);
319 return;
320 }
321 route_unlock_node(ei_node);
322
323 for (ALL_LIST_ELEMENTS_RO(isis->area_list, node, area))
324 for (level = ISIS_LEVEL1; level <= ISIS_LEVEL2; level++) {
325 redist = get_redist_settings(area, family, type, level);
326 if (!redist->redist)
327 continue;
328
329 isis_redist_uninstall(area, level, p, src_p);
330 }
331
332 XFREE(MTYPE_ISIS_EXT_INFO, ei_node->info);
333 route_unlock_node(ei_node);
334 }
335
336 static void isis_redist_routemap_set(struct isis_redist *redist,
337 const char *routemap)
338 {
339 if (redist->map_name) {
340 XFREE(MTYPE_ISIS, redist->map_name);
341 route_map_counter_decrement(redist->map);
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 route_map_counter_increment(redist->map);
349 }
350 }
351
352 static void isis_redist_update_zebra_subscriptions(struct isis *isis)
353 {
354 struct listnode *node;
355 struct isis_area *area;
356 int type;
357 int level;
358 int protocol;
359
360 char do_subscribe[REDIST_PROTOCOL_COUNT][ZEBRA_ROUTE_MAX + 1];
361
362 memset(do_subscribe, 0, sizeof(do_subscribe));
363
364 for (ALL_LIST_ELEMENTS_RO(isis->area_list, node, area))
365 for (protocol = 0; protocol < REDIST_PROTOCOL_COUNT; protocol++)
366 for (type = 0; type < ZEBRA_ROUTE_MAX + 1; type++)
367 for (level = 0; level < ISIS_LEVELS; level++)
368 if (area->redist_settings[protocol]
369 [type]
370 [level].redist)
371 do_subscribe[protocol][type] =
372 1;
373
374 for (protocol = 0; protocol < REDIST_PROTOCOL_COUNT; protocol++)
375 for (type = 0; type < ZEBRA_ROUTE_MAX + 1; type++) {
376 /* This field is actually controlling transmission of
377 * the IS-IS
378 * routes to Zebra and has nothing to do with
379 * redistribution,
380 * so skip it. */
381 if (type == PROTO_TYPE)
382 continue;
383
384 afi_t afi = afi_for_redist_protocol(protocol);
385
386 if (do_subscribe[protocol][type])
387 isis_zebra_redistribute_set(afi, type);
388 else
389 isis_zebra_redistribute_unset(afi, type);
390 }
391 }
392
393 void isis_redist_set(struct isis_area *area, int level, int family, int type,
394 uint32_t metric, const char *routemap, int originate_type)
395 {
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]) {
409 area->ext_reach[protocol][level - 1] = srcdest_table_init();
410 }
411
412 for (i = 0; i < REDIST_PROTOCOL_COUNT; i++) {
413 if (!area->isis->ext_info[i]) {
414 area->isis->ext_info[i] = srcdest_table_init();
415 }
416 }
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);
424 for (rn = route_top(ei_table); rn; rn = srcdest_route_next(rn)) {
425 if (!rn->info)
426 continue;
427 info = rn->info;
428
429 const struct prefix *p, *src_p;
430
431 srcdest_rnode_prefixes(rn, &p, &src_p);
432
433 if (type == DEFAULT_ROUTE) {
434 if (!is_default_prefix(p)
435 || (src_p && src_p->prefixlen)) {
436 continue;
437 }
438 } else {
439 if (info->origin != type)
440 continue;
441 }
442
443 isis_redist_update_ext_reach(area, level, redist, p,
444 (const struct prefix_ipv6 *)src_p,
445 info);
446 }
447 }
448
449 void isis_redist_unset(struct isis_area *area, int level, int family, int type)
450 {
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
467 for (rn = route_top(er_table); rn; rn = srcdest_route_next(rn)) {
468 if (!rn->info)
469 continue;
470 info = rn->info;
471
472 const struct prefix *p, *src_p;
473 srcdest_rnode_prefixes(rn, &p, &src_p);
474
475 if (type == DEFAULT_ROUTE) {
476 if (!is_default_prefix(p)
477 || (src_p && src_p->prefixlen)) {
478 continue;
479 }
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);
491 }
492
493 void isis_redist_area_finish(struct isis_area *area)
494 {
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 XFREE(MTYPE_ISIS, redist->map_name);
508 }
509 route_table_finish(area->ext_reach[protocol][level]);
510 }
511
512 isis_redist_update_zebra_subscriptions(area->isis);
513 }
514
515 #ifdef FABRICD
516 DEFUN (isis_redistribute,
517 isis_redistribute_cmd,
518 "redistribute <ipv4|ipv6> " PROTO_REDIST_STR
519 " [{metric (0-16777215)|route-map WORD}]",
520 REDIST_STR
521 "Redistribute IPv4 routes\n"
522 "Redistribute IPv6 routes\n"
523 PROTO_REDIST_HELP
524 "Metric for redistributed routes\n"
525 "ISIS default metric\n"
526 "Route map reference\n"
527 "Pointer to route-map entries\n")
528 {
529 int idx_afi = 1;
530 int idx_protocol = 2;
531 int idx_metric_rmap = 1;
532 VTY_DECLVAR_CONTEXT(isis_area, area);
533 int family;
534 int afi;
535 int type;
536 int level;
537 unsigned long metric = 0;
538 const char *routemap = NULL;
539
540 family = str2family(argv[idx_afi]->text);
541 if (family < 0)
542 return CMD_WARNING_CONFIG_FAILED;
543
544 afi = family2afi(family);
545 if (!afi)
546 return CMD_WARNING_CONFIG_FAILED;
547
548 type = proto_redistnum(afi, argv[idx_protocol]->text);
549 if (type < 0)
550 return CMD_WARNING_CONFIG_FAILED;
551
552 level = 2;
553
554 if ((area->is_type & level) != level) {
555 vty_out(vty, "Node is not a level-%d IS\n", level);
556 return CMD_WARNING_CONFIG_FAILED;
557 }
558
559 if (argv_find(argv, argc, "metric", &idx_metric_rmap)) {
560 metric = strtoul(argv[idx_metric_rmap + 1]->arg, NULL, 10);
561 }
562
563 idx_metric_rmap = 1;
564 if (argv_find(argv, argc, "route-map", &idx_metric_rmap)) {
565 routemap = argv[idx_metric_rmap + 1]->arg;
566 }
567
568 isis_redist_set(area, level, family, type, metric, routemap, 0);
569 return 0;
570 }
571
572 DEFUN (no_isis_redistribute,
573 no_isis_redistribute_cmd,
574 "no redistribute <ipv4|ipv6> " PROTO_REDIST_STR,
575 NO_STR
576 REDIST_STR
577 "Redistribute IPv4 routes\n"
578 "Redistribute IPv6 routes\n"
579 PROTO_REDIST_HELP)
580 {
581 int idx_afi = 2;
582 int idx_protocol = 3;
583 VTY_DECLVAR_CONTEXT(isis_area, area);
584 int type;
585 int level;
586 int family;
587 int afi;
588
589 family = str2family(argv[idx_afi]->arg);
590 if (family < 0)
591 return CMD_WARNING_CONFIG_FAILED;
592
593 afi = family2afi(family);
594 if (!afi)
595 return CMD_WARNING_CONFIG_FAILED;
596
597 type = proto_redistnum(afi, argv[idx_protocol]->text);
598 if (type < 0)
599 return CMD_WARNING_CONFIG_FAILED;
600
601 level = 2;
602
603 isis_redist_unset(area, level, family, type);
604 return 0;
605 }
606
607 DEFUN (isis_default_originate,
608 isis_default_originate_cmd,
609 "default-information originate <ipv4|ipv6>"
610 " [always] [{metric (0-16777215)|route-map WORD}]",
611 "Control distribution of default information\n"
612 "Distribute a default route\n"
613 "Distribute default route for IPv4\n"
614 "Distribute default route for IPv6\n"
615 "Always advertise default route\n"
616 "Metric for default route\n"
617 "ISIS default metric\n"
618 "Route map reference\n"
619 "Pointer to route-map entries\n")
620 {
621 int idx_afi = 2;
622 int idx_always = fabricd ? 3 : 4;
623 int idx_metric_rmap = 1;
624 VTY_DECLVAR_CONTEXT(isis_area, area);
625 int family;
626 int originate_type = DEFAULT_ORIGINATE;
627 int level;
628 unsigned long metric = 0;
629 const char *routemap = NULL;
630
631 family = str2family(argv[idx_afi]->text);
632 if (family < 0)
633 return CMD_WARNING_CONFIG_FAILED;
634
635 level = 2;
636
637 if ((area->is_type & level) != level) {
638 vty_out(vty, "Node is not a level-%d IS\n", level);
639 return CMD_WARNING_CONFIG_FAILED;
640 }
641
642 if (argc > idx_always && strmatch(argv[idx_always]->text, "always")) {
643 originate_type = DEFAULT_ORIGINATE_ALWAYS;
644 idx_metric_rmap++;
645 }
646
647 if (argv_find(argv, argc, "metric", &idx_metric_rmap)) {
648 metric = strtoul(argv[idx_metric_rmap + 1]->arg, NULL, 10);
649 }
650
651 idx_metric_rmap = 1;
652 if (argv_find(argv, argc, "route-map", &idx_metric_rmap)) {
653 routemap = argv[idx_metric_rmap + 1]->arg;
654 }
655
656 if (family == AF_INET6 && originate_type != DEFAULT_ORIGINATE_ALWAYS) {
657 vty_out(vty,
658 "Zebra doesn't implement default-originate for IPv6 yet\n");
659 vty_out(vty,
660 "so use with care or use default-originate always.\n");
661 }
662
663 isis_redist_set(area, level, family, DEFAULT_ROUTE, metric, routemap,
664 originate_type);
665 return 0;
666 }
667
668 DEFUN (no_isis_default_originate,
669 no_isis_default_originate_cmd,
670 "no default-information originate <ipv4|ipv6>",
671 NO_STR
672 "Control distribution of default information\n"
673 "Distribute a default route\n"
674 "Distribute default route for IPv4\n"
675 "Distribute default route for IPv6\n")
676 {
677 int idx_afi = 3;
678 VTY_DECLVAR_CONTEXT(isis_area, area);
679 int family;
680 int level;
681
682 family = str2family(argv[idx_afi]->text);
683 if (family < 0)
684 return CMD_WARNING_CONFIG_FAILED;
685
686 level = 2;
687
688 isis_redist_unset(area, level, family, DEFAULT_ROUTE);
689 return 0;
690 }
691 #endif /* ifdef FABRICD */
692
693 int isis_redist_config_write(struct vty *vty, struct isis_area *area,
694 int family)
695 {
696 int type;
697 int level;
698 int write = 0;
699 struct isis_redist *redist;
700 const char *family_str;
701
702 if (family == AF_INET)
703 family_str = "ipv4";
704 else if (family == AF_INET6)
705 family_str = "ipv6";
706 else
707 return 0;
708
709 for (type = 0; type < ZEBRA_ROUTE_MAX; type++) {
710 if (type == PROTO_TYPE)
711 continue;
712
713 for (level = 1; level <= ISIS_LEVELS; level++) {
714 redist = get_redist_settings(area, family, type, level);
715 if (!redist->redist)
716 continue;
717 vty_out(vty, " redistribute %s %s", family_str,
718 zebra_route_string(type));
719 if (!fabricd)
720 vty_out(vty, " level-%d", level);
721 if (redist->metric)
722 vty_out(vty, " metric %u", redist->metric);
723 if (redist->map_name)
724 vty_out(vty, " route-map %s", redist->map_name);
725 vty_out(vty, "\n");
726 write++;
727 }
728 }
729
730 for (level = 1; level <= ISIS_LEVELS; level++) {
731 redist =
732 get_redist_settings(area, family, DEFAULT_ROUTE, level);
733 if (!redist->redist)
734 continue;
735 vty_out(vty, " default-information originate %s",
736 family_str);
737 if (!fabricd)
738 vty_out(vty, " level-%d", level);
739 if (redist->redist == DEFAULT_ORIGINATE_ALWAYS)
740 vty_out(vty, " always");
741 if (redist->metric)
742 vty_out(vty, " metric %u", redist->metric);
743 if (redist->map_name)
744 vty_out(vty, " route-map %s", redist->map_name);
745 vty_out(vty, "\n");
746 write++;
747 }
748
749 return write;
750 }
751
752 void isis_redist_init(void)
753 {
754 #ifdef FABRICD
755 install_element(ROUTER_NODE, &isis_redistribute_cmd);
756 install_element(ROUTER_NODE, &no_isis_redistribute_cmd);
757
758 install_element(ROUTER_NODE, &isis_default_originate_cmd);
759 install_element(ROUTER_NODE, &no_isis_default_originate_cmd);
760 #endif /* ifdef FABRICD */
761 }