summaryrefslogtreecommitdiffstats
path: root/isisd/isis_redist.c
diff options
context:
space:
mode:
Diffstat (limited to 'isisd/isis_redist.c')
-rw-r--r--isisd/isis_redist.c103
1 files changed, 50 insertions, 53 deletions
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;