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) +/* + * 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") { - const char *level = yang_dnode_get_string(dnode, "./level"); - const char *protocol = yang_dnode_get_string(dnode, "./protocol"); + struct isis_redist_table_present_args rtda = {}; + char xpath[XPATH_MAXLEN]; + char xpath_entry[XPATH_MAXLEN + 128]; + int rv; - vty_out(vty, " redistribute %s %s %s", family, protocol, level); + rtda.rtda_table = table_str; + rtda.rtda_ip = ip; + rtda.rtda_level = 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..a3d8896e4f 100644 --- a/isisd/isis_nb_config.c +++ b/isisd/isis_nb_config.c @@ -1088,7 +1088,7 @@ void default_info_origin_apply_finish(const struct lyd_node *dnode, int family) routemap = yang_dnode_get_string(dnode, "./route-map"); isis_redist_set(area, level, family, DEFAULT_ROUTE, metric, routemap, - originate_type); + originate_type, 0); } void default_info_origin_ipv4_apply_finish(struct nb_cb_apply_finish_args *args) @@ -1119,7 +1119,7 @@ int isis_instance_default_information_originate_ipv4_destroy( area = nb_running_get_entry(args->dnode, NULL, true); level = yang_dnode_get_enum(args->dnode, "./level"); - isis_redist_unset(area, level, AF_INET, DEFAULT_ROUTE); + isis_redist_unset(area, level, AF_INET, DEFAULT_ROUTE, 0); return NB_OK; } @@ -1182,7 +1182,7 @@ int isis_instance_default_information_originate_ipv6_destroy( area = nb_running_get_entry(args->dnode, NULL, true); level = yang_dnode_get_enum(args->dnode, "./level"); - isis_redist_unset(area, level, AF_INET6, DEFAULT_ROUTE); + isis_redist_unset(area, level, AF_INET6, DEFAULT_ROUTE, 0); return NB_OK; } @@ -1244,7 +1244,7 @@ void redistribute_apply_finish(const struct lyd_node *dnode, int family) if (yang_dnode_exists(dnode, "./route-map")) routemap = yang_dnode_get_string(dnode, "./route-map"); - isis_redist_set(area, level, family, type, metric, routemap, 0); + isis_redist_set(area, level, family, type, metric, routemap, 0, 0); } void redistribute_ipv4_apply_finish(struct nb_cb_apply_finish_args *args) @@ -1274,13 +1274,14 @@ int isis_instance_redistribute_ipv4_destroy(struct nb_cb_destroy_args *args) area = nb_running_get_entry(args->dnode, NULL, true); level = yang_dnode_get_enum(args->dnode, "./level"); type = yang_dnode_get_enum(args->dnode, "./protocol"); - isis_redist_unset(area, level, AF_INET, type); + isis_redist_unset(area, level, AF_INET, type, 0); return NB_OK; } /* * 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,58 @@ 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) +{ + uint16_t table; + int type, level; + unsigned long metric = 0; + const char *routemap = NULL; + struct isis_area *area; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + type = yang_dnode_get_enum(args->dnode, "../protocol"); + level = yang_dnode_get_enum(args->dnode, "../level"); + area = nb_running_get_entry(args->dnode, "../.", true); + + if (yang_dnode_exists(args->dnode, "./metric")) + metric = yang_dnode_get_uint32(args->dnode, "./metric"); + if (yang_dnode_exists(args->dnode, "./route-map")) + routemap = yang_dnode_get_string(args->dnode, "./route-map"); + + table = yang_dnode_get_uint16(args->dnode, "./table"); + isis_redist_set(area, level, AF_INET, type, metric, routemap, 0, table); + + return NB_OK; +} +int isis_instance_redistribute_ipv4_table_destroy(struct nb_cb_destroy_args *args) +{ + struct isis_area *area; + int level, type; + uint16_t table; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + area = nb_running_get_entry(args->dnode, "../.", true); + level = yang_dnode_get_enum(args->dnode, "../level"); + type = yang_dnode_get_enum(args->dnode, "../protocol"); + table = yang_dnode_get_uint16(args->dnode, "./table"); + isis_redist_unset(area, level, AF_INET, type, table); + + return NB_OK; +} + /* * XPath: /frr-isisd:isis/instance/redistribute/ipv6 */ @@ -1326,7 +1380,7 @@ int isis_instance_redistribute_ipv6_destroy(struct nb_cb_destroy_args *args) area = nb_running_get_entry(args->dnode, NULL, true); level = yang_dnode_get_enum(args->dnode, "./level"); type = yang_dnode_get_enum(args->dnode, "./protocol"); - isis_redist_unset(area, level, AF_INET6, type); + isis_redist_unset(area, level, AF_INET6, type, 0); return NB_OK; } @@ -1358,6 +1412,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..2cb08db27b 100644 --- a/isisd/isis_redist.c +++ b/isisd/isis_redist.c @@ -31,6 +31,7 @@ DEFINE_MTYPE_STATIC(ISISD, ISIS_EXT_ROUTE, "ISIS redistributed route"); DEFINE_MTYPE_STATIC(ISISD, ISIS_EXT_INFO, "ISIS redistributed route info"); DEFINE_MTYPE_STATIC(ISISD, ISIS_RMAP_NAME, "ISIS redistribute route-map name"); +DEFINE_MTYPE_STATIC(ISISD, ISIS_REDISTRIBUTE, "ISIS redistribute"); static int redist_protocol(int family) { @@ -61,12 +62,43 @@ static struct route_table *get_ext_info(struct isis *i, int family) return i->ext_info[protocol]; } -static struct isis_redist *get_redist_settings(struct isis_area *area, - int family, int type, int level) +static struct isis_redist *isis_redist_lookup(struct isis_area *area, + int family, int type, int level, + uint16_t table) { int protocol = redist_protocol(family); + struct listnode *node; + struct isis_redist *red; - return &area->redist_settings[protocol][type][level - 1]; + if (area->redist_settings[protocol][type][level - 1]) { + for (ALL_LIST_ELEMENTS_RO(area->redist_settings[protocol][type] + [level - 1], + node, red)) + if (red->table == table) + return red; + } + return NULL; +} + +static struct isis_redist *isis_redist_get(struct isis_area *area, int family, + int type, int level, uint16_t table) +{ + struct isis_redist *red; + int protocol; + + red = isis_redist_lookup(area, family, type, level, table); + if (red) + return red; + + protocol = redist_protocol(family); + if (area->redist_settings[protocol][type][level - 1] == NULL) + area->redist_settings[protocol][type][level - 1] = list_new(); + + red = XCALLOC(MTYPE_ISIS_REDISTRIBUTE, sizeof(struct isis_redist)); + red->table = table; + + listnode_add(area->redist_settings[protocol][type][level - 1], red); + return red; } struct route_table *get_ext_reach(struct isis_area *area, int family, int level) @@ -206,10 +238,57 @@ 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, - uint32_t metric, const route_tag_t tag) + uint32_t metric, const route_tag_t tag, uint16_t table) { int family = p->family; struct route_table *ei_table = get_ext_info(isis, family); @@ -249,8 +328,9 @@ void isis_redist_add(struct isis *isis, int type, struct prefix *p, for (ALL_LIST_ELEMENTS_RO(isis->area_list, node, area)) for (level = 1; level <= ISIS_LEVELS; level++) { - redist = get_redist_settings(area, family, type, level); - if (!redist->redist) + redist = isis_redist_lookup(area, family, type, level, + table); + if (!redist || !redist->redist) continue; isis_redist_update_ext_reach(area, level, redist, p, @@ -259,7 +339,7 @@ void isis_redist_add(struct isis *isis, int type, struct prefix *p, } void isis_redist_delete(struct isis *isis, int type, struct prefix *p, - struct prefix_ipv6 *src_p) + struct prefix_ipv6 *src_p, uint16_t table) { int family = p->family; struct route_table *ei_table = get_ext_info(isis, family); @@ -279,7 +359,7 @@ void isis_redist_delete(struct isis *isis, int type, struct prefix *p, * "always" setting will ignore routes with origin * DEFAULT_ROUTE. */ isis_redist_add(isis, DEFAULT_ROUTE, p, NULL, 254, - MAX_WIDE_PATH_METRIC, 0); + MAX_WIDE_PATH_METRIC, 0, table); return; } @@ -302,8 +382,9 @@ void isis_redist_delete(struct isis *isis, int type, struct prefix *p, for (ALL_LIST_ELEMENTS_RO(isis->area_list, node, area)) for (level = ISIS_LEVEL1; level <= ISIS_LEVEL2; level++) { - redist = get_redist_settings(area, family, type, level); - if (!redist->redist) + redist = isis_redist_lookup(area, family, type, level, + table); + if (!redist || !redist->redist) continue; isis_redist_uninstall(area, level, p, src_p); @@ -329,53 +410,6 @@ static void isis_redist_routemap_set(struct isis_redist *redist, } } -static void isis_redist_update_zebra_subscriptions(struct isis *isis) -{ - struct listnode *node; - struct isis_area *area; - int type; - int level; - int protocol; - - if (isis->vrf_id == VRF_UNKNOWN) - return; - - char do_subscribe[REDIST_PROTOCOL_COUNT][ZEBRA_ROUTE_MAX + 1]; - - memset(do_subscribe, 0, sizeof(do_subscribe)); - - for (ALL_LIST_ELEMENTS_RO(isis->area_list, node, area)) - for (protocol = 0; protocol < REDIST_PROTOCOL_COUNT; protocol++) - for (type = 0; type < ZEBRA_ROUTE_MAX + 1; type++) - for (level = 0; level < ISIS_LEVELS; level++) - if (area->redist_settings[protocol] - [type][level] - .redist - == 1) - do_subscribe[protocol][type] = - 1; - - for (protocol = 0; protocol < REDIST_PROTOCOL_COUNT; protocol++) - for (type = 0; type < ZEBRA_ROUTE_MAX + 1; type++) { - /* This field is actually controlling transmission of - * the IS-IS - * routes to Zebra and has nothing to do with - * redistribution, - * so skip it. */ - if (type == PROTO_TYPE) - continue; - - afi_t afi = afi_for_redist_protocol(protocol); - - if (do_subscribe[protocol][type]) - isis_zebra_redistribute_set(afi, type, - isis->vrf_id); - else - isis_zebra_redistribute_unset(afi, type, - isis->vrf_id); - } -} - void isis_redist_free(struct isis *isis) { struct route_node *rn; @@ -397,11 +431,12 @@ void isis_redist_free(struct isis *isis) } void isis_redist_set(struct isis_area *area, int level, int family, int type, - uint32_t metric, const char *routemap, int originate_type) + uint32_t metric, const char *routemap, int originate_type, + uint16_t table) { int protocol = redist_protocol(family); - struct isis_redist *redist = - get_redist_settings(area, family, type, level); + struct isis_redist *redist = isis_redist_get(area, family, type, level, + table); int i; struct route_table *ei_table; struct route_node *rn; @@ -421,7 +456,8 @@ void isis_redist_set(struct isis_area *area, int level, int family, int type, } } - isis_redist_update_zebra_subscriptions(area->isis); + isis_zebra_redistribute_set(afi_for_redist_protocol(protocol), type, + area->isis->vrf_id, redist->table); if (type == DEFAULT_ROUTE && originate_type == DEFAULT_ORIGINATE_ALWAYS) isis_redist_ensure_default(area->isis, family); @@ -452,18 +488,26 @@ 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_unset(struct isis_area *area, int level, int family, int type, + uint16_t table) { - struct isis_redist *redist = - get_redist_settings(area, family, type, level); + struct isis_redist *redist = isis_redist_lookup(area, family, type, + level, table); struct route_table *er_table = get_ext_reach(area, family, level); struct route_node *rn; struct isis_ext_info *info; + struct list *redist_list; + int protocol = redist_protocol(family); - if (!redist->redist) + if (!redist || !redist->redist) return; redist->redist = 0; + + redist_list = area->redist_settings[protocol][type][level - 1]; + listnode_delete(redist_list, redist); + XFREE(MTYPE_ISIS_REDISTRIBUTE, redist); + if (!er_table) { zlog_warn("%s: External reachability table uninitialized.", __func__); @@ -493,7 +537,8 @@ void isis_redist_unset(struct isis_area *area, int level, int family, int type) } lsp_regenerate_schedule(area, level, 0); - isis_redist_update_zebra_subscriptions(area->isis); + isis_zebra_redistribute_unset(afi_for_redist_protocol(protocol), type, + area->isis->vrf_id, table); } void isis_redist_area_finish(struct isis_area *area) @@ -502,16 +547,30 @@ void isis_redist_area_finish(struct isis_area *area) int protocol; int level; int type; + struct isis_redist *redist; + struct listnode *node, *nnode; + struct list *redist_list; for (protocol = 0; protocol < REDIST_PROTOCOL_COUNT; protocol++) for (level = 0; level < ISIS_LEVELS; level++) { for (type = 0; type < ZEBRA_ROUTE_MAX + 1; type++) { - struct isis_redist *redist; - - redist = &area->redist_settings[protocol][type] - [level]; - redist->redist = 0; - XFREE(MTYPE_ISIS_RMAP_NAME, redist->map_name); + redist_list = area->redist_settings[protocol] + [type][level]; + if (!redist_list) + continue; + for (ALL_LIST_ELEMENTS(redist_list, node, nnode, + redist)) { + redist->redist = 0; + XFREE(MTYPE_ISIS_RMAP_NAME, + redist->map_name); + isis_zebra_redistribute_unset( + afi_for_redist_protocol(protocol), + type, area->isis->vrf_id, + redist->table); + listnode_delete(redist_list, redist); + XFREE(MTYPE_ISIS_REDISTRIBUTE, redist); + } + list_delete(&redist_list); } if (!area->ext_reach[protocol][level]) continue; @@ -523,8 +582,6 @@ void isis_redist_area_finish(struct isis_area *area) route_table_finish(area->ext_reach[protocol][level]); area->ext_reach[protocol][level] = NULL; } - - isis_redist_update_zebra_subscriptions(area->isis); } #ifdef FABRICD @@ -581,7 +638,7 @@ DEFUN (isis_redistribute, routemap = argv[idx_metric_rmap + 1]->arg; } - isis_redist_set(area, level, family, type, metric, routemap, 0); + isis_redist_set(area, level, family, type, metric, routemap, 0, 0); return 0; } @@ -617,7 +674,7 @@ DEFUN (no_isis_redistribute, level = 2; - isis_redist_unset(area, level, family, type); + isis_redist_unset(area, level, family, type, 0); return 0; } @@ -677,7 +734,7 @@ DEFUN (isis_default_originate, } isis_redist_set(area, level, family, DEFAULT_ROUTE, metric, routemap, - originate_type); + originate_type, 0); return 0; } @@ -701,7 +758,7 @@ DEFUN (no_isis_default_originate, level = 2; - isis_redist_unset(area, level, family, DEFAULT_ROUTE); + isis_redist_unset(area, level, family, DEFAULT_ROUTE, 0); return 0; } #endif /* ifdef FABRICD */ @@ -713,7 +770,9 @@ int isis_redist_config_write(struct vty *vty, struct isis_area *area, int level; int write = 0; struct isis_redist *redist; + struct list *redist_list; const char *family_str; + struct listnode *node; if (family == AF_INET) family_str = "ipv4"; @@ -727,25 +786,36 @@ int isis_redist_config_write(struct vty *vty, struct isis_area *area, continue; for (level = 1; level <= ISIS_LEVELS; level++) { - redist = get_redist_settings(area, family, type, level); - if (!redist->redist) + redist_list = area->redist_settings[redist_protocol( + family)][type][level - 1]; + if (!redist_list) continue; - vty_out(vty, " redistribute %s %s", family_str, - zebra_route_string(type)); - if (!fabricd) - vty_out(vty, " level-%d", level); - if (redist->metric) - vty_out(vty, " metric %u", redist->metric); - if (redist->map_name) - vty_out(vty, " route-map %s", redist->map_name); - vty_out(vty, "\n"); - write++; + for (ALL_LIST_ELEMENTS_RO(redist_list, node, redist)) { + if (!redist->redist) + continue; + vty_out(vty, " redistribute %s %s", family_str, + zebra_route_string(type)); + if (type == ZEBRA_ROUTE_TABLE) + vty_out(vty, " %u", redist->table); + if (!fabricd) + vty_out(vty, " level-%d", level); + if (redist->metric) + vty_out(vty, " metric %u", + redist->metric); + if (redist->map_name) + vty_out(vty, " route-map %s", + redist->map_name); + vty_out(vty, "\n"); + write++; + } } } for (level = 1; level <= ISIS_LEVELS; level++) { - redist = - get_redist_settings(area, family, DEFAULT_ROUTE, level); + redist = isis_redist_lookup(area, family, DEFAULT_ROUTE, level, + 0); + if (!redist) + continue; if (!redist->redist) continue; vty_out(vty, " default-information originate %s", diff --git a/isisd/isis_redist.h b/isisd/isis_redist.h index ae5ec2b3b3..688f27e62d 100644 --- a/isisd/isis_redist.h +++ b/isisd/isis_redist.h @@ -26,6 +26,15 @@ struct isis_redist { uint32_t metric; char *map_name; struct route_map *map; + uint16_t table; +}; + +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; @@ -40,17 +49,24 @@ struct route_table *get_ext_reach(struct isis_area *area, int family, int level); void isis_redist_add(struct isis *isis, int type, struct prefix *p, struct prefix_ipv6 *src_p, uint8_t distance, - uint32_t metric, route_tag_t tag); + uint32_t metric, route_tag_t tag, uint16_t instance); void isis_redist_delete(struct isis *isis, int type, struct prefix *p, - struct prefix_ipv6 *src_p); + struct prefix_ipv6 *src_p, uint16_t tableid); int isis_redist_config_write(struct vty *vty, struct isis_area *area, int family); void isis_redist_init(void); void isis_redist_area_finish(struct isis_area *area); void isis_redist_set(struct isis_area *area, int level, int family, int type, - uint32_t metric, const char *routemap, int originate_type); -void isis_redist_unset(struct isis_area *area, int level, int family, int type); + uint32_t metric, const char *routemap, int originate_type, + uint16_t table); +void isis_redist_unset(struct isis_area *area, int level, int family, int type, + uint16_t table); 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/isisd/isis_zebra.c b/isisd/isis_zebra.c index 95bd37812f..43e9865fce 100644 --- a/isisd/isis_zebra.c +++ b/isisd/isis_zebra.c @@ -498,10 +498,10 @@ static int isis_zebra_read(ZAPI_CALLBACK_ARGS) if (cmd == ZEBRA_REDISTRIBUTE_ROUTE_ADD) isis_redist_add(isis, api.type, &api.prefix, &api.src_prefix, - api.distance, api.metric, api.tag); + api.distance, api.metric, api.tag, api.instance); else - isis_redist_delete(isis, api.type, &api.prefix, - &api.src_prefix); + isis_redist_delete(isis, api.type, &api.prefix, &api.src_prefix, + api.instance); return 0; } @@ -511,24 +511,26 @@ int isis_distribute_list_update(int routetype) return 0; } -void isis_zebra_redistribute_set(afi_t afi, int type, vrf_id_t vrf_id) +void isis_zebra_redistribute_set(afi_t afi, int type, vrf_id_t vrf_id, + uint16_t tableid) { if (type == DEFAULT_ROUTE) zclient_redistribute_default(ZEBRA_REDISTRIBUTE_DEFAULT_ADD, zclient, afi, vrf_id); else zclient_redistribute(ZEBRA_REDISTRIBUTE_ADD, zclient, afi, type, - 0, vrf_id); + tableid, vrf_id); } -void isis_zebra_redistribute_unset(afi_t afi, int type, vrf_id_t vrf_id) +void isis_zebra_redistribute_unset(afi_t afi, int type, vrf_id_t vrf_id, + uint16_t tableid) { if (type == DEFAULT_ROUTE) zclient_redistribute_default(ZEBRA_REDISTRIBUTE_DEFAULT_DELETE, zclient, afi, vrf_id); else zclient_redistribute(ZEBRA_REDISTRIBUTE_DELETE, zclient, afi, - type, 0, vrf_id); + type, tableid, vrf_id); } /** diff --git a/isisd/isis_zebra.h b/isisd/isis_zebra.h index 045c75874a..1dcd896d0b 100644 --- a/isisd/isis_zebra.h +++ b/isisd/isis_zebra.h @@ -43,8 +43,10 @@ void isis_zebra_prefix_sid_uninstall(struct isis_area *area, struct isis_sr_psid_info *psid); void isis_zebra_send_adjacency_sid(int cmd, const struct sr_adjacency *sra); int isis_distribute_list_update(int routetype); -void isis_zebra_redistribute_set(afi_t afi, int type, vrf_id_t vrf_id); -void isis_zebra_redistribute_unset(afi_t afi, int type, vrf_id_t vrf_id); +void isis_zebra_redistribute_set(afi_t afi, int type, vrf_id_t vrf_id, + uint16_t tableid); +void isis_zebra_redistribute_unset(afi_t afi, int type, vrf_id_t vrf_id, + uint16_t tableid); int isis_zebra_rlfa_register(struct isis_spftree *spftree, struct rlfa *rlfa); void isis_zebra_rlfa_unregister_all(struct isis_spftree *spftree); bool isis_zebra_label_manager_ready(void); diff --git a/isisd/isisd.c b/isisd/isisd.c index c6a7e803c1..942073b70c 100644 --- a/isisd/isisd.c +++ b/isisd/isisd.c @@ -599,64 +599,66 @@ static int isis_vrf_delete(struct vrf *vrf) static void isis_set_redist_vrf_bitmaps(struct isis *isis, bool set) { - struct listnode *node; + struct listnode *node, *lnode; struct isis_area *area; int type; int level; int protocol; - - char do_subscribe[REDIST_PROTOCOL_COUNT][ZEBRA_ROUTE_MAX + 1]; - - memset(do_subscribe, 0, sizeof(do_subscribe)); + struct isis_redist *redist; for (ALL_LIST_ELEMENTS_RO(isis->area_list, node, area)) for (protocol = 0; protocol < REDIST_PROTOCOL_COUNT; protocol++) for (type = 0; type < ZEBRA_ROUTE_MAX + 1; type++) - for (level = 0; level < ISIS_LEVELS; level++) - if (area->redist_settings[protocol] - [type][level] - .redist - == 1) - do_subscribe[protocol][type] = - 1; + for (level = 0; level < ISIS_LEVELS; level++) { + if (area->redist_settings[protocol][type] + [level] == NULL) + continue; + for (ALL_LIST_ELEMENTS_RO(area->redist_settings + [protocol] + [type] + [level], + lnode, + redist)) { + if (redist->redist == 0) + continue; + /* This field is actually + * controlling transmission of + * the IS-IS + * routes to Zebra and has + * nothing to do with + * redistribution, + * so skip it. */ + afi_t afi = + afi_for_redist_protocol( + protocol); - for (protocol = 0; protocol < REDIST_PROTOCOL_COUNT; protocol++) - for (type = 0; type < ZEBRA_ROUTE_MAX + 1; type++) { - /* This field is actually controlling transmission of - * the IS-IS - * routes to Zebra and has nothing to do with - * redistribution, - * so skip it. */ - if (type == PROTO_TYPE) - continue; - - if (!do_subscribe[protocol][type]) - continue; - - afi_t afi = afi_for_redist_protocol(protocol); - - if (type == DEFAULT_ROUTE) { - if (set) - vrf_bitmap_set( - &zclient->default_information - [afi], - isis->vrf_id); - else - vrf_bitmap_unset( - &zclient->default_information - [afi], - isis->vrf_id); - } else { - if (set) - vrf_bitmap_set( - &zclient->redist[afi][type], - isis->vrf_id); - else - vrf_bitmap_unset( - &zclient->redist[afi][type], - isis->vrf_id); - } - } + if (type == DEFAULT_ROUTE) { + if (set) + vrf_bitmap_set( + &zclient->default_information + [afi], + isis->vrf_id); + else + vrf_bitmap_unset( + &zclient->default_information + [afi], + isis->vrf_id); + } else { + if (set) + vrf_bitmap_set( + &zclient->redist + [afi] + [type], + isis->vrf_id); + else + vrf_bitmap_unset( + &zclient->redist + [afi] + [type], + isis->vrf_id); + } + } + } } static int isis_vrf_enable(struct vrf *vrf) diff --git a/isisd/isisd.h b/isisd/isisd.h index f0d236b643..cd2a694453 100644 --- a/isisd/isisd.h +++ b/isisd/isisd.h @@ -230,8 +230,8 @@ struct isis_area { #endif /* ifndef FABRICD */ /* Counters */ uint32_t circuit_state_changes; - struct isis_redist redist_settings[REDIST_PROTOCOL_COUNT] - [ZEBRA_ROUTE_MAX + 1][ISIS_LEVELS]; + struct list *redist_settings[REDIST_PROTOCOL_COUNT][ZEBRA_ROUTE_MAX + 1] + [ISIS_LEVELS]; struct route_table *ext_reach[REDIST_PROTOCOL_COUNT][ISIS_LEVELS]; struct spf_backoff *spf_delay_ietf[ISIS_LEVELS]; /*Structure with IETF diff --git a/tests/topotests/isis_topo1/r3/r3_route.json b/tests/topotests/isis_topo1/r3/r3_route.json index 61d05e80bb..c3b6e3b0a6 100644 --- a/tests/topotests/isis_topo1/r3/r3_route.json +++ b/tests/topotests/isis_topo1/r3/r3_route.json @@ -146,5 +146,20 @@ "protocol": "isis", "selected": true } + ], + "192.0.2.6/32": [ + { + "nexthops": [ + { + "active": true, + "fib": true, + "ip": "10.0.10.1", + "interfaceName": "r3-eth1" + } + ], + "prefix": "192.0.2.6/32", + "protocol": "isis", + "selected": true + } ] } diff --git a/tests/topotests/isis_topo1/r4/r4_route.json b/tests/topotests/isis_topo1/r4/r4_route.json index 79361af4b5..8fd46add33 100644 --- a/tests/topotests/isis_topo1/r4/r4_route.json +++ b/tests/topotests/isis_topo1/r4/r4_route.json @@ -61,5 +61,20 @@ "protocol": "connected", "selected": true } + ], + "192.0.2.6/32": [ + { + "nexthops": [ + { + "active": true, + "fib": true, + "ip": "10.0.11.1", + "interfaceName": "r4-eth1" + } + ], + "prefix": "192.0.2.6/32", + "protocol": "isis", + "selected": true + } ] } diff --git a/tests/topotests/isis_topo1/r5/isisd.conf b/tests/topotests/isis_topo1/r5/isisd.conf index e0e9200d62..81686e0525 100644 --- a/tests/topotests/isis_topo1/r5/isisd.conf +++ b/tests/topotests/isis_topo1/r5/isisd.conf @@ -20,4 +20,5 @@ router isis 1 is-type level-1 redistribute ipv4 connected level-1 redistribute ipv6 connected level-1 + redistribute ipv4 table 20 level-1 ! diff --git a/tests/topotests/isis_topo1/r5/r5_route.json b/tests/topotests/isis_topo1/r5/r5_route.json index cca844b27c..ec544b8e85 100644 --- a/tests/topotests/isis_topo1/r5/r5_route.json +++ b/tests/topotests/isis_topo1/r5/r5_route.json @@ -141,5 +141,21 @@ "protocol": "connected", "selected": true } + ], + "192.0.2.6/32": [ + { + "nexthops": [ + { + "active": true, + "fib": true, + "ip": "10.0.10.6", + "interfaceName": "r5-eth0" + } + ], + "prefix": "192.0.2.6/32", + "protocol": "table", + "instance": 20, + "selected": true + } ] } diff --git a/tests/topotests/isis_topo1/r5/zebra.conf b/tests/topotests/isis_topo1/r5/zebra.conf index 48fed69662..7c400f797b 100644 --- a/tests/topotests/isis_topo1/r5/zebra.conf +++ b/tests/topotests/isis_topo1/r5/zebra.conf @@ -1,4 +1,6 @@ hostname r5 +ip route 192.0.2.6/32 10.0.10.6 table 20 +ip import 20 interface r5-eth0 ip address 10.0.10.1/24 ipv6 address 2001:db8:2:1::1/64 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; + } + } + } } diff --git a/zebra/redistribute.c b/zebra/redistribute.c index 11b7b7cf82..9ca9c7a55a 100644 --- a/zebra/redistribute.c +++ b/zebra/redistribute.c @@ -675,6 +675,8 @@ int zebra_add_import_table_entry(struct zebra_vrf *zvrf, struct route_node *rn, zebra_del_import_table_entry(zvrf, rn, same); } + UNSET_FLAG(re->flags, ZEBRA_FLAG_RR_USE_DISTANCE); + newre = zebra_rib_route_entry_new( 0, ZEBRA_ROUTE_TABLE, re->table, re->flags, re->nhe_id, zvrf->table_id, re->metric, re->mtu,