summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--isisd/Makefile.am5
-rw-r--r--isisd/isis_lsp.c138
-rw-r--r--isisd/isis_main.c5
-rw-r--r--isisd/isis_redist.c815
-rw-r--r--isisd/isis_redist.h41
-rw-r--r--isisd/isis_routemap.c551
-rw-r--r--isisd/isis_routemap.h6
-rw-r--r--isisd/isis_tlv.c21
-rw-r--r--isisd/isis_tlv.h13
-rw-r--r--isisd/isis_zebra.c72
-rw-r--r--isisd/isis_zebra.h1
-rw-r--r--isisd/isisd.c4
-rw-r--r--isisd/isisd.h38
-rw-r--r--lib/routemap.h3
14 files changed, 1611 insertions, 102 deletions
diff --git a/isisd/Makefile.am b/isisd/Makefile.am
index 4e9b2441..9aa331d1 100644
--- a/isisd/Makefile.am
+++ b/isisd/Makefile.am
@@ -17,14 +17,15 @@ libisis_a_SOURCES = \
isis_adjacency.c isis_lsp.c dict.c isis_circuit.c isis_pdu.c \
isis_tlv.c isisd.c isis_misc.c isis_zebra.c isis_dr.c \
isis_flags.c isis_dynhn.c iso_checksum.c isis_csm.c isis_events.c \
- isis_spf.c isis_route.c isis_routemap.c
+ isis_spf.c isis_redist.c isis_route.c isis_routemap.c
noinst_HEADERS = \
isisd.h isis_pdu.h isis_tlv.h isis_adjacency.h isis_constants.h \
isis_lsp.h dict.h isis_circuit.h isis_misc.h isis_network.h \
isis_zebra.h isis_dr.h isis_flags.h isis_dynhn.h isis_common.h \
- iso_checksum.h isis_csm.h isis_events.h isis_spf.h isis_route.h \
+ iso_checksum.h isis_csm.h isis_events.h isis_spf.h isis_redist.h \
+ isis_route.h \
include-netbsd/clnp.h include-netbsd/esis.h include-netbsd/iso.h
isisd_SOURCES = \
diff --git a/isisd/isis_lsp.c b/isisd/isis_lsp.c
index 9bbba7fc..43170f66 100644
--- a/isisd/isis_lsp.c
+++ b/isisd/isis_lsp.c
@@ -35,6 +35,7 @@
#include "if.h"
#include "checksum.h"
#include "md5.h"
+#include "table.h"
#include "isisd/dict.h"
#include "isisd/isis_constants.h"
@@ -950,7 +951,7 @@ lsp_print_detail (struct isis_lsp *lsp, struct vty *vty, char dynhost)
memcpy (in6.s6_addr, ipv6_reach->prefix,
PSIZE (ipv6_reach->prefix_len));
inet_ntop (AF_INET6, &in6, (char *)buff, BUFSIZ);
- if ((ipv6_reach->control_info &&
+ if ((ipv6_reach->control_info &
CTRL_INFO_DISTRIBUTION) == DISTRIBUTION_INTERNAL)
vty_out (vty, " Metric : %-8d IPv6-Internal : %s/%d%s",
ntohl (ipv6_reach->metric),
@@ -1144,6 +1145,123 @@ lsp_next_frag (u_char frag_num, struct isis_lsp *lsp0, struct isis_area *area,
return lsp;
}
+static void
+lsp_build_ext_reach_ipv4(struct isis_lsp *lsp, struct isis_area *area,
+ struct tlvs *tlv_data)
+{
+ struct route_table *er_table;
+ struct route_node *rn;
+ struct prefix_ipv4 *ipv4;
+ struct isis_ext_info *info;
+ struct ipv4_reachability *ipreach;
+ struct te_ipv4_reachability *te_ipreach;
+
+ er_table = get_ext_reach(area, AF_INET, lsp->level);
+ if (!er_table)
+ return;
+
+ for (rn = route_top(er_table); rn; rn = route_next(rn))
+ {
+ if (!rn->info)
+ continue;
+
+ ipv4 = (struct prefix_ipv4*)&rn->p;
+ info = rn->info;
+ if (area->oldmetric)
+ {
+ if (tlv_data->ipv4_ext_reachs == NULL)
+ {
+ tlv_data->ipv4_ext_reachs = list_new();
+ tlv_data->ipv4_ext_reachs->del = free_tlv;
+ }
+ ipreach = XMALLOC(MTYPE_ISIS_TLV, sizeof(*ipreach));
+
+ ipreach->prefix.s_addr = ipv4->prefix.s_addr;
+ masklen2ip(ipv4->prefixlen, &ipreach->mask);
+ ipreach->prefix.s_addr &= ipreach->mask.s_addr;
+
+ if ((info->metric & 0x3f) != info->metric)
+ ipreach->metrics.metric_default = 0x3f;
+ else
+ ipreach->metrics.metric_default = info->metric;
+ ipreach->metrics.metric_expense = METRICS_UNSUPPORTED;
+ ipreach->metrics.metric_error = METRICS_UNSUPPORTED;
+ ipreach->metrics.metric_delay = METRICS_UNSUPPORTED;
+ listnode_add(tlv_data->ipv4_ext_reachs, ipreach);
+ }
+ if (area->newmetric)
+ {
+ if (tlv_data->te_ipv4_reachs == NULL)
+ {
+ tlv_data->te_ipv4_reachs = list_new();
+ tlv_data->te_ipv4_reachs->del = free_tlv;
+ }
+ te_ipreach =
+ XCALLOC(MTYPE_ISIS_TLV,
+ sizeof(*te_ipreach) - 1 + PSIZE(ipv4->prefixlen));
+ if (info->metric > MAX_WIDE_PATH_METRIC)
+ te_ipreach->te_metric = htonl(MAX_WIDE_PATH_METRIC);
+ else
+ te_ipreach->te_metric = htonl(info->metric);
+ te_ipreach->control = ipv4->prefixlen & 0x3f;
+ memcpy(&te_ipreach->prefix_start, &ipv4->prefix.s_addr,
+ PSIZE(ipv4->prefixlen));
+ listnode_add(tlv_data->te_ipv4_reachs, te_ipreach);
+ }
+ }
+}
+
+#ifdef HAVE_IPV6
+static void
+lsp_build_ext_reach_ipv6(struct isis_lsp *lsp, struct isis_area *area,
+ struct tlvs *tlv_data)
+{
+ struct route_table *er_table;
+ struct route_node *rn;
+ struct prefix_ipv6 *ipv6;
+ struct isis_ext_info *info;
+ struct ipv6_reachability *ip6reach;
+
+ er_table = get_ext_reach(area, AF_INET6, lsp->level);
+ if (!er_table)
+ return;
+
+ for (rn = route_top(er_table); rn; rn = route_next(rn))
+ {
+ if (!rn->info)
+ continue;
+
+ ipv6 = (struct prefix_ipv6*)&rn->p;
+ info = rn->info;
+
+ if (tlv_data->ipv6_reachs == NULL)
+ {
+ tlv_data->ipv6_reachs = list_new();
+ tlv_data->ipv6_reachs->del = free_tlv;
+ }
+ ip6reach = XCALLOC(MTYPE_ISIS_TLV, sizeof(*ip6reach));
+ if (info->metric > MAX_WIDE_PATH_METRIC)
+ ip6reach->metric = htonl(MAX_WIDE_PATH_METRIC);
+ else
+ ip6reach->metric = htonl(info->metric);
+ ip6reach->control_info = DISTRIBUTION_EXTERNAL;
+ ip6reach->prefix_len = ipv6->prefixlen;
+ memcpy(ip6reach->prefix, ipv6->prefix.s6_addr, sizeof(ip6reach->prefix));
+ listnode_add(tlv_data->ipv6_reachs, ip6reach);
+ }
+}
+#endif
+
+static void
+lsp_build_ext_reach (struct isis_lsp *lsp, struct isis_area *area,
+ struct tlvs *tlv_data)
+{
+ lsp_build_ext_reach_ipv4(lsp, area, tlv_data);
+#ifdef HAVE_IPV6
+ lsp_build_ext_reach_ipv6(lsp, area, tlv_data);
+#endif
+}
+
/*
* Builds the LSP data part. This func creates a new frag whenever
* area->lsp_frag_threshold is exceeded.
@@ -1230,6 +1348,7 @@ lsp_build (struct isis_lsp *lsp, struct isis_area *area)
lsp->tlv_data.hostname = XMALLOC (MTYPE_ISIS_TLV,
sizeof (struct hostname));
+ /* FIXME: check length of hostname */
memcpy (lsp->tlv_data.hostname->name, unix_hostname (),
strlen (unix_hostname ()));
lsp->tlv_data.hostname->namelen = strlen (unix_hostname ());
@@ -1478,6 +1597,8 @@ lsp_build (struct isis_lsp *lsp, struct isis_area *area)
}
}
+ lsp_build_ext_reach(lsp, area, &tlv_data);
+
while (tlv_data.ipv4_int_reachs && listcount (tlv_data.ipv4_int_reachs))
{
if (lsp->tlv_data.ipv4_int_reachs == NULL)
@@ -1485,12 +1606,25 @@ lsp_build (struct isis_lsp *lsp, struct isis_area *area)
lsp_tlv_fit (lsp, &tlv_data.ipv4_int_reachs,
&lsp->tlv_data.ipv4_int_reachs,
IPV4_REACH_LEN, area->lsp_frag_threshold,
- tlv_add_ipv4_reachs);
+ tlv_add_ipv4_int_reachs);
if (tlv_data.ipv4_int_reachs && listcount (tlv_data.ipv4_int_reachs))
lsp = lsp_next_frag (LSP_FRAGMENT (lsp->lsp_header->lsp_id) + 1,
lsp0, area, level);
}
+ while (tlv_data.ipv4_ext_reachs && listcount (tlv_data.ipv4_ext_reachs))
+ {
+ if (lsp->tlv_data.ipv4_ext_reachs == NULL)
+ lsp->tlv_data.ipv4_ext_reachs = list_new ();
+ lsp_tlv_fit (lsp, &tlv_data.ipv4_ext_reachs,
+ &lsp->tlv_data.ipv4_ext_reachs,
+ IPV4_REACH_LEN, area->lsp_frag_threshold,
+ tlv_add_ipv4_ext_reachs);
+ if (tlv_data.ipv4_ext_reachs && listcount (tlv_data.ipv4_ext_reachs))
+ lsp = lsp_next_frag (LSP_FRAGMENT (lsp->lsp_header->lsp_id) + 1,
+ lsp0, area, level);
+ }
+
/* FIXME: We pass maximum te_ipv4_reachability length to the lsp_tlv_fit()
* for now. lsp_tlv_fit() needs to be fixed to deal with variable length
* TLVs (sub TLVs!). */
diff --git a/isisd/isis_main.c b/isisd/isis_main.c
index 283b7eaa..89877c65 100644
--- a/isisd/isis_main.c
+++ b/isisd/isis_main.c
@@ -34,6 +34,7 @@
#include "privs.h"
#include "sigevent.h"
#include "filter.h"
+#include "plist.h"
#include "zclient.h"
#include "isisd/dict.h"
@@ -46,6 +47,7 @@
#include "isisd/isis_dynhn.h"
#include "isisd/isis_spf.h"
#include "isisd/isis_route.h"
+#include "isisd/isis_routemap.h"
#include "isisd/isis_zebra.h"
/* Default configuration file name */
@@ -330,9 +332,12 @@ main (int argc, char **argv, char **envp)
vty_init (master);
memory_init ();
access_list_init();
+ prefix_list_init();
isis_init ();
isis_circuit_init ();
isis_spf_cmds_init ();
+ isis_redist_init ();
+ isis_route_map_init();
/* create the global 'isis' instance */
isis_new (1);
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
+}
diff --git a/isisd/isis_redist.h b/isisd/isis_redist.h
new file mode 100644
index 00000000..d2982bbc
--- /dev/null
+++ b/isisd/isis_redist.h
@@ -0,0 +1,41 @@
+#ifndef ISIS_REDIST_H
+#define ISIS_REDIST_H
+
+#ifdef HAVE_IPV6
+#define REDIST_PROTOCOL_COUNT 2
+#else
+#define REDIST_PROTOCOL_COUNT 1
+#endif
+
+#define DEFAULT_ROUTE ZEBRA_ROUTE_MAX
+#define DEFAULT_ORIGINATE 1
+#define DEFAULT_ORIGINATE_ALWAYS 2
+
+struct isis_ext_info
+{
+ int origin;
+ u_char distance;
+ uint32_t metric;
+};
+
+struct isis_redist
+{
+ int redist;
+ uint32_t metric;
+ char *map_name;
+ struct route_map *map;
+};
+
+struct isis_area;
+struct prefix;
+
+struct route_table *get_ext_reach(struct isis_area *area,
+ int family, int level);
+void isis_redist_add(int type, struct prefix *p,
+ u_char distance, uint32_t metric);
+void isis_redist_delete(int type, struct prefix *p);
+int isis_redist_config_write(struct vty *vty, struct isis_area *area,
+ int family);
+void isis_redist_init(void);
+
+#endif
diff --git a/isisd/isis_routemap.c b/isisd/isis_routemap.c
index 84a14ac5..8b944883 100644
--- a/isisd/isis_routemap.c
+++ b/isisd/isis_routemap.c
@@ -22,16 +22,19 @@
*/
#include <zebra.h>
-#include "thread.h"
+#include "command.h"
+#include "filter.h"
+#include "hash.h"
+#include "if.h"
#include "linklist.h"
-#include "vty.h"
#include "log.h"
#include "memory.h"
#include "prefix.h"
-#include "hash.h"
-#include "if.h"
-#include "table.h"
+#include "plist.h"
#include "routemap.h"
+#include "table.h"
+#include "thread.h"
+#include "vty.h"
#include "isis_constants.h"
#include "isis_common.h"
@@ -47,60 +50,528 @@
#include "isis_spf.h"
#include "isis_route.h"
#include "isis_zebra.h"
+#include "isis_routemap.h"
-extern struct isis *isis;
+static route_map_result_t
+route_match_ip_address(void *rule, struct prefix *prefix,
+ route_map_object_t type, void *object)
+{
+ struct access_list *alist;
-/*
- * Prototypes.
- */
-void isis_route_map_upd(const char *);
-void isis_route_map_event(route_map_event_t, const char *);
-void isis_route_map_init(void);
+ if (type != RMAP_ISIS)
+ return RMAP_NOMATCH;
+ alist = access_list_lookup(AFI_IP, (char*)rule);
+ if (access_list_apply(alist, prefix) != FILTER_DENY)
+ return RMAP_MATCH;
-void
-isis_route_map_upd (const char *name)
+ return RMAP_NOMATCH;
+}
+
+static void *
+route_match_ip_address_compile(const char *arg)
+{
+ return XSTRDUP(MTYPE_ROUTE_MAP_COMPILED, arg);
+}
+
+static void
+route_match_ip_address_free(void *rule)
{
- int i = 0;
+ XFREE(MTYPE_ROUTE_MAP_COMPILED, rule);
+}
+
+static struct route_map_rule_cmd route_match_ip_address_cmd =
+{
+ "ip address",
+ route_match_ip_address,
+ route_match_ip_address_compile,
+ route_match_ip_address_free
+};
+
+/* ------------------------------------------------------------*/
+
+static route_map_result_t
+route_match_ip_address_prefix_list(void *rule, struct prefix *prefix,
+ route_map_object_t type, void *object)
+{
+ struct prefix_list *plist;
+
+ if (type != RMAP_ISIS)
+ return RMAP_NOMATCH;
+
+ plist = prefix_list_lookup(AFI_IP, (char*)rule);
+ if (prefix_list_apply(plist, prefix) != PREFIX_DENY)
+ return RMAP_MATCH;
+
+ return RMAP_NOMATCH;
+}
+
+static void *
+route_match_ip_address_prefix_list_compile(const char *arg)
+{
+ return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg);
+}
+
+static void
+route_match_ip_address_prefix_list_free (void *rule)
+{
+ XFREE (MTYPE_ROUTE_MAP_COMPILED, rule);
+}
+
+struct route_map_rule_cmd route_match_ip_address_prefix_list_cmd =
+{
+ "ip address prefix-list",
+ route_match_ip_address_prefix_list,
+ route_match_ip_address_prefix_list_compile,
+ route_match_ip_address_prefix_list_free
+};
+
+/* ------------------------------------------------------------*/
- if (!isis)
- return;
+#ifdef HAVE_IPV6
- for (i = 0; i <= ZEBRA_ROUTE_MAX; i++)
+static route_map_result_t
+route_match_ipv6_address(void *rule, struct prefix *prefix,
+ route_map_object_t type, void *object)
+{
+ struct access_list *alist;
+
+ if (type != RMAP_ISIS)
+ return RMAP_NOMATCH;
+
+ alist = access_list_lookup(AFI_IP6, (char*)rule);
+ if (access_list_apply(alist, prefix) != FILTER_DENY)
+ return RMAP_MATCH;
+
+ return RMAP_NOMATCH;
+}
+
+static void *
+route_match_ipv6_address_compile(const char *arg)
+{
+ return XSTRDUP(MTYPE_ROUTE_MAP_COMPILED, arg);
+}
+
+static void
+route_match_ipv6_address_free(void *rule)
+{
+ XFREE(MTYPE_ROUTE_MAP_COMPILED, rule);
+}
+
+static struct route_map_rule_cmd route_match_ipv6_address_cmd =
+{
+ "ipv6 address",
+ route_match_ipv6_address,
+ route_match_ipv6_address_compile,
+ route_match_ipv6_address_free
+};
+
+/* ------------------------------------------------------------*/
+
+static route_map_result_t
+route_match_ipv6_address_prefix_list(void *rule, struct prefix *prefix,
+ route_map_object_t type, void *object)
+{
+ struct prefix_list *plist;
+
+ if (type != RMAP_ISIS)
+ return RMAP_NOMATCH;
+
+ plist = prefix_list_lookup(AFI_IP6, (char*)rule);
+ if (prefix_list_apply(plist, prefix) != PREFIX_DENY)
+ return RMAP_MATCH;
+
+ return RMAP_NOMATCH;
+}
+
+static void *
+route_match_ipv6_address_prefix_list_compile(const char *arg)
+{
+ return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg);
+}
+
+static void
+route_match_ipv6_address_prefix_list_free (void *rule)
+{
+ XFREE (MTYPE_ROUTE_MAP_COMPILED, rule);
+}
+
+struct route_map_rule_cmd route_match_ipv6_address_prefix_list_cmd =
+{
+ "ipv6 address prefix-list",
+ route_match_ipv6_address_prefix_list,
+ route_match_ipv6_address_prefix_list_compile,
+ route_match_ipv6_address_prefix_list_free
+};
+
+#endif /* HAVE_IPV6 */
+
+/* ------------------------------------------------------------*/
+
+static route_map_result_t
+route_set_metric(void *rule, struct prefix *prefix,
+ route_map_object_t type, void *object)
+{
+ uint32_t *metric;
+ struct isis_ext_info *info;
+
+ if (type == RMAP_ISIS)
{
- if (isis->rmap[i].name)
- isis->rmap[i].map = route_map_lookup_by_name (isis->rmap[i].name);
- else
- isis->rmap[i].map = NULL;
+ metric = rule;
+ info = object;
+
+ info->metric = *metric;
}
- /* FIXME: do the address family sub-mode AF_INET6 here ? */
+ return RMAP_OKAY;
}
-void
-isis_route_map_event (route_map_event_t event, const char *name)
+static void *
+route_set_metric_compile(const char *arg)
+{
+ unsigned long metric;
+ char *endp;
+ uint32_t *ret;
+
+ metric = strtoul(arg, &endp, 10);
+ if (arg[0] == '\0' || *endp != '\0' || metric > MAX_WIDE_PATH_METRIC)
+ return NULL;
+
+ ret = XCALLOC(MTYPE_ROUTE_MAP_COMPILED, sizeof(ret));
+ *ret = metric;
+
+ return ret;
+}
+
+static void
+route_set_metric_free(void *rule)
+{
+ XFREE(MTYPE_ROUTE_MAP_COMPILED, rule);
+}
+
+static struct route_map_rule_cmd route_set_metric_cmd =
+{
+ "metric",
+ route_set_metric,
+ route_set_metric_compile,
+ route_set_metric_free
+};
+
+/* ------------------------------------------------------------*/
+
+static int
+isis_route_match_add(struct vty *vty, struct route_map_index *index,
+ const char *command, const char *arg)
+{
+ int ret;
+
+ ret = route_map_add_match (index, command, arg);
+ if (ret)
+ {
+ switch (ret)
+ {
+ case RMAP_RULE_MISSING:
+ vty_out (vty, "%% Can't find rule.%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ case RMAP_COMPILE_ERROR:
+ vty_out (vty, "%% Argument is malformed.%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ }
+ return CMD_SUCCESS;
+}
+
+static int
+isis_route_match_delete(struct vty *vty, struct route_map_index *index,
+ const char *command, const char *arg)
+{
+ int ret;
+
+ ret = route_map_delete_match (index, command, arg);
+ if (ret)
+ {
+ switch (ret)
+ {
+ case RMAP_RULE_MISSING:
+ vty_out (vty, "%% Can't find rule.%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ case RMAP_COMPILE_ERROR:
+ vty_out (vty, "%% Argument is malformed.%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ }
+ return CMD_SUCCESS;
+}
+
+static int
+isis_route_set_add(struct vty *vty, struct route_map_index *index,
+ const char *command, const char *arg)
{
- int type;
+ int ret;
+
+ ret = route_map_add_set(index, command, arg);
+ if (ret)
+ {
+ switch (ret)
+ {
+ case RMAP_RULE_MISSING:
+ vty_out (vty, "%% Can't find rule.%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ case RMAP_COMPILE_ERROR:
+ vty_out (vty, "%% Argument is malformed.%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ }
- if (!isis)
- return;
+ return CMD_SUCCESS;
+}
- for (type = 0; type <= ZEBRA_ROUTE_MAX; type++)
+static int
+isis_route_set_delete (struct vty *vty, struct route_map_index *index,
+ const char *command, const char *arg)
+{
+ int ret;
+
+ ret = route_map_delete_set (index, command, arg);
+ if (ret)
{
- if (isis->rmap[type].name && isis->rmap[type].map &&
- !strcmp (isis->rmap[type].name, name))
- {
- isis_distribute_list_update (type);
- }
+ switch (ret)
+ {
+ case RMAP_RULE_MISSING:
+ vty_out (vty, "%% Can't find rule.%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ case RMAP_COMPILE_ERROR:
+ vty_out (vty, "%% Argument is malformed.%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
}
+
+ return CMD_SUCCESS;
}
+/* ------------------------------------------------------------*/
+
+DEFUN(match_ip_address,
+ match_ip_address_cmd,
+ "match ip address (<1-199>|<1300-2699>|WORD)",
+ MATCH_STR
+ IP_STR
+ "Match address of route\n"
+ "IP access-list number\n"
+ "IP access-list number (expanded range)\n"
+ "IP Access-list name\n")
+{
+ return isis_route_match_add(vty, vty->index, "ip address", argv[0]);
+}
+
+DEFUN(no_match_ip_address,
+ no_match_ip_address_val_cmd,
+ "no match ip address (<1-199>|<1300-2699>|WORD)",
+ NO_STR
+ MATCH_STR
+ IP_STR
+ "Match address of route\n"
+ "IP access-list number\n"
+ "IP access-list number (expanded range)\n"
+ "IP Access-list name\n")
+{
+ if (argc == 0)
+ return isis_route_match_delete(vty, vty->index, "ip address", NULL);
+ return isis_route_match_delete(vty, vty->index, "ip address", argv[0]);
+}
+
+ALIAS(no_match_ip_address,
+ no_match_ip_address_cmd,
+ "no match ip address",
+ NO_STR
+ MATCH_STR
+ IP_STR
+ "Match address of route\n"
+);
+
+/* ------------------------------------------------------------*/
+
+DEFUN(match_ip_address_prefix_list,
+ match_ip_address_prefix_list_cmd,
+ "match ip address prefix-list WORD",
+ MATCH_STR
+ IP_STR
+ "Match address of route\n"
+ "Match entries of prefix-lists\n"
+ "IP prefix-list name\n")
+{
+ return isis_route_match_add(vty, vty->index, "ip address prefix-list", argv[0]);
+}
+
+DEFUN(no_match_ip_address_prefix_list,
+ no_match_ip_address_prefix_list_cmd,
+ "no match ip address prefix-list",
+ NO_STR
+ MATCH_STR
+ IP_STR
+ "Match address of route\n"
+ "Match entries of prefix-lists\n")
+{
+ if (argc == 0)
+ return isis_route_match_delete (vty, vty->index, "ip address prefix-list", NULL);
+ return isis_route_match_delete (vty, vty->index, "ip address prefix-list", argv[0]);
+}
+
+ALIAS(no_match_ip_address_prefix_list,
+ no_match_ip_address_prefix_list_val_cmd,
+ "no match ip address prefix-list WORD",
+ NO_STR
+ MATCH_STR
+ IP_STR
+ "Match address of route\n"
+ "Match entries of prefix-lists\n"
+ "IP prefix-list name\n"
+);
+
+/* ------------------------------------------------------------*/
+
+#ifdef HAVE_IPV6
+
+DEFUN(match_ipv6_address,
+ match_ipv6_address_cmd,
+ "match ipv6 address WORD",
+ MATCH_STR
+ IPV6_STR
+ "Match IPv6 address of route\n"
+ "IPv6 access-list name\n")
+{
+ return isis_route_match_add(vty, vty->index, "ipv6 address", argv[0]);
+}
+
+DEFUN(no_match_ipv6_address,
+ no_match_ipv6_address_val_cmd,
+ "no match ipv6 address WORD",
+ NO_STR
+ MATCH_STR
+ IPV6_STR
+ "Match IPv6 address of route\n"
+ "IPv6 access-list name\n")
+{
+ if (argc == 0)
+ return isis_route_match_delete(vty, vty->index, "ipv6 address", NULL);
+ return isis_route_match_delete(vty, vty->index, "ipv6 address", argv[0]);
+}
+
+ALIAS(no_match_ipv6_address,
+ no_match_ipv6_address_cmd,
+ "no match ipv6 address",
+ NO_STR
+ MATCH_STR
+ IPV6_STR
+ "Match IPv6 address of route\n"
+);
+
+/* ------------------------------------------------------------*/
+
+DEFUN(match_ipv6_address_prefix_list,
+ match_ipv6_address_prefix_list_cmd,
+ "match ipv6 address prefix-list WORD",
+ MATCH_STR
+ IPV6_STR
+ "Match address of route\n"
+ "Match entries of prefix-lists\n"
+ "IP prefix-list name\n")
+{
+ return isis_route_match_add(vty, vty->index, "ipv6 address prefix-list", argv[0]);
+}
+
+DEFUN(no_match_ipv6_address_prefix_list,
+ no_match_ipv6_address_prefix_list_cmd,
+ "no match ipv6 address prefix-list",
+ NO_STR
+ MATCH_STR
+ IPV6_STR
+ "Match address of route\n"
+ "Match entries of prefix-lists\n")
+{
+ if (argc == 0)
+ return isis_route_match_delete (vty, vty->index, "ipv6 address prefix-list", NULL);
+ return isis_route_match_delete (vty, vty->index, "ipv6 address prefix-list", argv[0]);
+}
+
+ALIAS(no_match_ipv6_address_prefix_list,
+ no_match_ipv6_address_prefix_list_val_cmd,
+ "no match ipv6 address prefix-list WORD",
+ NO_STR
+ MATCH_STR
+ IPV6_STR
+ "Match address of route\n"
+ "Match entries of prefix-lists\n"
+ "IP prefix-list name\n"
+);
+
+#endif /* HAVE_IPV6 */
+
+/* ------------------------------------------------------------*/
+
+/* set metric already exists e.g. in the ospf routemap. vtysh doesn't cope well with different
+ * commands at the same node, therefore add set metric with the same 32-bit range as ospf and
+ * verify that the input is a valid isis metric */
+DEFUN(set_metric,
+ set_metric_cmd,
+ "set metric <0-4294967295>",
+ SET_STR
+ "Metric vale for destination routing protocol\n"
+ "Metric value\n")
+{
+ return isis_route_set_add(vty, vty->index, "metric", argv[0]);
+}
+
+DEFUN(no_set_metric,
+ no_set_metric_val_cmd,
+ "no set metric <0-4294967295>",
+ NO_STR
+ SET_STR
+ "Metric value for destination routing protocol\n"
+ "Metric value\n")
+{
+ if (argc == 0)
+ return isis_route_set_delete(vty, vty->index, "metric", NULL);
+ return isis_route_set_delete(vty, vty->index, "metric", argv[0]);
+}
+
+ALIAS(no_set_metric,
+ no_set_metric_cmd,
+ "no set metric",
+ NO_STR
+ SET_STR
+ "Metric vale for destination routing protocol\n"
+);
+
void
-isis_route_map_init (void)
+isis_route_map_init(void)
{
- route_map_init ();
- route_map_init_vty ();
+ route_map_init();
+ route_map_init_vty();
+
+ route_map_install_match(&route_match_ip_address_cmd);
+ install_element(RMAP_NODE, &match_ip_address_cmd);
+ install_element(RMAP_NODE, &no_match_ip_address_val_cmd);
+ install_element(RMAP_NODE, &no_match_ip_address_cmd);
+
+ route_map_install_match(&route_match_ip_address_prefix_list_cmd);
+ install_element(RMAP_NODE, &match_ip_address_prefix_list_cmd);
+ install_element(RMAP_NODE, &no_match_ip_address_prefix_list_val_cmd);
+ install_element(RMAP_NODE, &no_match_ip_address_prefix_list_cmd);
+
+#ifdef HAVE_IPV6
+ route_map_install_match(&route_match_ipv6_address_cmd);
+ install_element(RMAP_NODE, &match_ipv6_address_cmd);
+ install_element(RMAP_NODE, &no_match_ipv6_address_val_cmd);
+ install_element(RMAP_NODE, &no_match_ipv6_address_cmd);
+
+ route_map_install_match(&route_match_ipv6_address_prefix_list_cmd);
+ install_element(RMAP_NODE, &match_ipv6_address_prefix_list_cmd);
+ install_element(RMAP_NODE, &no_match_ipv6_address_prefix_list_val_cmd);
+ install_element(RMAP_NODE, &no_match_ipv6_address_prefix_list_cmd);
+#endif
- route_map_add_hook (isis_route_map_upd);
- route_map_delete_hook (isis_route_map_upd);
- route_map_event_hook (isis_route_map_event);
+ route_map_install_set(&route_set_metric_cmd);
+ install_element(RMAP_NODE, &set_metric_cmd);
+ install_element(RMAP_NODE, &no_set_metric_val_cmd);
+ install_element(RMAP_NODE, &no_set_metric_cmd);
}
diff --git a/isisd/isis_routemap.h b/isisd/isis_routemap.h
new file mode 100644
index 00000000..0f1e0625
--- /dev/null
+++ b/isisd/isis_routemap.h
@@ -0,0 +1,6 @@
+#ifndef ISIS_ROUTEMAP_H
+#define ISIS_ROUTEMAP_H
+
+void isis_route_map_init(void);
+
+#endif
diff --git a/isisd/isis_tlv.c b/isisd/isis_tlv.c
index 2c2415ae..42b40354 100644
--- a/isisd/isis_tlv.c
+++ b/isisd/isis_tlv.c
@@ -996,8 +996,8 @@ tlv_add_lsp_entries (struct list *lsps, struct stream *stream)
return add_tlv (LSP_ENTRIES, pos - value, value, stream);
}
-int
-tlv_add_ipv4_reachs (struct list *ipv4_reachs, struct stream *stream)
+static int
+tlv_add_ipv4_reachs (u_char tag, struct list *ipv4_reachs, struct stream *stream)
{
struct listnode *node;
struct ipv4_reachability *reach;
@@ -1010,7 +1010,7 @@ tlv_add_ipv4_reachs (struct list *ipv4_reachs, struct stream *stream)
if (pos - value + IPV4_REACH_LEN > 255)
{
retval =
- add_tlv (IPV4_INT_REACHABILITY, pos - value, value, stream);
+ add_tlv (tag, pos - value, value, stream);
if (retval != ISIS_OK)
return retval;
pos = value;
@@ -1029,10 +1029,23 @@ tlv_add_ipv4_reachs (struct list *ipv4_reachs, struct stream *stream)
pos += IPV4_MAX_BYTELEN;
}
- return add_tlv (IPV4_INT_REACHABILITY, pos - value, value, stream);
+ return add_tlv (tag, pos - value, value, stream);
+}
+
+int
+tlv_add_ipv4_int_reachs (struct list *ipv4_reachs, struct stream *stream)
+{
+ return tlv_add_ipv4_reachs(IPV4_INT_REACHABILITY, ipv4_reachs, stream);
}
int
+tlv_add_ipv4_ext_reachs (struct list *ipv4_reachs, struct stream *stream)
+{
+ return tlv_add_ipv4_reachs(IPV4_EXT_REACHABILITY, ipv4_reachs, stream);
+}
+
+
+int
tlv_add_te_ipv4_reachs (struct list *te_ipv4_reachs, struct stream *stream)
{
struct listnode *node;
diff --git a/isisd/isis_tlv.h b/isisd/isis_tlv.h
index e092f4d6..b69a17fc 100644
--- a/isisd/isis_tlv.h
+++ b/isisd/isis_tlv.h
@@ -228,11 +228,13 @@ struct ipv6_reachability
/* bits in control_info */
#define CTRL_INFO_DIRECTION 0x80
-#define DIRECTION_UP 0
-#define DIRECTION_DOWN 1
+#define DIRECTION_UP 0x00
+#define DIRECTION_DOWN 0x80
+
#define CTRL_INFO_DISTRIBUTION 0x40
-#define DISTRIBUTION_INTERNAL 0
-#define DISTRIBUTION_EXTERNAL 1
+#define DISTRIBUTION_INTERNAL 0x00
+#define DISTRIBUTION_EXTERNAL 0x40
+
#define CTRL_INFO_SUBTLVS 0x20
#endif /* HAVE_IPV6 */
@@ -311,7 +313,8 @@ int tlv_add_in_addr (struct in_addr *, struct stream *stream, u_char tag);
int tlv_add_dynamic_hostname (struct hostname *hostname,
struct stream *stream);
int tlv_add_lsp_entries (struct list *lsps, struct stream *stream);
-int tlv_add_ipv4_reachs (struct list *ipv4_reachs, struct stream *stream);
+int tlv_add_ipv4_int_reachs (struct list *ipv4_reachs, struct stream *stream);
+int tlv_add_ipv4_ext_reachs (struct list *ipv4_reachs, struct stream *stream);
int tlv_add_te_ipv4_reachs (struct list *te_ipv4_reachs, struct stream *stream);
#ifdef HAVE_IPV6
int tlv_add_ipv6_addrs (struct list *ipv6_addrs, struct stream *stream);
diff --git a/isisd/isis_zebra.c b/isisd/isis_zebra.c
index c2f0b11f..7f814fbb 100644
--- a/isisd/isis_zebra.c
+++ b/isisd/isis_zebra.c
@@ -318,7 +318,7 @@ isis_zebra_route_del_ipv4 (struct prefix *prefix,
}
#ifdef HAVE_IPV6
-void
+static void
isis_zebra_route_add_ipv6 (struct prefix *prefix,
struct isis_route_info *route_info)
{
@@ -519,11 +519,14 @@ isis_zebra_read_ipv4 (int command, struct zclient *zclient,
struct stream *stream;
struct zapi_ipv4 api;
struct prefix_ipv4 p;
- unsigned long ifindex;
+ struct prefix *p_generic = (struct prefix*)&p;
struct in_addr nexthop;
+ unsigned long ifindex;
stream = zclient->ibuf;
+ memset(&api, 0, sizeof(api));
memset (&p, 0, sizeof (struct prefix_ipv4));
+ memset(&nexthop, 0, sizeof(nexthop));
ifindex = 0;
api.type = stream_getc (stream);
@@ -548,14 +551,11 @@ isis_zebra_read_ipv4 (int command, struct zclient *zclient,
api.distance = stream_getc (stream);
if (CHECK_FLAG (api.message, ZAPI_MESSAGE_METRIC))
api.metric = stream_getl (stream);
- else
- api.metric = 0;
if (command == ZEBRA_IPV4_ROUTE_ADD)
- {
- if (isis->debugs & DEBUG_ZEBRA)
- zlog_debug ("IPv4 Route add from Z");
- }
+ isis_redist_add(api.type, p_generic, api.distance, api.metric);
+ else
+ isis_redist_delete(api.type, p_generic);
return 0;
}
@@ -565,27 +565,65 @@ static int
isis_zebra_read_ipv6 (int command, struct zclient *zclient,
zebra_size_t length)
{
+ struct stream *stream;
+ struct zapi_ipv6 api;
+ struct prefix_ipv6 p;
+ struct prefix *p_generic = (struct prefix*)&p;
+ struct in6_addr nexthop;
+ unsigned long ifindex;
+
+ stream = zclient->ibuf;
+ memset(&api, 0, sizeof(api));
+ memset(&p, 0, sizeof(struct prefix_ipv6));
+ memset(&nexthop, 0, sizeof(nexthop));
+ ifindex = 0;
+
+ api.type = stream_getc(stream);
+ api.flags = stream_getc(stream);
+ api.message = stream_getc(stream);
+
+ p.family = AF_INET6;
+ p.prefixlen = stream_getc(stream);
+ stream_get(&p.prefix, stream, PSIZE(p.prefixlen));
+
+ if (CHECK_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP))
+ {
+ api.nexthop_num = stream_getc(stream); /* this is always 1 */
+ stream_get(&nexthop, stream, sizeof(nexthop));
+ }
+ if (CHECK_FLAG(api.message, ZAPI_MESSAGE_IFINDEX))
+ {
+ api.ifindex_num = stream_getc(stream);
+ ifindex = stream_getl(stream);
+ }
+ if (CHECK_FLAG(api.message, ZAPI_MESSAGE_DISTANCE))
+ api.distance = stream_getc(stream);
+ if (CHECK_FLAG(api.message, ZAPI_MESSAGE_METRIC))
+ api.metric = stream_getl(stream);
+
+ if (command == ZEBRA_IPV6_ROUTE_ADD)
+ isis_redist_add(api.type, p_generic, api.distance, api.metric);
+ else
+ isis_redist_delete(api.type, p_generic);
+
return 0;
}
#endif
-#define ISIS_TYPE_IS_REDISTRIBUTED(T) \
-T == ZEBRA_ROUTE_MAX ? zclient->default_information : zclient->redist[type]
-
int
isis_distribute_list_update (int routetype)
{
return 0;
}
-#if 0 /* Not yet. */
-static int
-isis_redistribute_default_set (int routetype, int metric_type,
- int metric_value)
+void
+isis_zebra_redistribute_set(int type)
{
- return 0;
+ if (type == DEFAULT_ROUTE)
+ zclient_redistribute_default(ZEBRA_REDISTRIBUTE_DEFAULT_ADD, zclient);
+ else
+ zclient_redistribute(ZEBRA_REDISTRIBUTE_ADD, zclient, type);
}
-#endif /* 0 */
void
isis_zebra_init ()
diff --git a/isisd/isis_zebra.h b/isisd/isis_zebra.h
index 889cd9b6..8efd20ac 100644
--- a/isisd/isis_zebra.h
+++ b/isisd/isis_zebra.h
@@ -28,5 +28,6 @@ void isis_zebra_init (void);
void isis_zebra_route_update (struct prefix *prefix,
struct isis_route_info *route_info);
int isis_distribute_list_update (int routetype);
+void isis_zebra_redistribute_set(int type);
#endif /* _ZEBRA_ISIS_ZEBRA_H */
diff --git a/isisd/isisd.c b/isisd/isisd.c
index ce6a2621..a100319c 100644
--- a/isisd/isisd.c
+++ b/isisd/isisd.c
@@ -2882,6 +2882,10 @@ isis_config_write (struct vty *vty)
vty_out (vty, " is-type level-2-only%s", VTY_NEWLINE);
write++;
}
+ write += isis_redist_config_write(vty, area, AF_INET);
+#ifdef HAVE_IPV6
+ write += isis_redist_config_write(vty, area, AF_INET6);
+#endif
/* ISIS - Lsp generation interval */
if (area->lsp_gen_interval[0] == area->lsp_gen_interval[1])
{
diff --git a/isisd/isisd.h b/isisd/isisd.h
index 5db485f4..3a4e844d 100644
--- a/isisd/isisd.h
+++ b/isisd/isisd.h
@@ -25,16 +25,12 @@
#define ISISD_VERSION "0.0.7"
+#include "isisd/isis_redist.h"
+
/* uncomment if you are a developer in bug hunt */
-/* #define EXTREME_DEBUG */
+/* #define EXTREME_DEBUG */
/* #define EXTREME_TLV_DEBUG */
-struct rmap
-{
- char *name;
- struct route_map *map;
-};
-
struct isis
{
u_long process_id;
@@ -53,30 +49,7 @@ struct isis
time_t uptime; /* when did we start */
struct thread *t_dync_clean; /* dynamic hostname cache cleanup thread */
- /* Redistributed external information. */
- struct route_table *external_info[ZEBRA_ROUTE_MAX + 1];
- /* Redistribute metric info. */
- struct
- {
- int type; /* Internal or External */
- int value; /* metric value */
- } dmetric[ZEBRA_ROUTE_MAX + 1];
-
- struct
- {
- char *name;
- struct route_map *map;
- } rmap[ZEBRA_ROUTE_MAX + 1];
-#ifdef HAVE_IPV6
- struct
- {
- struct
- {
- char *name;
- struct route_map *map;
- } rmap[ZEBRA_ROUTE_MAX + 1];
- } inet6_afmode;
-#endif
+ struct route_table *ext_info[REDIST_PROTOCOL_COUNT];
};
extern struct isis *isis;
@@ -131,6 +104,9 @@ struct isis_area
#endif /* HAVE_IPV6 */
/* Counters */
u_int32_t circuit_state_changes;
+ struct isis_redist redist_settings[REDIST_PROTOCOL_COUNT]
+ [ZEBRA_ROUTE_MAX + 1][ISIS_LEVELS];
+ struct route_table *ext_reach[REDIST_PROTOCOL_COUNT][ISIS_LEVELS];
#ifdef TOPOLOGY_GENERATE
struct list *topology;
diff --git a/lib/routemap.h b/lib/routemap.h
index ba64553f..2479c81a 100644
--- a/lib/routemap.h
+++ b/lib/routemap.h
@@ -47,7 +47,8 @@ typedef enum
RMAP_OSPF,
RMAP_OSPF6,
RMAP_BGP,
- RMAP_ZEBRA
+ RMAP_ZEBRA,
+ RMAP_ISIS,
} route_map_object_t;
typedef enum