Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

added managed redistribution in ISIS #15617

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
107 changes: 107 additions & 0 deletions isisd/isis_cli.c
Original file line number Diff line number Diff line change
Expand Up @@ -1567,6 +1567,111 @@ int cli_cmp_isis_redistribute_table(const struct lyd_node *dnode1,
return table1 - table2;
}

/*
* XPath: /frr-isisd:isis/instance/route_leaking
*/
DEFPY_YANG(isis_leaking, isis_leaking_cmd,
"[no] redistribute <ipv4$ip isis$proto|ipv6$ip isis$proto>"
"<level-1|level-2>$level_from into <level-2|level-1>$level_to "
"[{metric (0-16777215)|route-map RMAP_NAME$route_map}]",
NO_STR LEAKING_STR
"Redistribute IPv4 routes\n"
"Intermediate System to Intermediate System (IS-IS)\n"
"Redistribute IPv6 routes\n"
"Intermediate System to Intermediate System (IS-IS)\n"
"Inter-area routes from level-1\n"
"Inter-area routes from level-2\n"
"Redistribute from level-m to level-n\n"
"Inter-area routes into level-1\n"
"Inter-area routes into level-2\n"
"Metric for redistributed routes\n"
"IS-IS default metric\n"
"Route map reference\n"
"Pointer to route-map entries\n")
{
if (no)
nb_cli_enqueue_change(vty, ".", NB_OP_DESTROY, NULL);
else {
nb_cli_enqueue_change(vty, ".", NB_OP_CREATE, NULL);
nb_cli_enqueue_change(vty, "./route-map",
route_map ? NB_OP_MODIFY : NB_OP_DESTROY,
route_map ? route_map : NULL);
nb_cli_enqueue_change(vty, "./metric", NB_OP_MODIFY,
metric_str ? metric_str : NULL);
}

return nb_cli_apply_changes(vty,
"./route_leaking/%s[protocol='%s'][level='%s']",
ip, proto, level_from);
}

static void vty_print_route_leaking(struct vty *vty,
const struct lyd_node *dnode,
bool show_defaults, const char *family,
bool table)
{
const char *level;
const char *protocol = NULL;
const char *routemap = NULL;

protocol = yang_dnode_get_string(dnode, "./protocol");
level = yang_dnode_get_string(dnode, "./level");

vty_out(vty, "redistribute %s %s ", family, protocol);
if (!strcmp(level, "level-1"))
vty_out(vty, "level-1 into level-2");
else
vty_out(vty, "level-2 into level-1");

if (show_defaults || !yang_dnode_is_default(dnode, "./metric"))
vty_out(vty, " metric %s",
yang_dnode_get_string(dnode, "%s", "./metric"));

if (yang_dnode_exists(dnode, "./route-map"))
routemap = yang_dnode_get_string(dnode, "./route-map");
if (routemap)
vty_out(vty, " route-map %s", routemap);
vty_out(vty, "\n");
}


void cli_show_isis_leaking_ipv4(struct vty *vty, const struct lyd_node *dnode,
bool show_defaults)
{
vty_print_route_leaking(vty, dnode, show_defaults, "ipv4", false);
}

void cli_show_isis_leaking_ipv6(struct vty *vty, const struct lyd_node *dnode,
bool show_defaults)
{
vty_print_route_leaking(vty, dnode, show_defaults, "ipv6", false);
}

void cli_show_isis_route_leaking_ipv4_table(struct vty *vty,
const struct lyd_node *dnode,
bool show_defaults)
{
/*TODO: support table redistribution between levels in IS-IS*/
vty_print_route_leaking(vty, dnode, show_defaults, "ipv4", true);
}

void cli_show_isis_route_leaking_ipv6_table(struct vty *vty,
const struct lyd_node *dnode,
bool show_defaults)
{
/*TODO: support table redistribution between levels in IS-IS*/
vty_print_route_leaking(vty, dnode, show_defaults, "ipv6", true);
}

int cli_cmp_isis_route_leaking_table(const struct lyd_node *dnode1,
const struct lyd_node *dnode2)
{
uint16_t table1 = yang_dnode_get_uint16(dnode1, "./table");
uint16_t table2 = yang_dnode_get_uint16(dnode2, "./table");

return table1 - table2;
}

/*
* XPath: /frr-isisd:isis/instance/multi-topology
*/
Expand Down Expand Up @@ -4018,6 +4123,8 @@ void isis_cli_init(void)
install_element(ISIS_NODE, &isis_redistribute_cmd);
install_element(ISIS_NODE, &isis_redistribute_table_cmd);

install_element(ISIS_NODE, &isis_leaking_cmd);

install_element(ISIS_NODE, &isis_topology_cmd);

install_element(ISIS_NODE, &isis_sr_enable_cmd);
Expand Down
9 changes: 9 additions & 0 deletions isisd/isis_constants.h
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,15 @@

#define LLC_LEN 3

/*
* implementation specific route-leaking values
*/

#define LEVEL2_TO_LEVEL1 4
#define LEVEL1_TO_LEVEL2 5
#define LVL_ISIS_LEAKING_1 0
#define LVL_ISIS_LEAKING_2 1

/* we need to be aware of the fact we are using ISO sized
* packets, using isomtu = mtu - LLC_LEN
*/
Expand Down
153 changes: 153 additions & 0 deletions isisd/isis_lsp.c
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
#include "isisd/isis_tx_queue.h"
#include "isisd/isis_nb.h"
#include "isisd/isis_flex_algo.h"
#include "isisd/isis_tlvs.h"

DEFINE_MTYPE_STATIC(ISISD, ISIS_LSP, "ISIS LSP");

Expand Down Expand Up @@ -1034,6 +1035,114 @@ static void lsp_build_ext_reach_ipv6(struct isis_lsp *lsp,
}
}

/*functions for adding routes from Level-1 DB to Level-2*/
static int check_prefix_before_add_ip(struct isis_extended_ip_reach *r,
struct isis_lsp *lsp_d)
{
for (struct isis_item *i = lsp_d->tlvs->extended_ip_reach.head; i;
i = i->next) {
struct isis_extended_ip_reach *rt =
(struct isis_extended_ip_reach *)i;
if (IPV4_ADDR_SAME(&r->prefix.prefix, &rt->prefix.prefix)) {
if ((r->metric > rt->metric) ||
(r->metric == rt->metric))
return 0;
}
}
return 1;
}

static int check_prefix_before_add_ipv6(struct isis_ipv6_reach *r,
struct isis_lsp *lsp_d)
{
for (struct isis_item *i = lsp_d->tlvs->ipv6_reach.head; i;
i = i->next) {
struct isis_ipv6_reach *rt = (struct isis_ipv6_reach *)i;

if (IPV6_ADDR_SAME(&r->prefix.prefix.s6_addr,
&rt->prefix.prefix.s6_addr)) {
if ((r->metric > rt->metric) ||
(r->metric == rt->metric))
return 0;
}
}
return 1;
}

static void add_prefix_from_l1_into_l2(struct isis_area *area,
struct isis_lsp *lsp_d,
struct isis_lsp *lsp_s)
{
for (struct isis_item *i = lsp_s->tlvs->extended_ip_reach.head; i;
i = i->next) {
struct isis_extended_ip_reach *ip_reach_s =
(struct isis_extended_ip_reach *)i;

if (check_prefix_before_add_ip(ip_reach_s, lsp_d))
copy_leaking_extended_ip_reach(lsp_d->tlvs,
(struct isis_item *)
ip_reach_s,
ip_reach_s->metric);
}

for (struct isis_item *i = lsp_s->tlvs->ipv6_reach.head; i;
i = i->next) {
struct isis_ipv6_reach *ipv6_reach_s =
(struct isis_ipv6_reach *)i;

if (check_prefix_before_add_ipv6(ipv6_reach_s, lsp_d))
copy_leaking_ipv6_reach(lsp_d->tlvs,
(struct isis_item *)ipv6_reach_s,
ipv6_reach_s->metric);
}
}

static void iteration_in_level1_lspdb(struct isis_area *area,
struct isis_lsp *lsp_d)
{
struct isis_lsp *lsp_s;
struct lspdb_head *head_s = &area->lspdb[ISIS_LEVEL1 - 1];

if (head_s) {
frr_each (lspdb, head_s, lsp_s)
add_prefix_from_l1_into_l2(area, lsp_d, lsp_s);
}
}

static void lsp_build_leaking_reach(struct isis_lsp *lsp,
struct isis_area *area, uint32_t metric)
{
struct listnode *node;
struct prefix_leaking *leaking;
struct isis_extended_ip_reach *ip_reach_s;
struct isis_ipv6_reach *ipv6_reach_s;

for (ALL_LIST_ELEMENTS_RO(area->leaking_list[lsp->level - 1], node,
leaking)) {
if (leaking->extended_ip_reach)
for (ALL_LIST_ELEMENTS_RO(leaking->extended_ip_reach,
node, ip_reach_s))
if (check_prefix_before_add_ip(ip_reach_s, lsp))
copy_leaking_extended_ip_reach(
lsp->tlvs,
(struct isis_item *)ip_reach_s,
metric);

if (leaking->ipv6_reach)
for (ALL_LIST_ELEMENTS_RO(leaking->ipv6_reach, node,
ipv6_reach_s))
if (check_prefix_before_add_ipv6(ipv6_reach_s,
lsp))
copy_leaking_ipv6_reach(lsp->tlvs,
(struct isis_item *)
ipv6_reach_s,
metric);
}

list_delete_all_node(area->leaking_list[LVL_ISIS_LEAKING_1]);
list_delete_all_node(area->leaking_list[LVL_ISIS_LEAKING_2]);
}

static void lsp_build_ext_reach(struct isis_lsp *lsp, struct isis_area *area)
{
lsp_build_ext_reach_ipv4(lsp, area);
Expand Down Expand Up @@ -1317,6 +1426,14 @@ static void lsp_build(struct isis_lsp *lsp, struct isis_area *area)
false, false, false);
}

struct isis_adjacency *adj;
bool adj_flag = false;

for (ALL_LIST_ELEMENTS_RO(area->adjacency_list, node, adj)) {
if (adj->level == IS_LEVEL_2)
adj_flag = true;
}

struct isis_circuit *circuit;
for (ALL_LIST_ELEMENTS_RO(area->circuit_list, node, circuit)) {
if (!circuit->interface)
Expand Down Expand Up @@ -1439,6 +1556,42 @@ static void lsp_build(struct isis_lsp *lsp, struct isis_area *area)

lsp_build_ext_reach(lsp, area);

struct listnode *node_redist;
struct isis_leaking *redist;

/*
* Flags required to track redistribution between layers
if lsp level 1, then you need to update lsp at level 2 if the router is 1_2 type
or there is redistribution to level 2
if lsp level 2, you need to update lsp at level 1 if there is redistribution to level 1

It is necessary to add all available prefixes from 1 to 2,
but if there is redistribution from 1 to 2, then only the hit prefixes are added
*/

bool redistribute_to_level_1 = false;
bool redistribute_to_level_2 = false;

for (ALL_LIST_ELEMENTS_RO(area->leaking_settings, node_redist, redist)) {
isis_iteration_in_lspdb(area, redist);
lsp_build_leaking_reach(lsp, area, redist->metric);
if (redist->level_to == LVL_ISIS_LEAKING_2)
redistribute_to_level_2 = true;
if (redist->level_to == LVL_ISIS_LEAKING_2)
redistribute_to_level_1 = true;
}

if (lsp->level == IS_LEVEL_1 &&
(area->is_type == IS_LEVEL_1_AND_2 || redistribute_to_level_2))
lsp_regenerate_schedule(area, IS_LEVEL_2, 0);

if (lsp->level == IS_LEVEL_2 && redistribute_to_level_1)
lsp_regenerate_schedule(area, IS_LEVEL_1, 0);

if (!redistribute_to_level_2 && adj_flag && lsp->level == IS_LEVEL_2 &&
area->is_type == IS_LEVEL_1_AND_2 && lsp->hdr.lsp_bits != LSPBIT_ATT)
iteration_in_level1_lspdb(area, lsp);

struct isis_tlvs *tlvs = lsp->tlvs;
lsp->tlvs = NULL;

Expand Down
58 changes: 58 additions & 0 deletions isisd/isis_nb.c
Original file line number Diff line number Diff line change
Expand Up @@ -453,6 +453,64 @@ const struct frr_yang_module_info frr_isisd_info = {
.modify = isis_instance_redistribute_ipv6_metric_modify,
},
},
{
.xpath = "/frr-isisd:isis/instance/route_leaking/ipv4",
.cbs = {
.apply_finish = leaking_ipv4_apply_finish,
.cli_show = cli_show_isis_leaking_ipv4,
.create = isis_instance_leaking_ipv4_create,
.destroy = isis_instance_leaking_ipv4_destroy,
},
},
{
.xpath = "/frr-isisd:isis/instance/route_leaking/ipv4/route-map",
.cbs = {
.destroy = isis_instance_route_leaking_ipv4_route_map_destroy,
.modify = isis_instance_route_leaking_ipv4_route_map_modify,
},
},
{
.xpath = "/frr-isisd:isis/instance/route_leaking/ipv4/metric",
.cbs = {
.modify = isis_instance_route_leaking_ipv4_metric_modify,
},
},
{
.xpath = "/frr-isisd:isis/instance/route_leaking/ipv6",
.cbs = {
.apply_finish = leaking_ipv6_apply_finish,
.cli_show = cli_show_isis_leaking_ipv6,
.create = isis_instance_leaking_ipv6_create,
.destroy = isis_instance_leaking_ipv6_destroy,
},
},
{
.xpath = "/frr-isisd:isis/instance/route_leaking/ipv6/route-map",
.cbs = {
.destroy = isis_instance_route_leaking_ipv6_route_map_destroy,
.modify = isis_instance_route_leaking_ipv6_route_map_modify,
},
},
{
.xpath = "/frr-isisd:isis/instance/route_leaking/ipv6/metric",
.cbs = {
.modify = isis_instance_route_leaking_ipv6_metric_modify,
},
},
{
.xpath = "/frr-isisd:isis/instance/redistribute/ipv4/level_from",
.cbs = {
.destroy = isis_instance_route_leaking_ipv6_route_map_destroy,
.modify = isis_instance_route_leaking_ipv6_metric_modify,
},
},
{
.xpath = "/frr-isisd:isis/instance/redistribute/ipv6/level_from",
.cbs = {
.destroy = isis_instance_route_leaking_ipv6_route_map_destroy,
.modify = isis_instance_route_leaking_ipv6_metric_modify,
},
},
{
.xpath = "/frr-isisd:isis/instance/multi-topology/ipv4-multicast",
.cbs = {
Expand Down