From 2150647069903840ef76353a5085eb5afc96cfaf Mon Sep 17 00:00:00 2001 From: Philippe Guibert Date: Mon, 3 Jul 2023 17:15:05 +0200 Subject: [PATCH] isisd: add redistribute table identifier in nb configuration The yang model does not handle the table identifier in IS-IS. For each redistributed each address family, a new list of table elements is added to store the table identifier to redistribute, and also the optional metric and route-map values for each table identifier. Signed-off-by: Philippe Guibert --- doc/user/isisd.rst | 5 ++ isisd/isis_cli.c | 128 +++++++++++++++++++++++++++++++++++++---- isisd/isis_nb.c | 46 +++++++++++++++ isisd/isis_nb.h | 19 ++++++ isisd/isis_nb_config.c | 51 ++++++++++++++++ isisd/isis_redist.c | 47 +++++++++++++++ isisd/isis_redist.h | 13 +++++ yang/frr-isisd.yang | 51 +++++++++++++++- 8 files changed, 345 insertions(+), 15 deletions(-) diff --git a/doc/user/isisd.rst b/doc/user/isisd.rst index 570b8bd182..83fc2e0281 100644 --- a/doc/user/isisd.rst +++ b/doc/user/isisd.rst @@ -166,6 +166,11 @@ flavors (local LFA, Remote LFA and TI-LFA). Configure a prefix-list to select eligible PQ nodes for remote LFA backups (valid for all protected interfaces). +.. clicmd:: redistribute table (1-65535) [metric (0-16777215)|route-map WORD] + + Redistribute routes from a given routing table into the given ISIS + level database. + .. _isis-region: ISIS region diff --git a/isisd/isis_cli.c b/isisd/isis_cli.c index 7c7a8d2389..6f53ab479f 100644 --- a/isisd/isis_cli.c +++ b/isisd/isis_cli.c @@ -1430,20 +1430,99 @@ DEFPY_YANG(isis_redistribute, isis_redistribute_cmd, level); } -static void vty_print_redistribute(struct vty *vty, - const struct lyd_node *dnode, - bool show_defaults, const char *family) -{ - const char *level = yang_dnode_get_string(dnode, "./level"); - const char *protocol = yang_dnode_get_string(dnode, "./protocol"); +/* + * XPath: /frr-isisd:isis/instance/redistribute/table + */ +DEFPY_YANG(isis_redistribute_table, isis_redistribute_table_cmd, + "[no] redistribute $ip table (1-65535)$table" + "$level [{metric (0-16777215)|route-map WORD}]", + NO_STR REDIST_STR "Redistribute IPv4 routes\n" + "Redistribute IPv6 routes\n" + "Non-main Kernel Routing Table\n" + "Table Id\n" + "Redistribute into level-1\n" + "Redistribute into level-2\n" + "Metric for redistributed routes\n" + "IS-IS default metric\n" + "Route map reference\n" + "Pointer to route-map entries\n") +{ + struct isis_redist_table_present_args rtda = {}; + char xpath[XPATH_MAXLEN]; + char xpath_entry[XPATH_MAXLEN + 128]; + int rv; + + rtda.rtda_table = table_str; + rtda.rtda_ip = ip; + rtda.rtda_level = level; - vty_out(vty, " redistribute %s %s %s", family, protocol, level); + if (no) { + if (!isis_redist_table_is_present(vty, &rtda)) + return CMD_WARNING_CONFIG_FAILED; + + snprintf(xpath, sizeof(xpath), "./table[table='%s']", table_str); + nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); + rv = nb_cli_apply_changes(vty, + "./redistribute/%s[protocol='table'][level='%s']", + ip, level); + if (rv == CMD_SUCCESS) { + if (isis_redist_table_get_first(vty, &rtda) > 0) + return CMD_SUCCESS; + nb_cli_enqueue_change(vty, "./table", NB_OP_DESTROY, + NULL); + nb_cli_apply_changes(vty, + "./redistribute/%s[protocol='table'][level='%s']", + ip, level); + } + return CMD_SUCCESS; + } + if (isis_redist_table_is_present(vty, &rtda)) + return CMD_SUCCESS; + + snprintf(xpath, sizeof(xpath), "./table[table='%s']", table_str); + nb_cli_enqueue_change(vty, ".", NB_OP_CREATE, NULL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + snprintf(xpath_entry, sizeof(xpath_entry), "%s/route-map", xpath); + nb_cli_enqueue_change(vty, xpath_entry, + route_map ? NB_OP_MODIFY : NB_OP_DESTROY, + route_map ? route_map : NULL); + snprintf(xpath_entry, sizeof(xpath_entry), "%s/metric", xpath); + nb_cli_enqueue_change(vty, xpath_entry, NB_OP_MODIFY, + metric_str ? metric_str : NULL); + return nb_cli_apply_changes(vty, + "./redistribute/%s[protocol='table'][level='%s']", + ip, level); +} + +static void vty_print_redistribute(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; + uint16_t tableid; + + if (table) { + level = yang_dnode_get_string(dnode, "../level"); + tableid = yang_dnode_get_uint16(dnode, "./table"); + vty_out(vty, " redistribute %s table %d ", family, tableid); + } else { + protocol = yang_dnode_get_string(dnode, "./protocol"); + if (!table && strmatch(protocol, "table")) + return; + level = yang_dnode_get_string(dnode, "./level"); + vty_out(vty, " redistribute %s %s ", family, protocol); + } + vty_out(vty, "%s", level); if (show_defaults || !yang_dnode_is_default(dnode, "./metric")) vty_out(vty, " metric %s", - yang_dnode_get_string(dnode, "./metric")); + yang_dnode_get_string(dnode, "%s", "./metric")); + if (yang_dnode_exists(dnode, "./route-map")) - vty_out(vty, " route-map %s", - yang_dnode_get_string(dnode, "./route-map")); + routemap = yang_dnode_get_string(dnode, "./route-map"); + if (routemap) + vty_out(vty, " route-map %s", routemap); vty_out(vty, "\n"); } @@ -1451,13 +1530,37 @@ void cli_show_isis_redistribute_ipv4(struct vty *vty, const struct lyd_node *dnode, bool show_defaults) { - vty_print_redistribute(vty, dnode, show_defaults, "ipv4"); + vty_print_redistribute(vty, dnode, show_defaults, "ipv4", false); } + void cli_show_isis_redistribute_ipv6(struct vty *vty, const struct lyd_node *dnode, bool show_defaults) { - vty_print_redistribute(vty, dnode, show_defaults, "ipv6"); + vty_print_redistribute(vty, dnode, show_defaults, "ipv6", false); +} + +void cli_show_isis_redistribute_ipv4_table(struct vty *vty, + const struct lyd_node *dnode, + bool show_defaults) +{ + vty_print_redistribute(vty, dnode, show_defaults, "ipv4", true); +} + +void cli_show_isis_redistribute_ipv6_table(struct vty *vty, + const struct lyd_node *dnode, + bool show_defaults) +{ + vty_print_redistribute(vty, dnode, show_defaults, "ipv6", true); +} + +int cli_cmp_isis_redistribute_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; } /* @@ -3681,6 +3784,7 @@ void isis_cli_init(void) install_element(ISIS_NODE, &isis_default_originate_cmd); install_element(ISIS_NODE, &isis_redistribute_cmd); + install_element(ISIS_NODE, &isis_redistribute_table_cmd); install_element(ISIS_NODE, &isis_topology_cmd); diff --git a/isisd/isis_nb.c b/isisd/isis_nb.c index 6da8fa2d28..c81412d24a 100644 --- a/isisd/isis_nb.c +++ b/isisd/isis_nb.c @@ -381,6 +381,29 @@ const struct frr_yang_module_info frr_isisd_info = { }, { .xpath = "/frr-isisd:isis/instance/redistribute/ipv4/metric", + .cbs = { + .destroy = isis_instance_redistribute_ipv4_metric_destroy, + .modify = isis_instance_redistribute_ipv4_metric_modify, + }, + }, + { + .xpath = "/frr-isisd:isis/instance/redistribute/ipv4/table", + .cbs = { + .cli_show = cli_show_isis_redistribute_ipv4_table, + .cli_cmp = cli_cmp_isis_redistribute_table, + .create = isis_instance_redistribute_ipv4_table_create, + .destroy = isis_instance_redistribute_ipv4_table_destroy, + }, + }, + { + .xpath = "/frr-isisd:isis/instance/redistribute/ipv4/table/route-map", + .cbs = { + .destroy = isis_instance_redistribute_ipv4_route_map_destroy, + .modify = isis_instance_redistribute_ipv4_route_map_modify, + }, + }, + { + .xpath = "/frr-isisd:isis/instance/redistribute/ipv4/table/metric", .cbs = { .modify = isis_instance_redistribute_ipv4_metric_modify, }, @@ -403,6 +426,29 @@ const struct frr_yang_module_info frr_isisd_info = { }, { .xpath = "/frr-isisd:isis/instance/redistribute/ipv6/metric", + .cbs = { + .destroy = isis_instance_redistribute_ipv6_metric_destroy, + .modify = isis_instance_redistribute_ipv6_metric_modify, + }, + }, + { + .xpath = "/frr-isisd:isis/instance/redistribute/ipv6/table", + .cbs = { + .cli_show = cli_show_isis_redistribute_ipv6_table, + .cli_cmp = cli_cmp_isis_redistribute_table, + .create = isis_instance_redistribute_ipv6_table_create, + .destroy = isis_instance_redistribute_ipv6_table_destroy, + }, + }, + { + .xpath = "/frr-isisd:isis/instance/redistribute/ipv6/table/route-map", + .cbs = { + .destroy = isis_instance_redistribute_ipv6_route_map_destroy, + .modify = isis_instance_redistribute_ipv6_route_map_modify, + }, + }, + { + .xpath = "/frr-isisd:isis/instance/redistribute/ipv6/table/metric", .cbs = { .modify = isis_instance_redistribute_ipv6_metric_modify, }, diff --git a/isisd/isis_nb.h b/isisd/isis_nb.h index 13efa36d78..3b8ddca4f8 100644 --- a/isisd/isis_nb.h +++ b/isisd/isis_nb.h @@ -121,6 +121,11 @@ int isis_instance_redistribute_ipv4_route_map_destroy( struct nb_cb_destroy_args *args); int isis_instance_redistribute_ipv4_metric_modify( struct nb_cb_modify_args *args); +int isis_instance_redistribute_ipv4_metric_destroy( + struct nb_cb_destroy_args *args); +int isis_instance_redistribute_ipv4_table_create(struct nb_cb_create_args *args); +int isis_instance_redistribute_ipv4_table_destroy( + struct nb_cb_destroy_args *args); int isis_instance_redistribute_ipv6_create(struct nb_cb_create_args *args); int isis_instance_redistribute_ipv6_destroy(struct nb_cb_destroy_args *args); int isis_instance_redistribute_ipv6_route_map_modify( @@ -129,6 +134,11 @@ int isis_instance_redistribute_ipv6_route_map_destroy( struct nb_cb_destroy_args *args); int isis_instance_redistribute_ipv6_metric_modify( struct nb_cb_modify_args *args); +int isis_instance_redistribute_ipv6_metric_destroy( + struct nb_cb_destroy_args *args); +int isis_instance_redistribute_ipv6_table_create(struct nb_cb_create_args *args); +int isis_instance_redistribute_ipv6_table_destroy( + struct nb_cb_destroy_args *args); int isis_instance_multi_topology_ipv4_multicast_create( struct nb_cb_create_args *args); int isis_instance_multi_topology_ipv4_multicast_destroy( @@ -587,6 +597,12 @@ void cli_show_isis_redistribute_ipv6(struct vty *vty, void cli_show_isis_mt_ipv4_multicast(struct vty *vty, const struct lyd_node *dnode, bool show_defaults); +void cli_show_isis_redistribute_ipv4_table(struct vty *vty, + const struct lyd_node *dnode, + bool show_defaults); +void cli_show_isis_redistribute_ipv6_table(struct vty *vty, + const struct lyd_node *dnode, + bool show_defaults); void cli_show_isis_mt_ipv4_mgmt(struct vty *vty, const struct lyd_node *dnode, bool show_defaults); void cli_show_isis_mt_ipv6_unicast(struct vty *vty, @@ -742,6 +758,9 @@ void isis_notif_seqno_skipped(const struct isis_circuit *circuit, const uint8_t *lsp_id); void isis_notif_own_lsp_purge(const struct isis_circuit *circuit, const uint8_t *lsp_id); +/* cmp */ +int cli_cmp_isis_redistribute_table(const struct lyd_node *dnode1, + const struct lyd_node *dnode2); /* We also declare hook for every notification */ diff --git a/isisd/isis_nb_config.c b/isisd/isis_nb_config.c index 8a111b301d..278d4a8d85 100644 --- a/isisd/isis_nb_config.c +++ b/isisd/isis_nb_config.c @@ -1281,6 +1281,7 @@ int isis_instance_redistribute_ipv4_destroy(struct nb_cb_destroy_args *args) /* * XPath: /frr-isisd:isis/instance/redistribute/ipv4/route-map + * XPath: /frr-isisd:isis/instance/redistribute/ipv4/table/route-map */ int isis_instance_redistribute_ipv4_route_map_modify( struct nb_cb_modify_args *args) @@ -1298,6 +1299,7 @@ int isis_instance_redistribute_ipv4_route_map_destroy( /* * XPath: /frr-isisd:isis/instance/redistribute/ipv4/metric + * XPath: /frr-isisd:isis/instance/redistribute/ipv4/table/metric */ int isis_instance_redistribute_ipv4_metric_modify( struct nb_cb_modify_args *args) @@ -1306,6 +1308,28 @@ int isis_instance_redistribute_ipv4_metric_modify( return NB_OK; } +int isis_instance_redistribute_ipv4_metric_destroy(struct nb_cb_destroy_args *args) +{ + /* It's all done by redistribute_apply_finish */ + return NB_OK; +} + +/* + * XPath: /frr-isisd:isis/instance/redistribute/ipv4/table + */ +int isis_instance_redistribute_ipv4_table_create(struct nb_cb_create_args *args) +{ + if (args->event != NB_EV_APPLY) + return NB_OK; + + /* TODO */ + return NB_OK; +} +int isis_instance_redistribute_ipv4_table_destroy(struct nb_cb_destroy_args *args) +{ + return NB_OK; +} + /* * XPath: /frr-isisd:isis/instance/redistribute/ipv6 */ @@ -1358,6 +1382,33 @@ int isis_instance_redistribute_ipv6_metric_modify( return NB_OK; } +int isis_instance_redistribute_ipv6_metric_destroy(struct nb_cb_destroy_args *args) +{ + /* It's all done by redistribute_apply_finish */ + return NB_OK; +} + +/* + * XPath: /frr-isisd:isis/instance/redistribute/ipv6/table + */ +int isis_instance_redistribute_ipv6_table_create(struct nb_cb_create_args *args) +{ + if (args->event != NB_EV_APPLY) + return NB_OK; + + /* TODO */ + return NB_OK; +} + +int isis_instance_redistribute_ipv6_table_destroy(struct nb_cb_destroy_args *args) +{ + if (args->event != NB_EV_APPLY) + return NB_OK; + + /* TODO */ + return NB_OK; +} + /* * XPath: /frr-isisd:isis/instance/multi-topology/ipv4-multicast */ diff --git a/isisd/isis_redist.c b/isisd/isis_redist.c index 6a822f02fe..2b3facc436 100644 --- a/isisd/isis_redist.c +++ b/isisd/isis_redist.c @@ -206,6 +206,53 @@ static void isis_redist_ensure_default(struct isis *isis, int family) info->metric = MAX_WIDE_PATH_METRIC; } +static int _isis_redist_table_is_present(const struct lyd_node *dnode, void *arg) +{ + struct isis_redist_table_present_args *rtda = arg; + + /* This entry is the caller, so skip it. */ + if (yang_dnode_get_uint16(dnode, "table") != + (uint16_t)atoi(rtda->rtda_table)) + return YANG_ITER_CONTINUE; + + /* found */ + rtda->rtda_found = true; + return YANG_ITER_CONTINUE; +} + +static int _isis_redist_table_get_first_cb(const struct lyd_node *dnode, + void *arg) +{ + uint16_t *table = arg; + + *table = yang_dnode_get_uint16(dnode, "table"); + return YANG_ITER_STOP; +} + +uint16_t isis_redist_table_get_first(const struct vty *vty, + struct isis_redist_table_present_args *rtda) +{ + uint16_t table = 0; + + yang_dnode_iterate(_isis_redist_table_get_first_cb, &table, + vty->candidate_config->dnode, + "%s/redistribute/%s[protocol='table'][level='%s']/table", + VTY_CURR_XPATH, rtda->rtda_ip, rtda->rtda_level); + return table; +} + +bool isis_redist_table_is_present(const struct vty *vty, + struct isis_redist_table_present_args *rtda) +{ + rtda->rtda_found = false; + yang_dnode_iterate(_isis_redist_table_is_present, rtda, + vty->candidate_config->dnode, + "%s/redistribute/%s[protocol='table'][level='%s']/table", + VTY_CURR_XPATH, rtda->rtda_ip, rtda->rtda_level); + + return rtda->rtda_found; +} + /* Handle notification about route being added */ void isis_redist_add(struct isis *isis, int type, struct prefix *p, struct prefix_ipv6 *src_p, uint8_t distance, diff --git a/isisd/isis_redist.h b/isisd/isis_redist.h index ae5ec2b3b3..eb82f3083a 100644 --- a/isisd/isis_redist.h +++ b/isisd/isis_redist.h @@ -28,6 +28,14 @@ struct isis_redist { struct route_map *map; }; +struct isis_redist_table_present_args { + /* from filter.h, struct acl_dup_args */ + const char *rtda_ip; + const char *rtda_level; + const char *rtda_table; + bool rtda_found; +}; + struct isis; struct isis_area; struct prefix; @@ -53,4 +61,9 @@ void isis_redist_set(struct isis_area *area, int level, int family, int type, void isis_redist_unset(struct isis_area *area, int level, int family, int type); void isis_redist_free(struct isis *isis); + +bool isis_redist_table_is_present(const struct vty *vty, + struct isis_redist_table_present_args *rtda); +uint16_t isis_redist_table_get_first(const struct vty *vty, + struct isis_redist_table_present_args *rtda); #endif diff --git a/yang/frr-isisd.yang b/yang/frr-isisd.yang index ae69d53ccc..478d058c19 100644 --- a/yang/frr-isisd.yang +++ b/yang/frr-isisd.yang @@ -1495,9 +1495,32 @@ module frr-isisd { "IS-IS level into which the routes should be redistributed."; } - uses redistribute-attributes; - } + choice protocol-type { + case protocol-table { + when "./protocol = \"table\""; + list table { + key "table"; + when "../protocol = \"table\""; + description + "Routing table number"; + + leaf table { + type uint16 { + range "1..65535"; + } + description + "Routing table number."; + } + + uses redistribute-attributes; + } + } + case protocol-other { + uses redistribute-attributes; + } + } + } list ipv6 { key "protocol level"; description @@ -1516,7 +1539,29 @@ module frr-isisd { "IS-IS level into which the routes should be redistributed."; } - uses redistribute-attributes; + choice protocol-type { + case protocol-table { + when "./protocol = \"table\""; + list table { + key "table"; + when "../protocol = \"table\""; + + leaf table { + type uint16 { + range "1..65535"; + } + description + "Routing table number."; + } + + uses redistribute-attributes; + } + } + case protocol-other { + uses redistribute-attributes; + } + } + } } -- 2.39.5