diff options
Diffstat (limited to 'isisd/isis_redist.c')
| -rw-r--r-- | isisd/isis_redist.c | 254 |
1 files changed, 162 insertions, 92 deletions
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; + + 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; - return &area->redist_settings[protocol][type][level - 1]; + 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", |
