diff options
author | Christian Franke <chris@opensourcerouting.org> | 2018-07-22 21:49:02 +0200 |
---|---|---|
committer | Christian Franke <chris@opensourcerouting.org> | 2018-08-03 13:25:39 +0200 |
commit | d43d2df5f3b63a4d364bd1136a246dd74647913c (patch) | |
tree | 99a128870f0ccd0e65d6981430fc061a2da1fa57 /isisd | |
parent | isisd: add debug message if adjacency is ignored because IP is unusable (diff) | |
download | frr-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.c | 21 | ||||
-rw-r--r-- | isisd/isis_mt.c | 12 | ||||
-rw-r--r-- | isisd/isis_mt.h | 8 | ||||
-rw-r--r-- | isisd/isis_redist.c | 103 | ||||
-rw-r--r-- | isisd/isis_redist.h | 7 | ||||
-rw-r--r-- | isisd/isis_tlvs.c | 20 | ||||
-rw-r--r-- | isisd/isis_tlvs.h | 4 | ||||
-rw-r--r-- | isisd/isis_zebra.c | 15 |
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; } |