diff --git a/.clang-format b/.clang-format index 3971384a3659..5f21a3f32453 100644 --- a/.clang-format +++ b/.clang-format @@ -103,6 +103,7 @@ ForEachMacros: - 'FOREACH_AFI_SAFI' - 'FOREACH_AFI_SAFI_NSF' - 'FOREACH_BE_APPLY_BATCH_IN_LIST' + - 'FOREACH_BE_CLIENT_BITS' - 'FOREACH_BE_TXN_BATCH_IN_LIST' - 'FOREACH_BE_TXN_IN_LIST' - 'FOREACH_CMT_REC' diff --git a/lib/frrstr.c b/lib/frrstr.c index e5440c509374..bb112afef7c0 100644 --- a/lib/frrstr.c +++ b/lib/frrstr.c @@ -3,6 +3,7 @@ * FRR string processing utilities. * Copyright (C) 2018 Cumulus Networks, Inc. * Quentin Young + * Copyright (c) 2023, LabN Consulting, L.L.C. */ #include "zebra.h" @@ -225,3 +226,26 @@ char *frrstr_hex(char *buff, size_t bufsiz, const uint8_t *str, size_t num) return buff; } + +const char *frrstr_skip_over_char(const char *s, int skipc) +{ + int c, quote = 0; + + while ((c = *s++)) { + if (c == '\\') { + if (!*s++) + return NULL; + continue; + } + if (quote) { + if (c == quote) + quote = 0; + continue; + } + if (c == skipc) + return s; + if (c == '"' || c == '\'') + quote = c; + } + return NULL; +} diff --git a/lib/frrstr.h b/lib/frrstr.h index 19ba09e21319..9a4fe257a23b 100644 --- a/lib/frrstr.h +++ b/lib/frrstr.h @@ -3,6 +3,7 @@ * FRR string processing utilities. * Copyright (C) 2018 Cumulus Networks, Inc. * Quentin Young + * Copyright (c) 2023, LabN Consulting, L.L.C. */ #ifndef _FRRSTR_H_ @@ -166,6 +167,13 @@ int all_digit(const char *str); */ char *frrstr_hex(char *buff, size_t bufsiz, const uint8_t *str, size_t num); + +/* + * Advance past a given char `skipc` in a string, while honoring quoting and + * backslash escapes (i.e., ignore `skipc` which occur in quoted sections). + */ +const char *frrstr_skip_over_char(const char *s, int skipc); + #ifdef __cplusplus } #endif diff --git a/lib/mgmt_be_client.c b/lib/mgmt_be_client.c index be10dcf6a19f..762ace136179 100644 --- a/lib/mgmt_be_client.c +++ b/lib/mgmt_be_client.c @@ -118,13 +118,6 @@ struct mgmt_be_client { struct debug mgmt_dbg_be_client = {0, "Management backend client operations"}; -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", -}; - static int mgmt_be_client_send_msg(struct mgmt_be_client *client_ctx, Mgmtd__BeMessage *be_msg) { diff --git a/lib/mgmt_be_client.h b/lib/mgmt_be_client.h index 4ad5ca5957cd..051c908a378a 100644 --- a/lib/mgmt_be_client.h +++ b/lib/mgmt_be_client.h @@ -16,27 +16,6 @@ extern "C" { #include "mgmt_pb.h" #include "mgmtd/mgmt_defines.h" -/*************************************************************** - * Client IDs - ***************************************************************/ - -/* - * Add enum value for each supported component, wrap with - * #ifdef HAVE_COMPONENT - */ -enum mgmt_be_client_id { - MGMTD_BE_CLIENT_ID_MIN = 0, - MGMTD_BE_CLIENT_ID_INIT = -1, -#ifdef HAVE_STATICD - MGMTD_BE_CLIENT_ID_STATICD, -#endif - MGMTD_BE_CLIENT_ID_MAX -}; - -#define FOREACH_MGMTD_BE_CLIENT_ID(id) \ - for ((id) = MGMTD_BE_CLIENT_ID_MIN; \ - (id) < MGMTD_BE_CLIENT_ID_MAX; (id)++) - /*************************************************************** * Constants ***************************************************************/ @@ -108,29 +87,6 @@ struct mgmt_be_client_cbs { * Global data exported ***************************************************************/ -extern const char *mgmt_be_client_names[MGMTD_BE_CLIENT_ID_MAX + 1]; - -static inline const char *mgmt_be_client_id2name(enum mgmt_be_client_id id) -{ - if (id > MGMTD_BE_CLIENT_ID_MAX) - id = MGMTD_BE_CLIENT_ID_MAX; - return mgmt_be_client_names[id]; -} - -static inline 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; -} - extern struct debug mgmt_dbg_be_client; /*************************************************************** diff --git a/lib/yang.c b/lib/yang.c index 4dd865421718..7046091baa77 100644 --- a/lib/yang.c +++ b/lib/yang.c @@ -254,15 +254,8 @@ struct lysc_node *yang_find_snode(struct ly_ctx *ly_ctx, const char *xpath, uint32_t options) { struct lysc_node *snode; - struct ly_set *set; - LY_ERR err; - err = lys_find_xpath(ly_native_ctx, NULL, xpath, options, &set); - if (err || !set->count) - return NULL; - - snode = set->snodes[0]; - ly_set_free(set, NULL); + snode = (struct lysc_node *)lys_find_path(ly_ctx, NULL, xpath, 0); return snode; } diff --git a/mgmtd/mgmt_be_adapter.c b/mgmtd/mgmt_be_adapter.c index 5ab11ea4917b..8330f6f36b70 100644 --- a/mgmtd/mgmt_be_adapter.c +++ b/mgmtd/mgmt_be_adapter.c @@ -10,6 +10,7 @@ #include #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); diff --git a/mgmtd/mgmt_be_adapter.h b/mgmtd/mgmt_be_adapter.h index ca8f55c457ff..0597136c8a7a 100644 --- a/mgmtd/mgmt_be_adapter.h +++ b/mgmtd/mgmt_be_adapter.h @@ -20,6 +20,22 @@ #define MGMTD_FIND_ADAPTER_BY_INDEX(adapter_index) \ mgmt_adaptr_ref[adapter_index] +/** + * CLIENT-ID + * + * Add enum value for each supported component, wrap with + * #ifdef HAVE_COMPONENT + */ +enum mgmt_be_client_id { + MGMTD_BE_CLIENT_ID_MIN = 0, + MGMTD_BE_CLIENT_ID_INIT = -1, +#ifdef HAVE_STATICD + MGMTD_BE_CLIENT_ID_STATICD, +#endif + MGMTD_BE_CLIENT_ID_MAX +}; + + enum mgmt_be_req_type { MGMTD_BE_REQ_NONE = 0, MGMTD_BE_REQ_CFG_VALIDATE, @@ -49,8 +65,6 @@ struct mgmt_be_client_adapter { enum mgmt_be_client_id id; uint32_t flags; char name[MGMTD_CLIENT_NAME_MAX_LEN]; - uint8_t num_xpath_reg; - char xpath_reg[MGMTD_MAX_NUM_XPATH_REG][MGMTD_MAX_XPATH_LEN]; int refcount; @@ -81,9 +95,36 @@ DECLARE_LIST(mgmt_be_adapters, struct mgmt_be_client_adapter, list_linkage); #define MGMT_SUBSCR_OPER_OWN 0x4 #define MGMT_SUBSCR_ALL 0x7 -struct mgmt_be_client_subscr_info { - uint xpath_subscr[MGMTD_BE_CLIENT_ID_MAX]; -}; +/* --------- */ +/* CLIENT-ID */ +/* --------- */ + +#define FOREACH_MGMTD_BE_CLIENT_ID(id) \ + for ((id) = MGMTD_BE_CLIENT_ID_MIN; (id) < MGMTD_BE_CLIENT_ID_MAX; \ + (id)++) + +#define IS_IDBIT_SET(v, id) (!IS_IDBIT_UNSET(v, id)) +#define IS_IDBIT_UNSET(v, id) (!((v) & (1ull << (id)))) + +#define __GET_NEXT_SET(id, bits) \ + ({ \ + enum mgmt_be_client_id __id = (id); \ + \ + for (; __id < MGMTD_BE_CLIENT_ID_MAX && \ + IS_IDBIT_UNSET(bits, __id); \ + __id++) \ + ; \ + __id; \ + }) + +#define FOREACH_BE_CLIENT_BITS(id, bits) \ + for ((id) = __GET_NEXT_SET(MGMTD_BE_CLIENT_ID_MIN, bits); \ + (id) < MGMTD_BE_CLIENT_ID_MAX; \ + (id) = __GET_NEXT_SET((id) + 1, bits)) + +/* ---------- */ +/* Prototypes */ +/* ---------- */ /* Initialise backend adapter module. */ extern void mgmt_be_adapter_init(struct event_loop *tm); @@ -177,17 +218,13 @@ extern void mgmt_be_xpath_register_write(struct vty *vty); * * Args: * xpath - the xpath to check for subscription information. - * subscr_info - An array of uint indexed by client id - * each eleemnt holds the subscription info - * for that client. + * config - true for config interest false for oper interest. */ -extern void mgmt_be_get_subscr_info_for_xpath( - const char *xpath, struct mgmt_be_client_subscr_info *subscr_info); +extern uint64_t mgmt_be_interested_clients(const char *xpath, bool config); /* * Dump backend client information for a given xpath to vty. */ -extern void mgmt_be_xpath_subscr_info_write(struct vty *vty, - const char *xpath); +extern void mgmt_be_show_xpath_registries(struct vty *vty, const char *xpath); #endif /* _FRR_MGMTD_BE_ADAPTER_H_ */ diff --git a/mgmtd/mgmt_txn.c b/mgmtd/mgmt_txn.c index ebad48e8323b..5d1d88b0630d 100644 --- a/mgmtd/mgmt_txn.c +++ b/mgmtd/mgmt_txn.c @@ -80,7 +80,6 @@ struct mgmt_txn_be_cfg_batch { uint64_t batch_id; enum mgmt_be_client_id be_id; struct mgmt_be_client_adapter *be_adapter; - uint xp_subscr[MGMTD_MAX_CFG_CHANGES_IN_BATCH]; Mgmtd__YangCfgDataReq cfg_data[MGMTD_MAX_CFG_CHANGES_IN_BATCH]; Mgmtd__YangCfgDataReq *cfg_datap[MGMTD_MAX_CFG_CHANGES_IN_BATCH]; Mgmtd__YangData data[MGMTD_MAX_CFG_CHANGES_IN_BATCH]; @@ -125,7 +124,7 @@ struct mgmt_commit_cfg_req { * Details on all the Backend Clients associated with * this commit. */ - struct mgmt_be_client_subscr_info subscr_info; + uint64_t clients; /* * List of backend batches for this commit to be validated @@ -546,8 +545,7 @@ static void mgmt_txn_req_free(struct mgmt_txn_req **txn_req) * send a txn delete message */ adapter = mgmt_be_get_adapter_by_id(id); - if (adapter && cleanup && - ccreq->subscr_info.xpath_subscr[id]) + if (adapter && cleanup && IS_IDBIT_SET(ccreq->clients, id)) mgmt_txn_send_be_txn_delete((*txn_req)->txn, adapter); } @@ -915,7 +913,7 @@ mgmt_try_move_commit_to_next_phase(struct mgmt_txn_ctx *txn, * Check if all clients has moved to next phase or not. */ FOREACH_MGMTD_BE_CLIENT_ID (id) { - if (cmtcfg_req->subscr_info.xpath_subscr[id] && + if (IS_IDBIT_SET(cmtcfg_req->clients, id) && mgmt_txn_batches_count(&cmtcfg_req->curr_batches[id])) { /* * There's atleast once client who hasn't moved to @@ -991,13 +989,15 @@ mgmt_move_be_commit_to_next_phase(struct mgmt_txn_ctx *txn, return 0; } +/* + * This is the real workhorse + */ static int mgmt_txn_create_config_batches(struct mgmt_txn_req *txn_req, struct nb_config_cbs *changes) { struct nb_config_cb *cb, *nxt; struct nb_config_change *chg; struct mgmt_txn_be_cfg_batch *batch; - struct mgmt_be_client_subscr_info subscr_info; char *xpath = NULL, *value = NULL; char err_buf[1024]; enum mgmt_be_client_id id; @@ -1006,6 +1006,7 @@ static int mgmt_txn_create_config_batches(struct mgmt_txn_req *txn_req, bool found_validator; int num_chgs = 0; int xpath_len, value_len; + uint64_t clients; cmtcfg_req = &txn_req->req.commit_cfg; @@ -1032,17 +1033,16 @@ static int mgmt_txn_create_config_batches(struct mgmt_txn_req *txn_req, MGMTD_TXN_DBG("XPATH: %s, Value: '%s'", xpath, value ? value : "NIL"); - mgmt_be_get_subscr_info_for_xpath(xpath, &subscr_info); + clients = mgmt_be_interested_clients(xpath, true); + cmtcfg_req->clients |= clients; + if (clients) + found_validator = true; + else + found_validator = false; xpath_len = strlen(xpath) + 1; value_len = strlen(value) + 1; - found_validator = false; - FOREACH_MGMTD_BE_CLIENT_ID (id) { - if (!(subscr_info.xpath_subscr[id] & - (MGMT_SUBSCR_VALIDATE_CFG | - MGMT_SUBSCR_NOTIFY_CFG))) - continue; - + FOREACH_BE_CLIENT_BITS (id, clients) { adapter = mgmt_be_get_adapter_by_id(id); if (!adapter) continue; @@ -1058,9 +1058,6 @@ static int mgmt_txn_create_config_batches(struct mgmt_txn_req *txn_req, } batch->buf_space_left -= (xpath_len + value_len); - memcpy(&batch->xp_subscr[batch->num_cfg_data], - &subscr_info.xpath_subscr[id], - sizeof(batch->xp_subscr[0])); mgmt_yang_cfg_data_req_init( &batch->cfg_data[batch->num_cfg_data]); @@ -1089,12 +1086,6 @@ static int mgmt_txn_create_config_batches(struct mgmt_txn_req *txn_req, value; value = NULL; - if (subscr_info.xpath_subscr[id] & - MGMT_SUBSCR_VALIDATE_CFG) - found_validator = true; - - cmtcfg_req->subscr_info.xpath_subscr[id] |= - subscr_info.xpath_subscr[id]; MGMTD_TXN_DBG(" -- %s, batch-id: %" PRIu64 " item:%d", adapter->name, batch->batch_id, (int)batch->num_cfg_data); @@ -1318,7 +1309,7 @@ static int mgmt_txn_send_be_txn_create(struct mgmt_txn_ctx *txn) cmtcfg_req = &txn->commit_cfg_req->req.commit_cfg; FOREACH_MGMTD_BE_CLIENT_ID (id) { - if (cmtcfg_req->subscr_info.xpath_subscr[id]) { + if (IS_IDBIT_SET(cmtcfg_req->clients, id)) { adapter = mgmt_be_get_adapter_by_id(id); if (mgmt_be_send_txn_req(adapter, txn->txn_id, true)) { (void)mgmt_txn_send_commit_cfg_reply( @@ -1364,7 +1355,7 @@ static int mgmt_txn_send_be_cfg_data(struct mgmt_txn_ctx *txn, assert(txn->type == MGMTD_TXN_TYPE_CONFIG && txn->commit_cfg_req); cmtcfg_req = &txn->commit_cfg_req->req.commit_cfg; - assert(cmtcfg_req->subscr_info.xpath_subscr[adapter->id]); + assert(IS_IDBIT_SET(cmtcfg_req->clients, adapter->id)); indx = 0; num_batches = @@ -1417,7 +1408,7 @@ static int mgmt_txn_send_be_txn_delete(struct mgmt_txn_ctx *txn, assert(txn->type == MGMTD_TXN_TYPE_CONFIG); assert(!mgmt_txn_batches_count(&cmtcfg_req->curr_batches[adapter->id])); - if (!cmtcfg_req->subscr_info.xpath_subscr[adapter->id]) + if (IS_IDBIT_UNSET(cmtcfg_req->clients, adapter->id)) return 0; return mgmt_be_send_txn_req(adapter, txn->txn_id, false); @@ -1476,8 +1467,7 @@ static int mgmt_txn_send_be_cfg_apply(struct mgmt_txn_ctx *txn) } FOREACH_MGMTD_BE_CLIENT_ID (id) { - if (cmtcfg_req->subscr_info.xpath_subscr[id] & - MGMT_SUBSCR_NOTIFY_CFG) { + if (IS_IDBIT_SET(cmtcfg_req->clients, id)) { adapter = mgmt_be_get_adapter_by_id(id); if (!adapter) return -1; @@ -2365,9 +2355,8 @@ int mgmt_txn_notify_be_adapter_conn(struct mgmt_be_client_adapter *adapter, ? &txn->commit_cfg_req->req .commit_cfg : NULL; - if (cmtcfg_req && - cmtcfg_req->subscr_info - .xpath_subscr[adapter->id]) { + if (cmtcfg_req && IS_IDBIT_SET(cmtcfg_req->clients, + adapter->id)) { mgmt_txn_send_commit_cfg_reply( txn, MGMTD_INTERNAL_ERROR, "Backend daemon disconnected while processing commit!"); diff --git a/mgmtd/mgmt_vty.c b/mgmtd/mgmt_vty.c index d8f5976f4d6e..e7d69667103b 100644 --- a/mgmtd/mgmt_vty.c +++ b/mgmtd/mgmt_vty.c @@ -273,7 +273,7 @@ DEFPY(show_mgmt_map_xpath, "Get YANG Backend Subscription\n" "XPath expression specifying the YANG data path\n") { - mgmt_be_xpath_subscr_info_write(vty, path); + mgmt_be_show_xpath_registries(vty, path); return CMD_SUCCESS; } diff --git a/tools/checkpatch.pl b/tools/checkpatch.pl index d007c1d32580..e3788bde16b6 100755 --- a/tools/checkpatch.pl +++ b/tools/checkpatch.pl @@ -547,7 +547,7 @@ sub hash_show_words { our $c90_Keywords = qr{do|for|while|if|else|return|goto|continue|switch|default|case|break}x; our $Iterators = qr{ - frr_each|frr_each_safe|frr_each_from| + darr_foreach_p|darr_foreach_i|frr_each|frr_each_safe|frr_each_from| frr_with_mutex|frr_with_privs| LIST_FOREACH|LIST_FOREACH_SAFE| SLIST_FOREACH|SLIST_FOREACH_SAFE|SLIST_FOREACH_PREVPTR| @@ -563,6 +563,7 @@ sub hash_show_words { SUBGRP_FOREACH_PEER|SUBGRP_FOREACH_PEER_SAFE| SUBGRP_FOREACH_ADJ|SUBGRP_FOREACH_ADJ_SAFE| AF_FOREACH|FOREACH_AFI_SAFI|FOREACH_SAFI| + FOREACH_BE_CLIENT_BITS|FOREACH_MGMTD_BE_CLIENT_ID| LSDB_LOOP }x; diff --git a/tools/checkpatch.sh b/tools/checkpatch.sh index 6071f4804d9e..bf63057b0219 100755 --- a/tools/checkpatch.sh +++ b/tools/checkpatch.sh @@ -3,7 +3,8 @@ usage="./checkpatch.sh " patch=$1 tree=$2 -checkpatch="$tree/tools/checkpatch.pl --no-tree -f" +scriptdir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd)" +checkpatch="$scriptdir/checkpatch.pl --no-tree -f" ignore="ldpd\|babeld" cwd=${PWD##*/} dirty=0