summaryrefslogtreecommitdiffstats
path: root/isisd
diff options
context:
space:
mode:
authorChristian Franke <chris@opensourcerouting.org>2018-07-22 21:49:02 +0200
committerChristian Franke <chris@opensourcerouting.org>2018-08-03 13:25:39 +0200
commitd43d2df5f3b63a4d364bd1136a246dd74647913c (patch)
tree99a128870f0ccd0e65d6981430fc061a2da1fa57 /isisd
parentisisd: add debug message if adjacency is ignored because IP is unusable (diff)
downloadfrr-d43d2df5f3b63a4d364bd1136a246dd74647913c.tar.xz
frr-d43d2df5f3b63a4d364bd1136a246dd74647913c.zip
isisd: learn and advertise IPv6 dst-src routes
Receive IPv6 dst-src routes from zebra and advertise them in our LSPs if so configured. Signed-off-by: Christian Franke <chris@opensourcerouting.org>
Diffstat (limited to 'isisd')
-rw-r--r--isisd/isis_lsp.c21
-rw-r--r--isisd/isis_mt.c12
-rw-r--r--isisd/isis_mt.h8
-rw-r--r--isisd/isis_redist.c103
-rw-r--r--isisd/isis_redist.h7
-rw-r--r--isisd/isis_tlvs.c20
-rw-r--r--isisd/isis_tlvs.h4
-rw-r--r--isisd/isis_zebra.c15
8 files changed, 120 insertions, 70 deletions
diff --git a/isisd/isis_lsp.c b/isisd/isis_lsp.c
index c8ef82906..37651163f 100644
--- a/isisd/isis_lsp.c
+++ b/isisd/isis_lsp.c
@@ -37,6 +37,7 @@
#include "checksum.h"
#include "md5.h"
#include "table.h"
+#include "srcdest_table.h"
#include "isisd/dict.h"
#include "isisd/isis_constants.h"
@@ -765,18 +766,28 @@ static void lsp_build_ext_reach_ipv6(struct isis_lsp *lsp,
return;
for (struct route_node *rn = route_top(er_table); rn;
- rn = route_next(rn)) {
+ rn = srcdest_route_next(rn)) {
if (!rn->info)
continue;
-
- struct prefix_ipv6 *ipv6 = (struct prefix_ipv6 *)&rn->p;
struct isis_ext_info *info = rn->info;
+ struct prefix_ipv6 *p, *src_p;
+ srcdest_rnode_prefixes(rn, (const struct prefix **)&p,
+ (const struct prefix **)&src_p);
+
uint32_t metric = info->metric;
if (info->metric > MAX_WIDE_PATH_METRIC)
metric = MAX_WIDE_PATH_METRIC;
- isis_tlvs_add_ipv6_reach(
- lsp->tlvs, isis_area_ipv6_topology(area), ipv6, metric);
+
+ if (!src_p || !src_p->prefixlen) {
+ isis_tlvs_add_ipv6_reach(lsp->tlvs,
+ isis_area_ipv6_topology(area),
+ p, metric);
+ } else if (isis_area_ipv6_dstsrc_enabled(area)) {
+ isis_tlvs_add_ipv6_dstsrc_reach(lsp->tlvs,
+ ISIS_MT_IPV6_DSTSRC,
+ p, src_p, metric);
+ }
}
}
diff --git a/isisd/isis_mt.c b/isisd/isis_mt.c
index d13f2a13f..2155bf584 100644
--- a/isisd/isis_mt.c
+++ b/isisd/isis_mt.c
@@ -33,6 +33,14 @@ DEFINE_MTYPE_STATIC(ISISD, MT_AREA_SETTING, "ISIS MT Area Setting")
DEFINE_MTYPE_STATIC(ISISD, MT_CIRCUIT_SETTING, "ISIS MT Circuit Setting")
DEFINE_MTYPE_STATIC(ISISD, MT_ADJ_INFO, "ISIS MT Adjacency Info")
+bool isis_area_ipv6_dstsrc_enabled(struct isis_area *area)
+{
+ struct isis_area_mt_setting *area_mt_setting;
+ area_mt_setting = area_lookup_mt_setting(area, ISIS_MT_IPV6_DSTSRC);
+
+ return (area_mt_setting && area_mt_setting->enabled);
+}
+
uint16_t isis_area_ipv6_topology(struct isis_area *area)
{
struct isis_area_mt_setting *area_mt_setting;
@@ -61,6 +69,8 @@ const char *isis_mtid2str(uint16_t mtid)
return "ipv6-multicast";
case ISIS_MT_IPV6_MGMT:
return "ipv6-mgmt";
+ case ISIS_MT_IPV6_DSTSRC:
+ return "ipv6-dstsrc";
default:
snprintf(buf, sizeof(buf), "%" PRIu16, mtid);
return buf;
@@ -81,6 +91,8 @@ uint16_t isis_str2mtid(const char *name)
return ISIS_MT_IPV6_MULTICAST;
if (!strcmp(name, "ipv6-mgmt"))
return ISIS_MT_IPV6_MGMT;
+ if (!strcmp(name, "ipv6-dstsrc"))
+ return ISIS_MT_IPV6_DSTSRC;
return -1;
}
diff --git a/isisd/isis_mt.h b/isisd/isis_mt.h
index 95aa99dba..8c57d24af 100644
--- a/isisd/isis_mt.h
+++ b/isisd/isis_mt.h
@@ -32,6 +32,7 @@
#define ISIS_MT_IPV4_MULTICAST 3
#define ISIS_MT_IPV6_MULTICAST 4
#define ISIS_MT_IPV6_MGMT 5
+#define ISIS_MT_IPV6_DSTSRC 3996 /* FIXME: IANA */
#define ISIS_MT_NAMES \
"<ipv4-unicast" \
@@ -40,6 +41,7 @@
"|ipv4-multicast" \
"|ipv6-multicast" \
"|ipv6-mgmt" \
+ "|ipv6-dstsrc" \
">"
#define ISIS_MT_DESCRIPTIONS \
@@ -48,7 +50,9 @@
"IPv6 unicast topology\n" \
"IPv4 multicast topology\n" \
"IPv6 multicast topology\n" \
- "IPv6 management topology\n"
+ "IPv6 management topology\n" \
+ "IPv6 dst-src topology\n" \
+ ""
#define ISIS_MT_INFO_FIELDS uint16_t mtid;
@@ -75,6 +79,8 @@ struct tlvs;
struct te_is_neigh;
struct isis_tlvs;
+bool isis_area_ipv6_dstsrc_enabled(struct isis_area *area);
+
uint16_t isis_area_ipv6_topology(struct isis_area *area);
struct isis_area_mt_setting *area_lookup_mt_setting(struct isis_area *area,
diff --git a/isisd/isis_redist.c b/isisd/isis_redist.c
index e903dc8c7..1c061fe1c 100644
--- a/isisd/isis_redist.c
+++ b/isisd/isis_redist.c
@@ -30,6 +30,7 @@
#include "stream.h"
#include "table.h"
#include "vty.h"
+#include "srcdest_table.h"
#include "isisd/dict.h"
#include "isisd/isis_constants.h"
@@ -86,33 +87,13 @@ struct route_table *get_ext_reach(struct isis_area *area, int family, int level)
return area->ext_reach[protocol][level - 1];
}
-static struct route_node *
-isis_redist_route_node_create(route_table_delegate_t *delegate,
- struct route_table *table)
-{
- struct route_node *node;
- node = XCALLOC(MTYPE_ISIS_EXT_ROUTE, sizeof(*node));
- return node;
-}
-
-static void isis_redist_route_node_destroy(route_table_delegate_t *delegate,
- struct route_table *table,
- struct route_node *node)
-{
- if (node->info)
- XFREE(MTYPE_ISIS_EXT_INFO, node->info);
- XFREE(MTYPE_ISIS_EXT_ROUTE, node);
-}
-
-static route_table_delegate_t isis_redist_rt_delegate = {
- .create_node = isis_redist_route_node_create,
- .destroy_node = isis_redist_route_node_destroy};
-
/* 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)
+ const struct prefix *p,
+ const struct prefix_ipv6 *src_p,
+ struct isis_ext_info *info)
{
int family = p->family;
struct route_table *er_table = get_ext_reach(area, family, level);
@@ -126,7 +107,7 @@ static void isis_redist_install(struct isis_area *area, int level,
return;
}
- er_node = route_node_get(er_table, p);
+ er_node = srcdest_rnode_get(er_table, p, src_p);
if (er_node->info) {
route_unlock_node(er_node);
@@ -145,7 +126,8 @@ static void isis_redist_install(struct isis_area *area, int level,
* 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)
+ const struct prefix *p,
+ const struct prefix_ipv6 *src_p)
{
int family = p->family;
struct route_table *er_table = get_ext_reach(area, family, level);
@@ -159,7 +141,7 @@ static void isis_redist_uninstall(struct isis_area *area, int level,
return;
}
- er_node = route_node_lookup(er_table, p);
+ er_node = srcdest_rnode_lookup(er_table, p, src_p);
if (!er_node)
return;
else
@@ -177,7 +159,8 @@ static void isis_redist_uninstall(struct isis_area *area, int 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,
+ const struct prefix *p,
+ const struct prefix_ipv6 *src_p,
struct isis_ext_info *info)
{
struct isis_ext_info area_info;
@@ -188,7 +171,8 @@ static void isis_redist_update_ext_reach(struct isis_area *area, int level,
if (redist->map_name) {
map_ret =
- route_map_apply(redist->map, p, RMAP_ISIS, &area_info);
+ route_map_apply(redist->map, (struct prefix *)p,
+ RMAP_ISIS, &area_info);
if (map_ret == RMAP_DENYMATCH)
area_info.distance = 255;
}
@@ -199,9 +183,9 @@ static void isis_redist_update_ext_reach(struct isis_area *area, int level,
area_info.distance = 255;
if (area_info.distance < 255)
- isis_redist_install(area, level, p, &area_info);
+ isis_redist_install(area, level, p, src_p, &area_info);
else
- isis_redist_uninstall(area, level, p);
+ isis_redist_uninstall(area, level, p, src_p);
}
static void isis_redist_ensure_default(struct isis *isis, int family)
@@ -222,7 +206,7 @@ static void isis_redist_ensure_default(struct isis *isis, int family)
} else
assert(!"Unknown family!");
- ei_node = route_node_get(ei_table, &p);
+ ei_node = srcdest_rnode_get(ei_table, &p, NULL);
if (ei_node->info) {
route_unlock_node(ei_node);
return;
@@ -238,8 +222,8 @@ static void isis_redist_ensure_default(struct isis *isis, int family)
}
/* Handle notification about route being added */
-void isis_redist_add(int type, struct prefix *p, uint8_t distance,
- uint32_t metric)
+void isis_redist_add(int type, struct prefix *p, struct prefix_ipv6 *src_p,
+ uint8_t distance, uint32_t metric)
{
int family = p->family;
struct route_table *ei_table = get_ext_info(isis, family);
@@ -262,7 +246,7 @@ void isis_redist_add(int type, struct prefix *p, uint8_t distance,
return;
}
- ei_node = route_node_get(ei_table, p);
+ ei_node = srcdest_rnode_get(ei_table, p, src_p);
if (ei_node->info)
route_unlock_node(ei_node);
else
@@ -274,8 +258,10 @@ void isis_redist_add(int type, struct prefix *p, uint8_t distance,
info->distance = distance;
info->metric = metric;
- if (is_default_prefix(p))
+ if (is_default_prefix(p)
+ && (!src_p || !src_p->prefixlen)) {
type = DEFAULT_ROUTE;
+ }
for (ALL_LIST_ELEMENTS_RO(isis->area_list, node, area))
for (level = 1; level <= ISIS_LEVELS; level++) {
@@ -284,11 +270,11 @@ void isis_redist_add(int type, struct prefix *p, uint8_t distance,
continue;
isis_redist_update_ext_reach(area, level, redist, p,
- info);
+ src_p, info);
}
}
-void isis_redist_delete(int type, struct prefix *p)
+void isis_redist_delete(int type, struct prefix *p, struct prefix_ipv6 *src_p)
{
int family = p->family;
struct route_table *ei_table = get_ext_info(isis, family);
@@ -304,12 +290,14 @@ void isis_redist_delete(int type, struct prefix *p)
zlog_debug("%s: Removing route %s from %s.", __func__, debug_buf,
zebra_route_string(type));
- if (is_default_prefix(p)) {
+ if (is_default_prefix(p)
+ && (!src_p || !src_p->prefixlen)) {
/* 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);
+ isis_redist_add(DEFAULT_ROUTE, p, NULL,
+ 254, MAX_WIDE_PATH_METRIC);
return;
}
@@ -319,7 +307,7 @@ void isis_redist_delete(int type, struct prefix *p)
return;
}
- ei_node = route_node_lookup(ei_table, p);
+ ei_node = srcdest_rnode_lookup(ei_table, p, src_p);
if (!ei_node || !ei_node->info) {
char buf[BUFSIZ];
prefix2str(p, buf, sizeof(buf));
@@ -339,7 +327,7 @@ void isis_redist_delete(int type, struct prefix *p)
if (!redist->redist)
continue;
- isis_redist_uninstall(area, level, p);
+ isis_redist_uninstall(area, level, p, src_p);
}
XFREE(MTYPE_ISIS_EXT_INFO, ei_node->info);
@@ -418,17 +406,14 @@ static void isis_redist_set(struct isis_area *area, int level, int family,
isis_redist_routemap_set(redist, routemap);
if (!area->ext_reach[protocol][level - 1]) {
- area->ext_reach[protocol][level - 1] =
- route_table_init_with_delegate(
- &isis_redist_rt_delegate);
+ area->ext_reach[protocol][level - 1] = srcdest_table_init();
}
- for (i = 0; i < REDIST_PROTOCOL_COUNT; i++)
+ for (i = 0; i < REDIST_PROTOCOL_COUNT; i++) {
if (!area->isis->ext_info[i]) {
- area->isis->ext_info[i] =
- route_table_init_with_delegate(
- &isis_redist_rt_delegate);
+ area->isis->ext_info[i] = srcdest_table_init();
}
+ }
isis_redist_update_zebra_subscriptions(area->isis);
@@ -436,20 +421,27 @@ static void isis_redist_set(struct isis_area *area, int level, int family,
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)) {
+ for (rn = route_top(ei_table); rn; rn = srcdest_route_next(rn)) {
if (!rn->info)
continue;
info = rn->info;
+ const struct prefix *p, *src_p;
+
+ srcdest_rnode_prefixes(rn, &p, &src_p);
+
if (type == DEFAULT_ROUTE) {
- if (!is_default_prefix(&rn->p))
+ if (!is_default_prefix(p)
+ || (src_p && src_p->prefixlen)) {
continue;
+ }
} else {
if (info->origin != type)
continue;
}
- isis_redist_update_ext_reach(area, level, redist, &rn->p, info);
+ isis_redist_update_ext_reach(area, level, redist, p,
+ (struct prefix_ipv6 *)src_p, info);
}
}
@@ -472,14 +464,19 @@ static void isis_redist_unset(struct isis_area *area, int level, int family,
return;
}
- for (rn = route_top(er_table); rn; rn = route_next(rn)) {
+ for (rn = route_top(er_table); rn; rn = srcdest_route_next(rn)) {
if (!rn->info)
continue;
info = rn->info;
+ const struct prefix *p, *src_p;
+ srcdest_rnode_prefixes(rn, &p, &src_p);
+
if (type == DEFAULT_ROUTE) {
- if (!is_default_prefix(&rn->p))
+ if (!is_default_prefix(p)
+ || (src_p && src_p->prefixlen)) {
continue;
+ }
} else {
if (info->origin != type)
continue;
diff --git a/isisd/isis_redist.h b/isisd/isis_redist.h
index c12363d50..95f06f71e 100644
--- a/isisd/isis_redist.h
+++ b/isisd/isis_redist.h
@@ -42,13 +42,14 @@ struct isis_redist {
struct isis_area;
struct prefix;
+struct prefix_ipv6;
struct vty;
struct route_table *get_ext_reach(struct isis_area *area, int family,
int level);
-void isis_redist_add(int type, struct prefix *p, uint8_t distance,
- uint32_t metric);
-void isis_redist_delete(int type, struct prefix *p);
+void isis_redist_add(int type, struct prefix *p, struct prefix_ipv6 *src_p,
+ uint8_t distance, uint32_t metric);
+void isis_redist_delete(int type, struct prefix *p, struct prefix_ipv6 *src_p);
int isis_redist_config_write(struct vty *vty, struct isis_area *area,
int family);
void isis_redist_init(void);
diff --git a/isisd/isis_tlvs.c b/isisd/isis_tlvs.c
index 9b2aa7470..a433fcdb4 100644
--- a/isisd/isis_tlvs.c
+++ b/isisd/isis_tlvs.c
@@ -1912,6 +1912,11 @@ static void append_item(struct isis_item_list *dest, struct isis_item *item)
dest->count++;
}
+static struct isis_item *last_item(struct isis_item_list *list)
+{
+ return container_of(list->tail, struct isis_item, next);
+}
+
static int unpack_item(uint16_t mtid, enum isis_tlv_context context,
uint8_t tlv_type, uint8_t len, struct stream *s,
struct sbuf *log, void *dest, int indent)
@@ -3168,6 +3173,21 @@ void isis_tlvs_add_ipv6_reach(struct isis_tlvs *tlvs, uint16_t mtid,
append_item(l, (struct isis_item *)r);
}
+void isis_tlvs_add_ipv6_dstsrc_reach(struct isis_tlvs *tlvs, uint16_t mtid,
+ struct prefix_ipv6 *dest,
+ struct prefix_ipv6 *src,
+ uint32_t metric)
+{
+ isis_tlvs_add_ipv6_reach(tlvs, mtid, dest, metric);
+ struct isis_item_list *l = isis_get_mt_items(&tlvs->mt_ipv6_reach,
+ mtid);
+
+ struct isis_ipv6_reach *r = (struct isis_ipv6_reach*)last_item(l);
+ r->subtlvs = isis_alloc_subtlvs();
+ r->subtlvs->source_prefix = XCALLOC(MTYPE_ISIS_SUBTLV, sizeof(*src));
+ memcpy(r->subtlvs->source_prefix, src, sizeof(*src));
+}
+
void isis_tlvs_add_oldstyle_reach(struct isis_tlvs *tlvs, uint8_t *id,
uint8_t metric)
{
diff --git a/isisd/isis_tlvs.h b/isisd/isis_tlvs.h
index 98edbf14e..bd1fa3e67 100644
--- a/isisd/isis_tlvs.h
+++ b/isisd/isis_tlvs.h
@@ -313,6 +313,10 @@ void isis_tlvs_add_extended_ip_reach(struct isis_tlvs *tlvs,
struct prefix_ipv4 *dest, uint32_t metric);
void isis_tlvs_add_ipv6_reach(struct isis_tlvs *tlvs, uint16_t mtid,
struct prefix_ipv6 *dest, uint32_t metric);
+void isis_tlvs_add_ipv6_dstsrc_reach(struct isis_tlvs *tlvs, uint16_t mtid,
+ struct prefix_ipv6 *dest,
+ struct prefix_ipv6 *src,
+ uint32_t metric);
void isis_tlvs_add_oldstyle_reach(struct isis_tlvs *tlvs, uint8_t *id,
uint8_t metric);
void isis_tlvs_add_extended_reach(struct isis_tlvs *tlvs, uint16_t mtid,
diff --git a/isisd/isis_zebra.c b/isisd/isis_zebra.c
index ac640c5e4..b225af106 100644
--- a/isisd/isis_zebra.c
+++ b/isisd/isis_zebra.c
@@ -359,24 +359,23 @@ static int isis_zebra_read(int command, struct zclient *zclient,
if (zapi_route_decode(zclient->ibuf, &api) < 0)
return -1;
- /* we completely ignore srcdest routes for now. */
- if (CHECK_FLAG(api.message, ZAPI_MESSAGE_SRCPFX))
- return 0;
-
/*
* Avoid advertising a false default reachability. (A default
* route installed by IS-IS gets redistributed from zebra back
* into IS-IS causing us to start advertising default reachabity
* without this check)
*/
- if (api.prefix.prefixlen == 0 && api.type == ZEBRA_ROUTE_ISIS)
+ if (api.prefix.prefixlen == 0
+ && api.src_prefix.prefixlen == 0
+ && api.type == ZEBRA_ROUTE_ISIS) {
command = ZEBRA_REDISTRIBUTE_ROUTE_DEL;
+ }
if (command == ZEBRA_REDISTRIBUTE_ROUTE_ADD)
- isis_redist_add(api.type, &api.prefix, api.distance,
- api.metric);
+ isis_redist_add(api.type, &api.prefix, &api.src_prefix,
+ api.distance, api.metric);
else
- isis_redist_delete(api.type, &api.prefix);
+ isis_redist_delete(api.type, &api.prefix, &api.src_prefix);
return 0;
}