diff options
| author | Christian Hopps <chopps@labn.net> | 2023-07-08 23:11:15 -0400 |
|---|---|---|
| committer | Christian Hopps <chopps@labn.net> | 2023-11-06 17:44:58 -0500 |
| commit | a65cda16b28bc84b052636118823082de9600cfc (patch) | |
| tree | 975a1abb64919cc9a9c201b8c50ef7602bd72483 /mgmtd/mgmt_be_adapter.c | |
| parent | e1b2381f40132650f1c0a2285432c0d00aef7383 (diff) | |
mgmtd: simplify xpath registries
- move from client id indexed array of uints for register info
per client to a u64 bitmask.
- add bit walking FOREACH macro
Walk the client IDs whose bits are set in a mask.
Signed-off-by: Christian Hopps <chopps@labn.net>
Diffstat (limited to 'mgmtd/mgmt_be_adapter.c')
| -rw-r--r-- | mgmtd/mgmt_be_adapter.c | 462 |
1 files changed, 195 insertions, 267 deletions
diff --git a/mgmtd/mgmt_be_adapter.c b/mgmtd/mgmt_be_adapter.c index 5ab11ea491..8330f6f36b 100644 --- a/mgmtd/mgmt_be_adapter.c +++ b/mgmtd/mgmt_be_adapter.c @@ -10,6 +10,7 @@ #include <zebra.h> #include "darr.h" #include "frrevent.h" +#include "frrstr.h" #include "sockopt.h" #include "network.h" #include "libfrr.h" @@ -28,29 +29,27 @@ #define FOREACH_ADAPTER_IN_LIST(adapter) \ frr_each_safe (mgmt_be_adapters, &mgmt_be_adapters, (adapter)) -/* - * Mapping of YANG XPath regular expressions to - * their corresponding backend clients. - */ -struct mgmt_be_xpath_map { - char *xpath_regexp; - uint subscr_info[MGMTD_BE_CLIENT_ID_MAX]; -}; +/* ---------- */ +/* Client IDs */ +/* ---------- */ -struct mgmt_be_client_xpath { - const char *xpath; - uint subscribed; +const char *mgmt_be_client_names[MGMTD_BE_CLIENT_ID_MAX + 1] = { +#ifdef HAVE_STATICD + [MGMTD_BE_CLIENT_ID_STATICD] = "staticd", +#endif + [MGMTD_BE_CLIENT_ID_MAX] = "Unknown/Invalid", }; -struct mgmt_be_client_xpath_map { - struct mgmt_be_client_xpath *xpaths; - uint nxpaths; -}; +/* ------------- */ +/* XPATH MAPPING */ +/* ------------- */ -struct mgmt_be_get_adapter_config_params { - struct mgmt_be_client_adapter *adapter; - struct nb_config_cbs *cfg_chgs; - uint32_t seq; +/* + * Mapping of YANG XPath prefixes to their corresponding backend clients. + */ +struct mgmt_be_xpath_map { + char *xpath_prefix; + uint64_t clients; }; /* @@ -58,31 +57,23 @@ struct mgmt_be_get_adapter_config_params { * above map as well. */ #if HAVE_STATICD -static struct mgmt_be_client_xpath staticd_xpaths[] = { - { - .xpath = "/frr-vrf:lib/*", - .subscribed = MGMT_SUBSCR_VALIDATE_CFG | MGMT_SUBSCR_NOTIFY_CFG, - }, - { - .xpath = "/frr-interface:lib/*", - .subscribed = MGMT_SUBSCR_VALIDATE_CFG | MGMT_SUBSCR_NOTIFY_CFG, - }, - { - .xpath = - "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-staticd:staticd/*", - .subscribed = MGMT_SUBSCR_VALIDATE_CFG | MGMT_SUBSCR_NOTIFY_CFG, - }, +static const char *const staticd_xpaths[] = { + "/frr-vrf:lib", + "/frr-interface:lib", + "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-staticd:staticd", + NULL, }; #endif -static struct mgmt_be_client_xpath_map - mgmt_client_xpaths[MGMTD_BE_CLIENT_ID_MAX] = { +static const char *const *be_client_xpaths[MGMTD_BE_CLIENT_ID_MAX] = { + #ifdef HAVE_STATICD - [MGMTD_BE_CLIENT_ID_STATICD] = {staticd_xpaths, - array_size(staticd_xpaths)}, + [MGMTD_BE_CLIENT_ID_STATICD] = staticd_xpaths, #endif }; +static const char *const *be_client_oper_xpaths[MGMTD_BE_CLIENT_ID_MAX] = {}; + /* * We would like to have a better ADT than one with O(n) comparisons * @@ -91,7 +82,9 @@ static struct mgmt_be_client_xpath_map * says this probably involves exact match/no-match on a stem in the map array * or something like that. */ -static struct mgmt_be_xpath_map *mgmt_xpath_map; + +static struct mgmt_be_xpath_map *be_cfg_xpath_map; +static struct mgmt_be_xpath_map *be_oper_xpath_map; static struct event_loop *mgmt_loop; static struct msg_server mgmt_be_server = {.fd = -1}; @@ -101,12 +94,34 @@ static struct mgmt_be_adapters_head mgmt_be_adapters; static struct mgmt_be_client_adapter *mgmt_be_adapters_by_id[MGMTD_BE_CLIENT_ID_MAX]; + /* Forward declarations */ static void mgmt_be_adapter_sched_init_event(struct mgmt_be_client_adapter *adapter); -static uint mgmt_be_get_subscr_for_xpath_and_client( - const char *xpath, enum mgmt_be_client_id client_id, uint subscr_mask); +static bool be_is_client_interested(const char *xpath, + enum mgmt_be_client_id id, bool config); + + +static const char *mgmt_be_client_id2name(enum mgmt_be_client_id id) +{ + if (id > MGMTD_BE_CLIENT_ID_MAX) + return "invalid client id"; + return mgmt_be_client_names[id]; +} + +static enum mgmt_be_client_id mgmt_be_client_name2id(const char *name) +{ + enum mgmt_be_client_id id; + + FOREACH_MGMTD_BE_CLIENT_ID (id) { + if (!strncmp(mgmt_be_client_names[id], name, + MGMTD_CLIENT_NAME_MAX_LEN)) + return id; + } + + return MGMTD_BE_CLIENT_ID_MAX; +} static struct mgmt_be_client_adapter * mgmt_be_find_adapter_by_fd(int conn_fd) @@ -135,178 +150,91 @@ mgmt_be_find_adapter_by_name(const char *name) } static void mgmt_register_client_xpath(enum mgmt_be_client_id id, - const char *xpath, uint subscribed) + const char *xpath, bool config) { - struct mgmt_be_xpath_map *map; + struct mgmt_be_xpath_map **maps, *map; - darr_foreach_p (mgmt_xpath_map, map) - if (!strcmp(xpath, map->xpath_regexp)) { - map->subscr_info[id] = subscribed; + maps = config ? &be_cfg_xpath_map : &be_oper_xpath_map; + + darr_foreach_p (*maps, map) { + if (!strcmp(xpath, map->xpath_prefix)) { + map->clients |= (1u << id); return; } + } /* we didn't find a matching entry */ - map = darr_append(mgmt_xpath_map); - map->xpath_regexp = XSTRDUP(MTYPE_MGMTD_XPATH, xpath); - map->subscr_info[id] = subscribed; + map = darr_append(*maps); + map->xpath_prefix = XSTRDUP(MTYPE_MGMTD_XPATH, xpath); + map->clients = (1ul << id); } /* - * Load the initial mapping from static init map + * initial the combined maps from per client maps */ static void mgmt_be_xpath_map_init(void) { - struct mgmt_be_client_xpath *init, *end; enum mgmt_be_client_id id; + const char *const *init; MGMTD_BE_ADAPTER_DBG("Init XPath Maps"); FOREACH_MGMTD_BE_CLIENT_ID (id) { - init = mgmt_client_xpaths[id].xpaths; - end = init + mgmt_client_xpaths[id].nxpaths; - for (; init < end; init++) { - MGMTD_BE_ADAPTER_DBG(" - XPATH: '%s'", init->xpath); - mgmt_register_client_xpath(id, init->xpath, - init->subscribed); + /* Initialize the common config init map */ + for (init = be_client_xpaths[id]; init && *init; init++) { + MGMTD_BE_ADAPTER_DBG(" - CFG XPATH: '%s'", *init); + mgmt_register_client_xpath(id, *init, true); + } + + /* Initialize the common oper init map */ + for (init = be_client_oper_xpaths[id]; init && *init; init++) { + MGMTD_BE_ADAPTER_DBG(" - OPER XPATH: '%s'", *init); + mgmt_register_client_xpath(id, *init, false); } } - MGMTD_BE_ADAPTER_DBG("Total XPath Maps: %u", darr_len(mgmt_xpath_map)); + MGMTD_BE_ADAPTER_DBG("Total Cfg XPath Maps: %u", + darr_len(be_cfg_xpath_map)); + MGMTD_BE_ADAPTER_DBG("Total Oper XPath Maps: %u", + darr_len(be_oper_xpath_map)); } static void mgmt_be_xpath_map_cleanup(void) { struct mgmt_be_xpath_map *map; - darr_foreach_p (mgmt_xpath_map, map) - XFREE(MTYPE_MGMTD_XPATH, map->xpath_regexp); - darr_free(mgmt_xpath_map); -} - -static int mgmt_be_eval_regexp_match(const char *xpath_regexp, - const char *xpath) -{ - int match_len = 0, re_indx = 0, xp_indx = 0; - int rexp_len, xpath_len; - bool match = true, re_wild = false, xp_wild = false; - bool delim = false, enter_wild_match = false; - char wild_delim = 0; - - rexp_len = strlen(xpath_regexp); - xpath_len = strlen(xpath); - - /* - * Remove the trailing wildcard from the regexp and Xpath. - */ - if (rexp_len && xpath_regexp[rexp_len-1] == '*') - rexp_len--; - if (xpath_len && xpath[xpath_len-1] == '*') - xpath_len--; + darr_foreach_p (be_cfg_xpath_map, map) + XFREE(MTYPE_MGMTD_XPATH, map->xpath_prefix); + darr_free(be_cfg_xpath_map); - if (!rexp_len || !xpath_len) - return 0; + darr_foreach_p (be_oper_xpath_map, map) + XFREE(MTYPE_MGMTD_XPATH, map->xpath_prefix); + darr_free(be_oper_xpath_map); +} - for (re_indx = 0, xp_indx = 0; - match && re_indx < rexp_len && xp_indx < xpath_len;) { - match = (xpath_regexp[re_indx] == xpath[xp_indx]); - /* - * Check if we need to enter wildcard matching. - */ - if (!enter_wild_match && !match && - (xpath_regexp[re_indx] == '*' - || xpath[xp_indx] == '*')) { - /* - * Found wildcard - */ - enter_wild_match = - (xpath_regexp[re_indx-1] == '/' - || xpath_regexp[re_indx-1] == '\'' - || xpath[xp_indx-1] == '/' - || xpath[xp_indx-1] == '\''); - if (enter_wild_match) { - if (xpath_regexp[re_indx] == '*') { - /* - * Begin RE wildcard match. - */ - re_wild = true; - wild_delim = xpath_regexp[re_indx-1]; - } else if (xpath[xp_indx] == '*') { - /* - * Begin XP wildcard match. - */ - xp_wild = true; - wild_delim = xpath[xp_indx-1]; - } - } - } - - /* - * Check if we need to exit wildcard matching. - */ - if (enter_wild_match) { - if (re_wild && xpath[xp_indx] == wild_delim) { - /* - * End RE wildcard matching. - */ - re_wild = false; - if (re_indx < rexp_len-1) - re_indx++; - enter_wild_match = false; - } else if (xp_wild - && xpath_regexp[re_indx] == wild_delim) { - /* - * End XP wildcard matching. - */ - xp_wild = false; - if (xp_indx < xpath_len-1) - xp_indx++; - enter_wild_match = false; - } - } - - match = (xp_wild || re_wild - || xpath_regexp[re_indx] == xpath[xp_indx]); +/* + * Check if either path or xpath is a prefix of the other. Before checking the + * xpath is converted to a regular path string (e..g, removing key value + * specifiers). + */ +static bool mgmt_be_xpath_prefix(const char *path, const char *xpath) +{ + int xc, pc; - /* - * Check if we found a delimiter in both the Xpaths - */ - if ((xpath_regexp[re_indx] == '/' - && xpath[xp_indx] == '/') - || (xpath_regexp[re_indx] == ']' - && xpath[xp_indx] == ']') - || (xpath_regexp[re_indx] == '[' - && xpath[xp_indx] == '[')) { - /* - * Increment the match count if we have a - * new delimiter. - */ - if (match && re_indx && xp_indx && !delim) - match_len++; - delim = true; - } else { - delim = false; + while ((xc = *xpath++)) { + if (xc == '[') { + xpath = frrstr_skip_over_char(xpath, ']'); + if (!xpath) + return false; + continue; } - - /* - * Proceed to the next character in the RE/XP string as - * necessary. - */ - if (!re_wild) - re_indx++; - if (!xp_wild) - xp_indx++; + pc = *path++; + if (!pc) + return true; + if (pc != xc) + return false; } - - /* - * If we finished matching and the last token was a full match - * increment the match count appropriately. - */ - if (match && !delim && - (xpath_regexp[re_indx] == '/' - || xpath_regexp[re_indx] == ']')) - match_len++; - - return match_len; + return true; } static void mgmt_be_adapter_delete(struct mgmt_be_client_adapter *adapter) @@ -596,16 +524,26 @@ static void mgmt_be_adapter_process_msg(uint8_t version, uint8_t *data, mgmtd__be_message__free_unpacked(be_msg, NULL); } +/* + * Args for callback + */ +struct mgmt_be_get_adapter_config_params { + struct mgmt_be_client_adapter *adapter; + struct nb_config_cbs *cfg_chgs; + uint32_t seq; +}; + +/* + * Callback to store the change a node in the datastore if it should be sync'd + * to the adapter (i.e., if the adapter is subscribed to it). + */ static void mgmt_be_iter_and_get_cfg(const char *xpath, struct lyd_node *node, struct nb_node *nb_node, void *ctx) { struct mgmt_be_get_adapter_config_params *parms = ctx; struct mgmt_be_client_adapter *adapter = parms->adapter; - uint subscr; - subscr = mgmt_be_get_subscr_for_xpath_and_client( - xpath, adapter->id, MGMT_SUBSCR_NOTIFY_CFG); - if (subscr) + if (be_is_client_interested(xpath, adapter->id, true)) nb_config_diff_created(node, &parms->seq, parms->cfg_chgs); } @@ -752,6 +690,10 @@ mgmt_be_get_adapter_by_name(const char *name) return mgmt_be_find_adapter_by_name(name); } +/* + * Get a full set of changes for all the config that an adapter is subscribed to + * receive. + */ int mgmt_be_get_adapter_config(struct mgmt_be_client_adapter *adapter, struct nb_config_cbs **cfg_chgs) { @@ -780,72 +722,65 @@ int mgmt_be_get_adapter_config(struct mgmt_be_client_adapter *adapter, return 0; } -void mgmt_be_get_subscr_info_for_xpath( - const char *xpath, struct mgmt_be_client_subscr_info *subscr_info) +uint64_t mgmt_be_interested_clients(const char *xpath, bool config) { - struct mgmt_be_xpath_map *map; + struct mgmt_be_xpath_map *maps, *map; enum mgmt_be_client_id id; + uint64_t clients; - memset(subscr_info, 0, sizeof(*subscr_info)); + maps = config ? be_cfg_xpath_map : be_oper_xpath_map; + + clients = 0; MGMTD_BE_ADAPTER_DBG("XPATH: '%s'", xpath); - darr_foreach_p (mgmt_xpath_map, map) { - if (!mgmt_be_eval_regexp_match(map->xpath_regexp, xpath)) - continue; - FOREACH_MGMTD_BE_CLIENT_ID (id) { - subscr_info->xpath_subscr[id] |= map->subscr_info[id]; - } - } + darr_foreach_p (maps, map) + if (mgmt_be_xpath_prefix(map->xpath_prefix, xpath)) + clients |= map->clients; if (DEBUG_MODE_CHECK(&mgmt_debug_be, DEBUG_MODE_ALL)) { - FOREACH_MGMTD_BE_CLIENT_ID (id) { - if (!subscr_info->xpath_subscr[id]) - continue; - MGMTD_BE_ADAPTER_DBG("Cient: %s: subscribed: 0x%x", - mgmt_be_client_id2name(id), - subscr_info->xpath_subscr[id]); - } + FOREACH_BE_CLIENT_BITS (id, clients) + MGMTD_BE_ADAPTER_DBG("Cient: %s: subscribed", + mgmt_be_client_id2name(id)); } + return clients; } /** - * Return the subscription info bits for a given `xpath` for a given - * `client_id`. + * Return true if `client_id` is interested in `xpath` for `config` + * or oper (!`config`). * * Args: - * xpath - the xpath to check for subscription information. + * xpath - the xpath to check for interest. * client_id - the BE client being checked for. - * subscr_mask - The subscr bits the caller is interested in seeing - * if set. + * bool - check for config (vs oper) subscription. * * Returns: - * The subscription info bits. + * Interested or not. */ -static uint mgmt_be_get_subscr_for_xpath_and_client( - const char *xpath, enum mgmt_be_client_id client_id, uint subscr_mask) +static bool be_is_client_interested(const char *xpath, + enum mgmt_be_client_id id, bool config) { - struct mgmt_be_client_xpath_map *map; - uint subscr = 0; - uint i; + const char *const *xpaths; - assert(client_id < MGMTD_BE_CLIENT_ID_MAX); + assert(id < MGMTD_BE_CLIENT_ID_MAX); MGMTD_BE_ADAPTER_DBG("Checking client: %s for xpath: '%s'", - mgmt_be_client_id2name(client_id), xpath); - - map = &mgmt_client_xpaths[client_id]; - for (i = 0; i < map->nxpaths; i++) { - if (!mgmt_be_eval_regexp_match(map->xpaths[i].xpath, xpath)) - continue; - MGMTD_BE_ADAPTER_DBG("xpath: %s: matched: %s", - map->xpaths[i].xpath, xpath); - subscr |= map->xpaths[i].subscribed; - if ((subscr & subscr_mask) == subscr_mask) - break; + mgmt_be_client_id2name(id), xpath); + + xpaths = config ? be_client_xpaths[id] : be_client_oper_xpaths[id]; + if (xpaths) { + for (; *xpaths; xpaths++) { + if (mgmt_be_xpath_prefix(*xpaths, xpath)) { + MGMTD_BE_ADAPTER_DBG("xpath: %s: matched: %s", + *xpaths, xpath); + return true; + } + } } - MGMTD_BE_ADAPTER_DBG("client: %s: subscribed: 0x%x", - mgmt_be_client_id2name(client_id), subscr); - return subscr; + + MGMTD_BE_ADAPTER_DBG("client: %s: not interested", + mgmt_be_client_id2name(id)); + return false; } void mgmt_be_adapter_status_write(struct vty *vty) @@ -872,56 +807,49 @@ void mgmt_be_adapter_status_write(struct vty *vty) (int)mgmt_be_adapters_count(&mgmt_be_adapters)); } -void mgmt_be_xpath_register_write(struct vty *vty) +static void be_show_xpath_register(struct vty *vty, + struct mgmt_be_xpath_map *map) { - struct mgmt_be_xpath_map *map; enum mgmt_be_client_id id; - struct mgmt_be_client_adapter *adapter; - uint info; - - vty_out(vty, "MGMTD Backend XPath Registry\n"); - - darr_foreach_p (mgmt_xpath_map, map) { - vty_out(vty, " - XPATH: '%s'\n", map->xpath_regexp); - FOREACH_MGMTD_BE_CLIENT_ID (id) { - info = map->subscr_info[id]; - if (!info) - continue; - vty_out(vty, - " -- Client: '%s'\tValidate:%d, Notify:%d, Own:%d\n", - mgmt_be_client_id2name(id), - (info & MGMT_SUBSCR_VALIDATE_CFG) != 0, - (info & MGMT_SUBSCR_NOTIFY_CFG) != 0, - (info & MGMT_SUBSCR_OPER_OWN) != 0); - adapter = mgmt_be_get_adapter_by_id(id); - if (adapter) - vty_out(vty, " -- Adapter: %p\n", adapter); - } + const char *astr; + + vty_out(vty, " - xpath: '%s'\n", map->xpath_prefix); + FOREACH_BE_CLIENT_BITS (id, map->clients) { + astr = mgmt_be_get_adapter_by_id(id) ? "active" : "inactive"; + vty_out(vty, " -- %s-client: '%s'\n", astr, + mgmt_be_client_id2name(id)); } +} +void mgmt_be_xpath_register_write(struct vty *vty) +{ + struct mgmt_be_xpath_map *map; - vty_out(vty, "Total XPath Registries: %u\n", darr_len(mgmt_xpath_map)); + vty_out(vty, "MGMTD Backend CFG XPath Registry: Count: %u\n", + darr_len(be_oper_xpath_map)); + darr_foreach_p (be_cfg_xpath_map, map) + be_show_xpath_register(vty, map); + + vty_out(vty, "\nMGMTD Backend OPER XPath Registry: Count: %u\n", + darr_len(be_oper_xpath_map)); + darr_foreach_p (be_oper_xpath_map, map) + be_show_xpath_register(vty, map); } -void mgmt_be_xpath_subscr_info_write(struct vty *vty, const char *xpath) +void mgmt_be_show_xpath_registries(struct vty *vty, const char *xpath) { - struct mgmt_be_client_subscr_info subscr; enum mgmt_be_client_id id; struct mgmt_be_client_adapter *adapter; - uint info; + uint64_t cclients, oclients, combined; - mgmt_be_get_subscr_info_for_xpath(xpath, &subscr); + cclients = mgmt_be_interested_clients(xpath, true); + oclients = mgmt_be_interested_clients(xpath, false); + combined = cclients | oclients; vty_out(vty, "XPath: '%s'\n", xpath); - FOREACH_MGMTD_BE_CLIENT_ID (id) { - info = subscr.xpath_subscr[id]; - if (!info) - continue; - vty_out(vty, - " -- Client: '%s'\tValidate:%d, Notify:%d, Own:%d\n", - mgmt_be_client_id2name(id), - (info & MGMT_SUBSCR_VALIDATE_CFG) != 0, - (info & MGMT_SUBSCR_NOTIFY_CFG) != 0, - (info & MGMT_SUBSCR_OPER_OWN) != 0); + FOREACH_BE_CLIENT_BITS (id, combined) { + vty_out(vty, " -- Client: '%s'\tconfig:%d oper:%d\n", + mgmt_be_client_id2name(id), IS_IDBIT_SET(cclients, id), + IS_IDBIT_SET(oclients, id)); adapter = mgmt_be_get_adapter_by_id(id); if (adapter) vty_out(vty, " -- Adapter: %p\n", adapter); |
