Skip to content

Commit

Permalink
isisd: added managed redistribution in ISIS
Browse files Browse the repository at this point in the history
1) added command "redistribute ipv4/ipv6 isis level-m into level-n route-map name"
in cli according to RFC5302
2) added adding prefixes with the best metric from the level-1 db to the level-2 db on l1_l2 end system

Signed-off-by: squirrelking57 <1248756005hfh@gmail.com>
  • Loading branch information
Sashhkaa committed Apr 13, 2024
1 parent 8cfa3b5 commit b3d817a
Show file tree
Hide file tree
Showing 14 changed files with 983 additions and 3 deletions.
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
Loading

0 comments on commit b3d817a

Please sign in to comment.