diff options
Diffstat (limited to 'mgmtd/mgmt_be_adapter.c')
-rw-r--r-- | mgmtd/mgmt_be_adapter.c | 895 |
1 files changed, 490 insertions, 405 deletions
diff --git a/mgmtd/mgmt_be_adapter.c b/mgmtd/mgmt_be_adapter.c index 399fdaf..b311bf4 100644 --- a/mgmtd/mgmt_be_adapter.c +++ b/mgmtd/mgmt_be_adapter.c @@ -10,79 +10,141 @@ #include <zebra.h> #include "darr.h" #include "frrevent.h" +#include "frrstr.h" #include "sockopt.h" #include "network.h" #include "libfrr.h" #include "mgmt_msg.h" +#include "mgmt_msg_native.h" #include "mgmt_pb.h" #include "mgmtd/mgmt.h" #include "mgmtd/mgmt_memory.h" #include "mgmt_be_client.h" #include "mgmtd/mgmt_be_adapter.h" -#define MGMTD_BE_ADAPTER_DBG(fmt, ...) \ +#define __dbg(fmt, ...) \ DEBUGD(&mgmt_debug_be, "BE-ADAPTER: %s: " fmt, __func__, ##__VA_ARGS__) -#define MGMTD_BE_ADAPTER_ERR(fmt, ...) \ +#define __log_err(fmt, ...) \ zlog_err("BE-ADAPTER: %s: ERROR: " fmt, __func__, ##__VA_ARGS__) #define FOREACH_ADAPTER_IN_LIST(adapter) \ frr_each_safe (mgmt_be_adapters, &mgmt_be_adapters, (adapter)) +/* ---------- */ +/* Client IDs */ +/* ---------- */ + +const char *mgmt_be_client_names[MGMTD_BE_CLIENT_ID_MAX + 1] = { + [MGMTD_BE_CLIENT_ID_TESTC] = "mgmtd-testc", /* always first */ + [MGMTD_BE_CLIENT_ID_ZEBRA] = "zebra", +#ifdef HAVE_RIPD + [MGMTD_BE_CLIENT_ID_RIPD] = "ripd", +#endif +#ifdef HAVE_RIPNGD + [MGMTD_BE_CLIENT_ID_RIPNGD] = "ripngd", +#endif +#ifdef HAVE_STATICD + [MGMTD_BE_CLIENT_ID_STATICD] = "staticd", +#endif + [MGMTD_BE_CLIENT_ID_MAX] = "Unknown/Invalid", +}; + +/* ------------- */ +/* XPATH MAPPING */ +/* ------------- */ + /* - * Mapping of YANG XPath regular expressions to - * their corresponding backend clients. + * Mapping of YANG XPath prefixes to their corresponding backend clients. */ struct mgmt_be_xpath_map { - char *xpath_regexp; - uint subscr_info[MGMTD_BE_CLIENT_ID_MAX]; + char *xpath_prefix; + uint64_t clients; }; -struct mgmt_be_client_xpath { - const char *xpath; - uint subscribed; +/* + * Each client gets their own map, but also union all the strings into the + * above map as well. + */ + +static const char *const zebra_config_xpaths[] = { + "/frr-affinity-map:lib", + "/frr-filter:lib", + "/frr-route-map:lib", + "/frr-zebra:zebra", + "/frr-interface:lib", + "/frr-vrf:lib", + NULL, }; -struct mgmt_be_client_xpath_map { - struct mgmt_be_client_xpath *xpaths; - uint nxpaths; +static const char *const zebra_oper_xpaths[] = { + "/frr-interface:lib/interface", + "/frr-vrf:lib/vrf/frr-zebra:zebra", + "/frr-zebra:zebra", + NULL, }; -struct mgmt_be_get_adapter_config_params { - struct mgmt_be_client_adapter *adapter; - struct nb_config_cbs *cfg_chgs; - uint32_t seq; +#if HAVE_RIPD +static const char *const ripd_config_xpaths[] = { + "/frr-filter:lib", + "/frr-interface:lib/interface", + "/frr-ripd:ripd", + "/frr-route-map:lib", + "/frr-vrf:lib", + NULL, +}; +static const char *const ripd_oper_xpaths[] = { + "/frr-ripd:ripd", + NULL, }; +#endif + +#if HAVE_RIPNGD +static const char *const ripngd_config_xpaths[] = { + "/frr-filter:lib", + "/frr-interface:lib/interface", + "/frr-ripngd:ripngd", + "/frr-route-map:lib", + "/frr-vrf:lib", + NULL, +}; +static const char *const ripngd_oper_xpaths[] = { + "/frr-ripngd:ripngd", + NULL, +}; +#endif -/* - * Each client gets their own map, but also union all the strings into the - * 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_config_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_config_xpaths[MGMTD_BE_CLIENT_ID_MAX] = { + [MGMTD_BE_CLIENT_ID_ZEBRA] = zebra_config_xpaths, +#ifdef HAVE_RIPD + [MGMTD_BE_CLIENT_ID_RIPD] = ripd_config_xpaths, +#endif +#ifdef HAVE_RIPNGD + [MGMTD_BE_CLIENT_ID_RIPNGD] = ripngd_config_xpaths, +#endif #ifdef HAVE_STATICD - [MGMTD_BE_CLIENT_ID_STATICD] = {staticd_xpaths, - array_size(staticd_xpaths)}, + [MGMTD_BE_CLIENT_ID_STATICD] = staticd_config_xpaths, #endif }; +static const char *const *be_client_oper_xpaths[MGMTD_BE_CLIENT_ID_MAX] = { +#ifdef HAVE_RIPD + [MGMTD_BE_CLIENT_ID_RIPD] = ripd_oper_xpaths, +#endif +#ifdef HAVE_RIPNGD + [MGMTD_BE_CLIENT_ID_RIPNGD] = ripngd_oper_xpaths, +#endif + [MGMTD_BE_CLIENT_ID_ZEBRA] = zebra_oper_xpaths, +}; + /* * We would like to have a better ADT than one with O(n) comparisons * @@ -91,7 +153,10 @@ 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 mgmt_be_xpath_map *be_notif_xpath_map; static struct event_loop *mgmt_loop; static struct msg_server mgmt_be_server = {.fd = -1}; @@ -101,12 +166,33 @@ 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); + +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,183 +221,103 @@ 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, bool oper) { - 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; + if (config) + maps = &be_cfg_xpath_map; + else if (oper) + maps = &be_oper_xpath_map; + else + maps = &be_notif_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"); + __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_config_xpaths[id]; init && *init; init++) { + __dbg(" - CFG XPATH: '%s'", *init); + mgmt_register_client_xpath(id, *init, true, false); + } + + /* Initialize the common oper init map */ + for (init = be_client_oper_xpaths[id]; init && *init; init++) { + __dbg(" - OPER XPATH: '%s'", *init); + mgmt_register_client_xpath(id, *init, false, true); } } - MGMTD_BE_ADAPTER_DBG("Total XPath Maps: %u", darr_len(mgmt_xpath_map)); + __dbg("Total Cfg XPath Maps: %u", darr_len(be_cfg_xpath_map)); + __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; + darr_foreach_p (be_cfg_xpath_map, map) + XFREE(MTYPE_MGMTD_XPATH, map->xpath_prefix); + darr_free(be_cfg_xpath_map); - 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_oper_xpath_map, map) + XFREE(MTYPE_MGMTD_XPATH, map->xpath_prefix); + darr_free(be_oper_xpath_map); - if (!rexp_len || !xpath_len) - return 0; - - 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]; - } - } - } + darr_foreach_p (be_notif_xpath_map, map) + XFREE(MTYPE_MGMTD_XPATH, map->xpath_prefix); + darr_free(be_notif_xpath_map); +} - /* - * 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) { - MGMTD_BE_ADAPTER_DBG("deleting client adapter '%s'", adapter->name); + __dbg("deleting client adapter '%s'", adapter->name); /* * Notify about disconnect for appropriate cleanup @@ -330,8 +336,7 @@ static int mgmt_be_adapter_notify_disconnect(struct msg_conn *conn) { struct mgmt_be_client_adapter *adapter = conn->user; - MGMTD_BE_ADAPTER_DBG("notify disconnect for client adapter '%s'", - adapter->name); + __dbg("notify disconnect for client adapter '%s'", adapter->name); mgmt_be_adapter_delete(adapter); @@ -349,17 +354,14 @@ mgmt_be_adapter_cleanup_old_conn(struct mgmt_be_client_adapter *adapter) /* * We have a Zombie lingering around */ - MGMTD_BE_ADAPTER_DBG( - "Client '%s' (FD:%d) seems to have reconnected. Removing old connection (FD:%d)!", - adapter->name, adapter->conn->fd, - old->conn->fd); + __dbg("Client '%s' (FD:%d) seems to have reconnected. Removing old connection (FD:%d)!", + adapter->name, adapter->conn->fd, old->conn->fd); /* this will/should delete old */ msg_conn_disconnect(old->conn, false); } } } - static int mgmt_be_adapter_send_msg(struct mgmt_be_client_adapter *adapter, Mgmtd__BeMessage *be_msg) { @@ -382,8 +384,8 @@ static int mgmt_be_send_subscr_reply(struct mgmt_be_client_adapter *adapter, be_msg.message_case = MGMTD__BE_MESSAGE__MESSAGE_SUBSCR_REPLY; be_msg.subscr_reply = &reply; - MGMTD_FE_CLIENT_DBG("Sending SUBSCR_REPLY client: %s sucess: %u", - adapter->name, success); + __dbg("Sending SUBSCR_REPLY client: %s sucess: %u", adapter->name, + success); return mgmt_be_adapter_send_msg(adapter, &be_msg); } @@ -392,32 +394,30 @@ static int mgmt_be_adapter_handle_msg(struct mgmt_be_client_adapter *adapter, Mgmtd__BeMessage *be_msg) { + const char *xpath; + uint i, num; + /* * protobuf-c adds a max size enum with an internal, and changing by * version, name; cast to an int to avoid unhandled enum warnings */ switch ((int)be_msg->message_case) { case MGMTD__BE_MESSAGE__MESSAGE_SUBSCR_REQ: - MGMTD_BE_ADAPTER_DBG( - "Got SUBSCR_REQ from '%s' to %sregister %zu xpaths", - be_msg->subscr_req->client_name, - !be_msg->subscr_req->subscribe_xpaths && - be_msg->subscr_req->n_xpath_reg - ? "de" - : "", - be_msg->subscr_req->n_xpath_reg); + __dbg("Got SUBSCR_REQ from '%s' to register xpaths config: %zu oper: %zu notif: %zu", + be_msg->subscr_req->client_name, + be_msg->subscr_req->n_config_xpaths, + be_msg->subscr_req->n_oper_xpaths, + be_msg->subscr_req->n_notif_xpaths); if (strlen(be_msg->subscr_req->client_name)) { strlcpy(adapter->name, be_msg->subscr_req->client_name, sizeof(adapter->name)); adapter->id = mgmt_be_client_name2id(adapter->name); if (adapter->id >= MGMTD_BE_CLIENT_ID_MAX) { - MGMTD_BE_ADAPTER_ERR( - "Unable to resolve adapter '%s' to a valid ID. Disconnecting!", - adapter->name); + __log_err("Unable to resolve adapter '%s' to a valid ID. Disconnecting!", + adapter->name); /* this will/should delete old */ msg_conn_disconnect(adapter->conn, false); - zlog_err("XXX different from original code"); break; } mgmt_be_adapters_by_id[adapter->id] = adapter; @@ -427,19 +427,34 @@ mgmt_be_adapter_handle_msg(struct mgmt_be_client_adapter *adapter, mgmt_be_adapter_sched_init_event(adapter); } - if (be_msg->subscr_req->n_xpath_reg) - /* we aren't handling dynamic xpaths yet */ - mgmt_be_send_subscr_reply(adapter, false); - else - mgmt_be_send_subscr_reply(adapter, true); + num = be_msg->subscr_req->n_config_xpaths; + for (i = 0; i < num; i++) { + xpath = be_msg->subscr_req->config_xpaths[i]; + mgmt_register_client_xpath(adapter->id, xpath, true, + false); + } + + num = be_msg->subscr_req->n_oper_xpaths; + for (i = 0; i < num; i++) { + xpath = be_msg->subscr_req->oper_xpaths[i]; + mgmt_register_client_xpath(adapter->id, xpath, false, + true); + } + + num = be_msg->subscr_req->n_notif_xpaths; + for (i = 0; i < num; i++) { + xpath = be_msg->subscr_req->notif_xpaths[i]; + mgmt_register_client_xpath(adapter->id, xpath, false, + false); + } + + mgmt_be_send_subscr_reply(adapter, true); break; case MGMTD__BE_MESSAGE__MESSAGE_TXN_REPLY: - MGMTD_BE_ADAPTER_DBG( - "Got %s TXN_REPLY from '%s' txn-id %" PRIx64 - " with '%s'", - be_msg->txn_reply->create ? "Create" : "Delete", - adapter->name, be_msg->txn_reply->txn_id, - be_msg->txn_reply->success ? "success" : "failure"); + __dbg("Got %s TXN_REPLY from '%s' txn-id %" PRIx64 " with '%s'", + be_msg->txn_reply->create ? "Create" : "Delete", + adapter->name, be_msg->txn_reply->txn_id, + be_msg->txn_reply->success ? "success" : "failure"); /* * Forward the TXN_REPLY to txn module. */ @@ -449,58 +464,40 @@ mgmt_be_adapter_handle_msg(struct mgmt_be_client_adapter *adapter, be_msg->txn_reply->success, adapter); break; case MGMTD__BE_MESSAGE__MESSAGE_CFG_DATA_REPLY: - MGMTD_BE_ADAPTER_DBG( - "Got CFGDATA_REPLY from '%s' txn-id %" PRIx64 - " batch-id %" PRIu64 " err:'%s'", - adapter->name, be_msg->cfg_data_reply->txn_id, - be_msg->cfg_data_reply->batch_id, - be_msg->cfg_data_reply->error_if_any - ? be_msg->cfg_data_reply->error_if_any - : "None"); + __dbg("Got CFGDATA_REPLY from '%s' txn-id %" PRIx64 " err:'%s'", + adapter->name, be_msg->cfg_data_reply->txn_id, + be_msg->cfg_data_reply->error_if_any + ? be_msg->cfg_data_reply->error_if_any + : "None"); /* * Forward the CGFData-create reply to txn module. */ mgmt_txn_notify_be_cfgdata_reply( be_msg->cfg_data_reply->txn_id, - be_msg->cfg_data_reply->batch_id, be_msg->cfg_data_reply->success, be_msg->cfg_data_reply->error_if_any, adapter); break; case MGMTD__BE_MESSAGE__MESSAGE_CFG_APPLY_REPLY: - MGMTD_BE_ADAPTER_DBG( - "Got %s CFG_APPLY_REPLY from '%s' txn-id %" PRIx64 - " for %zu batches id %" PRIu64 "-%" PRIu64 " err:'%s'", - be_msg->cfg_apply_reply->success ? "successful" - : "failed", - adapter->name, be_msg->cfg_apply_reply->txn_id, - be_msg->cfg_apply_reply->n_batch_ids, - be_msg->cfg_apply_reply->batch_ids[0], - be_msg->cfg_apply_reply->batch_ids - [be_msg->cfg_apply_reply->n_batch_ids - 1], - be_msg->cfg_apply_reply->error_if_any - ? be_msg->cfg_apply_reply->error_if_any - : "None"); + __dbg("Got %s CFG_APPLY_REPLY from '%s' txn-id %" PRIx64 + " err:'%s'", + be_msg->cfg_apply_reply->success ? "successful" : "failed", + adapter->name, be_msg->cfg_apply_reply->txn_id, + be_msg->cfg_apply_reply->error_if_any + ? be_msg->cfg_apply_reply->error_if_any + : "None"); /* * Forward the CGFData-apply reply to txn module. */ mgmt_txn_notify_be_cfg_apply_reply( be_msg->cfg_apply_reply->txn_id, be_msg->cfg_apply_reply->success, - (uint64_t *)be_msg->cfg_apply_reply->batch_ids, - be_msg->cfg_apply_reply->n_batch_ids, be_msg->cfg_apply_reply->error_if_any, adapter); break; - case MGMTD__BE_MESSAGE__MESSAGE_GET_REPLY: - /* - * TODO: Add handling code in future. - */ - break; /* * NOTE: The following messages are always sent from MGMTD to * Backend clients only and/or need not be handled on MGMTd. */ case MGMTD__BE_MESSAGE__MESSAGE_SUBSCR_REPLY: - case MGMTD__BE_MESSAGE__MESSAGE_GET_REQ: case MGMTD__BE_MESSAGE__MESSAGE_TXN_REQ: case MGMTD__BE_MESSAGE__MESSAGE_CFG_DATA_REQ: case MGMTD__BE_MESSAGE__MESSAGE_CFG_APPLY_REQ: @@ -532,14 +529,13 @@ int mgmt_be_send_txn_req(struct mgmt_be_client_adapter *adapter, be_msg.message_case = MGMTD__BE_MESSAGE__MESSAGE_TXN_REQ; be_msg.txn_req = &txn_req; - MGMTD_BE_ADAPTER_DBG("Sending TXN_REQ to '%s' txn-id: %" PRIu64, - adapter->name, txn_id); + __dbg("Sending TXN_REQ to '%s' txn-id: %" PRIu64, adapter->name, txn_id); return mgmt_be_adapter_send_msg(adapter, &be_msg); } int mgmt_be_send_cfgdata_req(struct mgmt_be_client_adapter *adapter, - uint64_t txn_id, uint64_t batch_id, + uint64_t txn_id, Mgmtd__YangCfgDataReq **cfgdata_reqs, size_t num_reqs, bool end_of_data) { @@ -547,7 +543,6 @@ int mgmt_be_send_cfgdata_req(struct mgmt_be_client_adapter *adapter, Mgmtd__BeCfgDataCreateReq cfgdata_req; mgmtd__be_cfg_data_create_req__init(&cfgdata_req); - cfgdata_req.batch_id = batch_id; cfgdata_req.txn_id = txn_id; cfgdata_req.data_req = cfgdata_reqs; cfgdata_req.n_data_req = num_reqs; @@ -557,10 +552,8 @@ int mgmt_be_send_cfgdata_req(struct mgmt_be_client_adapter *adapter, be_msg.message_case = MGMTD__BE_MESSAGE__MESSAGE_CFG_DATA_REQ; be_msg.cfg_data_req = &cfgdata_req; - MGMTD_BE_ADAPTER_DBG( - "Sending CFGDATA_CREATE_REQ to '%s' txn-id: %" PRIu64 - " batch-id: %" PRIu64, - adapter->name, txn_id, batch_id); + __dbg("Sending CFGDATA_CREATE_REQ to '%s' txn-id: %" PRIu64 " last: %s", + adapter->name, txn_id, end_of_data ? "yes" : "no"); return mgmt_be_adapter_send_msg(adapter, &be_msg); } @@ -578,42 +571,148 @@ int mgmt_be_send_cfgapply_req(struct mgmt_be_client_adapter *adapter, be_msg.message_case = MGMTD__BE_MESSAGE__MESSAGE_CFG_APPLY_REQ; be_msg.cfg_apply_req = &apply_req; - MGMTD_BE_ADAPTER_DBG("Sending CFG_APPLY_REQ to '%s' txn-id: %" PRIu64, - adapter->name, txn_id); + __dbg("Sending CFG_APPLY_REQ to '%s' txn-id: %" PRIu64, adapter->name, + txn_id); return mgmt_be_adapter_send_msg(adapter, &be_msg); } +int mgmt_be_send_native(enum mgmt_be_client_id id, void *msg) +{ + struct mgmt_be_client_adapter *adapter = mgmt_be_get_adapter_by_id(id); + + if (!adapter) + return -1; + + return mgmt_msg_native_send_msg(adapter->conn, msg, false); +} + +static void mgmt_be_adapter_send_notify(struct mgmt_msg_notify_data *msg, + size_t msglen) +{ + struct mgmt_be_client_adapter *adapter; + struct mgmt_be_xpath_map *map; + struct nb_node *nb_node; + const char *notif; + uint id, len; + + if (!darr_len(be_notif_xpath_map)) + return; + + notif = mgmt_msg_native_xpath_decode(msg, msglen); + if (!notif) { + __log_err("Corrupt notify msg"); + return; + } + + nb_node = nb_node_find(notif); + if (!nb_node) { + __log_err("No schema found for notification: %s", notif); + return; + } + + darr_foreach_p (be_notif_xpath_map, map) { + len = strlen(map->xpath_prefix); + if (strncmp(map->xpath_prefix, nb_node->xpath, len) && + strncmp(map->xpath_prefix, notif, len)) + continue; + + FOREACH_BE_CLIENT_BITS (id, map->clients) { + adapter = mgmt_be_get_adapter_by_id(id); + if (!adapter) + continue; + msg_conn_send_msg(adapter->conn, MGMT_MSG_VERSION_NATIVE, + msg, msglen, NULL, false); + } + } +} + +/* + * Handle a native encoded message + */ +static void be_adapter_handle_native_msg(struct mgmt_be_client_adapter *adapter, + struct mgmt_msg_header *msg, + size_t msg_len) +{ + struct mgmt_msg_notify_data *notify_msg; + struct mgmt_msg_tree_data *tree_msg; + struct mgmt_msg_error *error_msg; + + /* get the transaction */ + + switch (msg->code) { + case MGMT_MSG_CODE_ERROR: + error_msg = (typeof(error_msg))msg; + __dbg("Got ERROR from '%s' txn-id %" PRIx64, adapter->name, + msg->refer_id); + + /* Forward the reply to the txn module */ + mgmt_txn_notify_error(adapter, msg->refer_id, msg->req_id, + error_msg->error, error_msg->errstr); + + break; + case MGMT_MSG_CODE_TREE_DATA: + /* tree data from a backend client */ + tree_msg = (typeof(tree_msg))msg; + __dbg("Got TREE_DATA from '%s' txn-id %" PRIx64, adapter->name, + msg->refer_id); + + /* Forward the reply to the txn module */ + mgmt_txn_notify_tree_data_reply(adapter, tree_msg, msg_len); + break; + case MGMT_MSG_CODE_NOTIFY: + notify_msg = (typeof(notify_msg))msg; + __dbg("Got NOTIFY from '%s'", adapter->name); + mgmt_be_adapter_send_notify(notify_msg, msg_len); + mgmt_fe_adapter_send_notify(notify_msg, msg_len); + break; + default: + __log_err("unknown native message txn-id %" PRIu64 + " req-id %" PRIu64 + " code %u from BE client for adapter %s", + msg->refer_id, msg->req_id, msg->code, adapter->name); + break; + } +} + + static void mgmt_be_adapter_process_msg(uint8_t version, uint8_t *data, size_t len, struct msg_conn *conn) { struct mgmt_be_client_adapter *adapter = conn->user; - Mgmtd__BeMessage *be_msg = mgmtd__be_message__unpack(NULL, len, data); + Mgmtd__BeMessage *be_msg; + + if (version == MGMT_MSG_VERSION_NATIVE) { + struct mgmt_msg_header *msg = (typeof(msg))data; + + if (len >= sizeof(*msg)) + be_adapter_handle_native_msg(adapter, msg, len); + else + __log_err("native message to adapter %s too short %zu", + adapter->name, len); + return; + } + be_msg = mgmtd__be_message__unpack(NULL, len, data); if (!be_msg) { - MGMTD_BE_ADAPTER_DBG( - "Failed to decode %zu bytes for adapter: %s", len, - adapter->name); + __dbg("Failed to decode %zu bytes for adapter: %s", len, + adapter->name); return; } - MGMTD_BE_ADAPTER_DBG("Decoded %zu bytes of message: %u for adapter: %s", - len, be_msg->message_case, adapter->name); + __dbg("Decoded %zu bytes of message: %u for adapter: %s", len, + be_msg->message_case, adapter->name); (void)mgmt_be_adapter_handle_msg(adapter, be_msg); mgmtd__be_message__free_unpacked(be_msg, NULL); } -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) - nb_config_diff_created(node, &parms->seq, parms->cfg_chgs); -} +/* + * 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; +}; /* * Initialize a BE client over a new connection @@ -626,27 +725,16 @@ static void mgmt_be_adapter_conn_init(struct event *thread) assert(adapter && adapter->conn->fd >= 0); /* - * Check first if the current session can run a CONFIG - * transaction or not. Reschedule if a CONFIG transaction - * from another session is already in progress. - */ - if (mgmt_config_txn_in_progress() != MGMTD_SESSION_ID_NONE) { - zlog_err("XXX txn in progress, retry init"); - mgmt_be_adapter_sched_init_event(adapter); - return; - } - - /* * Notify TXN module to create a CONFIG transaction and * download the CONFIGs identified for this new client. * If the TXN module fails to initiate the CONFIG transaction - * disconnect from the client forcing a reconnect later. - * That should also take care of destroying the adapter. + * retry a bit later. It only fails if there's an existing config + * transaction in progress. */ if (mgmt_txn_notify_be_adapter_conn(adapter, true) != 0) { - zlog_err("XXX notify be adapter conn fail"); - msg_conn_disconnect(adapter->conn, false); - adapter = NULL; + zlog_err("XXX txn in progress, retry init"); + mgmt_be_adapter_sched_init_event(adapter); + return; } } @@ -686,15 +774,18 @@ extern void mgmt_be_adapter_unlock(struct mgmt_be_client_adapter **adapter) */ void mgmt_be_adapter_init(struct event_loop *tm) { + char server_path[MAXPATHLEN]; + assert(!mgmt_loop); mgmt_loop = tm; mgmt_be_adapters_init(&mgmt_be_adapters); mgmt_be_xpath_map_init(); - if (msg_server_init(&mgmt_be_server, MGMTD_BE_SERVER_PATH, tm, - mgmt_be_create_adapter, "backend", - &mgmt_debug_be)) { + snprintf(server_path, sizeof(server_path), MGMTD_BE_SOCK_NAME); + + if (msg_server_init(&mgmt_be_server, server_path, tm, + mgmt_be_create_adapter, "backend", &mgmt_debug_be)) { zlog_err("cannot initialize backend server"); exit(1); } @@ -733,14 +824,17 @@ struct msg_conn *mgmt_be_create_adapter(int conn_fd, union sockunion *from) mgmt_be_adapters_add_tail(&mgmt_be_adapters, adapter); RB_INIT(nb_config_cbs, &adapter->cfg_chgs); - adapter->conn = msg_server_conn_create( - mgmt_loop, conn_fd, mgmt_be_adapter_notify_disconnect, - mgmt_be_adapter_process_msg, MGMTD_BE_MAX_NUM_MSG_PROC, - MGMTD_BE_MAX_NUM_MSG_WRITE, MGMTD_BE_MSG_MAX_LEN, adapter, - "BE-adapter"); + adapter->conn = msg_server_conn_create(mgmt_loop, conn_fd, + mgmt_be_adapter_notify_disconnect, + mgmt_be_adapter_process_msg, + MGMTD_BE_MAX_NUM_MSG_PROC, + MGMTD_BE_MAX_NUM_MSG_WRITE, + MGMTD_BE_MAX_MSG_LEN, adapter, + "BE-adapter"); - MGMTD_BE_ADAPTER_DBG("Added new MGMTD Backend adapter '%s'", - adapter->name); + adapter->conn->debug = DEBUG_MODE_CHECK(&mgmt_debug_be, DEBUG_MODE_ALL); + + __dbg("Added new MGMTD Backend adapter '%s'", adapter->name); return adapter->conn; } @@ -748,8 +842,7 @@ struct msg_conn *mgmt_be_create_adapter(int conn_fd, union sockunion *from) struct mgmt_be_client_adapter * mgmt_be_get_adapter_by_id(enum mgmt_be_client_id id) { - return (id < MGMTD_BE_CLIENT_ID_MAX ? mgmt_be_adapters_by_id[id] - : NULL); + return (id < MGMTD_BE_CLIENT_ID_MAX ? mgmt_be_adapters_by_id[id] : NULL); } struct mgmt_be_client_adapter * @@ -758,100 +851,99 @@ mgmt_be_get_adapter_by_name(const char *name) return mgmt_be_find_adapter_by_name(name); } -int mgmt_be_get_adapter_config(struct mgmt_be_client_adapter *adapter, - struct nb_config_cbs **cfg_chgs) +void mgmt_be_adapter_toggle_client_debug(bool set) { - struct mgmt_be_get_adapter_config_params parms; - struct nb_config *cfg_root = mgmt_ds_get_nb_config(mm->running_ds); - - assert(cfg_chgs); + struct mgmt_be_client_adapter *adapter; - /* - * TODO: we should consider making this an assertable condition and - * guaranteeing it be true when this function is called. B/c what is - * going to happen if there are some changes being sent, and we don't - * gather a new snapshot, what new changes that came after the previous - * snapshot will then be lost? - */ - if (RB_EMPTY(nb_config_cbs, &adapter->cfg_chgs)) { - parms.adapter = adapter; - parms.cfg_chgs = &adapter->cfg_chgs; - parms.seq = 0; + FOREACH_ADAPTER_IN_LIST (adapter) + adapter->conn->debug = set; +} - mgmt_ds_iter_data(MGMTD_DS_RUNNING, cfg_root, "", - mgmt_be_iter_and_get_cfg, (void *)&parms); +/* + * Get a full set of changes for all the config that an adapter is subscribed to + * receive. + */ +void mgmt_be_get_adapter_config(struct mgmt_be_client_adapter *adapter, + struct nb_config_cbs **changes) +{ + const struct lyd_node *root, *dnode; + uint32_t seq = 0; + char *xpath; + + /* We can't be in the middle of sending other chgs when here. */ + assert(RB_EMPTY(nb_config_cbs, &adapter->cfg_chgs)); + + *changes = &adapter->cfg_chgs; + LY_LIST_FOR (running_config->dnode, root) { + LYD_TREE_DFS_BEGIN (root, dnode) { + if (lysc_is_key(dnode->schema)) + goto walk_cont; + + xpath = lyd_path(dnode, LYD_PATH_STD, NULL, 0); + if (be_is_client_interested(xpath, adapter->id, true)) + nb_config_diff_add_change(*changes, NB_CB_CREATE, &seq, dnode); + else + LYD_TREE_DFS_continue = 1; /* skip any subtree */ + free(xpath); + walk_cont: + LYD_TREE_DFS_END(root, dnode); + } } - - *cfg_chgs = &adapter->cfg_chgs; - 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; - 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]; - } - } + clients = 0; + + __dbg("XPATH: '%s'", xpath); + 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) + __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; + uint64_t clients; - 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); + __dbg("Checking client: %s for xpath: '%s'", mgmt_be_client_id2name(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; + clients = mgmt_be_interested_clients(xpath, config); + if (IS_IDBIT_SET(clients, id)) { + __dbg("client: %s: interested", mgmt_be_client_id2name(id)); + return true; } - MGMTD_BE_ADAPTER_DBG("client: %s: subscribed: 0x%x", - mgmt_be_client_id2name(client_id), subscr); - return subscr; + + __dbg("client: %s: not interested", mgmt_be_client_id2name(id)); + return false; } void mgmt_be_adapter_status_write(struct vty *vty) @@ -878,56 +970,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"); + const char *astr; - 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); - } + 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); |