summaryrefslogtreecommitdiff
path: root/isisd/isis_redist.c
diff options
context:
space:
mode:
Diffstat (limited to 'isisd/isis_redist.c')
-rw-r--r--isisd/isis_redist.c815
1 files changed, 815 insertions, 0 deletions
diff --git a/isisd/isis_redist.c b/isisd/isis_redist.c
new file mode 100644
index 00000000..f0ad6941
--- /dev/null
+++ b/isisd/isis_redist.c
@@ -0,0 +1,815 @@
+/*
+ * IS-IS Rout(e)ing protocol - isis_redist.c
+ *
+ * Copyright (C) 2013 Christian Franke
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <zebra.h>
+
+#include "command.h"
+#include "if.h"
+#include "linklist.h"
+#include "memory.h"
+#include "memtypes.h"
+#include "prefix.h"
+#include "routemap.h"
+#include "stream.h"
+#include "table.h"
+#include "vty.h"
+
+#include "isisd/dict.h"
+#include "isisd/isis_constants.h"
+#include "isisd/isis_common.h"
+#include "isisd/isis_flags.h"
+#include "isisd/isis_misc.h"
+#include "isisd/isis_circuit.h"
+#include "isisd/isis_tlv.h"
+#include "isisd/isisd.h"
+#include "isisd/isis_lsp.h"
+#include "isisd/isis_route.h"
+#include "isisd/isis_zebra.h"
+
+static int
+redist_protocol(int family)
+{
+ if (family == AF_INET)
+ return 0;
+#ifdef HAVE_IPV6
+ if (family == AF_INET6)
+ return 1;
+#endif
+
+ assert(!"Unsupported address family!");
+}
+
+static int
+is_default(struct prefix *p)
+{
+ if (p->family == AF_INET)
+ if (p->u.prefix4.s_addr == 0 && p->prefixlen == 0)
+ return 1;
+#ifdef HAVE_IPV6
+ if (p->family == AF_INET6)
+ if (IN6_IS_ADDR_UNSPECIFIED(&p->u.prefix6) && p->prefixlen == 0)
+ return 1;
+#endif
+ return 0;
+}
+
+static int
+str2family(const char *string)
+{
+ if (!strcmp("ipv4", string))
+ return AF_INET;
+#ifdef HAVE_IPV6
+ else if (!strcmp("ipv6", string))
+ return AF_INET6;
+#endif
+ else
+ return -1;
+}
+
+static struct route_table*
+get_ext_info(struct isis *i, int family)
+{
+ int protocol = redist_protocol(family);
+
+ return i->ext_info[protocol];
+}
+
+static struct isis_redist*
+get_redist_settings(struct isis_area *area, int family, int type, int level)
+{
+ int protocol = redist_protocol(family);
+
+ return &area->redist_settings[protocol][type][level-1];
+}
+
+struct route_table*
+get_ext_reach(struct isis_area *area, int family, int level)
+{
+ int protocol = redist_protocol(family);
+
+ return area->ext_reach[protocol][level-1];
+}
+
+/* Install external reachability information into a
+ * specific area for a specific level.
+ * Schedule an lsp regenerate if necessary */
+static void
+isis_redist_install(struct isis_area *area, int level,
+ struct prefix *p, struct isis_ext_info *info)
+{
+ int family = p->family;
+ struct route_table *er_table = get_ext_reach(area, family, level);
+ struct route_node *er_node;
+
+ if (!er_table)
+ {
+ zlog_warn("%s: External reachability table of area %s"
+ " is not initialized.", __func__, area->area_tag);
+ return;
+ }
+
+ er_node = route_node_get(er_table, p);
+ if (er_node->info)
+ {
+ route_unlock_node(er_node);
+
+ /* Don't update/reschedule lsp generation if nothing changed. */
+ if (!memcmp(er_node->info, info, sizeof(*info)))
+ return;
+ }
+ else
+ {
+ er_node->info = XMALLOC(MTYPE_ISIS, sizeof(*info));
+ }
+
+ memcpy(er_node->info, info, sizeof(*info));
+ lsp_regenerate_schedule(area, level, 0);
+}
+
+/* Remove external reachability information from a
+ * specific area for a specific level.
+ * Schedule an lsp regenerate if necessary. */
+static void
+isis_redist_uninstall(struct isis_area *area, int level, struct prefix *p)
+{
+ int family = p->family;
+ struct route_table *er_table = get_ext_reach(area, family, level);
+ struct route_node *er_node;
+
+ if (!er_table)
+ {
+ zlog_warn("%s: External reachability table of area %s"
+ " is not initialized.", __func__, area->area_tag);
+ return;
+ }
+
+ er_node = route_node_lookup(er_table, p);
+ if (!er_node)
+ return;
+ else
+ route_unlock_node(er_node);
+
+ if (!er_node->info)
+ return;
+
+ XFREE(MTYPE_ISIS, er_node->info);
+ route_unlock_node(er_node);
+ lsp_regenerate_schedule(area, level, 0);
+}
+
+/* Update external reachability info of area for a given level
+ * and prefix, using the given redistribution settings. */
+static void
+isis_redist_update_ext_reach(struct isis_area *area, int level,
+ struct isis_redist *redist, struct prefix *p,
+ struct isis_ext_info *info)
+{
+ struct isis_ext_info area_info;
+ route_map_result_t map_ret;
+
+ memcpy(&area_info, info, sizeof(area_info));
+ if (redist->metric != 0xffffffff)
+ area_info.metric = redist->metric;
+
+ if (redist->map_name)
+ {
+ map_ret = route_map_apply(redist->map, p, RMAP_ISIS, &area_info);
+ if (map_ret == RMAP_DENYMATCH)
+ area_info.distance = 255;
+ }
+
+ /* Allow synthesized default routes only on always orignate */
+ if (area_info.origin == DEFAULT_ROUTE
+ && redist->redist != DEFAULT_ORIGINATE_ALWAYS)
+ area_info.distance = 255;
+
+ if (area_info.distance < 255)
+ isis_redist_install(area, level, p, &area_info);
+ else
+ isis_redist_uninstall(area, level, p);
+}
+
+static void
+isis_redist_ensure_default(struct isis *isis, int family)
+{
+ struct prefix p;
+ struct route_table *ei_table = get_ext_info(isis, family);
+ struct route_node *ei_node;
+ struct isis_ext_info *info;
+
+ if (family == AF_INET)
+ {
+ p.family = AF_INET;
+ p.prefixlen = 0;
+ memset(&p.u.prefix4, 0, sizeof(p.u.prefix4));
+ }
+#ifdef HAVE_IPV6
+ else if (family == AF_INET6)
+ {
+ p.family = AF_INET6;
+ p.prefixlen = 0;
+ memset(&p.u.prefix6, 0, sizeof(p.u.prefix6));
+ }
+#endif
+ else
+ assert(!"Unknown family!");
+
+ ei_node = route_node_get(ei_table, &p);
+ if (ei_node->info)
+ {
+ route_unlock_node(ei_node);
+ return;
+ }
+
+ ei_node->info = XCALLOC(MTYPE_ISIS, sizeof(struct isis_ext_info));
+
+ info = ei_node->info;
+ info->origin = DEFAULT_ROUTE;
+ info->distance = 254;
+ info->metric = MAX_WIDE_PATH_METRIC;
+}
+
+/* Handle notification about route being added */
+void
+isis_redist_add(int type, struct prefix *p, u_char distance, uint32_t metric)
+{
+ int family = p->family;
+ struct route_table *ei_table = get_ext_info(isis, family);
+ struct route_node *ei_node;
+ struct isis_ext_info *info;
+ struct listnode *node;
+ struct isis_area *area;
+ int level;
+ struct isis_redist *redist;
+
+#ifdef EXTREME_DEBUG
+ char debug_buf[BUFSIZ];
+ prefix2str(p, debug_buf, sizeof(debug_buf));
+
+ zlog_debug("%s: New route %s from %s.", __func__, debug_buf,
+ zebra_route_string(type));
+#endif
+
+ if (!ei_table)
+ {
+ zlog_warn("%s: External information table not initialized.",
+ __func__);
+ return;
+ }
+
+ ei_node = route_node_get(ei_table, p);
+ if (ei_node->info)
+ route_unlock_node(ei_node);
+ else
+ ei_node->info = XCALLOC(MTYPE_ISIS, sizeof(struct isis_ext_info));
+
+ info = ei_node->info;
+ info->origin = type;
+ info->distance = distance;
+ info->metric = metric;
+
+ if (is_default(p))
+ type = DEFAULT_ROUTE;
+
+ for (ALL_LIST_ELEMENTS_RO(isis->area_list, node, area))
+ for (level = 1; level <= ISIS_LEVELS; level++)
+ {
+ redist = get_redist_settings(area, family, type, level);
+ if (!redist->redist)
+ continue;
+
+ isis_redist_update_ext_reach(area, level, redist, p, info);
+ }
+}
+
+void
+isis_redist_delete(int type, struct prefix *p)
+{
+ int family = p->family;
+ struct route_table *ei_table = get_ext_info(isis, family);
+ struct route_node *ei_node;
+ struct listnode *node;
+ struct isis_area *area;
+ int level;
+ struct isis_redist *redist;
+
+#ifdef EXTREME_DEBUG
+ char debug_buf[BUFSIZ];
+ prefix2str(p, debug_buf, sizeof(debug_buf));
+
+ zlog_debug("%s: Removing route %s from %s.", __func__, debug_buf,
+ zebra_route_string(type));
+#endif
+
+ if (is_default(p))
+ {
+ /* Don't remove default route but add synthetic route for use
+ * by "default-information originate always". Areas without the
+ * "always" setting will ignore routes with origin DEFAULT_ROUTE. */
+ isis_redist_add(DEFAULT_ROUTE, p, 254, MAX_WIDE_PATH_METRIC);
+ return;
+ }
+
+ if (!ei_table)
+ {
+ zlog_warn("%s: External information table not initialized.",
+ __func__);
+ return;
+ }
+
+ ei_node = route_node_lookup(ei_table, p);
+ if (!ei_node || !ei_node->info)
+ {
+ char buf[BUFSIZ];
+ prefix2str(p, buf, sizeof(buf));
+ zlog_warn("%s: Got a delete for %s route %s, but that route"
+ " was never added.", __func__, zebra_route_string(type),
+ buf);
+ if (ei_node)
+ route_unlock_node(ei_node);
+ return;
+ }
+ route_unlock_node(ei_node);
+
+ for (ALL_LIST_ELEMENTS_RO(isis->area_list, node, area))
+ for (level = 1; level < ISIS_LEVELS; level++)
+ {
+ redist = get_redist_settings(area, family, type, level);
+ if (!redist->redist)
+ continue;
+
+ isis_redist_uninstall(area, level, p);
+ }
+
+ XFREE(MTYPE_ISIS, ei_node->info);
+ route_unlock_node(ei_node);
+}
+
+static void
+isis_redist_routemap_set(struct isis_redist *redist, const char *routemap)
+{
+ if (redist->map_name) {
+ XFREE(MTYPE_ISIS, redist->map_name);
+ redist->map = NULL;
+ }
+
+ if (routemap && strlen(routemap)) {
+ redist->map_name = XSTRDUP(MTYPE_ISIS, routemap);
+ redist->map = route_map_lookup_by_name(routemap);
+ }
+}
+
+static void
+isis_redist_set(struct isis_area *area, int level,
+ int family, int type, uint32_t metric,
+ const char *routemap, int originate_type)
+{
+ int protocol = redist_protocol(family);
+ struct isis_redist *redist = get_redist_settings(area, family, type, level);
+ int i;
+ struct route_table *ei_table;
+ struct route_node *rn;
+ struct isis_ext_info *info;
+
+ redist->redist = (type == DEFAULT_ROUTE) ? originate_type : 1;
+ redist->metric = metric;
+ isis_redist_routemap_set(redist, routemap);
+
+ if (!area->ext_reach[protocol][level-1])
+ area->ext_reach[protocol][level-1] = route_table_init();
+
+ for (i = 0; i < REDIST_PROTOCOL_COUNT; i++)
+ if (!area->isis->ext_info[i])
+ area->isis->ext_info[i] = route_table_init();
+
+ isis_zebra_redistribute_set(type);
+
+ if (type == DEFAULT_ROUTE && originate_type == DEFAULT_ORIGINATE_ALWAYS)
+ isis_redist_ensure_default(area->isis, family);
+
+ ei_table = get_ext_info(area->isis, family);
+ for (rn = route_top(ei_table); rn; rn = route_next(rn))
+ {
+ if (!rn->info)
+ continue;
+ info = rn->info;
+
+ if (type == DEFAULT_ROUTE)
+ {
+ if (!is_default(&rn->p))
+ continue;
+ }
+ else
+ {
+ if (info->origin != type)
+ continue;
+ }
+
+ isis_redist_update_ext_reach(area, level, redist, &rn->p, info);
+ }
+}
+
+static void
+isis_redist_unset(struct isis_area *area, int level,
+ int family, int type)
+{
+ struct isis_redist *redist = get_redist_settings(area, family, type, level);
+ struct route_table *er_table = get_ext_reach(area, family, level);
+ struct route_node *rn;
+ struct isis_ext_info *info;
+
+ if (!redist->redist)
+ return;
+
+ redist->redist = 0;
+ if (!er_table)
+ {
+ zlog_warn("%s: External reachability table uninitialized.", __func__);
+ return;
+ }
+
+ for (rn = route_top(er_table); rn; rn = route_next(rn))
+ {
+ if (!rn->info)
+ continue;
+ info = rn->info;
+
+ if (type == DEFAULT_ROUTE)
+ {
+ if (!is_default(&rn->p))
+ continue;
+ }
+ else
+ {
+ if (info->origin != type)
+ continue;
+ }
+
+ XFREE(MTYPE_ISIS, rn->info);
+ route_unlock_node(rn);
+ }
+
+ lsp_regenerate_schedule(area, level, 0);
+}
+
+DEFUN(isis_redistribute_ipv4,
+ isis_redistribute_ipv4_cmd,
+ "redistribute (ipv4|) " QUAGGA_REDIST_STR_ISISD
+ " (level-1|level-2) {metric <0-16777215>|route-map WORD}",
+ REDIST_STR
+ "Redistribute IPv4 routes\n"
+ "DUMMY\n"
+ QUAGGA_REDIST_HELP_STR_ISISD
+ "Redistribute into level-1\n"
+ "Redistribute into level-2\n"
+ "Metric for redistributed routes\n"
+ "ISIS default metric\n"
+ "Route map reference\n"
+ "Pointer to route-map entries\n")
+{
+ struct isis_area *area = vty->index;
+ int family;
+ int type;
+ int level;
+ unsigned long metric;
+ const char *routemap;
+
+ if (argc < 5)
+ return CMD_WARNING;
+
+ family = str2family(argv[0]);
+ if (family < 0)
+ return CMD_WARNING;
+
+ type = proto_redistnum(AFI_IP, argv[1]);
+ if (type < 0 || type == ZEBRA_ROUTE_ISIS)
+ return CMD_WARNING;
+
+ if (!strcmp("level-1", argv[2]))
+ level = 1;
+ else if (!strcmp("level-2", argv[2]))
+ level = 2;
+ else
+ return CMD_WARNING;
+
+ if ((area->is_type & level) != level)
+ {
+ vty_out(vty, "Node is not a level-%d IS%s", level, VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ if (argv[3])
+ {
+ char *endp;
+ metric = strtoul(argv[3], &endp, 10);
+ if (argv[3][0] == '\0' || *endp != '\0')
+ return CMD_WARNING;
+ }
+ else
+ {
+ metric = 0xffffffff;
+ }
+
+ routemap = argv[4];
+
+ isis_redist_set(area, level, family, type, metric, routemap, 0);
+ return 0;
+}
+
+DEFUN(no_isis_redistribute_ipv4,
+ no_isis_redistribute_ipv4_cmd,
+ "no redistribute (ipv4|) " QUAGGA_REDIST_STR_ISISD
+ " (level-1|level-2)",
+ NO_STR
+ REDIST_STR
+ "Redistribute IPv4 routes\n"
+ "DUMMY\n"
+ QUAGGA_REDIST_HELP_STR_ISISD
+ "Redistribute into level-1\n"
+ "Redistribute into level-2\n")
+{
+ struct isis_area *area = vty->index;
+ int type;
+ int level;
+ int family;
+
+ if (argc < 3)
+ return CMD_WARNING;
+
+ family = str2family(argv[0]);
+ if (family < 0)
+ return CMD_WARNING;
+
+ type = proto_redistnum(AFI_IP, argv[1]);
+ if (type < 0 || type == ZEBRA_ROUTE_ISIS)
+ return CMD_WARNING;
+
+ if (!strcmp("level-1", argv[2]))
+ level = 1;
+ else if (!strcmp("level-2", argv[2]))
+ level = 2;
+ else
+ return CMD_WARNING;
+
+ isis_redist_unset(area, level, family, type);
+ return 0;
+}
+
+DEFUN(isis_default_originate_ipv4,
+ isis_default_originate_ipv4_cmd,
+ "default-information originate (ipv4|) (level-1|level-2) "
+ "{always|metric <0-16777215>|route-map WORD}",
+ "Control distribution of default information\n"
+ "Distribute a default route\n"
+ "Distribute default route for IPv4\n"
+ "DUMMY\n"
+ "Distribute default route into level-1\n"
+ "Distribute default route into level-2\n"
+ "Always advertise default route\n"
+ "Metric for default route\n"
+ "ISIS default metric\n"
+ "Route map reference\n"
+ "Pointer to route-map entries\n")
+{
+ struct isis_area *area = vty->index;
+ int family;
+ int originate_type;
+ int level;
+ unsigned long metric;
+ const char *routemap;
+
+ if (argc < 5)
+ return CMD_WARNING;
+
+ family = str2family(argv[0]);
+ if (family < 0)
+ return CMD_WARNING;
+
+ if (!strcmp("level-1", argv[1]))
+ level = 1;
+ else if (!strcmp("level-2", argv[1]))
+ level = 2;
+ else
+ return CMD_WARNING;
+
+ if ((area->is_type & level) != level)
+ {
+ vty_out(vty, "Node is not a level-%d IS%s", level, VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ if (argv[2] && *argv[2] != '\0')
+ originate_type = DEFAULT_ORIGINATE_ALWAYS;
+ else
+ originate_type = DEFAULT_ORIGINATE;
+
+#ifdef HAVE_IPV6
+ if (family == AF_INET6 && originate_type != DEFAULT_ORIGINATE_ALWAYS)
+ {
+ vty_out(vty, "Zebra doesn't implement default-originate for IPv6 yet%s", VTY_NEWLINE);
+ vty_out(vty, "so use with care or use default-originate always.%s", VTY_NEWLINE);
+ }
+#endif
+
+ if (argv[3])
+ {
+ char *endp;
+ metric = strtoul(argv[3], &endp, 10);
+ if (argv[3][0] == '\0' || *endp != '\0')
+ return CMD_WARNING;
+ }
+ else
+ {
+ metric = 0xffffffff;
+ }
+
+ routemap = argv[4];
+
+ isis_redist_set(area, level, family, DEFAULT_ROUTE, metric, routemap, originate_type);
+ return 0;
+}
+
+DEFUN(no_isis_default_originate_ipv4,
+ no_isis_default_originate_ipv4_cmd,
+ "no default-information originate (ipv4|) (level-1|level-2)",
+ NO_STR
+ "Control distribution of default information\n"
+ "Distribute a default route\n"
+ "Distribute default route for IPv4\n"
+ "DUMMY\n"
+ "Distribute default route into level-1\n"
+ "Distribute default route into level-2\n")
+{
+ struct isis_area *area = vty->index;
+
+ int family;
+ int level;
+
+ if (argc < 2)
+ return CMD_WARNING;
+
+ family = str2family(argv[0]);
+ if (family < 0)
+ return CMD_WARNING;
+
+ if (!strcmp("level-1", argv[1]))
+ level = 1;
+ else if (!strcmp("level-2", argv[1]))
+ level = 2;
+ else
+ return CMD_WARNING;
+
+ isis_redist_unset(area, level, family, DEFAULT_ROUTE);
+ return 0;
+}
+
+#ifdef HAVE_IPV6
+ALIAS(isis_redistribute_ipv4,
+ isis_redistribute_ipv6_cmd,
+ "redistribute (ipv6|)" QUAGGA_REDIST_STR_ISISD
+ " (level-1|level-2) {metric <0-16777215>|route-map WORD}",
+ REDIST_STR
+ "Redistribute IPv6 routes\n"
+ "DUMMY\n"
+ QUAGGA_REDIST_HELP_STR_ISISD
+ "Redistribute into level-1\n"
+ "Redistribute into level-2\n"
+ "Metric for redistributed routes\n"
+ "ISIS default metric\n"
+ "Route map reference\n"
+ "Pointer to route-map entries\n"
+);
+
+ALIAS(no_isis_redistribute_ipv4,
+ no_isis_redistribute_ipv6_cmd,
+ "no redistribute (ipv6|)" QUAGGA_REDIST_STR_ISISD
+ " (level-1|level-2)",
+ NO_STR
+ REDIST_STR
+ "Redistribute IPv6 routes\n"
+ "DUMMY\n"
+ QUAGGA_REDIST_HELP_STR_ISISD
+ "Redistribute into level-1\n"
+ "Redistribute into level-2\n"
+);
+
+ALIAS(isis_default_originate_ipv4,
+ isis_default_originate_ipv6_cmd,
+ "default-information originate (ipv6|) (level-1|level-2) "
+ "{always|metric <0-16777215>|route-map WORD}",
+ "Control distribution of default information\n"
+ "Distribute a default route\n"
+ "Distribute default route for IPv6\n"
+ "DUMMY\n"
+ "Distribute default route into level-1\n"
+ "Distribute default route into level-2\n"
+ "Always advertise default route\n"
+ "Metric for default route\n"
+ "ISIS default metric\n"
+ "Route map reference\n"
+ "Pointer to route-map entries\n")
+
+ALIAS(no_isis_default_originate_ipv4,
+ no_isis_default_originate_ipv6_cmd,
+ "no default-information originate (ipv6|) (level-1|level-2)",
+ NO_STR
+ "Control distribution of default information\n"
+ "Distribute a default route\n"
+ "Distribute default route for IPv6\n"
+ "DUMMY\n"
+ "Distribute default route into level-1\n"
+ "Distribute default route into level-2\n"
+);
+#endif
+
+int
+isis_redist_config_write(struct vty *vty, struct isis_area *area,
+ int family)
+{
+ int type;
+ int level;
+ int write = 0;
+ struct isis_redist *redist;
+ const char *family_str;
+
+ if (family == AF_INET)
+ family_str = "ipv4";
+#ifdef HAVE_IPV6
+ else if (family == AF_INET6)
+ family_str = "ipv6";
+#endif
+ else
+ return 0;
+
+ for (type = 0; type < ZEBRA_ROUTE_MAX; type++)
+ {
+ if (type == ZEBRA_ROUTE_ISIS)
+ continue;
+
+ for (level = 1; level <= ISIS_LEVELS; level++)
+ {
+ redist = get_redist_settings(area, family, type, level);
+ if (!redist->redist)
+ continue;
+ vty_out(vty, " redistribute %s %s level-%d",
+ family_str, zebra_route_string(type), level);
+ if (redist->metric != 0xffffffff)
+ vty_out(vty, " metric %u", redist->metric);
+ if (redist->map_name)
+ vty_out(vty, " route-map %s", redist->map_name);
+ vty_out(vty, "%s", VTY_NEWLINE);
+ write++;
+ }
+ }
+
+ for (level = 1; level <= ISIS_LEVELS; level++)
+ {
+ redist = get_redist_settings(area, family, DEFAULT_ROUTE, level);
+ if (!redist->redist)
+ continue;
+ vty_out(vty, " default-information originate %s level-%d",
+ family_str, level);
+ if (redist->redist == DEFAULT_ORIGINATE_ALWAYS)
+ vty_out(vty, " always");
+ if (redist->metric != 0xffffffff)
+ vty_out(vty, " metric %u", redist->metric);
+ if (redist->map_name)
+ vty_out(vty, " route-map %s", redist->map_name);
+ vty_out(vty, "%s", VTY_NEWLINE);
+ write++;
+ }
+
+ return write;
+}
+
+void
+isis_redist_init(void)
+{
+ install_element(ISIS_NODE, &isis_redistribute_ipv4_cmd);
+ install_element(ISIS_NODE, &no_isis_redistribute_ipv4_cmd);
+ install_element(ISIS_NODE, &isis_default_originate_ipv4_cmd);
+ install_element(ISIS_NODE, &no_isis_default_originate_ipv4_cmd);
+#ifdef HAVE_IPV6
+ install_element(ISIS_NODE, &isis_redistribute_ipv6_cmd);
+ install_element(ISIS_NODE, &no_isis_redistribute_ipv6_cmd);
+ install_element(ISIS_NODE, &isis_default_originate_ipv6_cmd);
+ install_element(ISIS_NODE, &no_isis_default_originate_ipv6_cmd);
+#endif
+}