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

isisd: added prefix propogation/leaking #15863

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
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
164 changes: 164 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,140 @@ static void lsp_build_ext_reach_ipv6(struct isis_lsp *lsp,
}
}

/*
* Need to check the match of same prefixes in the database/
* prefix with a lower metric
*/

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;
}

/*Functions for adding routes from Level-1 DB to Level-2*/
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;
bool up_down_flag = 0;

if (check_prefix_before_add_ip(ip_reach_s, lsp_d)) {
struct isis_extended_ip_reach *ip_reach_d = copy_extended_ip_reach((struct isis_item *)
ip_reach_s,
ip_reach_s->metric, up_down_flag);
append_extended_ip_reach(lsp_d->tlvs,
(struct isis_item *)ip_reach_d);
}
}

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;
bool up_down_flag = 0;

if (check_prefix_before_add_ipv6(ipv6_reach_s, lsp_d)) {
struct isis_ipv6_reach* ipv6_reach_d = copy_ipv6_reach((struct isis_item *)ipv6_reach_s,
ipv6_reach_s->metric, up_down_flag);
append_ipv6_reach(lsp_d->tlvs, (struct isis_item *)ipv6_reach_d);
}
}
}

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)
if (lsp_s->own_lsp == 0)
add_prefix_from_l1_into_l2(area, lsp_d, lsp_s);
}
}

static void lsp_free_redist_reach(struct isis_area* area)
{
list_delete_all_node(area->levels_redist_list[LVL_ISIS_LEAKING_1]);
list_delete_all_node(area->levels_redist_list[LVL_ISIS_LEAKING_2]);
}

static void lsp_build_ip_redist_reach(struct isis_area *area, struct isis_lsp *lsp)
{
struct listnode *node;
struct levels_redist_match *leaking;
struct isis_extended_ip_reach *ip_reach_s;

for (ALL_LIST_ELEMENTS_RO(area->levels_redist_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))
append_extended_ip_reach(lsp->tlvs,
(struct isis_item *)ip_reach_s);
}
}
}

static void lsp_build_ipv6_redist_reach(struct isis_area *area, struct isis_lsp *lsp)
{
struct listnode *node;
struct levels_redist_match *leaking;
struct isis_ipv6_reach *ipv6_reach_s;

for (ALL_LIST_ELEMENTS_RO(area->levels_redist_list[lsp->level - 1], node,
leaking)) {
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))
append_ipv6_reach(lsp->tlvs, (struct isis_item *)ipv6_reach_s);
}
}
}

static void lsp_build_redist_reach(struct isis_area *area, struct isis_lsp *lsp)
{
lsp_build_ip_redist_reach(area, lsp);
lsp_build_ipv6_redist_reach(area, lsp);
lsp_free_redist_reach(area);
}

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 +1452,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 +1582,27 @@ static void lsp_build(struct isis_lsp *lsp, struct isis_area *area)

lsp_build_ext_reach(lsp, area);

struct listnode *node_redist;
struct isis_levels_redist *redist;
bool propogation_flag = true;

/*
* Flag required to track redistribution between layers
* It is necessary to add all available prefixes from 1 to 2,
* but if there is redistribution from 1 to 2,
* then only the matched prefixes are added
*/

for (ALL_LIST_ELEMENTS_RO(area->levels_redist_sett, node_redist, redist)) {
isis_iteration_in_lspdb(area, redist);
lsp_build_redist_reach(area, lsp);
if (redist->level_to == LVL_ISIS_LEAKING_2) propogation_flag = false;
}

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

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

Expand Down
3 changes: 2 additions & 1 deletion isisd/isis_lsp.h
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,8 @@ void lsp_purge_non_exist(int level, struct isis_lsp_hdr *hdr,
memcpy((I), isis->sysid, ISIS_SYS_ID_LEN); \
(I)[ISIS_SYS_ID_LEN] = 0; \
(I)[ISIS_SYS_ID_LEN + 1] = 0
void iteration_in_level1_lspdb(struct isis_area *area,
struct isis_lsp *lsp_d);
int lsp_id_cmp(uint8_t *id1, uint8_t *id2);
int lsp_compare(char *areatag, struct isis_lsp *lsp, uint32_t seqno,
uint16_t checksum, uint16_t rem_lifetime);
Expand Down Expand Up @@ -149,5 +151,4 @@ int isis_lsp_iterate_is_reach(struct isis_lsp *lsp, uint16_t mtid,
void _lsp_flood(struct isis_lsp *lsp, struct isis_circuit *circuit,
const char *func, const char *file, int line);
void lsp_init(void);

#endif /* ISIS_LSP */