summaryrefslogtreecommitdiffstats
path: root/mgmtd
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--lib/mgmt_defines.h (renamed from mgmtd/mgmt_defines.h)26
-rw-r--r--mgmtd/mgmt.c17
-rw-r--r--mgmtd/mgmt.h8
-rw-r--r--mgmtd/mgmt_be_adapter.c895
-rw-r--r--mgmtd/mgmt_be_adapter.h107
-rw-r--r--mgmtd/mgmt_ds.c46
-rw-r--r--mgmtd/mgmt_ds.h6
-rw-r--r--mgmtd/mgmt_fe_adapter.c596
-rw-r--r--mgmtd/mgmt_fe_adapter.h52
-rw-r--r--mgmtd/mgmt_history.c35
-rw-r--r--mgmtd/mgmt_main.c154
-rw-r--r--mgmtd/mgmt_memory.c1
-rw-r--r--mgmtd/mgmt_memory.h1
-rw-r--r--mgmtd/mgmt_testc.c230
-rw-r--r--mgmtd/mgmt_txn.c1392
-rw-r--r--mgmtd/mgmt_txn.h82
-rw-r--r--mgmtd/mgmt_vty.c196
-rw-r--r--mgmtd/subdir.am53
18 files changed, 2442 insertions, 1455 deletions
diff --git a/mgmtd/mgmt_defines.h b/lib/mgmt_defines.h
index 40fa670..b02341e 100644
--- a/mgmtd/mgmt_defines.h
+++ b/lib/mgmt_defines.h
@@ -11,6 +11,9 @@
#include "yang.h"
+#define MGMTD_FE_SOCK_NAME "%s/mgmtd_fe.sock", frr_runstatedir
+#define MGMTD_BE_SOCK_NAME "%s/mgmtd_be.sock", frr_runstatedir
+
#define MGMTD_CLIENT_NAME_MAX_LEN 32
#define MGMTD_MAX_XPATH_LEN XPATH_MAXLEN
@@ -32,27 +35,4 @@ enum mgmt_result {
MGMTD_UNKNOWN_FAILURE
};
-enum mgmt_fe_event {
- MGMTD_FE_SERVER = 1,
- MGMTD_FE_CONN_READ,
- MGMTD_FE_CONN_WRITE,
- MGMTD_FE_PROC_MSG
-};
-
-enum mgmt_be_event {
- MGMTD_BE_SERVER = 1,
- MGMTD_BE_CONN_INIT,
- MGMTD_BE_CONN_READ,
- MGMTD_BE_CONN_WRITE,
- MGMTD_BE_PROC_MSG,
- MGMTD_BE_SCHED_CFG_PREPARE,
- MGMTD_BE_RESCHED_CFG_PREPARE,
- MGMTD_BE_SCHED_CFG_APPLY,
- MGMTD_BE_RESCHED_CFG_APPLY,
-};
-
-#define MGMTD_TXN_ID_NONE 0
-
-#define MGMTD_TXN_BATCH_ID_NONE 0
-
#endif /* _FRR_MGMTD_DEFINES_H */
diff --git a/mgmtd/mgmt.c b/mgmtd/mgmt.c
index 77c4473..8d41643 100644
--- a/mgmtd/mgmt.c
+++ b/mgmtd/mgmt.c
@@ -52,17 +52,26 @@ void mgmt_init(void)
/* Initialize the MGMTD Frontend Adapter Module */
mgmt_fe_adapter_init(mm->master);
- /* Initialize the CLI frontend client */
+ /*
+ * Initialize the CLI frontend client -- this queues an event for the
+ * client to short-circuit connect to the server (ourselves).
+ */
vty_init_mgmt_fe();
- /* MGMTD VTY commands installation. */
+ /*
+ * MGMTD VTY commands installation -- the frr lib code will queue an
+ * event to read the config files which needs to happen after the
+ * connect from above is made.
+ */
mgmt_vty_init();
/*
* Initialize the MGMTD Backend Adapter Module
*
- * We do this after the FE stuff so that we always read our config file
- * prior to any BE connection.
+ * We do this after the FE stuff so that we have read our config file
+ * prior to any BE connection. Setting up the server will queue a
+ * "socket read" event to accept BE connections. So the code is counting
+ * on the above 2 events to run prior to any `accept` event from here.
*/
mgmt_be_adapter_init(mm->master);
}
diff --git a/mgmtd/mgmt.h b/mgmtd/mgmt.h
index d89d76f..665e8d8 100644
--- a/mgmtd/mgmt.h
+++ b/mgmtd/mgmt.h
@@ -13,14 +13,13 @@
#include "vrf.h"
#include "defaults.h"
#include "stream.h"
+#include "mgmt_defines.h"
#include "mgmtd/mgmt_memory.h"
-#include "mgmtd/mgmt_defines.h"
#include "mgmtd/mgmt_history.h"
#include "mgmtd/mgmt_txn.h"
#include "mgmtd/mgmt_ds.h"
-#define MGMTD_VTY_PORT 2623
#define MGMTD_SOCKET_BUF_SIZE 65535
#define MGMTD_MAX_COMMIT_LIST 10
@@ -70,11 +69,6 @@ struct mgmt_master {
extern struct mgmt_master *mm;
/* Inline functions */
-static inline unsigned long timeval_elapsed(struct timeval a, struct timeval b)
-{
- return (((a.tv_sec - b.tv_sec) * TIMER_SECOND_MICRO)
- + (a.tv_usec - b.tv_usec));
-}
/*
* Remove trailing separator from a string.
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);
diff --git a/mgmtd/mgmt_be_adapter.h b/mgmtd/mgmt_be_adapter.h
index ca8f55c..491410a 100644
--- a/mgmtd/mgmt_be_adapter.h
+++ b/mgmtd/mgmt_be_adapter.h
@@ -12,14 +12,37 @@
#include "mgmt_be_client.h"
#include "mgmt_msg.h"
-#include "mgmtd/mgmt_defines.h"
+#include "mgmt_defines.h"
#include "mgmtd/mgmt_ds.h"
#define MGMTD_BE_CONN_INIT_DELAY_MSEC 50
-#define MGMTD_FIND_ADAPTER_BY_INDEX(adapter_index) \
+#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_TESTC, /* always first */
+ MGMTD_BE_CLIENT_ID_ZEBRA,
+#ifdef HAVE_RIPD
+ MGMTD_BE_CLIENT_ID_RIPD,
+#endif
+#ifdef HAVE_RIPNGD
+ MGMTD_BE_CLIENT_ID_RIPNGD,
+#endif
+#ifdef HAVE_STATICD
+ MGMTD_BE_CLIENT_ID_STATICD,
+#endif
+ MGMTD_BE_CLIENT_ID_MAX
+};
+#define MGMTD_BE_CLIENT_ID_MIN 0
+
+
enum mgmt_be_req_type {
MGMTD_BE_REQ_NONE = 0,
MGMTD_BE_REQ_CFG_VALIDATE,
@@ -49,8 +72,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 +102,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);
@@ -109,9 +157,15 @@ mgmt_be_get_adapter_by_name(const char *name);
extern struct mgmt_be_client_adapter *
mgmt_be_get_adapter_by_id(enum mgmt_be_client_id id);
+/* Get the client name given a client ID */
+extern const char *mgmt_be_client_id2name(enum mgmt_be_client_id id);
+
+/* Toggle debug on or off for connected clients. */
+extern void mgmt_be_adapter_toggle_client_debug(bool set);
+
/* Fetch backend adapter config. */
-extern int mgmt_be_get_adapter_config(struct mgmt_be_client_adapter *adapter,
- struct nb_config_cbs **cfg_chgs);
+extern void mgmt_be_get_adapter_config(struct mgmt_be_client_adapter *adapter,
+ struct nb_config_cbs **changes);
/* Create/destroy a transaction. */
extern int mgmt_be_send_txn_req(struct mgmt_be_client_adapter *adapter,
@@ -126,9 +180,6 @@ extern int mgmt_be_send_txn_req(struct mgmt_be_client_adapter *adapter,
* txn_id
* Unique transaction identifier.
*
- * batch_id
- * Request batch ID.
- *
* cfgdata_reqs
* An array of pointer to Mgmtd__YangCfgDataReq.
*
@@ -142,7 +193,7 @@ extern int mgmt_be_send_txn_req(struct mgmt_be_client_adapter *adapter,
* 0 on success, -1 on failure.
*/
extern 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);
@@ -171,23 +222,39 @@ extern void mgmt_be_adapter_status_write(struct vty *vty);
*/
extern void mgmt_be_xpath_register_write(struct vty *vty);
+
+/**
+ * Send a native message to a backend client
+ *
+ * Args:
+ * adapter: the client to send the message to.
+ * msg: a native message from mgmt_msg_native_alloc_msg()
+ *
+ * Return:
+ * Any return value from msg_conn_send_msg().
+ */
+extern int mgmt_be_send_native(enum mgmt_be_client_id id, void *msg);
+
/**
* Lookup the clients which are subscribed to a given `xpath`
* and the way they are subscribed.
*
* 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);
+/**
+ * mgmt_fe_adapter_send_notify() - notify FE clients of a notification.
+ * @msg: the notify message from the backend client.
+ * @msglen: the length of the notify message.
+ */
+extern void mgmt_fe_adapter_send_notify(struct mgmt_msg_notify_data *msg,
+ size_t msglen);
/*
* 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_ds.c b/mgmtd/mgmt_ds.c
index a0e610c..eaf52df 100644
--- a/mgmtd/mgmt_ds.c
+++ b/mgmtd/mgmt_ds.c
@@ -15,10 +15,9 @@
#include "mgmtd/mgmt_txn.h"
#include "libyang/libyang.h"
-#define MGMTD_DS_DBG(fmt, ...) \
+#define __dbg(fmt, ...) \
DEBUGD(&mgmt_debug_ds, "DS: %s: " fmt, __func__, ##__VA_ARGS__)
-#define MGMTD_DS_ERR(fmt, ...) \
- zlog_err("%s: ERROR: " fmt, __func__, ##__VA_ARGS__)
+#define __log_err(fmt, ...) zlog_err("%s: ERROR: " fmt, __func__, ##__VA_ARGS__)
struct mgmt_ds_ctx {
Mgmtd__DatastoreId ds_id;
@@ -81,8 +80,8 @@ static int mgmt_ds_replace_dst_with_src_ds(struct mgmt_ds_ctx *src,
if (!src || !dst)
return -1;
- MGMTD_DS_DBG("Replacing %s with %s", mgmt_ds_id2name(dst->ds_id),
- mgmt_ds_id2name(src->ds_id));
+ __dbg("Replacing %s with %s", mgmt_ds_id2name(dst->ds_id),
+ mgmt_ds_id2name(src->ds_id));
if (src->config_ds && dst->config_ds)
nb_config_replace(dst->root.cfg_root, src->root.cfg_root, true);
@@ -93,14 +92,6 @@ static int mgmt_ds_replace_dst_with_src_ds(struct mgmt_ds_ctx *src,
dst->root.dnode_root = yang_dnode_dup(src->root.dnode_root);
}
- if (src->ds_id == MGMTD_DS_CANDIDATE) {
- /*
- * Drop the changes in scratch-buffer.
- */
- MGMTD_DS_DBG("Emptying Candidate Scratch buffer!");
- nb_config_diff_del_changes(&src->root.cfg_root->cfg_chgs);
- }
-
return 0;
}
@@ -112,7 +103,7 @@ static int mgmt_ds_merge_src_with_dst_ds(struct mgmt_ds_ctx *src,
if (!src || !dst)
return -1;
- MGMTD_DS_DBG("Merging DS %d with %d", dst->ds_id, src->ds_id);
+ __dbg("Merging DS %d with %d", dst->ds_id, src->ds_id);
if (src->config_ds && dst->config_ds)
ret = nb_config_merge(dst->root.cfg_root, src->root.cfg_root,
true);
@@ -122,18 +113,10 @@ static int mgmt_ds_merge_src_with_dst_ds(struct mgmt_ds_ctx *src,
src->root.dnode_root, 0);
}
if (ret != 0) {
- MGMTD_DS_ERR("merge failed with err: %d", ret);
+ __log_err("merge failed with err: %d", ret);
return ret;
}
- if (src->ds_id == MGMTD_DS_CANDIDATE) {
- /*
- * Drop the changes in scratch-buffer.
- */
- MGMTD_DS_DBG("Emptying Candidate Scratch buffer!");
- nb_config_diff_del_changes(&src->root.cfg_root->cfg_chgs);
- }
-
return 0;
}
@@ -315,7 +298,7 @@ static int mgmt_walk_ds_nodes(
assert(mgmt_ds_node_iter_fn);
- MGMTD_DS_DBG(" -- START: base xpath: '%s'", base_xpath);
+ __dbg(" -- START: base xpath: '%s'", base_xpath);
if (!base_dnode)
/*
@@ -326,9 +309,9 @@ static int mgmt_walk_ds_nodes(
if (!base_dnode)
return -1;
- MGMTD_DS_DBG(" search base schema: '%s'",
- lysc_path(base_dnode->schema, LYSC_PATH_LOG, xpath,
- sizeof(xpath)));
+ __dbg(" search base schema: '%s'",
+ lysc_path(base_dnode->schema, LYSC_PATH_LOG, xpath,
+ sizeof(xpath)));
nbnode = (struct nb_node *)base_dnode->schema->priv;
(*mgmt_ds_node_iter_fn)(base_xpath, base_dnode, nbnode, ctx);
@@ -351,7 +334,7 @@ static int mgmt_walk_ds_nodes(
(void)lyd_path(dnode, LYD_PATH_STD, xpath, sizeof(xpath));
- MGMTD_DS_DBG(" -- Child xpath: %s", xpath);
+ __dbg(" -- Child xpath: %s", xpath);
ret = mgmt_walk_ds_nodes(root, xpath, dnode,
mgmt_ds_node_iter_fn, ctx);
@@ -359,7 +342,7 @@ static int mgmt_walk_ds_nodes(
break;
}
- MGMTD_DS_DBG(" -- END: base xpath: '%s'", base_xpath);
+ __dbg(" -- END: base xpath: '%s'", base_xpath);
return ret;
}
@@ -423,8 +406,7 @@ int mgmt_ds_load_config_from_file(struct mgmt_ds_ctx *dst,
return -1;
if (mgmt_ds_load_cfg_from_file(file_path, &iter) != 0) {
- MGMTD_DS_ERR("Failed to load config from the file %s",
- file_path);
+ __log_err("Failed to load config from the file %s", file_path);
return -1;
}
@@ -467,7 +449,7 @@ int mgmt_ds_iter_data(Mgmtd__DatastoreId ds_id, struct nb_config *root,
* Oper-state should be kept in mind though for the prefix walk
*/
- MGMTD_DS_DBG(" -- START DS walk for DSid: %d", ds_id);
+ __dbg(" -- START DS walk for DSid: %d", ds_id);
/* If the base_xpath is empty then crawl the sibblings */
if (xpath[0] == 0) {
diff --git a/mgmtd/mgmt_ds.h b/mgmtd/mgmt_ds.h
index 1cf4816..b8e77e3 100644
--- a/mgmtd/mgmt_ds.h
+++ b/mgmtd/mgmt_ds.h
@@ -11,8 +11,8 @@
#include "mgmt_fe_client.h"
#include "northbound.h"
+#include "mgmt_defines.h"
-#include "mgmtd/mgmt_defines.h"
#include "mgmtd/mgmt_be_adapter.h"
#include "mgmtd/mgmt_fe_adapter.h"
@@ -29,8 +29,8 @@
#define MGMTD_MAX_COMMIT_LIST 10
-#define MGMTD_COMMIT_FILE_PATH DAEMON_DB_DIR "/commit-%s.json"
-#define MGMTD_COMMIT_INDEX_FILE_NAME DAEMON_DB_DIR "/commit-index.dat"
+#define MGMTD_COMMIT_FILE_PATH(id) "%s/commit-%s.json", frr_libstatedir, id
+#define MGMTD_COMMIT_INDEX_FILE_PATH "%s/commit-index.dat", frr_libstatedir
extern struct nb_config *running_config;
diff --git a/mgmtd/mgmt_fe_adapter.c b/mgmtd/mgmt_fe_adapter.c
index 2b2471c..ec8e773 100644
--- a/mgmtd/mgmt_fe_adapter.c
+++ b/mgmtd/mgmt_fe_adapter.c
@@ -8,11 +8,13 @@
*/
#include <zebra.h>
+#include "darr.h"
#include "sockopt.h"
#include "network.h"
#include "libfrr.h"
#include "mgmt_fe_client.h"
#include "mgmt_msg.h"
+#include "mgmt_msg_native.h"
#include "mgmt_pb.h"
#include "hash.h"
#include "jhash.h"
@@ -21,9 +23,9 @@
#include "mgmtd/mgmt_memory.h"
#include "mgmtd/mgmt_fe_adapter.h"
-#define MGMTD_FE_ADAPTER_DBG(fmt, ...) \
+#define __dbg(fmt, ...) \
DEBUGD(&mgmt_debug_fe, "FE-ADAPTER: %s: " fmt, __func__, ##__VA_ARGS__)
-#define MGMTD_FE_ADAPTER_ERR(fmt, ...) \
+#define __log_err(fmt, ...) \
zlog_err("FE-ADAPTER: %s: ERROR: " fmt, __func__, ##__VA_ARGS__)
#define FOREACH_ADAPTER_IN_LIST(adapter) \
@@ -76,20 +78,18 @@ mgmt_fe_session_write_lock_ds(Mgmtd__DatastoreId ds_id,
session->session_id, mgmt_ds_id2name(ds_id));
else {
if (mgmt_ds_lock(ds_ctx, session->session_id)) {
- MGMTD_FE_ADAPTER_DBG(
- "Failed to lock the DS:%s for session-id: %" PRIu64
- " from %s!",
- mgmt_ds_id2name(ds_id), session->session_id,
- session->adapter->name);
+ __dbg("Failed to lock the DS:%s for session-id: %" PRIu64
+ " from %s!",
+ mgmt_ds_id2name(ds_id), session->session_id,
+ session->adapter->name);
return -1;
}
session->ds_locked[ds_id] = true;
- MGMTD_FE_ADAPTER_DBG(
- "Write-Locked the DS:%s for session-id: %" PRIu64
- " from %s",
- mgmt_ds_id2name(ds_id), session->session_id,
- session->adapter->name);
+ __dbg("Write-Locked the DS:%s for session-id: %" PRIu64
+ " from %s",
+ mgmt_ds_id2name(ds_id), session->session_id,
+ session->adapter->name);
}
return 0;
@@ -105,11 +105,10 @@ static void mgmt_fe_session_unlock_ds(Mgmtd__DatastoreId ds_id,
session->ds_locked[ds_id] = false;
mgmt_ds_unlock(ds_ctx);
- MGMTD_FE_ADAPTER_DBG(
- "Unlocked DS:%s write-locked earlier by session-id: %" PRIu64
- " from %s",
- mgmt_ds_id2name(ds_id), session->session_id,
- session->adapter->name);
+ __dbg("Unlocked DS:%s write-locked earlier by session-id: %" PRIu64
+ " from %s",
+ mgmt_ds_id2name(ds_id), session->session_id,
+ session->adapter->name);
}
static void
@@ -204,14 +203,13 @@ mgmt_fe_find_session_by_client_id(struct mgmt_fe_client_adapter *adapter,
FOREACH_SESSION_IN_LIST (adapter, session) {
if (session->client_id == client_id) {
- MGMTD_FE_ADAPTER_DBG("Found session-id %" PRIu64
- " using client-id %" PRIu64,
- session->session_id, client_id);
+ __dbg("Found session-id %" PRIu64
+ " using client-id %" PRIu64,
+ session->session_id, client_id);
return session;
}
}
- MGMTD_FE_ADAPTER_DBG("Session not found using client-id %" PRIu64,
- client_id);
+ __dbg("Session not found using client-id %" PRIu64, client_id);
return NULL;
}
@@ -246,6 +244,23 @@ mgmt_session_id2ctx(uint64_t session_id)
return session;
}
+void mgmt_fe_adapter_toggle_client_debug(bool set)
+{
+ struct mgmt_fe_client_adapter *adapter;
+
+ FOREACH_ADAPTER_IN_LIST (adapter)
+ adapter->conn->debug = set;
+}
+
+static struct mgmt_fe_session_ctx *fe_adapter_session_by_txn_id(uint64_t txn_id)
+{
+ uint64_t session_id = mgmt_txn_get_session_id(txn_id);
+
+ if (session_id == MGMTD_SESSION_ID_NONE)
+ return NULL;
+ return mgmt_session_id2ctx(session_id);
+}
+
static struct mgmt_fe_session_ctx *
mgmt_fe_create_session(struct mgmt_fe_client_adapter *adapter,
uint64_t client_id)
@@ -273,6 +288,14 @@ mgmt_fe_create_session(struct mgmt_fe_client_adapter *adapter,
return session;
}
+static int fe_adapter_send_native_msg(struct mgmt_fe_client_adapter *adapter,
+ void *msg, size_t len,
+ bool short_circuit_ok)
+{
+ return msg_conn_send_msg(adapter->conn, MGMT_MSG_VERSION_NATIVE, msg,
+ len, NULL, short_circuit_ok);
+}
+
static int fe_adapter_send_msg(struct mgmt_fe_client_adapter *adapter,
Mgmtd__FeMessage *fe_msg, bool short_circuit_ok)
{
@@ -303,9 +326,8 @@ static int fe_adapter_send_session_reply(struct mgmt_fe_client_adapter *adapter,
fe_msg.message_case = MGMTD__FE_MESSAGE__MESSAGE_SESSION_REPLY;
fe_msg.session_reply = &session_reply;
- MGMTD_FE_ADAPTER_DBG(
- "Sending SESSION_REPLY message to MGMTD Frontend client '%s'",
- adapter->name);
+ __dbg("Sending SESSION_REPLY message to MGMTD Frontend client '%s'",
+ adapter->name);
return fe_adapter_send_msg(adapter, &fe_msg, true);
}
@@ -334,9 +356,8 @@ static int fe_adapter_send_lockds_reply(struct mgmt_fe_session_ctx *session,
fe_msg.message_case = MGMTD__FE_MESSAGE__MESSAGE_LOCKDS_REPLY;
fe_msg.lockds_reply = &lockds_reply;
- MGMTD_FE_ADAPTER_DBG(
- "Sending LOCK_DS_REPLY message to MGMTD Frontend client '%s' scok: %d",
- session->adapter->name, scok);
+ __dbg("Sending LOCK_DS_REPLY message to MGMTD Frontend client '%s' scok: %d",
+ session->adapter->name, scok);
return fe_adapter_send_msg(session->adapter, &fe_msg, scok);
}
@@ -369,9 +390,8 @@ static int fe_adapter_send_set_cfg_reply(struct mgmt_fe_session_ctx *session,
fe_msg.message_case = MGMTD__FE_MESSAGE__MESSAGE_SETCFG_REPLY;
fe_msg.setcfg_reply = &setcfg_reply;
- MGMTD_FE_ADAPTER_DBG(
- "Sending SETCFG_REPLY message to MGMTD Frontend client '%s'",
- session->adapter->name);
+ __dbg("Sending SETCFG_REPLY message to MGMTD Frontend client '%s'",
+ session->adapter->name);
if (implicit_commit) {
if (mm->perf_stats_en)
@@ -415,9 +435,8 @@ static int fe_adapter_send_commit_cfg_reply(
fe_msg.message_case = MGMTD__FE_MESSAGE__MESSAGE_COMMCFG_REPLY;
fe_msg.commcfg_reply = &commcfg_reply;
- MGMTD_FE_ADAPTER_DBG(
- "Sending COMMIT_CONFIG_REPLY message to MGMTD Frontend client '%s'",
- session->adapter->name);
+ __dbg("Sending COMMIT_CONFIG_REPLY message to MGMTD Frontend client '%s'",
+ session->adapter->name);
/*
* Cleanup the CONFIG transaction associated with this session.
@@ -457,8 +476,8 @@ static int fe_adapter_send_get_reply(struct mgmt_fe_session_ctx *session,
fe_msg.message_case = MGMTD__FE_MESSAGE__MESSAGE_GET_REPLY;
fe_msg.get_reply = &get_reply;
- MGMTD_FE_ADAPTER_DBG("Sending GET_REPLY message to MGMTD Frontend client '%s'",
- session->adapter->name);
+ __dbg("Sending GET_REPLY message to MGMTD Frontend client '%s'",
+ session->adapter->name);
/*
* Cleanup the SHOW transaction associated with this session.
@@ -470,6 +489,28 @@ static int fe_adapter_send_get_reply(struct mgmt_fe_session_ctx *session,
return fe_adapter_send_msg(session->adapter, &fe_msg, false);
}
+static int fe_adapter_send_error(struct mgmt_fe_session_ctx *session,
+ uint64_t req_id, bool short_circuit_ok,
+ int16_t error, const char *errfmt, ...)
+ PRINTFRR(5, 6);
+
+static int fe_adapter_send_error(struct mgmt_fe_session_ctx *session,
+ uint64_t req_id, bool short_circuit_ok,
+ int16_t error, const char *errfmt, ...)
+{
+ va_list ap;
+ int ret;
+
+ va_start(ap, errfmt);
+ ret = vmgmt_msg_native_send_error(session->adapter->conn,
+ session->session_id, req_id,
+ short_circuit_ok, error, errfmt, ap);
+ va_end(ap);
+
+ return ret;
+}
+
+
static void mgmt_fe_session_cfg_txn_clnup(struct event *thread)
{
struct mgmt_fe_session_ctx *session;
@@ -523,7 +564,7 @@ mgmt_fe_find_adapter_by_fd(int conn_fd)
static void mgmt_fe_adapter_delete(struct mgmt_fe_client_adapter *adapter)
{
struct mgmt_fe_session_ctx *session;
- MGMTD_FE_ADAPTER_DBG("deleting client adapter '%s'", adapter->name);
+ __dbg("deleting client adapter '%s'", adapter->name);
/* TODO: notify about client disconnect for appropriate cleanup */
FOREACH_SESSION_IN_LIST (adapter, session)
@@ -538,8 +579,7 @@ static int mgmt_fe_adapter_notify_disconnect(struct msg_conn *conn)
{
struct mgmt_fe_client_adapter *adapter = conn->user;
- MGMTD_FE_ADAPTER_DBG("notify disconnect for client adapter '%s'",
- adapter->name);
+ __dbg("notify disconnect for client adapter '%s'", adapter->name);
mgmt_fe_adapter_delete(adapter);
@@ -560,10 +600,8 @@ mgmt_fe_adapter_cleanup_old_conn(struct mgmt_fe_client_adapter *adapter)
if (strncmp(adapter->name, old->name, sizeof(adapter->name)))
continue;
- MGMTD_FE_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);
msg_conn_disconnect(old->conn, false);
}
}
@@ -616,11 +654,10 @@ mgmt_fe_session_handle_lockds_req_msg(struct mgmt_fe_session_ctx *session,
if (fe_adapter_send_lockds_reply(session, lockds_req->ds_id,
lockds_req->req_id, lockds_req->lock,
true, NULL) != 0) {
- MGMTD_FE_ADAPTER_DBG(
- "Failed to send LOCK_DS_REPLY for DS %u session-id: %" PRIu64
- " from %s",
- lockds_req->ds_id, session->session_id,
- session->adapter->name);
+ __dbg("Failed to send LOCK_DS_REPLY for DS %u session-id: %" PRIu64
+ " from %s",
+ lockds_req->ds_id, session->session_id,
+ session->adapter->name);
}
return 0;
@@ -674,9 +711,6 @@ mgmt_fe_session_handle_setcfg_req_msg(struct mgmt_fe_session_ctx *session,
}
if (session->cfg_txn_id == MGMTD_TXN_ID_NONE) {
- /* as we have the lock no-one else should have a config txn */
- assert(mgmt_config_txn_in_progress() == MGMTD_SESSION_ID_NONE);
-
/* Start a CONFIG Transaction (if not started already) */
session->cfg_txn_id = mgmt_create_txn(session->session_id,
MGMTD_TXN_TYPE_CONFIG);
@@ -690,14 +724,13 @@ mgmt_fe_session_handle_setcfg_req_msg(struct mgmt_fe_session_ctx *session,
}
txn_created = true;
- MGMTD_FE_ADAPTER_DBG("Created new Config txn-id: %" PRIu64
- " for session-id %" PRIu64,
- session->cfg_txn_id, session->session_id);
+ __dbg("Created new Config txn-id: %" PRIu64
+ " for session-id %" PRIu64,
+ session->cfg_txn_id, session->session_id);
} else {
- MGMTD_FE_ADAPTER_DBG("Config txn-id: %" PRIu64
- " for session-id: %" PRIu64
- " already created",
- session->cfg_txn_id, session->session_id);
+ __dbg("Config txn-id: %" PRIu64 " for session-id: %" PRIu64
+ " already created",
+ session->cfg_txn_id, session->session_id);
if (setcfg_req->implicit_commit) {
/*
@@ -740,14 +773,8 @@ static int mgmt_fe_session_handle_get_req_msg(struct mgmt_fe_session_ctx *sessio
struct nb_config *cfg_root = NULL;
Mgmtd__DatastoreId ds_id = get_req->ds_id;
uint64_t req_id = get_req->req_id;
- bool is_cfg = get_req->config;
- bool ds_ok = true;
-
- if (is_cfg && ds_id != MGMTD_DS_CANDIDATE && ds_id != MGMTD_DS_RUNNING)
- ds_ok = false;
- else if (!is_cfg && ds_id != MGMTD_DS_OPERATIONAL)
- ds_ok = false;
- if (!ds_ok) {
+
+ if (ds_id != MGMTD_DS_CANDIDATE && ds_id != MGMTD_DS_RUNNING) {
fe_adapter_send_get_reply(session, ds_id, req_id, false, NULL,
"get-req on unsupported datastore");
return 0;
@@ -768,23 +795,22 @@ static int mgmt_fe_session_handle_get_req_msg(struct mgmt_fe_session_ctx *sessio
return -1;
}
- MGMTD_FE_ADAPTER_DBG("Created new show txn-id: %" PRIu64
- " for session-id: %" PRIu64,
- session->txn_id, session->session_id);
+ __dbg("Created new show txn-id: %" PRIu64
+ " for session-id: %" PRIu64,
+ session->txn_id, session->session_id);
} else {
fe_adapter_send_get_reply(session, ds_id, req_id, false, NULL,
"Request processing for GET failed!");
- MGMTD_FE_ADAPTER_DBG("Transaction in progress txn-id: %" PRIu64
- " for session-id: %" PRIu64,
- session->txn_id, session->session_id);
+ __dbg("Transaction in progress txn-id: %" PRIu64
+ " for session-id: %" PRIu64,
+ session->txn_id, session->session_id);
return -1;
}
/*
* Get a copy of the datastore config root, avoids locking.
*/
- if (is_cfg)
- cfg_root = nb_config_dup(mgmt_ds_get_nb_config(ds_ctx));
+ cfg_root = nb_config_dup(mgmt_ds_get_nb_config(ds_ctx));
/*
* Create a GET request under the transaction.
@@ -848,6 +874,9 @@ static int mgmt_fe_session_handle_commit_config_req_msg(
}
if (session->cfg_txn_id == MGMTD_TXN_ID_NONE) {
+ /* as we have the lock no-one else should have a config txn */
+ assert(!mgmt_config_txn_in_progress());
+
/*
* Start a CONFIG Transaction (if not started already)
*/
@@ -861,10 +890,9 @@ static int mgmt_fe_session_handle_commit_config_req_msg(
"Failed to create a Configuration session!");
return 0;
}
- MGMTD_FE_ADAPTER_DBG("Created txn-id: %" PRIu64
- " for session-id %" PRIu64
- " for COMMIT-CFG-REQ",
- session->cfg_txn_id, session->session_id);
+ __dbg("Created txn-id: %" PRIu64 " for session-id %" PRIu64
+ " for COMMIT-CFG-REQ",
+ session->cfg_txn_id, session->session_id);
}
/*
@@ -898,8 +926,8 @@ mgmt_fe_adapter_handle_msg(struct mgmt_fe_client_adapter *adapter,
*/
switch ((int)fe_msg->message_case) {
case MGMTD__FE_MESSAGE__MESSAGE_REGISTER_REQ:
- MGMTD_FE_ADAPTER_DBG("Got REGISTER_REQ from '%s'",
- fe_msg->register_req->client_name);
+ __dbg("Got REGISTER_REQ from '%s'",
+ fe_msg->register_req->client_name);
if (strlen(fe_msg->register_req->client_name)) {
strlcpy(adapter->name,
@@ -912,11 +940,10 @@ mgmt_fe_adapter_handle_msg(struct mgmt_fe_client_adapter *adapter,
if (fe_msg->session_req->create
&& fe_msg->session_req->id_case
== MGMTD__FE_SESSION_REQ__ID_CLIENT_CONN_ID) {
- MGMTD_FE_ADAPTER_DBG(
- "Got SESSION_REQ (create) for client-id %" PRIu64
- " from '%s'",
- fe_msg->session_req->client_conn_id,
- adapter->name);
+ __dbg("Got SESSION_REQ (create) for client-id %" PRIu64
+ " from '%s'",
+ fe_msg->session_req->client_conn_id,
+ adapter->name);
session = mgmt_fe_create_session(
adapter, fe_msg->session_req->client_conn_id);
@@ -926,10 +953,9 @@ mgmt_fe_adapter_handle_msg(struct mgmt_fe_client_adapter *adapter,
!fe_msg->session_req->create
&& fe_msg->session_req->id_case
== MGMTD__FE_SESSION_REQ__ID_SESSION_ID) {
- MGMTD_FE_ADAPTER_DBG(
- "Got SESSION_REQ (destroy) for session-id %" PRIu64
- "from '%s'",
- fe_msg->session_req->session_id, adapter->name);
+ __dbg("Got SESSION_REQ (destroy) for session-id %" PRIu64
+ "from '%s'",
+ fe_msg->session_req->session_id, adapter->name);
session = mgmt_session_id2ctx(
fe_msg->session_req->session_id);
@@ -941,12 +967,11 @@ mgmt_fe_adapter_handle_msg(struct mgmt_fe_client_adapter *adapter,
case MGMTD__FE_MESSAGE__MESSAGE_LOCKDS_REQ:
session = mgmt_session_id2ctx(
fe_msg->lockds_req->session_id);
- MGMTD_FE_ADAPTER_DBG(
- "Got LOCKDS_REQ (%sLOCK) for DS:%s for session-id %" PRIu64
- " from '%s'",
- fe_msg->lockds_req->lock ? "" : "UN",
- mgmt_ds_id2name(fe_msg->lockds_req->ds_id),
- fe_msg->lockds_req->session_id, adapter->name);
+ __dbg("Got LOCKDS_REQ (%sLOCK) for DS:%s for session-id %" PRIu64
+ " from '%s'",
+ fe_msg->lockds_req->lock ? "" : "UN",
+ mgmt_ds_id2name(fe_msg->lockds_req->ds_id),
+ fe_msg->lockds_req->session_id, adapter->name);
mgmt_fe_session_handle_lockds_req_msg(
session, fe_msg->lockds_req);
break;
@@ -954,13 +979,12 @@ mgmt_fe_adapter_handle_msg(struct mgmt_fe_client_adapter *adapter,
session = mgmt_session_id2ctx(
fe_msg->setcfg_req->session_id);
session->adapter->setcfg_stats.set_cfg_count++;
- MGMTD_FE_ADAPTER_DBG(
- "Got SETCFG_REQ (%d Xpaths, Implicit:%c) on DS:%s for session-id %" PRIu64
- " from '%s'",
- (int)fe_msg->setcfg_req->n_data,
- fe_msg->setcfg_req->implicit_commit ? 'T' : 'F',
- mgmt_ds_id2name(fe_msg->setcfg_req->ds_id),
- fe_msg->setcfg_req->session_id, adapter->name);
+ __dbg("Got SETCFG_REQ (%d Xpaths, Implicit:%c) on DS:%s for session-id %" PRIu64
+ " from '%s'",
+ (int)fe_msg->setcfg_req->n_data,
+ fe_msg->setcfg_req->implicit_commit ? 'T' : 'F',
+ mgmt_ds_id2name(fe_msg->setcfg_req->ds_id),
+ fe_msg->setcfg_req->session_id, adapter->name);
mgmt_fe_session_handle_setcfg_req_msg(
session, fe_msg->setcfg_req);
@@ -968,31 +992,28 @@ mgmt_fe_adapter_handle_msg(struct mgmt_fe_client_adapter *adapter,
case MGMTD__FE_MESSAGE__MESSAGE_COMMCFG_REQ:
session = mgmt_session_id2ctx(
fe_msg->commcfg_req->session_id);
- MGMTD_FE_ADAPTER_DBG(
- "Got COMMCFG_REQ for src-DS:%s dst-DS:%s (Abort:%c) on session-id %" PRIu64
- " from '%s'",
- mgmt_ds_id2name(fe_msg->commcfg_req->src_ds_id),
- mgmt_ds_id2name(fe_msg->commcfg_req->dst_ds_id),
- fe_msg->commcfg_req->abort ? 'T' : 'F',
- fe_msg->commcfg_req->session_id, adapter->name);
+ __dbg("Got COMMCFG_REQ for src-DS:%s dst-DS:%s (Abort:%c) on session-id %" PRIu64
+ " from '%s'",
+ mgmt_ds_id2name(fe_msg->commcfg_req->src_ds_id),
+ mgmt_ds_id2name(fe_msg->commcfg_req->dst_ds_id),
+ fe_msg->commcfg_req->abort ? 'T' : 'F',
+ fe_msg->commcfg_req->session_id, adapter->name);
mgmt_fe_session_handle_commit_config_req_msg(
session, fe_msg->commcfg_req);
break;
case MGMTD__FE_MESSAGE__MESSAGE_GET_REQ:
session = mgmt_session_id2ctx(fe_msg->get_req->session_id);
- MGMTD_FE_ADAPTER_DBG("Got GET_REQ (iscfg %d) for DS:%s (xpaths: %d) on session-id %" PRIu64
- " from '%s'",
- (int)fe_msg->get_req->config,
- mgmt_ds_id2name(fe_msg->get_req->ds_id),
- (int)fe_msg->get_req->n_data,
- fe_msg->get_req->session_id, adapter->name);
+ __dbg("Got GET_REQ for DS:%s (xpaths: %d) on session-id %" PRIu64
+ " from '%s'",
+ mgmt_ds_id2name(fe_msg->get_req->ds_id),
+ (int)fe_msg->get_req->n_data, fe_msg->get_req->session_id,
+ adapter->name);
mgmt_fe_session_handle_get_req_msg(session, fe_msg->get_req);
break;
case MGMTD__FE_MESSAGE__MESSAGE_NOTIFY_DATA_REQ:
case MGMTD__FE_MESSAGE__MESSAGE_REGNOTIFY_REQ:
- MGMTD_FE_ADAPTER_ERR(
- "Got unhandled message of type %u from '%s'",
- fe_msg->message_case, adapter->name);
+ __log_err("Got unhandled message of type %u from '%s'",
+ fe_msg->message_case, adapter->name);
/*
* TODO: Add handling code in future.
*/
@@ -1020,25 +1041,265 @@ mgmt_fe_adapter_handle_msg(struct mgmt_fe_client_adapter *adapter,
return 0;
}
+/**
+ * Send result of get-tree request back to the FE client.
+ *
+ * Args:
+ * session: the session.
+ * req_id: the request ID.
+ * short_circuit_ok: if allowed to short circuit the message.
+ * result_format: LYD_FORMAT for the sent output.
+ * tree: the tree to send, can be NULL which will send an empty tree.
+ * partial_error: if an error occurred during gathering results.
+ *
+ * Return:
+ * Any error that occurs -- the message is likely not sent if non-zero.
+ */
+static int fe_adapter_send_tree_data(struct mgmt_fe_session_ctx *session,
+ uint64_t req_id, bool short_circuit_ok,
+ uint8_t result_type, uint32_t wd_options,
+ const struct lyd_node *tree,
+ int partial_error)
+
+{
+ struct mgmt_msg_tree_data *msg;
+ uint8_t **darrp = NULL;
+ int ret = 0;
+
+ msg = mgmt_msg_native_alloc_msg(struct mgmt_msg_tree_data, 0,
+ MTYPE_MSG_NATIVE_TREE_DATA);
+ msg->refer_id = session->session_id;
+ msg->req_id = req_id;
+ msg->code = MGMT_MSG_CODE_TREE_DATA;
+ msg->partial_error = partial_error;
+ msg->result_type = result_type;
+
+ darrp = mgmt_msg_native_get_darrp(msg);
+ ret = yang_print_tree_append(darrp, tree, result_type,
+ (wd_options | LYD_PRINT_WITHSIBLINGS));
+ if (ret != LY_SUCCESS) {
+ __log_err("Error building get-tree result for client %s session-id %" PRIu64
+ " req-id %" PRIu64 " scok %d result type %u",
+ session->adapter->name, session->session_id, req_id,
+ short_circuit_ok, result_type);
+ goto done;
+ }
+
+ __dbg("Sending get-tree result from adapter %s to session-id %" PRIu64
+ " req-id %" PRIu64 " scok %d result type %u len %u",
+ session->adapter->name, session->session_id, req_id,
+ short_circuit_ok, result_type, mgmt_msg_native_get_msg_len(msg));
+
+ ret = fe_adapter_send_native_msg(session->adapter, msg,
+ mgmt_msg_native_get_msg_len(msg),
+ short_circuit_ok);
+done:
+ mgmt_msg_native_free_msg(msg);
+
+ return ret;
+}
+
+/**
+ * fe_adapter_handle_get_data() - Handle a get-tree message from a FE client.
+ * @session: the client session.
+ * @msg_raw: the message data.
+ * @msg_len: the length of the message data.
+ */
+static void fe_adapter_handle_get_data(struct mgmt_fe_session_ctx *session,
+ void *__msg, size_t msg_len)
+{
+ struct mgmt_msg_get_data *msg = __msg;
+ struct lysc_node **snodes = NULL;
+ char *xpath_resolved = NULL;
+ uint64_t req_id = msg->req_id;
+ Mgmtd__DatastoreId ds_id;
+ uint64_t clients;
+ uint32_t wd_options;
+ bool simple_xpath;
+ LY_ERR err;
+ int ret;
+
+ __dbg("Received get-data request from client %s for session-id %" PRIu64
+ " req-id %" PRIu64,
+ session->adapter->name, session->session_id, msg->req_id);
+
+ if (!MGMT_MSG_VALIDATE_NUL_TERM(msg, msg_len)) {
+ fe_adapter_send_error(session, req_id, false, -EINVAL,
+ "Invalid message rcvd from session-id: %" PRIu64,
+ session->session_id);
+ goto done;
+ }
+
+ if (session->txn_id != MGMTD_TXN_ID_NONE) {
+ fe_adapter_send_error(session, req_id, false, -EINPROGRESS,
+ "Transaction in progress txn-id: %" PRIu64
+ " for session-id: %" PRIu64,
+ session->txn_id, session->session_id);
+ goto done;
+ }
+
+ switch (msg->defaults) {
+ case GET_DATA_DEFAULTS_EXPLICIT:
+ wd_options = LYD_PRINT_WD_EXPLICIT;
+ break;
+ case GET_DATA_DEFAULTS_TRIM:
+ wd_options = LYD_PRINT_WD_TRIM;
+ break;
+ case GET_DATA_DEFAULTS_ALL:
+ wd_options = LYD_PRINT_WD_ALL;
+ break;
+ case GET_DATA_DEFAULTS_ALL_ADD_TAG:
+ wd_options = LYD_PRINT_WD_IMPL_TAG;
+ break;
+ default:
+ fe_adapter_send_error(session, req_id, false, -EINVAL,
+ "Invalid defaults value %u for session-id: %" PRIu64,
+ msg->defaults, session->session_id);
+ goto done;
+ }
+
+ switch (msg->datastore) {
+ case MGMT_MSG_DATASTORE_CANDIDATE:
+ ds_id = MGMTD_DS_CANDIDATE;
+ break;
+ case MGMT_MSG_DATASTORE_RUNNING:
+ ds_id = MGMTD_DS_RUNNING;
+ break;
+ case MGMT_MSG_DATASTORE_OPERATIONAL:
+ ds_id = MGMTD_DS_OPERATIONAL;
+ break;
+ default:
+ fe_adapter_send_error(session, req_id, false, -EINVAL,
+ "Unsupported datastore %" PRIu8
+ " requested from session-id: %" PRIu64,
+ msg->datastore, session->session_id);
+ goto done;
+ }
+
+ err = yang_resolve_snode_xpath(ly_native_ctx, msg->xpath, &snodes,
+ &simple_xpath);
+ if (err) {
+ fe_adapter_send_error(session, req_id, false, -EINPROGRESS,
+ "XPath doesn't resolve for session-id: %" PRIu64,
+ session->session_id);
+ goto done;
+ }
+ darr_free(snodes);
+
+ clients = mgmt_be_interested_clients(msg->xpath, false);
+ if (!clients && !CHECK_FLAG(msg->flags, GET_DATA_FLAG_CONFIG)) {
+ __dbg("No backends provide xpath: %s for txn-id: %" PRIu64
+ " session-id: %" PRIu64,
+ msg->xpath, session->txn_id, session->session_id);
+
+ fe_adapter_send_tree_data(session, req_id, false,
+ msg->result_type, wd_options, NULL, 0);
+ goto done;
+ }
+
+ /* Start a SHOW Transaction */
+ session->txn_id = mgmt_create_txn(session->session_id,
+ MGMTD_TXN_TYPE_SHOW);
+ if (session->txn_id == MGMTD_SESSION_ID_NONE) {
+ fe_adapter_send_error(session, req_id, false, -EINPROGRESS,
+ "failed to create a 'show' txn");
+ goto done;
+ }
+
+ __dbg("Created new show txn-id: %" PRIu64 " for session-id: %" PRIu64,
+ session->txn_id, session->session_id);
+
+ /* Create a GET-TREE request under the transaction */
+ ret = mgmt_txn_send_get_tree_oper(session->txn_id, req_id, clients,
+ ds_id, msg->result_type, msg->flags,
+ wd_options, simple_xpath, msg->xpath);
+ if (ret) {
+ /* destroy the just created txn */
+ mgmt_destroy_txn(&session->txn_id);
+ fe_adapter_send_error(session, req_id, false, -EINPROGRESS,
+ "failed to create a 'show' txn");
+ }
+done:
+ darr_free(snodes);
+ darr_free(xpath_resolved);
+}
+
+/**
+ * Handle a native encoded message from the FE client.
+ */
+static void fe_adapter_handle_native_msg(struct mgmt_fe_client_adapter *adapter,
+ struct mgmt_msg_header *msg,
+ size_t msg_len)
+{
+ struct mgmt_fe_session_ctx *session;
+
+ session = mgmt_session_id2ctx(msg->refer_id);
+ if (!session) {
+ __log_err("adapter %s: recv msg unknown session-id %" PRIu64,
+ adapter->name, msg->refer_id);
+ return;
+ }
+ assert(session->adapter == adapter);
+
+ switch (msg->code) {
+ case MGMT_MSG_CODE_GET_DATA:
+ fe_adapter_handle_get_data(session, msg, msg_len);
+ break;
+ default:
+ __log_err("unknown native message session-id %" PRIu64
+ " req-id %" PRIu64 " code %u to FE adapter %s",
+ msg->refer_id, msg->req_id, msg->code, adapter->name);
+ break;
+ }
+}
+
+
static void mgmt_fe_adapter_process_msg(uint8_t version, uint8_t *data,
size_t len, struct msg_conn *conn)
{
struct mgmt_fe_client_adapter *adapter = conn->user;
- Mgmtd__FeMessage *fe_msg = mgmtd__fe_message__unpack(NULL, len, data);
+ Mgmtd__FeMessage *fe_msg;
+
+ if (version == MGMT_MSG_VERSION_NATIVE) {
+ struct mgmt_msg_header *msg = (typeof(msg))data;
+ if (len >= sizeof(*msg))
+ fe_adapter_handle_native_msg(adapter, msg, len);
+ else
+ __log_err("native message to adapter %s too short %zu",
+ adapter->name, len);
+ return;
+ }
+
+ fe_msg = mgmtd__fe_message__unpack(NULL, len, data);
if (!fe_msg) {
- MGMTD_FE_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_FE_ADAPTER_DBG(
- "Decoded %zu bytes of message: %u from adapter: %s", len,
- fe_msg->message_case, adapter->name);
+ __dbg("Decoded %zu bytes of message: %u from adapter: %s", len,
+ fe_msg->message_case, adapter->name);
(void)mgmt_fe_adapter_handle_msg(adapter, fe_msg);
mgmtd__fe_message__free_unpacked(fe_msg, NULL);
}
+void mgmt_fe_adapter_send_notify(struct mgmt_msg_notify_data *msg, size_t msglen)
+{
+ struct mgmt_fe_client_adapter *adapter;
+ struct mgmt_fe_session_ctx *session;
+
+ assert(msg->refer_id == 0);
+
+ FOREACH_ADAPTER_IN_LIST (adapter) {
+ FOREACH_SESSION_IN_LIST (adapter, session) {
+ msg->refer_id = session->session_id;
+ (void)fe_adapter_send_native_msg(adapter, msg, msglen,
+ false);
+ }
+ }
+ msg->refer_id = 0;
+}
+
void mgmt_fe_adapter_lock(struct mgmt_fe_client_adapter *adapter)
{
adapter->refcount++;
@@ -1062,6 +1323,8 @@ extern void mgmt_fe_adapter_unlock(struct mgmt_fe_client_adapter **adapter)
*/
void mgmt_fe_adapter_init(struct event_loop *tm)
{
+ char server_path[MAXPATHLEN];
+
assert(!mgmt_loop);
mgmt_loop = tm;
@@ -1072,9 +1335,10 @@ void mgmt_fe_adapter_init(struct event_loop *tm)
hash_create(mgmt_fe_session_hash_key, mgmt_fe_session_hash_cmp,
"MGMT Frontend Sessions");
- if (msg_server_init(&mgmt_fe_server, MGMTD_FE_SERVER_PATH, tm,
- mgmt_fe_create_adapter, "frontend",
- &mgmt_debug_fe)) {
+ snprintf(server_path, sizeof(server_path), MGMTD_FE_SOCK_NAME);
+
+ if (msg_server_init(&mgmt_fe_server, server_path, tm,
+ mgmt_fe_create_adapter, "frontend", &mgmt_debug_fe)) {
zlog_err("cannot initialize frontend server");
exit(1);
}
@@ -1084,11 +1348,10 @@ static void mgmt_fe_abort_if_session(void *data)
{
struct mgmt_fe_session_ctx *session = data;
- MGMTD_FE_ADAPTER_ERR("found orphaned session id %" PRIu64
- " client id %" PRIu64 " adapter %s",
- session->session_id, session->client_id,
- session->adapter ? session->adapter->name
- : "NULL");
+ __log_err("found orphaned session id %" PRIu64 " client id %" PRIu64
+ " adapter %s",
+ session->session_id, session->client_id,
+ session->adapter ? session->adapter->name : "NULL");
abort();
}
@@ -1129,13 +1392,15 @@ struct msg_conn *mgmt_fe_create_adapter(int conn_fd, union sockunion *from)
adapter->conn = msg_server_conn_create(
mgmt_loop, conn_fd, mgmt_fe_adapter_notify_disconnect,
mgmt_fe_adapter_process_msg, MGMTD_FE_MAX_NUM_MSG_PROC,
- MGMTD_FE_MAX_NUM_MSG_WRITE, MGMTD_FE_MSG_MAX_LEN,
+ MGMTD_FE_MAX_NUM_MSG_WRITE, MGMTD_FE_MAX_MSG_LEN,
adapter, "FE-adapter");
+ adapter->conn->debug = DEBUG_MODE_CHECK(&mgmt_debug_fe,
+ DEBUG_MODE_ALL);
+
adapter->setcfg_stats.min_tm = ULONG_MAX;
adapter->cmt_stats.min_tm = ULONG_MAX;
- MGMTD_FE_ADAPTER_DBG("Added new MGMTD Frontend adapter '%s'",
- adapter->name);
+ __dbg("Added new MGMTD Frontend adapter '%s'", adapter->name);
}
return adapter->conn;
}
@@ -1151,10 +1416,9 @@ int mgmt_fe_send_set_cfg_reply(uint64_t session_id, uint64_t txn_id,
session = mgmt_session_id2ctx(session_id);
if (!session || session->cfg_txn_id != txn_id) {
if (session)
- MGMTD_FE_ADAPTER_ERR(
- "txn-id doesn't match, session txn-id is %" PRIu64
- " current txnid: %" PRIu64,
- session->cfg_txn_id, txn_id);
+ __log_err("txn-id doesn't match, session txn-id is %" PRIu64
+ " current txnid: %" PRIu64,
+ session->cfg_txn_id, txn_id);
return -1;
}
@@ -1198,8 +1462,56 @@ int mgmt_fe_send_get_reply(uint64_t session_id, uint64_t txn_id,
error_if_any);
}
-struct mgmt_setcfg_stats *
-mgmt_fe_get_session_setcfg_stats(uint64_t session_id)
+int mgmt_fe_adapter_send_tree_data(uint64_t session_id, uint64_t txn_id,
+ uint64_t req_id, LYD_FORMAT result_type,
+ uint32_t wd_options,
+ const struct lyd_node *tree,
+ int partial_error, bool short_circuit_ok)
+{
+ struct mgmt_fe_session_ctx *session;
+ int ret;
+
+ session = mgmt_session_id2ctx(session_id);
+ if (!session || session->txn_id != txn_id)
+ return -1;
+
+ ret = fe_adapter_send_tree_data(session, req_id, short_circuit_ok,
+ result_type, wd_options, tree,
+ partial_error);
+
+ mgmt_destroy_txn(&session->txn_id);
+
+ return ret;
+}
+
+/**
+ * Send an error back to the FE client and cleanup any in-progress txn.
+ */
+int mgmt_fe_adapter_txn_error(uint64_t txn_id, uint64_t req_id,
+ bool short_circuit_ok, int16_t error,
+ const char *errstr)
+{
+ struct mgmt_fe_session_ctx *session;
+ int ret;
+
+ session = fe_adapter_session_by_txn_id(txn_id);
+ if (!session) {
+ __log_err("failed sending error for txn-id %" PRIu64
+ " session not found",
+ txn_id);
+ return -ENOENT;
+ }
+
+
+ ret = fe_adapter_send_error(session, req_id, false, error, "%s", errstr);
+
+ mgmt_destroy_txn(&session->txn_id);
+
+ return ret;
+}
+
+
+struct mgmt_setcfg_stats *mgmt_fe_get_session_setcfg_stats(uint64_t session_id)
{
struct mgmt_fe_session_ctx *session;
diff --git a/mgmtd/mgmt_fe_adapter.h b/mgmtd/mgmt_fe_adapter.h
index d2991ec..2150f86 100644
--- a/mgmtd/mgmt_fe_adapter.h
+++ b/mgmtd/mgmt_fe_adapter.h
@@ -12,7 +12,7 @@
#include "mgmt_fe_client.h"
#include "mgmt_msg.h"
-#include "mgmtd/mgmt_defines.h"
+#include "mgmt_defines.h"
struct mgmt_fe_client_adapter;
struct mgmt_master;
@@ -138,6 +138,52 @@ extern int mgmt_fe_send_get_reply(uint64_t session_id, uint64_t txn_id,
Mgmtd__YangDataReply *data_resp,
const char *error_if_any);
+/**
+ * Send get-tree data reply back to client.
+ *
+ * This also cleans up and frees the transaction.
+ *
+ * Args:
+ * session_id: the session.
+ * txn_id: the txn_id this data pertains to
+ * req_id: the req id for the get_tree message
+ * result_type: the format of the result data.
+ * wd_options: with-defaults options.
+ * tree: the results.
+ * partial_error: if there were errors while gather results.
+ * short_circuit_ok: True if OK to short-circuit the call.
+ *
+ * Return:
+ * the return value from the underlying send function.
+ *
+ */
+extern int
+mgmt_fe_adapter_send_tree_data(uint64_t session_id, uint64_t txn_id,
+ uint64_t req_id, LYD_FORMAT result_type,
+ uint32_t wd_options, const struct lyd_node *tree,
+ int partial_error, bool short_circuit_ok);
+
+/**
+ * Send an error back to the FE client using native messaging.
+ *
+ * This also cleans up and frees the transaction.
+ *
+ * Args:
+ * txn_id: the txn_id this error pertains to.
+ * short_circuit_ok: True if OK to short-circuit the call.
+ * error: An integer error value.
+ * errfmt: An error format string (i.e., printfrr)
+ * ...: args for use by the `errfmt` format string.
+ *
+ * Return:
+ * the return value from the underlying send function.
+ *
+ */
+extern int mgmt_fe_adapter_txn_error(uint64_t txn_id, uint64_t req_id,
+ bool short_circuit_ok, int16_t error,
+ const char *errstr);
+
+
/* Fetch frontend client session set-config stats */
extern struct mgmt_setcfg_stats *
mgmt_fe_get_session_setcfg_stats(uint64_t session_id);
@@ -149,4 +195,8 @@ mgmt_fe_get_session_commit_stats(uint64_t session_id);
extern void mgmt_fe_adapter_status_write(struct vty *vty, bool detail);
extern void mgmt_fe_adapter_perf_measurement(struct vty *vty, bool config);
extern void mgmt_fe_adapter_reset_perf_stats(struct vty *vty);
+
+/* Toggle debug on or off for connected clients. */
+extern void mgmt_fe_adapter_toggle_client_debug(bool set);
+
#endif /* _FRR_MGMTD_FE_ADAPTER_H_ */
diff --git a/mgmtd/mgmt_history.c b/mgmtd/mgmt_history.c
index d406932..c97cb7f 100644
--- a/mgmtd/mgmt_history.c
+++ b/mgmtd/mgmt_history.c
@@ -63,7 +63,7 @@ static struct mgmt_cmt_info_t *mgmt_history_new_cmt_info(void)
mgmt_time_to_string(&tv, true, new->time_str, sizeof(new->time_str));
mgmt_time_to_string(&tv, false, new->cmtid_str, sizeof(new->cmtid_str));
snprintf(new->cmt_json_file, sizeof(new->cmt_json_file),
- MGMTD_COMMIT_FILE_PATH, new->cmtid_str);
+ MGMTD_COMMIT_FILE_PATH(new->cmtid_str));
return new;
}
@@ -104,18 +104,21 @@ mgmt_history_find_cmt_record(const char *cmtid_str)
static bool mgmt_history_read_cmt_record_index(void)
{
+ char index_path[MAXPATHLEN];
FILE *fp;
struct mgmt_cmt_info_t cmt_info;
struct mgmt_cmt_info_t *new;
int cnt = 0;
- if (!file_exists(MGMTD_COMMIT_FILE_PATH))
- return false;
+ snprintf(index_path, sizeof(index_path), MGMTD_COMMIT_INDEX_FILE_PATH);
- fp = fopen(MGMTD_COMMIT_INDEX_FILE_NAME, "rb");
+ fp = fopen(index_path, "rb");
if (!fp) {
- zlog_err("Failed to open commit history %s for reading: %s",
- MGMTD_COMMIT_INDEX_FILE_NAME, safe_strerror(errno));
+ if (errno == ENOENT || errno == ENOTDIR)
+ return false;
+
+ zlog_err("Failed to open commit history %pSQq for reading: %m",
+ index_path);
return false;
}
@@ -132,9 +135,8 @@ static bool mgmt_history_read_cmt_record_index(void)
memcpy(new, &cmt_info, sizeof(struct mgmt_cmt_info_t));
mgmt_cmt_infos_add_tail(&mm->cmts, new);
} else {
- zlog_warn(
- "More records found in commit history file %s than expected",
- MGMTD_COMMIT_INDEX_FILE_NAME);
+ zlog_warn("More records found in commit history file %pSQq than expected",
+ index_path);
fclose(fp);
return false;
}
@@ -148,16 +150,19 @@ static bool mgmt_history_read_cmt_record_index(void)
static bool mgmt_history_dump_cmt_record_index(void)
{
+ char index_path[MAXPATHLEN];
FILE *fp;
int ret = 0;
struct mgmt_cmt_info_t *cmt_info;
struct mgmt_cmt_info_t cmt_info_set[10];
int cnt = 0;
- fp = fopen(MGMTD_COMMIT_INDEX_FILE_NAME, "wb");
+ snprintf(index_path, sizeof(index_path), MGMTD_COMMIT_INDEX_FILE_PATH);
+
+ fp = fopen(index_path, "wb");
if (!fp) {
- zlog_err("Failed to open commit history %s for writing: %s",
- MGMTD_COMMIT_INDEX_FILE_NAME, safe_strerror(errno));
+ zlog_err("Failed to open commit history %pSQq for writing: %m",
+ index_path);
return false;
}
@@ -176,7 +181,7 @@ static bool mgmt_history_dump_cmt_record_index(void)
fclose(fp);
if (ret != cnt) {
zlog_err("Failed to write full commit history, removing file");
- remove_file(MGMTD_COMMIT_INDEX_FILE_NAME);
+ remove_file(index_path);
return false;
}
return true;
@@ -261,7 +266,9 @@ failed_unlock:
void mgmt_history_rollback_complete(bool success)
{
- vty_mgmt_resume_response(rollback_vty, success);
+ vty_mgmt_resume_response(rollback_vty,
+ success ? CMD_SUCCESS
+ : CMD_WARNING_CONFIG_FAILED);
rollback_vty = NULL;
}
diff --git a/mgmtd/mgmt_main.c b/mgmtd/mgmt_main.c
index 39362fa..cce16f5 100644
--- a/mgmtd/mgmt_main.c
+++ b/mgmtd/mgmt_main.c
@@ -14,18 +14,21 @@
#include "frr_pthread.h"
#include "mgmtd/mgmt.h"
#include "mgmtd/mgmt_ds.h"
+#include "ripd/rip_nb.h"
+#include "ripngd/ripng_nb.h"
#include "routing_nb.h"
-
+#include "affinitymap.h"
+#include "zebra/zebra_cli.h"
/* mgmt options, we use GNU getopt library. */
static const struct option longopts[] = {
{"skip_runas", no_argument, NULL, 'S'},
{"no_zebra", no_argument, NULL, 'Z'},
{"socket_size", required_argument, NULL, 's'},
+ {"vrfwnetns", no_argument, NULL, 'n'},
{0}};
static void mgmt_exit(int);
-static void mgmt_vrf_terminate(void);
/* privileges */
static zebra_capabilities_t _caps_p[] = {ZCAP_BIND, ZCAP_NET_RAW,
@@ -45,7 +48,6 @@ struct zebra_privs_t mgmt_privs = {
};
static struct frr_daemon_info mgmtd_di;
-char backup_config_file[256];
/* SIGHUP handler. */
static void sighup(void)
@@ -114,8 +116,6 @@ static __attribute__((__noreturn__)) void mgmt_exit(int status)
/* stop pthreads (if any) */
frr_pthread_stop_all();
- mgmt_vrf_terminate();
-
frr_fini();
exit(status);
}
@@ -139,87 +139,81 @@ static struct frr_signal_t mgmt_signals[] = {
},
};
-static int mgmt_vrf_new(struct vrf *vrf)
-{
- zlog_debug("VRF Created: %s(%u)", vrf->name, vrf->vrf_id);
-
- return 0;
-}
-
-static int mgmt_vrf_delete(struct vrf *vrf)
-{
- zlog_debug("VRF Deletion: %s(%u)", vrf->name, vrf->vrf_id);
-
- return 0;
-}
-
-static int mgmt_vrf_enable(struct vrf *vrf)
-{
- zlog_debug("VRF Enable: %s(%u)", vrf->name, vrf->vrf_id);
-
- return 0;
-}
-
-static int mgmt_vrf_disable(struct vrf *vrf)
-{
- zlog_debug("VRF Disable: %s(%u)", vrf->name, vrf->vrf_id);
-
- /* Note: This is a callback, the VRF will be deleted by the caller. */
- return 0;
-}
-
-static int mgmt_vrf_config_write(struct vty *vty)
-{
- return 0;
-}
+#ifdef HAVE_STATICD
+extern const struct frr_yang_module_info frr_staticd_cli_info;
+#endif
-static void mgmt_vrf_init(void)
-{
- vrf_init(mgmt_vrf_new, mgmt_vrf_enable, mgmt_vrf_disable,
- mgmt_vrf_delete);
- vrf_cmd_init(mgmt_vrf_config_write);
-}
+/*
+ * These are modules that are only needed by mgmtd and hence not included into
+ * the lib and backend daemons.
+ */
+const struct frr_yang_module_info ietf_netconf_with_defaults_info = {
+ .name = "ietf-netconf-with-defaults",
+ .ignore_cfg_cbs = true,
+ .nodes = { { .xpath = NULL } },
+};
-static void mgmt_vrf_terminate(void)
-{
- vrf_terminate();
-}
+/*
+ * These are stub info structs that are used to load the modules used by backend
+ * clients into mgmtd. The modules are used by libyang in order to support
+ * parsing binary data returns from the backend.
+ */
+const struct frr_yang_module_info zebra_route_map_info = {
+ .name = "frr-zebra-route-map",
+ .ignore_cfg_cbs = true,
+ .nodes = { { .xpath = NULL } },
+};
/*
* List of YANG modules to be loaded in the process context of
* MGMTd.
- *
- * NOTE: In future this will also include the YANG modules of
- * all individual Backend clients.
*/
static const struct frr_yang_module_info *const mgmt_yang_modules[] = {
- &frr_filter_info,
- &frr_interface_info,
- &frr_route_map_info,
- &frr_routing_info,
- &frr_vrf_info,
-/*
- * YANG module info supported by backend clients get added here.
- * NOTE: Always set .ignore_cbs true for to avoid validating
- * backend northbound callbacks during loading.
- */
+ &frr_filter_cli_info,
+ &frr_interface_cli_info,
+ &frr_route_map_cli_info,
+ &frr_routing_cli_info,
+ &frr_vrf_cli_info,
+ &frr_affinity_map_cli_info,
+
+ /* mgmtd-only modules */
+ &ietf_netconf_with_defaults_info,
+
+ /*
+ * YANG module info used by backend clients get added here.
+ */
+
+ &frr_zebra_cli_info,
+ &zebra_route_map_info,
+
+#ifdef HAVE_RIPD
+ &frr_ripd_cli_info,
+#endif
+#ifdef HAVE_RIPNGD
+ &frr_ripngd_cli_info,
+#endif
#ifdef HAVE_STATICD
- &(struct frr_yang_module_info){.name = "frr-staticd",
- .ignore_cbs = true},
+ &frr_staticd_cli_info,
#endif
};
-FRR_DAEMON_INFO(mgmtd, MGMTD, .vty_port = MGMTD_VTY_PORT,
+/* clang-format off */
+FRR_DAEMON_INFO(mgmtd, MGMTD,
+ .vty_port = MGMTD_VTY_PORT,
+ .proghelp = "FRR Management Daemon.",
- .proghelp = "FRR Management Daemon.",
+ .signals = mgmt_signals,
+ .n_signals = array_size(mgmt_signals),
- .signals = mgmt_signals, .n_signals = array_size(mgmt_signals),
+ .privs = &mgmt_privs,
- .privs = &mgmt_privs, .yang_modules = mgmt_yang_modules,
- .n_yang_modules = array_size(mgmt_yang_modules),
+ .yang_modules = mgmt_yang_modules,
+ .n_yang_modules = array_size(mgmt_yang_modules),
- /* avoid libfrr trying to read our config file for us */
- .flags = FRR_MANUAL_VTY_START);
+ /* avoid libfrr trying to read our config file for us */
+ .flags = FRR_MANUAL_VTY_START | FRR_NO_SPLIT_CONFIG,
+);
+/* clang-format on */
#define DEPRECATED_OPTIONS ""
@@ -235,8 +229,9 @@ int main(int argc, char **argv)
frr_preinit(&mgmtd_di, argc, argv);
frr_opt_add(
- "s:" DEPRECATED_OPTIONS, longopts,
- " -s, --socket_size Set MGMTD peer socket send buffer size\n");
+ "s:n" DEPRECATED_OPTIONS, longopts,
+ " -s, --socket_size Set MGMTD peer socket send buffer size\n"
+ " -n, --vrfwnetns Use NetNS as VRF backend\n");
/* Command line argument treatment. */
while (1) {
@@ -258,6 +253,9 @@ int main(int argc, char **argv)
case 's':
buffer_size = atoi(optarg);
break;
+ case 'n':
+ vrf_configure_backend(VRF_BACKEND_NETNS);
+ break;
default:
frr_help_exit(1);
break;
@@ -267,17 +265,15 @@ int main(int argc, char **argv)
/* MGMTD master init. */
mgmt_master_init(frr_init(), buffer_size);
- /* VRF Initializations. */
- mgmt_vrf_init();
+ /* VRF commands initialization. */
+ vrf_cmd_init(NULL);
+
+ /* Interface commands initialization. */
+ if_cmd_init(NULL);
/* MGMTD related initialization. */
mgmt_init();
- snprintf(backup_config_file, sizeof(backup_config_file),
- "%s/zebra.conf", frr_sysconfdir);
- mgmtd_di.backup_config_file = backup_config_file;
-
- /* this will queue a read configs event */
frr_config_fork();
frr_run(mm->master);
diff --git a/mgmtd/mgmt_memory.c b/mgmtd/mgmt_memory.c
index b2a0f0e..0fce61a 100644
--- a/mgmtd/mgmt_memory.c
+++ b/mgmtd/mgmt_memory.c
@@ -29,5 +29,6 @@ DEFINE_MTYPE(MGMTD, MGMTD_TXN_SETCFG_REQ, "txn set-config requests");
DEFINE_MTYPE(MGMTD, MGMTD_TXN_COMMCFG_REQ, "txn commit-config requests");
DEFINE_MTYPE(MGMTD, MGMTD_TXN_GETDATA_REQ, "txn get-data requests");
DEFINE_MTYPE(MGMTD, MGMTD_TXN_GETDATA_REPLY, "txn get-data replies");
+DEFINE_MTYPE(MGMTD, MGMTD_TXN_GETTREE_REQ, "txn get-tree requests");
DEFINE_MTYPE(MGMTD, MGMTD_TXN_CFG_BATCH, "txn config batches");
DEFINE_MTYPE(MGMTD, MGMTD_CMT_INFO, "commit info");
diff --git a/mgmtd/mgmt_memory.h b/mgmtd/mgmt_memory.h
index 06518e3..d5b6aa6 100644
--- a/mgmtd/mgmt_memory.h
+++ b/mgmtd/mgmt_memory.h
@@ -23,6 +23,7 @@ DECLARE_MTYPE(MGMTD_TXN_SETCFG_REQ);
DECLARE_MTYPE(MGMTD_TXN_COMMCFG_REQ);
DECLARE_MTYPE(MGMTD_TXN_GETDATA_REQ);
DECLARE_MTYPE(MGMTD_TXN_GETDATA_REPLY);
+DECLARE_MTYPE(MGMTD_TXN_GETTREE_REQ);
DECLARE_MTYPE(MGMTD_TXN_CFG_BATCH);
DECLARE_MTYPE(MGMTD_BE_ADAPTER_MSG_BUF);
DECLARE_MTYPE(MGMTD_CMT_INFO);
diff --git a/mgmtd/mgmt_testc.c b/mgmtd/mgmt_testc.c
new file mode 100644
index 0000000..7e3ded8
--- /dev/null
+++ b/mgmtd/mgmt_testc.c
@@ -0,0 +1,230 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * January 29 2024, Christian Hopps <chopps@labn.net>
+ *
+ * Copyright (c) 2024, LabN Consulting, L.L.C.
+ *
+ */
+
+#include <zebra.h>
+#include <lib/version.h>
+#include "darr.h"
+#include "libfrr.h"
+#include "mgmt_be_client.h"
+#include "northbound.h"
+
+/* ---------------- */
+/* Local Prototypes */
+/* ---------------- */
+
+static void async_notification(struct nb_cb_notify_args *args);
+
+static void sigusr1(void);
+static void sigint(void);
+
+/* ----------- */
+/* Global Data */
+/* ----------- */
+
+/* privileges */
+static zebra_capabilities_t _caps_p[] = {};
+
+struct zebra_privs_t __privs = {
+#if defined(FRR_USER) && defined(FRR_GROUP)
+ .user = FRR_USER,
+ .group = FRR_GROUP,
+#endif
+#ifdef VTY_GROUP
+ .vty_group = VTY_GROUP,
+#endif
+ .caps_p = _caps_p,
+ .cap_num_p = array_size(_caps_p),
+ .cap_num_i = 0,
+};
+
+#define OPTION_LISTEN 2000
+#define OPTION_NOTIF_COUNT 2001
+#define OPTION_TIMEOUT 2002
+const struct option longopts[] = {
+ { "listen", no_argument, NULL, OPTION_LISTEN },
+ { "notif-count", required_argument, NULL, OPTION_NOTIF_COUNT },
+ { "timeout", required_argument, NULL, OPTION_TIMEOUT },
+ { 0 }
+};
+
+
+/* Master of threads. */
+struct event_loop *master;
+
+struct mgmt_be_client *mgmt_be_client;
+
+static struct frr_daemon_info mgmtd_testc_di;
+
+struct frr_signal_t __signals[] = {
+ {
+ .signal = SIGUSR1,
+ .handler = &sigusr1,
+ },
+ {
+ .signal = SIGINT,
+ .handler = &sigint,
+ },
+ {
+ .signal = SIGTERM,
+ .handler = &sigint,
+ },
+};
+
+#define MGMTD_TESTC_VTY_PORT 2624
+
+/* clang-format off */
+static const struct frr_yang_module_info frr_ripd_info = {
+ .name = "frr-ripd",
+ .ignore_cfg_cbs = true,
+ .nodes = {
+ {
+ .xpath = "/frr-ripd:authentication-failure",
+ .cbs.notify = async_notification,
+ },
+ {
+ .xpath = NULL,
+ }
+ }
+};
+
+static const struct frr_yang_module_info *const mgmt_yang_modules[] = {
+ &frr_ripd_info,
+};
+
+FRR_DAEMON_INFO(mgmtd_testc, MGMTD_TESTC,
+ .proghelp = "FRR Management Daemon Test Client.",
+
+ .signals = __signals,
+ .n_signals = array_size(__signals),
+
+ .privs = &__privs,
+
+ .yang_modules = mgmt_yang_modules,
+ .n_yang_modules = array_size(mgmt_yang_modules),
+
+ /* avoid libfrr trying to read our config file for us */
+ .flags = FRR_MANUAL_VTY_START,
+ );
+/* clang-format on */
+
+const char **__notif_xpaths;
+
+struct mgmt_be_client_cbs __client_cbs = {};
+struct event *event_timeout;
+
+int o_notif_count = 1;
+int o_timeout;
+
+/* --------- */
+/* Functions */
+/* --------- */
+
+
+static void sigusr1(void)
+{
+ zlog_rotate();
+}
+
+static void quit(int exit_code)
+{
+ EVENT_OFF(event_timeout);
+ frr_fini();
+ darr_free(__client_cbs.notif_xpaths);
+ exit(exit_code);
+}
+
+static void sigint(void)
+{
+ zlog_notice("Terminating on signal");
+ quit(0);
+}
+
+static void timeout(struct event *event)
+{
+ zlog_notice("Timeout, exiting");
+ quit(1);
+}
+
+static void async_notification(struct nb_cb_notify_args *args)
+{
+ zlog_notice("Received YANG notification");
+
+ printf("{\"frr-ripd:authentication-failure\": {\"interface-name\": \"%s\"}}\n",
+ yang_dnode_get_string(args->dnode, "interface-name"));
+
+ if (o_notif_count && !--o_notif_count)
+ quit(0);
+}
+
+int main(int argc, char **argv)
+{
+ int f_listen = 0;
+ int i;
+
+ frr_preinit(&mgmtd_testc_di, argc, argv);
+ frr_opt_add("", longopts, "");
+
+ while (1) {
+ int opt;
+
+ opt = frr_getopt(argc, argv, NULL);
+
+ if (opt == EOF)
+ break;
+
+ switch (opt) {
+ case OPTION_LISTEN:
+ f_listen = 1;
+ break;
+ case OPTION_NOTIF_COUNT:
+ o_notif_count = atoi(optarg);
+ break;
+ case OPTION_TIMEOUT:
+ o_timeout = atoi(optarg);
+ break;
+ case 0:
+ break;
+ default:
+ frr_help_exit(1);
+ }
+ }
+
+ master = frr_init();
+
+ /*
+ * Setup notification listen
+ */
+ argv += optind;
+ argc -= optind;
+ if (!argc && f_listen) {
+ fprintf(stderr,
+ "Must specify at least one notification xpath to listen to\n");
+ exit(1);
+ }
+ if (argc && f_listen) {
+ for (i = 0; i < argc; i++) {
+ zlog_notice("Listen on xpath: %s", argv[i]);
+ darr_push(__notif_xpaths, argv[i]);
+ }
+ __client_cbs.notif_xpaths = __notif_xpaths;
+ __client_cbs.nnotif_xpaths = darr_len(__notif_xpaths);
+ }
+
+ mgmt_be_client = mgmt_be_client_create("mgmtd-testc", &__client_cbs, 0,
+ master);
+
+ frr_config_fork();
+
+ if (o_timeout)
+ event_add_timer(master, timeout, NULL, o_timeout, &event_timeout);
+
+ frr_run(master);
+
+ /* Reached. */
+ return 0;
+}
diff --git a/mgmtd/mgmt_txn.c b/mgmtd/mgmt_txn.c
index 452f9c8..c1cb33f 100644
--- a/mgmtd/mgmt_txn.c
+++ b/mgmtd/mgmt_txn.c
@@ -7,17 +7,19 @@
*/
#include <zebra.h>
+#include "darr.h"
#include "hash.h"
#include "jhash.h"
#include "libfrr.h"
+#include "mgmt_msg.h"
+#include "mgmt_msg_native.h"
#include "mgmtd/mgmt.h"
#include "mgmtd/mgmt_memory.h"
#include "mgmtd/mgmt_txn.h"
-#define MGMTD_TXN_DBG(fmt, ...) \
+#define __dbg(fmt, ...) \
DEBUGD(&mgmt_debug_txn, "TXN: %s: " fmt, __func__, ##__VA_ARGS__)
-#define MGMTD_TXN_ERR(fmt, ...) \
- zlog_err("%s: ERROR: " fmt, __func__, ##__VA_ARGS__)
+#define __log_err(fmt, ...) zlog_err("%s: ERROR: " fmt, __func__, ##__VA_ARGS__)
#define MGMTD_TXN_LOCK(txn) mgmt_txn_lock(txn, __FILE__, __LINE__)
#define MGMTD_TXN_UNLOCK(txn) mgmt_txn_unlock(txn, __FILE__, __LINE__)
@@ -26,9 +28,9 @@ enum mgmt_txn_event {
MGMTD_TXN_PROC_SETCFG = 1,
MGMTD_TXN_PROC_COMMITCFG,
MGMTD_TXN_PROC_GETCFG,
- MGMTD_TXN_PROC_GETDATA,
+ MGMTD_TXN_PROC_GETTREE,
MGMTD_TXN_COMMITCFG_TIMEOUT,
- MGMTD_TXN_CLEANUP
+ MGMTD_TXN_GETTREE_TIMEOUT,
};
PREDECL_LIST(mgmt_txn_reqs);
@@ -77,17 +79,14 @@ PREDECL_LIST(mgmt_txn_batches);
struct mgmt_txn_be_cfg_batch {
struct mgmt_txn_ctx *txn;
- 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];
Mgmtd__YangDataValue value[MGMTD_MAX_CFG_CHANGES_IN_BATCH];
size_t num_cfg_data;
int buf_space_left;
- enum mgmt_commit_phase comm_phase;
struct mgmt_txn_batches_item list_linkage;
};
@@ -106,10 +105,12 @@ struct mgmt_commit_cfg_req {
uint8_t abort : 1;
uint8_t implicit : 1;
uint8_t rollback : 1;
+ uint8_t init : 1;
/* Track commit phases */
- enum mgmt_commit_phase curr_phase;
- enum mgmt_commit_phase next_phase;
+ enum mgmt_commit_phase phase;
+
+ enum mgmt_commit_phase be_phase[MGMTD_BE_CLIENT_ID_MAX];
/*
* Set of config changes to commit. This is used only
@@ -125,26 +126,17 @@ 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
* and applied at the backend.
- *
- * FIXME: Need to re-think this design for the case set of
- * validators for a given YANG data item is different from
- * the set of notifiers for the same. We may need to have
- * separate list of batches for VALIDATE and APPLY.
*/
- struct mgmt_txn_batches_head curr_batches[MGMTD_BE_CLIENT_ID_MAX];
- struct mgmt_txn_batches_head next_batches[MGMTD_BE_CLIENT_ID_MAX];
+ struct mgmt_txn_batches_head batches[MGMTD_BE_CLIENT_ID_MAX];
/*
- * The last batch added for any backend client. This is always on
- * 'curr_batches'
+ * The last batch added for any backend client.
*/
struct mgmt_txn_be_cfg_batch *last_be_cfg_batch[MGMTD_BE_CLIENT_ID_MAX];
- struct hash *batches;
- uint64_t next_batch_id;
struct mgmt_commit_stats *cmt_stats;
};
@@ -176,6 +168,19 @@ struct mgmt_get_data_req {
int total_reply;
};
+
+struct txn_req_get_tree {
+ char *xpath; /* xpath of tree to get */
+ uint64_t sent_clients; /* Bitmask of clients sent req to */
+ uint64_t recv_clients; /* Bitmask of clients recv reply from */
+ int32_t partial_error; /* an error while gather results */
+ uint8_t result_type; /* LYD_FORMAT for results */
+ uint8_t wd_options; /* LYD_PRINT_WD_* flags for results */
+ uint8_t exact; /* if exact node is requested */
+ uint8_t simple_xpath; /* if xpath is simple */
+ struct lyd_node *client_results; /* result tree from clients */
+};
+
struct mgmt_txn_req {
struct mgmt_txn_ctx *txn;
enum mgmt_txn_event req_event;
@@ -183,10 +188,10 @@ struct mgmt_txn_req {
union {
struct mgmt_set_cfg_req *set_cfg;
struct mgmt_get_data_req *get_data;
+ struct txn_req_get_tree *get_tree;
struct mgmt_commit_cfg_req commit_cfg;
} req;
- bool pending_be_proc;
struct mgmt_txn_reqs_item list_linkage;
};
@@ -206,7 +211,9 @@ struct mgmt_txn_ctx {
struct event *proc_comm_cfg;
struct event *proc_get_cfg;
struct event *proc_get_data;
+ struct event *proc_get_tree;
struct event *comm_cfg_timeout;
+ struct event *get_tree_timeout;
struct event *clnup;
/* List of backend adapters involved in this transaction */
@@ -216,6 +223,10 @@ struct mgmt_txn_ctx {
struct mgmt_txns_item list_linkage;
+ /* TODO: why do we need unique lists for each type of transaction since
+ * a transaction is of only 1 type?
+ */
+
/*
* List of pending set-config requests for a given
* transaction/session. Just one list for requests
@@ -231,13 +242,9 @@ struct mgmt_txn_ctx {
*/
struct mgmt_txn_reqs_head get_cfg_reqs;
/*
- * List of pending get-data requests for a given
- * transaction/session Two lists, one for requests
- * not processed at all, and one for requests that
- * has been sent to backend for processing.
+ * List of pending get-tree requests.
*/
- struct mgmt_txn_reqs_head get_data_reqs;
- struct mgmt_txn_reqs_head pending_get_datas;
+ struct mgmt_txn_reqs_head get_tree_reqs;
/*
* There will always be one commit-config allowed for a given
* transaction/session. No need to maintain lists for it.
@@ -254,15 +261,12 @@ static int mgmt_txn_send_commit_cfg_reply(struct mgmt_txn_ctx *txn,
enum mgmt_result result,
const char *error_if_any);
-static inline const char *mgmt_txn_commit_phase_str(struct mgmt_txn_ctx *txn,
- bool curr)
+static inline const char *mgmt_txn_commit_phase_str(struct mgmt_txn_ctx *txn)
{
if (!txn->commit_cfg_req)
return "None";
- return (mgmt_commit_phase2str(
- curr ? txn->commit_cfg_req->req.commit_cfg.curr_phase
- : txn->commit_cfg_req->req.commit_cfg.next_phase));
+ return mgmt_commit_phase2str(txn->commit_cfg_req->req.commit_cfg.phase);
}
static void mgmt_txn_lock(struct mgmt_txn_ctx *txn, const char *file, int line);
@@ -277,9 +281,7 @@ static struct mgmt_master *mgmt_txn_mm;
static void mgmt_txn_register_event(struct mgmt_txn_ctx *txn,
enum mgmt_txn_event event);
-static int
-mgmt_move_be_commit_to_next_phase(struct mgmt_txn_ctx *txn,
- struct mgmt_be_client_adapter *adapter);
+static void mgmt_txn_cleanup_txn(struct mgmt_txn_ctx **txn);
static struct mgmt_txn_be_cfg_batch *
mgmt_txn_cfg_batch_alloc(struct mgmt_txn_ctx *txn, enum mgmt_be_client_id id,
@@ -296,7 +298,7 @@ mgmt_txn_cfg_batch_alloc(struct mgmt_txn_ctx *txn, enum mgmt_be_client_id id,
MGMTD_TXN_LOCK(txn);
assert(txn->commit_cfg_req);
mgmt_txn_batches_add_tail(&txn->commit_cfg_req->req.commit_cfg
- .curr_batches[id],
+ .batches[id],
batch);
batch->be_adapter = be_adapter;
batch->buf_space_left = MGMTD_BE_CFGDATA_MAX_MSG_LEN;
@@ -304,11 +306,6 @@ mgmt_txn_cfg_batch_alloc(struct mgmt_txn_ctx *txn, enum mgmt_be_client_id id,
mgmt_be_adapter_lock(be_adapter);
txn->commit_cfg_req->req.commit_cfg.last_be_cfg_batch[id] = batch;
- if (!txn->commit_cfg_req->req.commit_cfg.next_batch_id)
- txn->commit_cfg_req->req.commit_cfg.next_batch_id++;
- batch->batch_id = txn->commit_cfg_req->req.commit_cfg.next_batch_id++;
- hash_get(txn->commit_cfg_req->req.commit_cfg.batches, batch,
- hash_alloc_intern);
return batch;
}
@@ -318,15 +315,12 @@ static void mgmt_txn_cfg_batch_free(struct mgmt_txn_be_cfg_batch **batch)
size_t indx;
struct mgmt_commit_cfg_req *cmtcfg_req;
- MGMTD_TXN_DBG(" freeing batch-id: %" PRIu64 " txn-id %" PRIu64,
- (*batch)->batch_id, (*batch)->txn->txn_id);
+ __dbg(" freeing batch txn-id %" PRIu64, (*batch)->txn->txn_id);
assert((*batch)->txn && (*batch)->txn->type == MGMTD_TXN_TYPE_CONFIG);
cmtcfg_req = &(*batch)->txn->commit_cfg_req->req.commit_cfg;
- hash_release(cmtcfg_req->batches, *batch);
- mgmt_txn_batches_del(&cmtcfg_req->curr_batches[(*batch)->be_id], *batch);
- mgmt_txn_batches_del(&cmtcfg_req->next_batches[(*batch)->be_id], *batch);
+ mgmt_txn_batches_del(&cmtcfg_req->batches[(*batch)->be_id], *batch);
if ((*batch)->be_adapter)
mgmt_be_adapter_unlock(&(*batch)->be_adapter);
@@ -344,57 +338,13 @@ static void mgmt_txn_cfg_batch_free(struct mgmt_txn_be_cfg_batch **batch)
*batch = NULL;
}
-static unsigned int mgmt_txn_cfgbatch_hash_key(const void *data)
-{
- const struct mgmt_txn_be_cfg_batch *batch = data;
-
- return jhash2((uint32_t *)&batch->batch_id,
- sizeof(batch->batch_id) / sizeof(uint32_t), 0);
-}
-
-static bool mgmt_txn_cfgbatch_hash_cmp(const void *d1, const void *d2)
-{
- const struct mgmt_txn_be_cfg_batch *batch1 = d1;
- const struct mgmt_txn_be_cfg_batch *batch2 = d2;
-
- return (batch1->batch_id == batch2->batch_id);
-}
-
-static void mgmt_txn_cfgbatch_hash_free(void *data)
-{
- struct mgmt_txn_be_cfg_batch *batch = data;
-
- mgmt_txn_cfg_batch_free(&batch);
-}
-
-static inline struct mgmt_txn_be_cfg_batch *
-mgmt_txn_cfgbatch_id2ctx(struct mgmt_txn_ctx *txn, uint64_t batch_id)
-{
- struct mgmt_txn_be_cfg_batch key = { 0 };
- struct mgmt_txn_be_cfg_batch *batch;
-
- if (!txn->commit_cfg_req)
- return NULL;
-
- key.batch_id = batch_id;
- batch = hash_lookup(txn->commit_cfg_req->req.commit_cfg.batches, &key);
-
- return batch;
-}
-
static void mgmt_txn_cleanup_be_cfg_batches(struct mgmt_txn_ctx *txn,
enum mgmt_be_client_id id)
{
struct mgmt_txn_be_cfg_batch *batch;
struct mgmt_txn_batches_head *list;
- list = &txn->commit_cfg_req->req.commit_cfg.curr_batches[id];
- FOREACH_TXN_CFG_BATCH_IN_LIST (list, batch)
- mgmt_txn_cfg_batch_free(&batch);
-
- mgmt_txn_batches_fini(list);
-
- list = &txn->commit_cfg_req->req.commit_cfg.next_batches[id];
+ list = &txn->commit_cfg_req->req.commit_cfg.batches[id];
FOREACH_TXN_CFG_BATCH_IN_LIST (list, batch)
mgmt_txn_cfg_batch_free(&batch);
@@ -415,7 +365,6 @@ static struct mgmt_txn_req *mgmt_txn_req_alloc(struct mgmt_txn_ctx *txn,
txn_req->txn = txn;
txn_req->req_id = req_id;
txn_req->req_event = req_event;
- txn_req->pending_be_proc = false;
switch (txn_req->req_event) {
case MGMTD_TXN_PROC_SETCFG:
@@ -423,27 +372,24 @@ static struct mgmt_txn_req *mgmt_txn_req_alloc(struct mgmt_txn_ctx *txn,
sizeof(struct mgmt_set_cfg_req));
assert(txn_req->req.set_cfg);
mgmt_txn_reqs_add_tail(&txn->set_cfg_reqs, txn_req);
- MGMTD_TXN_DBG("Added a new SETCFG req-id: %" PRIu64
- " txn-id: %" PRIu64 ", session-id: %" PRIu64,
- txn_req->req_id, txn->txn_id, txn->session_id);
+ __dbg("Added a new SETCFG req-id: %" PRIu64 " txn-id: %" PRIu64
+ ", session-id: %" PRIu64,
+ txn_req->req_id, txn->txn_id, txn->session_id);
break;
case MGMTD_TXN_PROC_COMMITCFG:
txn->commit_cfg_req = txn_req;
- MGMTD_TXN_DBG("Added a new COMMITCFG req-id: %" PRIu64
- " txn-id: %" PRIu64 " session-id: %" PRIu64,
- txn_req->req_id, txn->txn_id, txn->session_id);
+ __dbg("Added a new COMMITCFG req-id: %" PRIu64
+ " txn-id: %" PRIu64 " session-id: %" PRIu64,
+ txn_req->req_id, txn->txn_id, txn->session_id);
FOREACH_MGMTD_BE_CLIENT_ID (id) {
+ txn_req->req.commit_cfg.be_phase[id] =
+ MGMTD_COMMIT_PHASE_PREPARE_CFG;
mgmt_txn_batches_init(
- &txn_req->req.commit_cfg.curr_batches[id]);
- mgmt_txn_batches_init(
- &txn_req->req.commit_cfg.next_batches[id]);
+ &txn_req->req.commit_cfg.batches[id]);
}
- txn_req->req.commit_cfg.batches =
- hash_create(mgmt_txn_cfgbatch_hash_key,
- mgmt_txn_cfgbatch_hash_cmp,
- "MGMT Config Batches");
+ txn_req->req.commit_cfg.phase = MGMTD_COMMIT_PHASE_PREPARE_CFG;
break;
case MGMTD_TXN_PROC_GETCFG:
txn_req->req.get_data =
@@ -451,22 +397,20 @@ static struct mgmt_txn_req *mgmt_txn_req_alloc(struct mgmt_txn_ctx *txn,
sizeof(struct mgmt_get_data_req));
assert(txn_req->req.get_data);
mgmt_txn_reqs_add_tail(&txn->get_cfg_reqs, txn_req);
- MGMTD_TXN_DBG("Added a new GETCFG req-id: %" PRIu64
- " txn-id: %" PRIu64 " session-id: %" PRIu64,
- txn_req->req_id, txn->txn_id, txn->session_id);
+ __dbg("Added a new GETCFG req-id: %" PRIu64 " txn-id: %" PRIu64
+ " session-id: %" PRIu64,
+ txn_req->req_id, txn->txn_id, txn->session_id);
break;
- case MGMTD_TXN_PROC_GETDATA:
- txn_req->req.get_data =
- XCALLOC(MTYPE_MGMTD_TXN_GETDATA_REQ,
- sizeof(struct mgmt_get_data_req));
- assert(txn_req->req.get_data);
- mgmt_txn_reqs_add_tail(&txn->get_data_reqs, txn_req);
- MGMTD_TXN_DBG("Added a new GETDATA req-id: %" PRIu64
- " txn-id: %" PRIu64 " session-id: %" PRIu64,
- txn_req->req_id, txn->txn_id, txn->session_id);
+ case MGMTD_TXN_PROC_GETTREE:
+ txn_req->req.get_tree = XCALLOC(MTYPE_MGMTD_TXN_GETTREE_REQ,
+ sizeof(struct txn_req_get_tree));
+ mgmt_txn_reqs_add_tail(&txn->get_tree_reqs, txn_req);
+ __dbg("Added a new GETTREE req-id: %" PRIu64 " txn-id: %" PRIu64
+ " session-id: %" PRIu64,
+ txn_req->req_id, txn->txn_id, txn->session_id);
break;
case MGMTD_TXN_COMMITCFG_TIMEOUT:
- case MGMTD_TXN_CLEANUP:
+ case MGMTD_TXN_GETTREE_TIMEOUT:
break;
}
@@ -479,49 +423,31 @@ static void mgmt_txn_req_free(struct mgmt_txn_req **txn_req)
{
int indx;
struct mgmt_txn_reqs_head *req_list = NULL;
- struct mgmt_txn_reqs_head *pending_list = NULL;
enum mgmt_be_client_id id;
struct mgmt_be_client_adapter *adapter;
struct mgmt_commit_cfg_req *ccreq;
+ struct mgmt_set_cfg_req *set_cfg;
bool cleanup;
switch ((*txn_req)->req_event) {
case MGMTD_TXN_PROC_SETCFG:
- for (indx = 0; indx < (*txn_req)->req.set_cfg->num_cfg_changes;
- indx++) {
- if ((*txn_req)->req.set_cfg->cfg_changes[indx].value) {
- MGMTD_TXN_DBG("Freeing value for %s at %p ==> '%s'",
- (*txn_req)
- ->req.set_cfg
- ->cfg_changes[indx]
- .xpath,
- (*txn_req)
- ->req.set_cfg
- ->cfg_changes[indx]
- .value,
- (*txn_req)
- ->req.set_cfg
- ->cfg_changes[indx]
- .value);
- free((void *)(*txn_req)
- ->req.set_cfg->cfg_changes[indx]
- .value);
- }
+ set_cfg = (*txn_req)->req.set_cfg;
+ for (indx = 0; indx < set_cfg->num_cfg_changes; indx++) {
+ if (set_cfg->cfg_changes[indx].value)
+ free((void *)set_cfg->cfg_changes[indx].value);
}
req_list = &(*txn_req)->txn->set_cfg_reqs;
- MGMTD_TXN_DBG("Deleting SETCFG req-id: %" PRIu64
- " txn-id: %" PRIu64,
- (*txn_req)->req_id, (*txn_req)->txn->txn_id);
+ __dbg("Deleting SETCFG req-id: %" PRIu64 " txn-id: %" PRIu64,
+ (*txn_req)->req_id, (*txn_req)->txn->txn_id);
XFREE(MTYPE_MGMTD_TXN_SETCFG_REQ, (*txn_req)->req.set_cfg);
break;
case MGMTD_TXN_PROC_COMMITCFG:
- MGMTD_TXN_DBG("Deleting COMMITCFG req-id: %" PRIu64
- " txn-id: %" PRIu64,
- (*txn_req)->req_id, (*txn_req)->txn->txn_id);
+ __dbg("Deleting COMMITCFG req-id: %" PRIu64 " txn-id: %" PRIu64,
+ (*txn_req)->req_id, (*txn_req)->txn->txn_id);
ccreq = &(*txn_req)->req.commit_cfg;
- cleanup = (ccreq->curr_phase >= MGMTD_COMMIT_PHASE_TXN_CREATE &&
- ccreq->curr_phase < MGMTD_COMMIT_PHASE_TXN_DELETE);
+ cleanup = (ccreq->phase >= MGMTD_COMMIT_PHASE_TXN_CREATE &&
+ ccreq->phase < MGMTD_COMMIT_PHASE_TXN_DELETE);
FOREACH_MGMTD_BE_CLIENT_ID (id) {
/*
@@ -534,20 +460,13 @@ static void mgmt_txn_req_free(struct mgmt_txn_req **txn_req)
* anything more with them
*/
mgmt_txn_cleanup_be_cfg_batches((*txn_req)->txn, id);
- if (ccreq->batches) {
- hash_clean(ccreq->batches,
- mgmt_txn_cfgbatch_hash_free);
- hash_free(ccreq->batches);
- ccreq->batches = NULL;
- }
/*
* If we were in the middle of the state machine then
* 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);
}
@@ -560,9 +479,8 @@ static void mgmt_txn_req_free(struct mgmt_txn_req **txn_req)
->req.get_data->xpaths[indx]);
}
req_list = &(*txn_req)->txn->get_cfg_reqs;
- MGMTD_TXN_DBG("Deleting GETCFG req-id: %" PRIu64
- " txn-id: %" PRIu64,
- (*txn_req)->req_id, (*txn_req)->txn->txn_id);
+ __dbg("Deleting GETCFG req-id: %" PRIu64 " txn-id: %" PRIu64,
+ (*txn_req)->req_id, (*txn_req)->txn->txn_id);
if ((*txn_req)->req.get_data->reply)
XFREE(MTYPE_MGMTD_TXN_GETDATA_REPLY,
(*txn_req)->req.get_data->reply);
@@ -572,42 +490,25 @@ static void mgmt_txn_req_free(struct mgmt_txn_req **txn_req)
XFREE(MTYPE_MGMTD_TXN_GETDATA_REQ, (*txn_req)->req.get_data);
break;
- case MGMTD_TXN_PROC_GETDATA:
- for (indx = 0; indx < (*txn_req)->req.get_data->num_xpaths;
- indx++) {
- if ((*txn_req)->req.get_data->xpaths[indx])
- free((void *)(*txn_req)
- ->req.get_data->xpaths[indx]);
- }
- pending_list = &(*txn_req)->txn->pending_get_datas;
- req_list = &(*txn_req)->txn->get_data_reqs;
- MGMTD_TXN_DBG("Deleting GETDATA req-id: %" PRIu64
- " txn-id: %" PRIu64,
- (*txn_req)->req_id, (*txn_req)->txn->txn_id);
- if ((*txn_req)->req.get_data->reply)
- XFREE(MTYPE_MGMTD_TXN_GETDATA_REPLY,
- (*txn_req)->req.get_data->reply);
- XFREE(MTYPE_MGMTD_TXN_GETDATA_REQ, (*txn_req)->req.get_data);
+ case MGMTD_TXN_PROC_GETTREE:
+ __dbg("Deleting GETTREE req-id: %" PRIu64 " of txn-id: %" PRIu64,
+ (*txn_req)->req_id, (*txn_req)->txn->txn_id);
+ req_list = &(*txn_req)->txn->get_tree_reqs;
+ lyd_free_all((*txn_req)->req.get_tree->client_results);
+ XFREE(MTYPE_MGMTD_XPATH, (*txn_req)->req.get_tree->xpath);
+ XFREE(MTYPE_MGMTD_TXN_GETTREE_REQ, (*txn_req)->req.get_tree);
break;
case MGMTD_TXN_COMMITCFG_TIMEOUT:
- case MGMTD_TXN_CLEANUP:
+ case MGMTD_TXN_GETTREE_TIMEOUT:
break;
}
- if ((*txn_req)->pending_be_proc && pending_list) {
- mgmt_txn_reqs_del(pending_list, *txn_req);
- MGMTD_TXN_DBG("Removed req-id: %" PRIu64
- " from pending-list (left:%zu)",
- (*txn_req)->req_id,
- mgmt_txn_reqs_count(pending_list));
- } else if (req_list) {
+ if (req_list) {
mgmt_txn_reqs_del(req_list, *txn_req);
- MGMTD_TXN_DBG("Removed req-id: %" PRIu64
- " from request-list (left:%zu)",
- (*txn_req)->req_id, mgmt_txn_reqs_count(req_list));
+ __dbg("Removed req-id: %" PRIu64 " from request-list (left:%zu)",
+ (*txn_req)->req_id, mgmt_txn_reqs_count(req_list));
}
- (*txn_req)->pending_be_proc = false;
MGMTD_TXN_UNLOCK(&(*txn_req)->txn);
XFREE(MTYPE_MGMTD_TXN_REQ, (*txn_req));
*txn_req = NULL;
@@ -630,10 +531,10 @@ static void mgmt_txn_process_set_cfg(struct event *thread)
assert(txn);
cmt_stats = mgmt_fe_get_session_commit_stats(txn->session_id);
- MGMTD_TXN_DBG("Processing %zu SET_CONFIG requests txn-id:%" PRIu64
- " session-id: %" PRIu64,
- mgmt_txn_reqs_count(&txn->set_cfg_reqs), txn->txn_id,
- txn->session_id);
+ __dbg("Processing %zu SET_CONFIG requests txn-id:%" PRIu64
+ " session-id: %" PRIu64,
+ mgmt_txn_reqs_count(&txn->set_cfg_reqs), txn->txn_id,
+ txn->session_id);
FOREACH_TXN_REQ_IN_LIST (&txn->set_cfg_reqs, txn_req) {
assert(txn_req->req_event == MGMTD_TXN_PROC_SETCFG);
@@ -666,7 +567,7 @@ static void mgmt_txn_process_set_cfg(struct event *thread)
txn_req->req.set_cfg->cfg_changes,
(size_t)txn_req->req.set_cfg
->num_cfg_changes,
- NULL, NULL, 0, err_buf,
+ NULL, false, err_buf,
sizeof(err_buf), &error);
if (error) {
mgmt_fe_send_set_cfg_reply(txn->session_id, txn->txn_id,
@@ -685,14 +586,17 @@ static void mgmt_txn_process_set_cfg(struct event *thread)
/* We expect the user to have locked the DST DS */
if (!mgmt_ds_is_locked(txn_req->req.set_cfg->dst_ds_ctx,
txn->session_id)) {
- MGMTD_TXN_ERR("DS %u not locked for implicit commit txn-id: %" PRIu64
- " session-id: %" PRIu64 " err: %s",
- txn_req->req.set_cfg->dst_ds_id,
- txn->txn_id, txn->session_id,
- strerror(ret));
- mgmt_txn_send_commit_cfg_reply(
- txn, MGMTD_DS_LOCK_FAILED,
- "running DS not locked for implicit commit");
+ __log_err("DS %u not locked for implicit commit txn-id: %" PRIu64
+ " session-id: %" PRIu64 " err: %s",
+ txn_req->req.set_cfg->dst_ds_id,
+ txn->txn_id, txn->session_id,
+ strerror(ret));
+ mgmt_fe_send_set_cfg_reply(
+ txn->session_id, txn->txn_id,
+ txn_req->req.set_cfg->ds_id,
+ txn_req->req_id, MGMTD_DS_LOCK_FAILED,
+ "running DS not locked for implicit commit",
+ txn_req->req.set_cfg->implicit_commit);
goto mgmt_txn_process_set_cfg_done;
}
@@ -717,9 +621,9 @@ static void mgmt_txn_process_set_cfg(struct event *thread)
txn_req->req_id,
MGMTD_SUCCESS, NULL,
false) != 0) {
- MGMTD_TXN_ERR("Failed to send SET_CONFIG_REPLY txn-id %" PRIu64
- " session-id: %" PRIu64,
- txn->txn_id, txn->session_id);
+ __log_err("Failed to send SET_CONFIG_REPLY txn-id %" PRIu64
+ " session-id: %" PRIu64,
+ txn->txn_id, txn->session_id);
}
mgmt_txn_process_set_cfg_done:
@@ -736,9 +640,8 @@ mgmt_txn_process_set_cfg_done:
left = mgmt_txn_reqs_count(&txn->set_cfg_reqs);
if (left) {
- MGMTD_TXN_DBG("Processed maximum number of Set-Config requests (%d/%d/%d). Rescheduling for rest.",
- num_processed, MGMTD_TXN_MAX_NUM_SETCFG_PROC,
- (int)left);
+ __dbg("Processed maximum number of Set-Config requests (%d/%d/%d). Rescheduling for rest.",
+ num_processed, MGMTD_TXN_MAX_NUM_SETCFG_PROC, (int)left);
mgmt_txn_register_event(txn, MGMTD_TXN_PROC_SETCFG);
}
}
@@ -769,9 +672,9 @@ static int mgmt_txn_send_commit_cfg_reply(struct mgmt_txn_ctx *txn,
txn->commit_cfg_req->req.commit_cfg
.validate_only,
result, error_if_any) != 0) {
- MGMTD_TXN_ERR("Failed to send COMMIT-CONFIG-REPLY txn-id: %" PRIu64
- " session-id: %" PRIu64,
- txn->txn_id, txn->session_id);
+ __log_err("Failed to send COMMIT-CONFIG-REPLY txn-id: %" PRIu64
+ " session-id: %" PRIu64,
+ txn->txn_id, txn->session_id);
}
if (txn->commit_cfg_req->req.commit_cfg.implicit && txn->session_id &&
@@ -783,9 +686,9 @@ static int mgmt_txn_send_commit_cfg_reply(struct mgmt_txn_ctx *txn,
success ? MGMTD_SUCCESS
: MGMTD_INTERNAL_ERROR,
error_if_any, true) != 0) {
- MGMTD_TXN_ERR("Failed to send SET-CONFIG-REPLY txn-id: %" PRIu64
- " session-id: %" PRIu64,
- txn->txn_id, txn->session_id);
+ __log_err("Failed to send SET-CONFIG-REPLY txn-id: %" PRIu64
+ " session-id: %" PRIu64,
+ txn->txn_id, txn->session_id);
}
if (success) {
@@ -848,6 +751,14 @@ static int mgmt_txn_send_commit_cfg_reply(struct mgmt_txn_ctx *txn,
mgmt_history_rollback_complete(success);
}
+ if (txn->commit_cfg_req->req.commit_cfg.init) {
+ /*
+ * This is the backend init request.
+ * We need to unlock the running datastore.
+ */
+ mgmt_ds_unlock(txn->commit_cfg_req->req.commit_cfg.dst_ds_ctx);
+ }
+
txn->commit_cfg_req->req.commit_cfg.cmt_stats = NULL;
mgmt_txn_req_free(&txn->commit_cfg_req);
@@ -857,66 +768,26 @@ static int mgmt_txn_send_commit_cfg_reply(struct mgmt_txn_ctx *txn,
* we need to cleanup by itself.
*/
if (!txn->session_id)
- mgmt_txn_register_event(txn, MGMTD_TXN_CLEANUP);
+ mgmt_txn_cleanup_txn(&txn);
return 0;
}
-static void
-mgmt_move_txn_cfg_batch_to_next(struct mgmt_commit_cfg_req *cmtcfg_req,
- struct mgmt_txn_be_cfg_batch *batch,
- struct mgmt_txn_batches_head *src_list,
- struct mgmt_txn_batches_head *dst_list,
- bool update_commit_phase,
- enum mgmt_commit_phase to_phase)
-{
- mgmt_txn_batches_del(src_list, batch);
-
- if (update_commit_phase) {
- MGMTD_TXN_DBG("Move txn-id %" PRIu64 " batch-id: %" PRIu64
- " from '%s' --> '%s'",
- batch->txn->txn_id, batch->batch_id,
- mgmt_commit_phase2str(batch->comm_phase),
- mgmt_txn_commit_phase_str(batch->txn, false));
- batch->comm_phase = to_phase;
- }
-
- mgmt_txn_batches_add_tail(dst_list, batch);
-}
-
-static void mgmt_move_txn_cfg_batches(struct mgmt_txn_ctx *txn,
- struct mgmt_commit_cfg_req *cmtcfg_req,
- struct mgmt_txn_batches_head *src_list,
- struct mgmt_txn_batches_head *dst_list,
- bool update_commit_phase,
- enum mgmt_commit_phase to_phase)
-{
- struct mgmt_txn_be_cfg_batch *batch;
-
- FOREACH_TXN_CFG_BATCH_IN_LIST (src_list, batch) {
- mgmt_move_txn_cfg_batch_to_next(cmtcfg_req, batch, src_list,
- dst_list, update_commit_phase,
- to_phase);
- }
-}
-
static int
mgmt_try_move_commit_to_next_phase(struct mgmt_txn_ctx *txn,
struct mgmt_commit_cfg_req *cmtcfg_req)
{
- struct mgmt_txn_batches_head *curr_list, *next_list;
enum mgmt_be_client_id id;
- MGMTD_TXN_DBG("txn-id: %" PRIu64 ", Phase(current:'%s' next:'%s')",
- txn->txn_id, mgmt_txn_commit_phase_str(txn, true),
- mgmt_txn_commit_phase_str(txn, false));
+ __dbg("txn-id: %" PRIu64 ", Phase '%s'", txn->txn_id,
+ mgmt_txn_commit_phase_str(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] &&
- mgmt_txn_batches_count(&cmtcfg_req->curr_batches[id])) {
+ if (IS_IDBIT_SET(cmtcfg_req->clients, id) &&
+ cmtcfg_req->be_phase[id] == cmtcfg_req->phase) {
/*
* There's atleast once client who hasn't moved to
* next phase.
@@ -929,83 +800,36 @@ mgmt_try_move_commit_to_next_phase(struct mgmt_txn_ctx *txn,
}
}
- MGMTD_TXN_DBG("Move entire txn-id: %" PRIu64 " from '%s' to '%s'",
- txn->txn_id, mgmt_txn_commit_phase_str(txn, true),
- mgmt_txn_commit_phase_str(txn, false));
-
/*
* If we are here, it means all the clients has moved to next phase.
* So we can move the whole commit to next phase.
*/
- cmtcfg_req->curr_phase = cmtcfg_req->next_phase;
- cmtcfg_req->next_phase++;
- MGMTD_TXN_DBG("Move back all config batches for txn-id: %" PRIu64
- " from next to current branch",
- txn->txn_id);
- FOREACH_MGMTD_BE_CLIENT_ID (id) {
- curr_list = &cmtcfg_req->curr_batches[id];
- next_list = &cmtcfg_req->next_batches[id];
- mgmt_move_txn_cfg_batches(txn, cmtcfg_req, next_list, curr_list,
- false, 0);
- }
-
- mgmt_txn_register_event(txn, MGMTD_TXN_PROC_COMMITCFG);
-
- return 0;
-}
-
-static int
-mgmt_move_be_commit_to_next_phase(struct mgmt_txn_ctx *txn,
- struct mgmt_be_client_adapter *adapter)
-{
- struct mgmt_commit_cfg_req *cmtcfg_req;
- struct mgmt_txn_batches_head *curr_list, *next_list;
-
- if (txn->type != MGMTD_TXN_TYPE_CONFIG || !txn->commit_cfg_req)
- return -1;
-
- cmtcfg_req = &txn->commit_cfg_req->req.commit_cfg;
-
- MGMTD_TXN_DBG("Move txn-id: %" PRIu64
- " for '%s' Phase(current: '%s' next:'%s')",
- txn->txn_id, adapter->name,
- mgmt_txn_commit_phase_str(txn, true),
- mgmt_txn_commit_phase_str(txn, false));
-
- MGMTD_TXN_DBG("Move all config batches for '%s' from current to next list",
- adapter->name);
- curr_list = &cmtcfg_req->curr_batches[adapter->id];
- next_list = &cmtcfg_req->next_batches[adapter->id];
- mgmt_move_txn_cfg_batches(txn, cmtcfg_req, curr_list, next_list, true,
- cmtcfg_req->next_phase);
+ cmtcfg_req->phase++;
- MGMTD_TXN_DBG("txn-id: %" PRIu64 ", Phase(current:'%s' next:'%s')",
- txn->txn_id, mgmt_txn_commit_phase_str(txn, true),
- mgmt_txn_commit_phase_str(txn, false));
+ __dbg("Move entire txn-id: %" PRIu64 " to phase '%s'", txn->txn_id,
+ mgmt_txn_commit_phase_str(txn));
- /*
- * Check if all clients has moved to next phase or not.
- */
- mgmt_try_move_commit_to_next_phase(txn, cmtcfg_req);
+ mgmt_txn_register_event(txn, MGMTD_TXN_PROC_COMMITCFG);
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;
struct mgmt_be_client_adapter *adapter;
struct mgmt_commit_cfg_req *cmtcfg_req;
- bool found_validator;
int num_chgs = 0;
int xpath_len, value_len;
+ uint64_t clients, chg_clients;
cmtcfg_req = &txn_req->req.commit_cfg;
@@ -1029,24 +853,21 @@ static int mgmt_txn_create_config_batches(struct mgmt_txn_req *txn_req,
if (!value)
value = (char *)MGMTD_BE_CONTAINER_NODE_VAL;
- MGMTD_TXN_DBG("XPATH: %s, Value: '%s'", xpath,
- value ? value : "NIL");
+ __dbg("XPATH: %s, Value: '%s'", xpath, value ? value : "NIL");
+
+ clients = mgmt_be_interested_clients(xpath, true);
- mgmt_be_get_subscr_info_for_xpath(xpath, &subscr_info);
+ chg_clients = 0;
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;
+ chg_clients |= (1ull << id);
+
batch = cmtcfg_req->last_be_cfg_batch[id];
if (!batch ||
(batch->num_cfg_data ==
@@ -1058,18 +879,20 @@ 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]);
batch->cfg_datap[batch->num_cfg_data] =
&batch->cfg_data[batch->num_cfg_data];
- if (chg->cb.operation == NB_OP_DESTROY)
+ /*
+ * On the backend, we don't really care if it's CREATE
+ * or MODIFY, because the existence was already checked
+ * on the frontend. Therefore we use SET for both.
+ */
+ if (chg->cb.operation == NB_CB_DESTROY)
batch->cfg_data[batch->num_cfg_data].req_type =
- MGMTD__CFG_DATA_REQ_TYPE__DELETE_DATA;
+ MGMTD__CFG_DATA_REQ_TYPE__REMOVE_DATA;
else
batch->cfg_data[batch->num_cfg_data].req_type =
MGMTD__CFG_DATA_REQ_TYPE__SET_DATA;
@@ -1087,28 +910,19 @@ static int mgmt_txn_create_config_batches(struct mgmt_txn_req *txn_req,
MGMTD__YANG_DATA_VALUE__VALUE_ENCODED_STR_VAL;
batch->value[batch->num_cfg_data].encoded_str_val =
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);
+ __dbg(" -- %s, batch item:%d", adapter->name,
+ (int)batch->num_cfg_data);
batch->num_cfg_data++;
num_chgs++;
}
- if (!found_validator) {
- snprintf(err_buf, sizeof(err_buf),
- "No validator module found for XPATH: '%s",
- xpath);
- MGMTD_TXN_ERR("***** %s", err_buf);
- }
+ if (!chg_clients)
+ __log_err("No connected daemon is interested in XPATH %s",
+ xpath);
+
+ cmtcfg_req->clients |= chg_clients;
free(xpath);
}
@@ -1121,7 +935,13 @@ static int mgmt_txn_create_config_batches(struct mgmt_txn_req *txn_req,
return -1;
}
- cmtcfg_req->next_phase = MGMTD_COMMIT_PHASE_TXN_CREATE;
+ /* Move all BE clients to create phase */
+ FOREACH_MGMTD_BE_CLIENT_ID(id) {
+ if (IS_IDBIT_SET(cmtcfg_req->clients, id))
+ cmtcfg_req->be_phase[id] =
+ MGMTD_COMMIT_PHASE_TXN_CREATE;
+ }
+
return 0;
}
@@ -1194,25 +1014,28 @@ static int mgmt_txn_prepare_config(struct mgmt_txn_ctx *txn)
}
/*
- * Check for diffs from scratch buffer. If found empty
- * get the diff from Candidate DS itself.
+ * Validate YANG contents of the source DS and get the diff
+ * between source and destination DS contents.
*/
- cfg_chgs = &nb_config->cfg_chgs;
- if (RB_EMPTY(nb_config_cbs, cfg_chgs)) {
- /*
- * This could be the case when the config is directly
- * loaded onto the candidate DS from a file. Get the
- * diff from a full comparison of the candidate and
- * running DSs.
- */
- nb_config_diff(mgmt_ds_get_nb_config(
- txn->commit_cfg_req->req.commit_cfg
- .dst_ds_ctx),
- nb_config, &changes);
- cfg_chgs = &changes;
- del_cfg_chgs = true;
+ char err_buf[BUFSIZ] = { 0 };
+
+ ret = nb_candidate_validate_yang(nb_config, true, err_buf,
+ sizeof(err_buf) - 1);
+ if (ret != NB_OK) {
+ if (strncmp(err_buf, " ", strlen(err_buf)) == 0)
+ strlcpy(err_buf, "Validation failed", sizeof(err_buf));
+ (void)mgmt_txn_send_commit_cfg_reply(txn, MGMTD_INVALID_PARAM,
+ err_buf);
+ ret = -1;
+ goto mgmt_txn_prepare_config_done;
}
+ nb_config_diff(mgmt_ds_get_nb_config(txn->commit_cfg_req->req.commit_cfg
+ .dst_ds_ctx),
+ nb_config, &changes);
+ cfg_chgs = &changes;
+ del_cfg_chgs = true;
+
if (RB_EMPTY(nb_config_cbs, cfg_chgs)) {
/*
* This means there's no changes to commit whatsoever
@@ -1230,28 +1053,12 @@ static int mgmt_txn_prepare_config(struct mgmt_txn_ctx *txn)
->validate_start,
NULL);
/*
- * Validate YANG contents of the source DS and get the diff
- * between source and destination DS contents.
- */
- char err_buf[1024] = { 0 };
- nb_ctx.client = NB_CLIENT_MGMTD_SERVER;
- nb_ctx.user = (void *)txn;
-
- ret = nb_candidate_validate_yang(nb_config, true, err_buf,
- sizeof(err_buf) - 1);
- if (ret != NB_OK) {
- if (strncmp(err_buf, " ", strlen(err_buf)) == 0)
- strlcpy(err_buf, "Validation failed", sizeof(err_buf));
- (void)mgmt_txn_send_commit_cfg_reply(txn, MGMTD_INVALID_PARAM,
- err_buf);
- ret = -1;
- goto mgmt_txn_prepare_config_done;
- }
- /*
* Perform application level validations locally on the MGMTD
* process by calling application specific validation routines
* loaded onto MGMTD process using libraries.
*/
+ nb_ctx.client = NB_CLIENT_MGMTD_SERVER;
+ nb_ctx.user = (void *)txn;
ret = nb_candidate_validate_code(&nb_ctx, nb_config, &changes, err_buf,
sizeof(err_buf) - 1);
if (ret != NB_OK) {
@@ -1290,7 +1097,7 @@ mgmt_txn_prep_config_validation_done:
}
/* Move to the Transaction Create Phase */
- txn->commit_cfg_req->req.commit_cfg.curr_phase =
+ txn->commit_cfg_req->req.commit_cfg.phase =
MGMTD_COMMIT_PHASE_TXN_CREATE;
mgmt_txn_register_event(txn, MGMTD_TXN_PROC_COMMITCFG);
@@ -1312,13 +1119,12 @@ static int mgmt_txn_send_be_txn_create(struct mgmt_txn_ctx *txn)
enum mgmt_be_client_id id;
struct mgmt_be_client_adapter *adapter;
struct mgmt_commit_cfg_req *cmtcfg_req;
- struct mgmt_txn_be_cfg_batch *batch;
assert(txn->type == MGMTD_TXN_TYPE_CONFIG && txn->commit_cfg_req);
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(
@@ -1326,29 +1132,16 @@ static int mgmt_txn_send_be_txn_create(struct mgmt_txn_ctx *txn)
"Could not send TXN_CREATE to backend adapter");
return -1;
}
-
- FOREACH_TXN_CFG_BATCH_IN_LIST (&txn->commit_cfg_req->req
- .commit_cfg
- .curr_batches[id],
- batch)
- batch->comm_phase =
- MGMTD_COMMIT_PHASE_TXN_CREATE;
}
}
- txn->commit_cfg_req->req.commit_cfg.next_phase =
- MGMTD_COMMIT_PHASE_SEND_CFG;
-
/*
* Dont move the commit to next phase yet. Wait for the TXN_REPLY to
* come back.
*/
- MGMTD_TXN_DBG("txn-id: %" PRIu64 " session-id: %" PRIu64
- " Phase(Current:'%s', Next: '%s')",
- txn->txn_id, txn->session_id,
- mgmt_txn_commit_phase_str(txn, true),
- mgmt_txn_commit_phase_str(txn, false));
+ __dbg("txn-id: %" PRIu64 " session-id: %" PRIu64 " Phase '%s'",
+ txn->txn_id, txn->session_id, mgmt_txn_commit_phase_str(txn));
return 0;
}
@@ -1364,41 +1157,34 @@ 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 =
- mgmt_txn_batches_count(&cmtcfg_req->curr_batches[adapter->id]);
- FOREACH_TXN_CFG_BATCH_IN_LIST (&cmtcfg_req->curr_batches[adapter->id],
+ num_batches = mgmt_txn_batches_count(&cmtcfg_req->batches[adapter->id]);
+ FOREACH_TXN_CFG_BATCH_IN_LIST (&cmtcfg_req->batches[adapter->id],
batch) {
- assert(cmtcfg_req->next_phase == MGMTD_COMMIT_PHASE_SEND_CFG);
cfg_req.cfgdata_reqs = batch->cfg_datap;
cfg_req.num_reqs = batch->num_cfg_data;
indx++;
if (mgmt_be_send_cfgdata_req(adapter, txn->txn_id,
- batch->batch_id,
cfg_req.cfgdata_reqs,
cfg_req.num_reqs,
indx == num_batches)) {
(void)mgmt_txn_send_commit_cfg_reply(
txn, MGMTD_INTERNAL_ERROR,
"Internal Error! Could not send config data to backend!");
- MGMTD_TXN_ERR("Could not send CFGDATA_CREATE txn-id: %" PRIu64
- " batch-id: %" PRIu64 " to client '%s",
- txn->txn_id, batch->batch_id,
- adapter->name);
+ __log_err("Could not send CFGDATA_CREATE txn-id: %" PRIu64
+ " to client '%s",
+ txn->txn_id, adapter->name);
return -1;
}
cmtcfg_req->cmt_stats->last_num_cfgdata_reqs++;
- mgmt_move_txn_cfg_batch_to_next(
- cmtcfg_req, batch,
- &cmtcfg_req->curr_batches[adapter->id],
- &cmtcfg_req->next_batches[adapter->id], true,
- MGMTD_COMMIT_PHASE_SEND_CFG);
}
+ cmtcfg_req->be_phase[adapter->id] = MGMTD_COMMIT_PHASE_SEND_CFG;
+
/*
* This could be the last Backend Client to send CFGDATA_CREATE_REQ to.
* Try moving the commit to next phase.
@@ -1415,9 +1201,8 @@ static int mgmt_txn_send_be_txn_delete(struct mgmt_txn_ctx *txn,
&txn->commit_cfg_req->req.commit_cfg;
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);
@@ -1435,8 +1220,8 @@ static void mgmt_txn_cfg_commit_timedout(struct event *thread)
if (!txn->commit_cfg_req)
return;
- MGMTD_TXN_ERR("Backend timeout txn-id: %" PRIu64 " aborting commit",
- txn->txn_id);
+ __log_err("Backend timeout txn-id: %" PRIu64 " aborting commit",
+ txn->txn_id);
/*
* Send a COMMIT_CONFIG_REPLY with failure.
@@ -1448,6 +1233,84 @@ static void mgmt_txn_cfg_commit_timedout(struct event *thread)
"Operation on the backend timed-out. Aborting commit!");
}
+
+static int txn_get_tree_data_done(struct mgmt_txn_ctx *txn,
+ struct mgmt_txn_req *txn_req)
+{
+ struct txn_req_get_tree *get_tree = txn_req->req.get_tree;
+ uint64_t req_id = txn_req->req_id;
+ struct lyd_node *result;
+ int ret = NB_OK;
+
+ /* cancel timer and send reply onward */
+ EVENT_OFF(txn->get_tree_timeout);
+
+ if (!get_tree->simple_xpath && get_tree->client_results) {
+ /*
+ * We have a complex query so Filter results by the xpath query.
+ */
+ if (yang_lyd_trim_xpath(&get_tree->client_results,
+ txn_req->req.get_tree->xpath))
+ ret = NB_ERR;
+ }
+
+ result = get_tree->client_results;
+
+ if (ret == NB_OK && result && get_tree->exact)
+ result = yang_dnode_get(result, get_tree->xpath);
+
+ if (ret == NB_OK)
+ ret = mgmt_fe_adapter_send_tree_data(txn->session_id,
+ txn->txn_id,
+ txn_req->req_id,
+ get_tree->result_type,
+ get_tree->wd_options,
+ result,
+ get_tree->partial_error,
+ false);
+
+ /* we're done with the request */
+ mgmt_txn_req_free(&txn_req);
+
+ if (ret) {
+ __log_err("Error sending the results of GETTREE for txn-id %" PRIu64
+ " req_id %" PRIu64 " to requested type %u",
+ txn->txn_id, req_id, get_tree->result_type);
+
+ (void)mgmt_fe_adapter_txn_error(txn->txn_id, req_id, false, ret,
+ "Error converting results of GETTREE");
+ }
+
+ return ret;
+}
+
+
+static void txn_get_tree_timeout(struct event *thread)
+{
+ struct mgmt_txn_ctx *txn;
+ struct mgmt_txn_req *txn_req;
+
+ txn_req = (struct mgmt_txn_req *)EVENT_ARG(thread);
+ txn = txn_req->txn;
+
+ assert(txn);
+ assert(txn->type == MGMTD_TXN_TYPE_SHOW);
+
+
+ __log_err("Backend timeout txn-id: %" PRIu64 " ending get-tree",
+ txn->txn_id);
+
+ /*
+ * Send a get-tree data reply.
+ *
+ * NOTE: The transaction cleanup will be triggered from Front-end
+ * adapter.
+ */
+
+ txn_req->req.get_tree->partial_error = -ETIMEDOUT;
+ txn_get_tree_data_done(txn, txn_req);
+}
+
/*
* Send CFG_APPLY_REQs to all the backend client.
*
@@ -1461,8 +1324,6 @@ static int mgmt_txn_send_be_cfg_apply(struct mgmt_txn_ctx *txn)
enum mgmt_be_client_id id;
struct mgmt_be_client_adapter *adapter;
struct mgmt_commit_cfg_req *cmtcfg_req;
- struct mgmt_txn_batches_head *batch_list;
- struct mgmt_txn_be_cfg_batch *batch;
assert(txn->type == MGMTD_TXN_TYPE_CONFIG && txn->commit_cfg_req);
@@ -1476,13 +1337,11 @@ 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;
- batch_list = &cmtcfg_req->curr_batches[id];
if (mgmt_be_send_cfgapply_req(adapter, txn->txn_id)) {
(void)mgmt_txn_send_commit_cfg_reply(
txn, MGMTD_INTERNAL_ERROR,
@@ -1493,15 +1352,9 @@ static int mgmt_txn_send_be_cfg_apply(struct mgmt_txn_ctx *txn)
UNSET_FLAG(adapter->flags,
MGMTD_BE_ADAPTER_FLAGS_CFG_SYNCED);
-
- FOREACH_TXN_CFG_BATCH_IN_LIST (batch_list, batch)
- batch->comm_phase = MGMTD_COMMIT_PHASE_APPLY_CFG;
}
}
- txn->commit_cfg_req->req.commit_cfg.next_phase =
- MGMTD_COMMIT_PHASE_TXN_DELETE;
-
/*
* Dont move the commit to next phase yet. Wait for all VALIDATE_REPLIES
* to come back.
@@ -1518,15 +1371,13 @@ static void mgmt_txn_process_commit_cfg(struct event *thread)
txn = (struct mgmt_txn_ctx *)EVENT_ARG(thread);
assert(txn);
- MGMTD_TXN_DBG("Processing COMMIT_CONFIG for txn-id: %" PRIu64
- " session-id: %" PRIu64 " Phase(Current:'%s', Next: '%s')",
- txn->txn_id, txn->session_id,
- mgmt_txn_commit_phase_str(txn, true),
- mgmt_txn_commit_phase_str(txn, false));
+ __dbg("Processing COMMIT_CONFIG for txn-id: %" PRIu64
+ " session-id: %" PRIu64 " Phase '%s'",
+ txn->txn_id, txn->session_id, mgmt_txn_commit_phase_str(txn));
assert(txn->commit_cfg_req);
cmtcfg_req = &txn->commit_cfg_req->req.commit_cfg;
- switch (cmtcfg_req->curr_phase) {
+ switch (cmtcfg_req->phase) {
case MGMTD_COMMIT_PHASE_PREPARE_CFG:
mgmt_txn_prepare_config(txn);
break;
@@ -1548,15 +1399,13 @@ static void mgmt_txn_process_commit_cfg(struct event *thread)
* Backend by now.
*/
#ifndef MGMTD_LOCAL_VALIDATIONS_ENABLED
- assert(cmtcfg_req->next_phase == MGMTD_COMMIT_PHASE_APPLY_CFG);
- MGMTD_TXN_DBG("txn-id: %" PRIu64 " session-id: %" PRIu64
- " trigger sending CFG_VALIDATE_REQ to all backend clients",
- txn->txn_id, txn->session_id);
+ __dbg("txn-id: %" PRIu64 " session-id: %" PRIu64
+ " trigger sending CFG_VALIDATE_REQ to all backend clients",
+ txn->txn_id, txn->session_id);
#else /* ifndef MGMTD_LOCAL_VALIDATIONS_ENABLED */
- assert(cmtcfg_req->next_phase == MGMTD_COMMIT_PHASE_APPLY_CFG);
- MGMTD_TXN_DBG("txn-id: %" PRIu64 " session-id: %" PRIu64
- " trigger sending CFG_APPLY_REQ to all backend clients",
- txn->txn_id, txn->session_id);
+ __dbg("txn-id: %" PRIu64 " session-id: %" PRIu64
+ " trigger sending CFG_APPLY_REQ to all backend clients",
+ txn->txn_id, txn->session_id);
#endif /* ifndef MGMTD_LOCAL_VALIDATIONS_ENABLED */
break;
case MGMTD_COMMIT_PHASE_APPLY_CFG:
@@ -1587,12 +1436,6 @@ static void mgmt_txn_process_commit_cfg(struct event *thread)
case MGMTD_COMMIT_PHASE_MAX:
break;
}
-
- MGMTD_TXN_DBG("txn-id:%" PRIu64 " session-id: %" PRIu64
- " phase updated to (current:'%s', next: '%s')",
- txn->txn_id, txn->session_id,
- mgmt_txn_commit_phase_str(txn, true),
- mgmt_txn_commit_phase_str(txn, false));
}
static void mgmt_init_get_data_reply(struct mgmt_get_data_reply *get_reply)
@@ -1613,8 +1456,6 @@ static void mgmt_reset_get_data_reply(struct mgmt_get_data_reply *get_reply)
get_reply->reply_xpathp[indx] = 0;
}
if (get_reply->reply_data[indx].xpath) {
- zlog_debug("%s free xpath %p", __func__,
- get_reply->reply_data[indx].xpath);
free(get_reply->reply_data[indx].xpath);
get_reply->reply_data[indx].xpath = 0;
}
@@ -1653,8 +1494,8 @@ static void mgmt_txn_send_getcfg_reply_data(struct mgmt_txn_req *txn_req,
data_reply->next_indx = (!get_reply->last_batch ? get_req->total_reply
: -1);
- MGMTD_TXN_DBG("Sending %zu Get-Config/Data replies next-index:%" PRId64,
- data_reply->n_data, data_reply->next_indx);
+ __dbg("Sending %zu Get-Config/Data replies next-index:%" PRId64,
+ data_reply->n_data, data_reply->next_indx);
switch (txn_req->req_event) {
case MGMTD_TXN_PROC_GETCFG:
@@ -1662,30 +1503,18 @@ static void mgmt_txn_send_getcfg_reply_data(struct mgmt_txn_req *txn_req,
txn_req->txn->txn_id, get_req->ds_id,
txn_req->req_id, MGMTD_SUCCESS,
data_reply, NULL) != 0) {
- MGMTD_TXN_ERR("Failed to send GET-CONFIG-REPLY txn-id: %" PRIu64
- " session-id: %" PRIu64
- " req-id: %" PRIu64,
- txn_req->txn->txn_id,
- txn_req->txn->session_id, txn_req->req_id);
- }
- break;
- case MGMTD_TXN_PROC_GETDATA:
- if (mgmt_fe_send_get_reply(txn_req->txn->session_id,
- txn_req->txn->txn_id, get_req->ds_id,
- txn_req->req_id, MGMTD_SUCCESS,
- data_reply, NULL) != 0) {
- MGMTD_TXN_ERR("Failed to send GET-DATA-REPLY txn-id: %" PRIu64
- " session-id: %" PRIu64
- " req-id: %" PRIu64,
- txn_req->txn->txn_id,
- txn_req->txn->session_id, txn_req->req_id);
+ __log_err("Failed to send GET-CONFIG-REPLY txn-id: %" PRIu64
+ " session-id: %" PRIu64 " req-id: %" PRIu64,
+ txn_req->txn->txn_id,
+ txn_req->txn->session_id, txn_req->req_id);
}
break;
case MGMTD_TXN_PROC_SETCFG:
case MGMTD_TXN_PROC_COMMITCFG:
+ case MGMTD_TXN_PROC_GETTREE:
+ case MGMTD_TXN_GETTREE_TIMEOUT:
case MGMTD_TXN_COMMITCFG_TIMEOUT:
- case MGMTD_TXN_CLEANUP:
- MGMTD_TXN_ERR("Invalid Txn-Req-Event %u", txn_req->req_event);
+ __log_err("Invalid Txn-Req-Event %u", txn_req->req_event);
break;
}
@@ -1695,10 +1524,8 @@ static void mgmt_txn_send_getcfg_reply_data(struct mgmt_txn_req *txn_req,
mgmt_reset_get_data_reply_buf(get_req);
}
-static void mgmt_txn_iter_and_send_get_cfg_reply(const char *xpath,
- struct lyd_node *node,
- struct nb_node *nb_node,
- void *ctx)
+static void txn_iter_get_config_data_cb(const char *xpath, struct lyd_node *node,
+ struct nb_node *nb_node, void *ctx)
{
struct mgmt_txn_req *txn_req;
struct mgmt_get_data_req *get_req;
@@ -1713,8 +1540,7 @@ static void mgmt_txn_iter_and_send_get_cfg_reply(const char *xpath,
if (!(node->schema->nodetype & LYD_NODE_TERM))
return;
- assert(txn_req->req_event == MGMTD_TXN_PROC_GETCFG ||
- txn_req->req_event == MGMTD_TXN_PROC_GETDATA);
+ assert(txn_req->req_event == MGMTD_TXN_PROC_GETCFG);
get_req = txn_req->req.get_data;
assert(get_req);
@@ -1731,8 +1557,8 @@ static void mgmt_txn_iter_and_send_get_cfg_reply(const char *xpath,
get_reply->num_reply++;
get_req->total_reply++;
- MGMTD_TXN_DBG(" [%d] XPATH: '%s', Value: '%s'", get_req->total_reply,
- data->xpath, data_value->encoded_str_val);
+ __dbg(" [%d] XPATH: '%s', Value: '%s'", get_req->total_reply,
+ data->xpath, data_value->encoded_str_val);
if (get_reply->num_reply == MGMTD_MAX_NUM_DATA_REPLY_IN_BATCH)
mgmt_txn_send_getcfg_reply_data(txn_req, get_req);
@@ -1766,8 +1592,8 @@ static int mgmt_txn_get_config(struct mgmt_txn_ctx *txn,
*/
get_reply = get_data->reply;
for (indx = 0; indx < get_data->num_xpaths; indx++) {
- MGMTD_TXN_DBG("Trying to get all data under '%s'",
- get_data->xpaths[indx]);
+ __dbg("Trying to get all data under '%s'",
+ get_data->xpaths[indx]);
mgmt_init_get_data_reply(get_reply);
/*
* mgmt_ds_iter_data works on path prefixes, but the user may
@@ -1776,18 +1602,17 @@ static int mgmt_txn_get_config(struct mgmt_txn_ctx *txn,
*/
if (mgmt_ds_iter_data(get_data->ds_id, root,
get_data->xpaths[indx],
- mgmt_txn_iter_and_send_get_cfg_reply,
+ txn_iter_get_config_data_cb,
(void *)txn_req) == -1) {
- MGMTD_TXN_DBG("Invalid Xpath '%s",
- get_data->xpaths[indx]);
+ __dbg("Invalid Xpath '%s", get_data->xpaths[indx]);
mgmt_fe_send_get_reply(txn->session_id, txn->txn_id,
get_data->ds_id, txn_req->req_id,
MGMTD_INTERNAL_ERROR, NULL,
"Invalid xpath");
goto mgmt_txn_get_config_failed;
}
- MGMTD_TXN_DBG("Got %d remaining data-replies for xpath '%s'",
- get_reply->num_reply, get_data->xpaths[indx]);
+ __dbg("Got %d remaining data-replies for xpath '%s'",
+ get_reply->num_reply, get_data->xpaths[indx]);
get_reply->last_batch = true;
mgmt_txn_send_getcfg_reply_data(txn_req, get_data);
}
@@ -1814,10 +1639,10 @@ static void mgmt_txn_process_get_cfg(struct event *thread)
txn = (struct mgmt_txn_ctx *)EVENT_ARG(thread);
assert(txn);
- MGMTD_TXN_DBG("Processing %zu GET_CONFIG requests txn-id: %" PRIu64
- " session-id: %" PRIu64,
- mgmt_txn_reqs_count(&txn->get_cfg_reqs), txn->txn_id,
- txn->session_id);
+ __dbg("Processing %zu GET_CONFIG requests txn-id: %" PRIu64
+ " session-id: %" PRIu64,
+ mgmt_txn_reqs_count(&txn->get_cfg_reqs), txn->txn_id,
+ txn->session_id);
FOREACH_TXN_REQ_IN_LIST (&txn->get_cfg_reqs, txn_req) {
error = false;
@@ -1826,11 +1651,10 @@ static void mgmt_txn_process_get_cfg(struct event *thread)
assert(cfg_root);
if (mgmt_txn_get_config(txn, txn_req, cfg_root) != 0) {
- MGMTD_TXN_ERR("Unable to retrieve config from DS %d txn-id: %" PRIu64
- " session-id: %" PRIu64
- " req-id: %" PRIu64,
- txn_req->req.get_data->ds_id, txn->txn_id,
- txn->session_id, txn_req->req_id);
+ __log_err("Unable to retrieve config from DS %d txn-id: %" PRIu64
+ " session-id: %" PRIu64 " req-id: %" PRIu64,
+ txn_req->req.get_data->ds_id, txn->txn_id,
+ txn->session_id, txn_req->req_id);
error = true;
}
@@ -1853,60 +1677,12 @@ static void mgmt_txn_process_get_cfg(struct event *thread)
}
if (mgmt_txn_reqs_count(&txn->get_cfg_reqs)) {
- MGMTD_TXN_DBG("Processed maximum number of Get-Config requests (%d/%d). Rescheduling for rest.",
- num_processed, MGMTD_TXN_MAX_NUM_GETCFG_PROC);
+ __dbg("Processed maximum number of Get-Config requests (%d/%d). Rescheduling for rest.",
+ num_processed, MGMTD_TXN_MAX_NUM_GETCFG_PROC);
mgmt_txn_register_event(txn, MGMTD_TXN_PROC_GETCFG);
}
}
-static void mgmt_txn_process_get_data(struct event *thread)
-{
- struct mgmt_txn_ctx *txn;
- struct mgmt_txn_req *txn_req;
- int num_processed = 0;
-
- txn = (struct mgmt_txn_ctx *)EVENT_ARG(thread);
- assert(txn);
-
- MGMTD_TXN_DBG("Processing %zu GET_DATA requests txn-id: %" PRIu64
- " session-id: %" PRIu64,
- mgmt_txn_reqs_count(&txn->get_data_reqs), txn->txn_id,
- txn->session_id);
-
- FOREACH_TXN_REQ_IN_LIST (&txn->get_data_reqs, txn_req) {
- assert(txn_req->req_event == MGMTD_TXN_PROC_GETDATA);
-
- /*
- * TODO: Trigger GET procedures for Backend
- * For now return back error.
- */
- mgmt_fe_send_get_reply(txn->session_id, txn->txn_id,
- txn_req->req.get_data->ds_id,
- txn_req->req_id, MGMTD_INTERNAL_ERROR,
- NULL, "GET-DATA is not supported yet!");
- /*
- * Delete the txn request.
- * Note: The following will remove it from the list
- * as well.
- */
- mgmt_txn_req_free(&txn_req);
-
- /*
- * Else the transaction would have been already deleted or
- * moved to corresponding pending list. No need to delete it.
- */
- num_processed++;
- if (num_processed == MGMTD_TXN_MAX_NUM_GETDATA_PROC)
- break;
- }
-
- if (mgmt_txn_reqs_count(&txn->get_data_reqs)) {
- MGMTD_TXN_DBG("Processed maximum number of Get-Data requests (%d/%d). Rescheduling for rest.",
- num_processed, MGMTD_TXN_MAX_NUM_GETDATA_PROC);
- mgmt_txn_register_event(txn, MGMTD_TXN_PROC_GETDATA);
- }
-}
-
static struct mgmt_txn_ctx *
mgmt_fe_find_txn_by_session_id(struct mgmt_master *cm, uint64_t session_id,
enum mgmt_txn_type type)
@@ -1926,15 +1702,9 @@ static struct mgmt_txn_ctx *mgmt_txn_create_new(uint64_t session_id,
{
struct mgmt_txn_ctx *txn = NULL;
- /*
- * For 'CONFIG' transaction check if one is already created
- * or not.
- */
- if (type == MGMTD_TXN_TYPE_CONFIG && mgmt_txn_mm->cfg_txn) {
- if (mgmt_config_txn_in_progress() == session_id)
- txn = mgmt_txn_mm->cfg_txn;
- goto mgmt_create_txn_done;
- }
+ /* Do not allow multiple config transactions */
+ if (type == MGMTD_TXN_TYPE_CONFIG && mgmt_config_txn_in_progress())
+ return NULL;
txn = mgmt_fe_find_txn_by_session_id(mgmt_txn_mm, session_id, type);
if (!txn) {
@@ -1944,10 +1714,10 @@ static struct mgmt_txn_ctx *mgmt_txn_create_new(uint64_t session_id,
txn->session_id = session_id;
txn->type = type;
mgmt_txns_add_tail(&mgmt_txn_mm->txn_list, txn);
+ /* TODO: why do we need N lists for one transaction */
mgmt_txn_reqs_init(&txn->set_cfg_reqs);
mgmt_txn_reqs_init(&txn->get_cfg_reqs);
- mgmt_txn_reqs_init(&txn->get_data_reqs);
- mgmt_txn_reqs_init(&txn->pending_get_datas);
+ mgmt_txn_reqs_init(&txn->get_tree_reqs);
txn->commit_cfg_req = NULL;
txn->refcount = 0;
if (!mgmt_txn_mm->next_txn_id)
@@ -1955,8 +1725,8 @@ static struct mgmt_txn_ctx *mgmt_txn_create_new(uint64_t session_id,
txn->txn_id = mgmt_txn_mm->next_txn_id++;
hash_get(mgmt_txn_mm->txn_hash, txn, hash_alloc_intern);
- MGMTD_TXN_DBG("Added new '%s' txn-id: %" PRIu64,
- mgmt_txn_type2str(type), txn->txn_id);
+ __dbg("Added new '%s' txn-id: %" PRIu64,
+ mgmt_txn_type2str(type), txn->txn_id);
if (type == MGMTD_TXN_TYPE_CONFIG)
mgmt_txn_mm->cfg_txn = txn;
@@ -1964,7 +1734,6 @@ static struct mgmt_txn_ctx *mgmt_txn_create_new(uint64_t session_id,
MGMTD_TXN_LOCK(txn);
}
-mgmt_create_txn_done:
return txn;
}
@@ -2029,12 +1798,18 @@ static inline struct mgmt_txn_ctx *mgmt_txn_id2ctx(uint64_t txn_id)
return txn;
}
+uint64_t mgmt_txn_get_session_id(uint64_t txn_id)
+{
+ struct mgmt_txn_ctx *txn = mgmt_txn_id2ctx(txn_id);
+
+ return txn ? txn->session_id : MGMTD_SESSION_ID_NONE;
+}
+
static void mgmt_txn_lock(struct mgmt_txn_ctx *txn, const char *file, int line)
{
txn->refcount++;
- MGMTD_TXN_DBG("%s:%d --> Lock %s txn-id: %" PRIu64 " refcnt: %d", file,
- line, mgmt_txn_type2str(txn->type), txn->txn_id,
- txn->refcount);
+ __dbg("%s:%d --> Lock %s txn-id: %" PRIu64 " refcnt: %d", file, line,
+ mgmt_txn_type2str(txn->type), txn->txn_id, txn->refcount);
}
static void mgmt_txn_unlock(struct mgmt_txn_ctx **txn, const char *file,
@@ -2043,9 +1818,8 @@ static void mgmt_txn_unlock(struct mgmt_txn_ctx **txn, const char *file,
assert(*txn && (*txn)->refcount);
(*txn)->refcount--;
- MGMTD_TXN_DBG("%s:%d --> Unlock %s txn-id: %" PRIu64 " refcnt: %d",
- file, line, mgmt_txn_type2str((*txn)->type),
- (*txn)->txn_id, (*txn)->refcount);
+ __dbg("%s:%d --> Unlock %s txn-id: %" PRIu64 " refcnt: %d", file, line,
+ mgmt_txn_type2str((*txn)->type), (*txn)->txn_id, (*txn)->refcount);
if (!(*txn)->refcount) {
if ((*txn)->type == MGMTD_TXN_TYPE_CONFIG)
if (mgmt_txn_mm->cfg_txn == *txn)
@@ -2054,13 +1828,13 @@ static void mgmt_txn_unlock(struct mgmt_txn_ctx **txn, const char *file,
EVENT_OFF((*txn)->proc_get_data);
EVENT_OFF((*txn)->proc_comm_cfg);
EVENT_OFF((*txn)->comm_cfg_timeout);
+ EVENT_OFF((*txn)->get_tree_timeout);
hash_release(mgmt_txn_mm->txn_hash, *txn);
mgmt_txns_del(&mgmt_txn_mm->txn_list, *txn);
- MGMTD_TXN_DBG("Deleted %s txn-id: %" PRIu64
- " session-id: %" PRIu64,
- mgmt_txn_type2str((*txn)->type), (*txn)->txn_id,
- (*txn)->session_id);
+ __dbg("Deleted %s txn-id: %" PRIu64 " session-id: %" PRIu64,
+ mgmt_txn_type2str((*txn)->type), (*txn)->txn_id,
+ (*txn)->session_id);
XFREE(MTYPE_MGMTD_TXN, *txn);
}
@@ -2086,16 +1860,6 @@ static void mgmt_txn_cleanup_all_txns(void)
mgmt_txn_cleanup_txn(&txn);
}
-static void mgmt_txn_cleanup(struct event *thread)
-{
- struct mgmt_txn_ctx *txn;
-
- txn = (struct mgmt_txn_ctx *)EVENT_ARG(thread);
- assert(txn);
-
- mgmt_txn_cleanup_txn(&txn);
-}
-
static void mgmt_txn_register_event(struct mgmt_txn_ctx *txn,
enum mgmt_txn_event event)
{
@@ -2117,19 +1881,19 @@ static void mgmt_txn_register_event(struct mgmt_txn_ctx *txn,
event_add_timer_tv(mgmt_txn_tm, mgmt_txn_process_get_cfg, txn,
&tv, &txn->proc_get_cfg);
break;
- case MGMTD_TXN_PROC_GETDATA:
- event_add_timer_tv(mgmt_txn_tm, mgmt_txn_process_get_data, txn,
- &tv, &txn->proc_get_data);
- break;
case MGMTD_TXN_COMMITCFG_TIMEOUT:
- event_add_timer_msec(mgmt_txn_tm, mgmt_txn_cfg_commit_timedout,
- txn, MGMTD_TXN_CFG_COMMIT_MAX_DELAY_MSEC,
- &txn->comm_cfg_timeout);
+ event_add_timer(mgmt_txn_tm, mgmt_txn_cfg_commit_timedout, txn,
+ MGMTD_TXN_CFG_COMMIT_MAX_DELAY_SEC,
+ &txn->comm_cfg_timeout);
+ break;
+ case MGMTD_TXN_GETTREE_TIMEOUT:
+ event_add_timer(mgmt_txn_tm, txn_get_tree_timeout, txn,
+ MGMTD_TXN_GET_TREE_MAX_DELAY_SEC,
+ &txn->get_tree_timeout);
+ break;
+ case MGMTD_TXN_PROC_GETTREE:
+ assert(!"code bug do not register this event");
break;
- case MGMTD_TXN_CLEANUP:
- tv.tv_usec = MGMTD_TXN_CLEANUP_DELAY_USEC;
- event_add_timer_tv(mgmt_txn_tm, mgmt_txn_cleanup, txn, &tv,
- &txn->clnup);
}
}
@@ -2154,12 +1918,12 @@ void mgmt_txn_destroy(void)
mgmt_txn_hash_destroy();
}
-uint64_t mgmt_config_txn_in_progress(void)
+bool mgmt_config_txn_in_progress(void)
{
if (mgmt_txn_mm && mgmt_txn_mm->cfg_txn)
- return mgmt_txn_mm->cfg_txn->session_id;
+ return true;
- return MGMTD_SESSION_ID_NONE;
+ return false;
}
uint64_t mgmt_create_txn(uint64_t session_id, enum mgmt_txn_type type)
@@ -2195,13 +1959,14 @@ int mgmt_txn_send_set_config_req(uint64_t txn_id, uint64_t req_id,
size_t indx;
uint16_t *num_chgs;
struct nb_cfg_change *cfg_chg;
+ struct nb_node *node;
txn = mgmt_txn_id2ctx(txn_id);
if (!txn)
return -1;
if (implicit_commit && mgmt_txn_reqs_count(&txn->set_cfg_reqs)) {
- MGMTD_TXN_ERR(
+ __log_err(
"For implicit commit config only one SETCFG-REQ can be allowed!");
return -1;
}
@@ -2213,27 +1978,42 @@ int mgmt_txn_send_set_config_req(uint64_t txn_id, uint64_t req_id,
for (indx = 0; indx < num_req; indx++) {
cfg_chg = &txn_req->req.set_cfg->cfg_changes[*num_chgs];
- if (cfg_req[indx]->req_type ==
- MGMTD__CFG_DATA_REQ_TYPE__DELETE_DATA)
+ switch (cfg_req[indx]->req_type) {
+ case MGMTD__CFG_DATA_REQ_TYPE__DELETE_DATA:
+ cfg_chg->operation = NB_OP_DELETE;
+ break;
+ case MGMTD__CFG_DATA_REQ_TYPE__REMOVE_DATA:
cfg_chg->operation = NB_OP_DESTROY;
- else if (cfg_req[indx]->req_type ==
- MGMTD__CFG_DATA_REQ_TYPE__SET_DATA)
- cfg_chg->operation =
- mgmt_ds_find_data_node_by_xpath(ds_ctx,
- cfg_req[indx]
- ->data
- ->xpath)
- ? NB_OP_MODIFY
- : NB_OP_CREATE;
- else
+ break;
+ case MGMTD__CFG_DATA_REQ_TYPE__SET_DATA:
+ /*
+ * For backward compatibility, we need to allow creating
+ * *new* list keys with SET_DATA operation. NB_OP_MODIFY
+ * is not allowed for keys, so use NB_OP_CREATE_EXCL.
+ */
+ node = nb_node_find(cfg_req[indx]->data->xpath);
+ if (node && lysc_is_key(node->snode))
+ cfg_chg->operation = NB_OP_CREATE_EXCL;
+ else
+ cfg_chg->operation = NB_OP_MODIFY;
+ break;
+ case MGMTD__CFG_DATA_REQ_TYPE__CREATE_DATA:
+ cfg_chg->operation = NB_OP_CREATE_EXCL;
+ break;
+ case MGMTD__CFG_DATA_REQ_TYPE__REPLACE_DATA:
+ cfg_chg->operation = NB_OP_REPLACE;
+ break;
+ case MGMTD__CFG_DATA_REQ_TYPE__REQ_TYPE_NONE:
+ case _MGMTD__CFG_DATA_REQ_TYPE_IS_INT_SIZE:
+ default:
continue;
+ }
- MGMTD_TXN_DBG("XPath: '%s', Value: '%s'",
- cfg_req[indx]->data->xpath,
- (cfg_req[indx]->data->value &&
- cfg_req[indx]->data->value->encoded_str_val
- ? cfg_req[indx]->data->value->encoded_str_val
- : "NULL"));
+ __dbg("XPath: '%s', Value: '%s'", cfg_req[indx]->data->xpath,
+ (cfg_req[indx]->data->value &&
+ cfg_req[indx]->data->value->encoded_str_val
+ ? cfg_req[indx]->data->value->encoded_str_val
+ : "NULL"));
strlcpy(cfg_chg->xpath, cfg_req[indx]->data->xpath,
sizeof(cfg_chg->xpath));
cfg_chg->value =
@@ -2243,8 +2023,8 @@ int mgmt_txn_send_set_config_req(uint64_t txn_id, uint64_t req_id,
->data->value->encoded_str_val)
: NULL);
if (cfg_chg->value)
- MGMTD_TXN_DBG("Allocated value at %p ==> '%s'",
- cfg_chg->value, cfg_chg->value);
+ __dbg("Allocated value at %p ==> '%s'", cfg_chg->value,
+ cfg_chg->value);
(*num_chgs)++;
}
@@ -2274,9 +2054,9 @@ int mgmt_txn_send_commit_config_req(uint64_t txn_id, uint64_t req_id,
return -1;
if (txn->commit_cfg_req) {
- MGMTD_TXN_ERR("Commit already in-progress txn-id: %" PRIu64
- " session-id: %" PRIu64 ". Cannot start another",
- txn->txn_id, txn->session_id);
+ __log_err("Commit already in-progress txn-id: %" PRIu64
+ " session-id: %" PRIu64 ". Cannot start another",
+ txn->txn_id, txn->session_id);
return -1;
}
@@ -2306,15 +2086,26 @@ int mgmt_txn_notify_be_adapter_conn(struct mgmt_be_client_adapter *adapter,
struct mgmt_commit_cfg_req *cmtcfg_req;
static struct mgmt_commit_stats dummy_stats;
struct nb_config_cbs *adapter_cfgs = NULL;
+ struct mgmt_ds_ctx *ds_ctx;
memset(&dummy_stats, 0, sizeof(dummy_stats));
if (connect) {
- /* Get config for this single backend client */
+ ds_ctx = mgmt_ds_get_ctx_by_id(mm, MGMTD_DS_RUNNING);
+ assert(ds_ctx);
+
+ /*
+ * Lock the running datastore to prevent any changes while we
+ * are initializing the backend.
+ */
+ if (mgmt_ds_lock(ds_ctx, 0) != 0)
+ return -1;
+ /* Get config for this single backend client */
mgmt_be_get_adapter_config(adapter, &adapter_cfgs);
if (!adapter_cfgs || RB_EMPTY(nb_config_cbs, adapter_cfgs)) {
SET_FLAG(adapter->flags,
MGMTD_BE_ADAPTER_FLAGS_CFG_SYNCED);
+ mgmt_ds_unlock(ds_ctx);
return 0;
}
@@ -2324,14 +2115,15 @@ int mgmt_txn_notify_be_adapter_conn(struct mgmt_be_client_adapter *adapter,
*/
txn = mgmt_txn_create_new(0, MGMTD_TXN_TYPE_CONFIG);
if (!txn) {
- MGMTD_TXN_ERR("Failed to create CONFIG Transaction for downloading CONFIGs for client '%s'",
- adapter->name);
+ __log_err("Failed to create CONFIG Transaction for downloading CONFIGs for client '%s'",
+ adapter->name);
+ mgmt_ds_unlock(ds_ctx);
+ nb_config_diff_del_changes(adapter_cfgs);
return -1;
}
- MGMTD_TXN_DBG("Created initial txn-id: %" PRIu64
- " for BE client '%s'",
- txn->txn_id, adapter->name);
+ __dbg("Created initial txn-id: %" PRIu64 " for BE client '%s'",
+ txn->txn_id, adapter->name);
/*
* Set the changeset for transaction to commit and trigger the
* commit request.
@@ -2339,10 +2131,11 @@ int mgmt_txn_notify_be_adapter_conn(struct mgmt_be_client_adapter *adapter,
txn_req = mgmt_txn_req_alloc(txn, 0, MGMTD_TXN_PROC_COMMITCFG);
txn_req->req.commit_cfg.src_ds_id = MGMTD_DS_NONE;
txn_req->req.commit_cfg.src_ds_ctx = 0;
- txn_req->req.commit_cfg.dst_ds_id = MGMTD_DS_NONE;
- txn_req->req.commit_cfg.dst_ds_ctx = 0;
+ txn_req->req.commit_cfg.dst_ds_id = MGMTD_DS_RUNNING;
+ txn_req->req.commit_cfg.dst_ds_ctx = ds_ctx;
txn_req->req.commit_cfg.validate_only = false;
txn_req->req.commit_cfg.abort = false;
+ txn_req->req.commit_cfg.init = true;
txn_req->req.commit_cfg.cmt_stats = &dummy_stats;
txn_req->req.commit_cfg.cfg_chgs = adapter_cfgs;
@@ -2365,9 +2158,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!");
@@ -2400,7 +2192,7 @@ int mgmt_txn_notify_be_txn_reply(uint64_t txn_id, bool create, bool success,
* Done with TXN_CREATE. Move the backend client to
* next phase.
*/
- assert(cmtcfg_req->curr_phase ==
+ assert(cmtcfg_req->phase ==
MGMTD_COMMIT_PHASE_TXN_CREATE);
/*
@@ -2412,23 +2204,16 @@ int mgmt_txn_notify_be_txn_reply(uint64_t txn_id, bool create, bool success,
txn, MGMTD_INTERNAL_ERROR,
"Internal error! Failed to initiate transaction at backend!");
}
- } else {
- /*
- * Done with TXN_DELETE. Move the backend client to next phase.
- */
- if (false)
- mgmt_move_be_commit_to_next_phase(txn, adapter);
}
return 0;
}
-int mgmt_txn_notify_be_cfgdata_reply(uint64_t txn_id, uint64_t batch_id,
- bool success, char *error_if_any,
+int mgmt_txn_notify_be_cfgdata_reply(uint64_t txn_id, bool success,
+ char *error_if_any,
struct mgmt_be_client_adapter *adapter)
{
struct mgmt_txn_ctx *txn;
- struct mgmt_txn_be_cfg_batch *batch;
struct mgmt_commit_cfg_req *cmtcfg_req;
txn = mgmt_txn_id2ctx(txn_id);
@@ -2439,15 +2224,11 @@ int mgmt_txn_notify_be_cfgdata_reply(uint64_t txn_id, uint64_t batch_id,
return -1;
cmtcfg_req = &txn->commit_cfg_req->req.commit_cfg;
- batch = mgmt_txn_cfgbatch_id2ctx(txn, batch_id);
- if (!batch || batch->txn != txn)
- return -1;
-
if (!success) {
- MGMTD_TXN_ERR("CFGDATA_CREATE_REQ sent to '%s' failed txn-id: %" PRIu64
- " batch-id %" PRIu64 " err: %s",
- adapter->name, txn->txn_id, batch->batch_id,
- error_if_any ? error_if_any : "None");
+ __log_err("CFGDATA_CREATE_REQ sent to '%s' failed txn-id: %" PRIu64
+ " err: %s",
+ adapter->name, txn->txn_id,
+ error_if_any ? error_if_any : "None");
mgmt_txn_send_commit_cfg_reply(
txn, MGMTD_INTERNAL_ERROR,
error_if_any
@@ -2456,14 +2237,11 @@ int mgmt_txn_notify_be_cfgdata_reply(uint64_t txn_id, uint64_t batch_id,
return 0;
}
- MGMTD_TXN_DBG("CFGDATA_CREATE_REQ sent to '%s' was successful txn-id: %" PRIu64
- " batch-id %" PRIu64 " err: %s",
- adapter->name, txn->txn_id, batch->batch_id,
- error_if_any ? error_if_any : "None");
- mgmt_move_txn_cfg_batch_to_next(cmtcfg_req, batch,
- &cmtcfg_req->curr_batches[adapter->id],
- &cmtcfg_req->next_batches[adapter->id],
- true, MGMTD_COMMIT_PHASE_APPLY_CFG);
+ __dbg("CFGDATA_CREATE_REQ sent to '%s' was successful txn-id: %" PRIu64
+ " err: %s",
+ adapter->name, txn->txn_id, error_if_any ? error_if_any : "None");
+
+ cmtcfg_req->be_phase[adapter->id] = MGMTD_COMMIT_PHASE_APPLY_CFG;
mgmt_try_move_commit_to_next_phase(txn, cmtcfg_req);
@@ -2471,14 +2249,11 @@ int mgmt_txn_notify_be_cfgdata_reply(uint64_t txn_id, uint64_t batch_id,
}
int mgmt_txn_notify_be_cfg_apply_reply(uint64_t txn_id, bool success,
- uint64_t batch_ids[],
- size_t num_batch_ids, char *error_if_any,
+ char *error_if_any,
struct mgmt_be_client_adapter *adapter)
{
struct mgmt_txn_ctx *txn;
- struct mgmt_txn_be_cfg_batch *batch;
struct mgmt_commit_cfg_req *cmtcfg_req = NULL;
- size_t indx;
txn = mgmt_txn_id2ctx(txn_id);
if (!txn || txn->type != MGMTD_TXN_TYPE_CONFIG || !txn->commit_cfg_req)
@@ -2487,11 +2262,10 @@ int mgmt_txn_notify_be_cfg_apply_reply(uint64_t txn_id, bool success,
cmtcfg_req = &txn->commit_cfg_req->req.commit_cfg;
if (!success) {
- MGMTD_TXN_ERR("CFGDATA_APPLY_REQ sent to '%s' failed txn-id: %" PRIu64
- " batch ids %" PRIu64 " - %" PRIu64 " err: %s",
- adapter->name, txn->txn_id, batch_ids[0],
- batch_ids[num_batch_ids - 1],
- error_if_any ? error_if_any : "None");
+ __log_err("CFGDATA_APPLY_REQ sent to '%s' failed txn-id: %" PRIu64
+ " err: %s",
+ adapter->name, txn->txn_id,
+ error_if_any ? error_if_any : "None");
mgmt_txn_send_commit_cfg_reply(
txn, MGMTD_INTERNAL_ERROR,
error_if_any
@@ -2500,25 +2274,14 @@ int mgmt_txn_notify_be_cfg_apply_reply(uint64_t txn_id, bool success,
return 0;
}
- for (indx = 0; indx < num_batch_ids; indx++) {
- batch = mgmt_txn_cfgbatch_id2ctx(txn, batch_ids[indx]);
- if (batch->txn != txn)
- return -1;
- mgmt_move_txn_cfg_batch_to_next(
- cmtcfg_req, batch,
- &cmtcfg_req->curr_batches[adapter->id],
- &cmtcfg_req->next_batches[adapter->id], true,
- MGMTD_COMMIT_PHASE_TXN_DELETE);
- }
+ cmtcfg_req->be_phase[adapter->id] = MGMTD_COMMIT_PHASE_TXN_DELETE;
- if (!mgmt_txn_batches_count(&cmtcfg_req->curr_batches[adapter->id])) {
- /*
- * All configuration for the specific backend has been applied.
- * Send TXN-DELETE to wrap up the transaction for this backend.
- */
- SET_FLAG(adapter->flags, MGMTD_BE_ADAPTER_FLAGS_CFG_SYNCED);
- mgmt_txn_send_be_txn_delete(txn, adapter);
- }
+ /*
+ * All configuration for the specific backend has been applied.
+ * Send TXN-DELETE to wrap up the transaction for this backend.
+ */
+ SET_FLAG(adapter->flags, MGMTD_BE_ADAPTER_FLAGS_CFG_SYNCED);
+ mgmt_txn_send_be_txn_delete(txn, adapter);
mgmt_try_move_commit_to_next_phase(txn, cmtcfg_req);
if (mm->perf_stats_en)
@@ -2540,15 +2303,14 @@ int mgmt_txn_send_get_req(uint64_t txn_id, uint64_t req_id,
if (!txn)
return -1;
- req_event = cfg_root ? MGMTD_TXN_PROC_GETCFG : MGMTD_TXN_PROC_GETDATA;
-
+ req_event = MGMTD_TXN_PROC_GETCFG;
txn_req = mgmt_txn_req_alloc(txn, req_id, req_event);
txn_req->req.get_data->ds_id = ds_id;
txn_req->req.get_data->cfg_root = cfg_root;
for (indx = 0;
indx < num_reqs && indx < MGMTD_MAX_NUM_DATA_REPLY_IN_BATCH;
indx++) {
- MGMTD_TXN_DBG("XPath: '%s'", data_req[indx]->data->xpath);
+ __dbg("XPath: '%s'", data_req[indx]->data->xpath);
txn_req->req.get_data->xpaths[indx] =
strdup(data_req[indx]->data->xpath);
txn_req->req.get_data->num_xpaths++;
@@ -2559,6 +2321,266 @@ int mgmt_txn_send_get_req(uint64_t txn_id, uint64_t req_id,
return 0;
}
+
+/**
+ * Send get-tree requests to each client indicated in `clients` bitmask, which
+ * has registered operational state that matches the given `xpath`
+ */
+int mgmt_txn_send_get_tree_oper(uint64_t txn_id, uint64_t req_id,
+ uint64_t clients, Mgmtd__DatastoreId ds_id,
+ LYD_FORMAT result_type, uint8_t flags,
+ uint32_t wd_options, bool simple_xpath,
+ const char *xpath)
+{
+ struct mgmt_msg_get_tree *msg;
+ struct mgmt_txn_ctx *txn;
+ struct mgmt_txn_req *txn_req;
+ struct txn_req_get_tree *get_tree;
+ enum mgmt_be_client_id id;
+ ssize_t slen = strlen(xpath);
+ int ret;
+
+ txn = mgmt_txn_id2ctx(txn_id);
+ if (!txn)
+ return -1;
+
+ /* If error in this function below here, be sure to free the req */
+ txn_req = mgmt_txn_req_alloc(txn, req_id, MGMTD_TXN_PROC_GETTREE);
+ get_tree = txn_req->req.get_tree;
+ get_tree->result_type = result_type;
+ get_tree->wd_options = wd_options;
+ get_tree->exact = CHECK_FLAG(flags, GET_DATA_FLAG_EXACT);
+ get_tree->simple_xpath = simple_xpath;
+ get_tree->xpath = XSTRDUP(MTYPE_MGMTD_XPATH, xpath);
+
+ if (CHECK_FLAG(flags, GET_DATA_FLAG_CONFIG)) {
+ /*
+ * If the requested datastore is operational, get the config
+ * from running.
+ */
+ struct mgmt_ds_ctx *ds =
+ mgmt_ds_get_ctx_by_id(mm, ds_id == MGMTD_DS_OPERATIONAL
+ ? MGMTD_DS_RUNNING
+ : ds_id);
+ struct nb_config *config = mgmt_ds_get_nb_config(ds);
+
+ if (config) {
+ struct ly_set *set = NULL;
+ LY_ERR err;
+
+ err = lyd_find_xpath(config->dnode, xpath, &set);
+ if (err) {
+ get_tree->partial_error = err;
+ goto state;
+ }
+
+ /*
+ * If there's a single result, duplicate the returned
+ * node. If there are multiple results, duplicate the
+ * whole config and mark simple_xpath as false so the
+ * result is trimmed later in txn_get_tree_data_done.
+ */
+ if (set->count == 1) {
+ err = lyd_dup_single(set->dnodes[0], NULL,
+ LYD_DUP_WITH_PARENTS |
+ LYD_DUP_WITH_FLAGS |
+ LYD_DUP_RECURSIVE,
+ &get_tree->client_results);
+ if (!err)
+ while (get_tree->client_results->parent)
+ get_tree->client_results = lyd_parent(
+ get_tree->client_results);
+ } else if (set->count > 1) {
+ err = lyd_dup_siblings(config->dnode, NULL,
+ LYD_DUP_RECURSIVE |
+ LYD_DUP_WITH_FLAGS,
+ &get_tree->client_results);
+ if (!err)
+ get_tree->simple_xpath = false;
+ }
+
+ if (err)
+ get_tree->partial_error = err;
+
+ ly_set_free(set, NULL);
+ }
+ }
+state:
+ /* If we are only getting config, we are done */
+ if (!CHECK_FLAG(flags, GET_DATA_FLAG_STATE) ||
+ ds_id != MGMTD_DS_OPERATIONAL || !clients)
+ return txn_get_tree_data_done(txn, txn_req);
+
+ msg = mgmt_msg_native_alloc_msg(struct mgmt_msg_get_tree, slen + 1,
+ MTYPE_MSG_NATIVE_GET_TREE);
+ msg->refer_id = txn_id;
+ msg->req_id = req_id;
+ msg->code = MGMT_MSG_CODE_GET_TREE;
+ /* Always operate with the binary format in the backend */
+ msg->result_type = LYD_LYB;
+ strlcpy(msg->xpath, xpath, slen + 1);
+
+ assert(clients);
+ FOREACH_BE_CLIENT_BITS (id, clients) {
+ ret = mgmt_be_send_native(id, msg);
+ if (ret) {
+ __log_err("Could not send get-tree message to backend client %s",
+ mgmt_be_client_id2name(id));
+ continue;
+ }
+
+ __dbg("Sent get-tree req to backend client %s",
+ mgmt_be_client_id2name(id));
+
+ /* record that we sent the request to the client */
+ get_tree->sent_clients |= (1u << id);
+ }
+
+ mgmt_msg_native_free_msg(msg);
+
+ /* Return if we didn't send any messages to backends */
+ if (!get_tree->sent_clients)
+ return txn_get_tree_data_done(txn, txn_req);
+
+ /* Start timeout timer - pulled out of register event code so we can
+ * pass a different arg
+ */
+ event_add_timer(mgmt_txn_tm, txn_get_tree_timeout, txn_req,
+ MGMTD_TXN_GET_TREE_MAX_DELAY_SEC,
+ &txn->get_tree_timeout);
+ return 0;
+}
+
+/*
+ * Error reply from the backend client.
+ */
+int mgmt_txn_notify_error(struct mgmt_be_client_adapter *adapter,
+ uint64_t txn_id, uint64_t req_id, int error,
+ const char *errstr)
+{
+ enum mgmt_be_client_id id = adapter->id;
+ struct mgmt_txn_ctx *txn = mgmt_txn_id2ctx(txn_id);
+ struct txn_req_get_tree *get_tree;
+ struct mgmt_txn_req *txn_req;
+
+ if (!txn) {
+ __log_err("Error reply from %s cannot find txn-id %" PRIu64,
+ adapter->name, txn_id);
+ return -1;
+ }
+
+ /* Find the request. */
+ FOREACH_TXN_REQ_IN_LIST (&txn->get_tree_reqs, txn_req)
+ if (txn_req->req_id == req_id)
+ break;
+ if (!txn_req) {
+ __log_err("Error reply from %s for txn-id %" PRIu64
+ " cannot find req_id %" PRIu64,
+ adapter->name, txn_id, req_id);
+ return -1;
+ }
+
+ __log_err("Error reply from %s for txn-id %" PRIu64 " req_id %" PRIu64,
+ adapter->name, txn_id, req_id);
+
+ switch (txn_req->req_event) {
+ case MGMTD_TXN_PROC_GETTREE:
+ get_tree = txn_req->req.get_tree;
+ get_tree->recv_clients |= (1u << id);
+ get_tree->partial_error = error;
+
+ /* check if done yet */
+ if (get_tree->recv_clients != get_tree->sent_clients)
+ return 0;
+ return txn_get_tree_data_done(txn, txn_req);
+
+ /* non-native message events */
+ case MGMTD_TXN_PROC_SETCFG:
+ case MGMTD_TXN_PROC_COMMITCFG:
+ case MGMTD_TXN_PROC_GETCFG:
+ case MGMTD_TXN_COMMITCFG_TIMEOUT:
+ case MGMTD_TXN_GETTREE_TIMEOUT:
+ default:
+ assert(!"non-native req event in native erorr path");
+ return -1;
+ }
+}
+
+/*
+ * Get-tree data from the backend client.
+ */
+int mgmt_txn_notify_tree_data_reply(struct mgmt_be_client_adapter *adapter,
+ struct mgmt_msg_tree_data *data_msg,
+ size_t msg_len)
+{
+ uint64_t txn_id = data_msg->refer_id;
+ uint64_t req_id = data_msg->req_id;
+
+ enum mgmt_be_client_id id = adapter->id;
+ struct mgmt_txn_ctx *txn = mgmt_txn_id2ctx(txn_id);
+ struct mgmt_txn_req *txn_req;
+ struct txn_req_get_tree *get_tree;
+ struct lyd_node *tree = NULL;
+ LY_ERR err;
+
+ if (!txn) {
+ __log_err("GETTREE reply from %s for a missing txn-id %" PRIu64,
+ adapter->name, txn_id);
+ return -1;
+ }
+
+ /* Find the request. */
+ FOREACH_TXN_REQ_IN_LIST (&txn->get_tree_reqs, txn_req)
+ if (txn_req->req_id == req_id)
+ break;
+ if (!txn_req) {
+ __log_err("GETTREE reply from %s for txn-id %" PRIu64
+ " missing req_id %" PRIu64,
+ adapter->name, txn_id, req_id);
+ return -1;
+ }
+
+ get_tree = txn_req->req.get_tree;
+
+ /* store the result */
+ err = lyd_parse_data_mem(ly_native_ctx, (const char *)data_msg->result,
+ data_msg->result_type,
+ LYD_PARSE_STRICT | LYD_PARSE_ONLY,
+ 0 /*LYD_VALIDATE_OPERATIONAL*/, &tree);
+ if (err) {
+ __log_err("GETTREE reply from %s for txn-id %" PRIu64
+ " req_id %" PRIu64 " error parsing result of type %u",
+ adapter->name, txn_id, req_id, data_msg->result_type);
+ }
+ if (!err) {
+ /* TODO: we could merge ly_errs here if it's not binary */
+
+ if (!get_tree->client_results)
+ get_tree->client_results = tree;
+ else
+ err = lyd_merge_siblings(&get_tree->client_results,
+ tree, LYD_MERGE_DESTRUCT);
+ if (err) {
+ __log_err("GETTREE reply from %s for txn-id %" PRIu64
+ " req_id %" PRIu64 " error merging result",
+ adapter->name, txn_id, req_id);
+ }
+ }
+ if (!get_tree->partial_error)
+ get_tree->partial_error = (data_msg->partial_error
+ ? data_msg->partial_error
+ : (int)err);
+
+ if (!data_msg->more)
+ get_tree->recv_clients |= (1u << id);
+
+ /* check if done yet */
+ if (get_tree->recv_clients != get_tree->sent_clients)
+ return 0;
+
+ return txn_get_tree_data_done(txn, txn_req);
+}
+
void mgmt_txn_status_write(struct vty *vty)
{
struct mgmt_txn_ctx *txn;
@@ -2614,12 +2636,12 @@ int mgmt_txn_rollback_trigger_cfg_apply(struct mgmt_ds_ctx *src_ds_ctx,
*/
txn = mgmt_txn_create_new(0, MGMTD_TXN_TYPE_CONFIG);
if (!txn) {
- MGMTD_TXN_ERR(
+ __log_err(
"Failed to create CONFIG Transaction for downloading CONFIGs");
return -1;
}
- MGMTD_TXN_DBG("Created rollback txn-id: %" PRIu64, txn->txn_id);
+ __dbg("Created rollback txn-id: %" PRIu64, txn->txn_id);
/*
* Set the changeset for transaction to commit and trigger the commit
diff --git a/mgmtd/mgmt_txn.h b/mgmtd/mgmt_txn.h
index 068f07a..b719832 100644
--- a/mgmtd/mgmt_txn.h
+++ b/mgmtd/mgmt_txn.h
@@ -9,23 +9,23 @@
#ifndef _FRR_MGMTD_TXN_H_
#define _FRR_MGMTD_TXN_H_
+#include "lib/mgmt_msg_native.h"
#include "mgmtd/mgmt_be_adapter.h"
#include "mgmtd/mgmt.h"
#include "mgmtd/mgmt_ds.h"
-#define MGMTD_TXN_PROC_DELAY_MSEC 5
#define MGMTD_TXN_PROC_DELAY_USEC 10
#define MGMTD_TXN_MAX_NUM_SETCFG_PROC 128
#define MGMTD_TXN_MAX_NUM_GETCFG_PROC 128
#define MGMTD_TXN_MAX_NUM_GETDATA_PROC 128
-#define MGMTD_TXN_SEND_CFGVALIDATE_DELAY_MSEC 100
-#define MGMTD_TXN_SEND_CFGAPPLY_DELAY_MSEC 100
-#define MGMTD_TXN_CFG_COMMIT_MAX_DELAY_MSEC 30000 /* 30 seconds */
+#define MGMTD_TXN_CFG_COMMIT_MAX_DELAY_SEC 600
+#define MGMTD_TXN_GET_TREE_MAX_DELAY_SEC 600
-#define MGMTD_TXN_CLEANUP_DELAY_MSEC 100
#define MGMTD_TXN_CLEANUP_DELAY_USEC 10
+#define MGMTD_TXN_ID_NONE 0
+
/*
* The following definition enables local validation of config
* on the MGMTD process by loading client-defined NB callbacks
@@ -71,12 +71,18 @@ extern int mgmt_txn_init(struct mgmt_master *cm, struct event_loop *tm);
extern void mgmt_txn_destroy(void);
/*
- * Check if transaction is in progress.
+ * Check if configuration transaction is in progress.
*
* Returns:
- * session ID if in-progress, MGMTD_SESSION_ID_NONE otherwise.
+ * true if in-progress, false otherwise.
*/
-extern uint64_t mgmt_config_txn_in_progress(void);
+extern bool mgmt_config_txn_in_progress(void);
+
+/**
+ * Get the session ID associated with the given ``txn-id``.
+ *
+ */
+extern uint64_t mgmt_txn_get_session_id(uint64_t txn_id);
/*
* Create transaction.
@@ -188,6 +194,31 @@ extern int mgmt_txn_send_get_req(uint64_t txn_id, uint64_t req_id,
Mgmtd__YangGetDataReq **data_req,
size_t num_reqs);
+
+/**
+ * Send get-tree to the backend `clients`.
+ *
+ * Args:
+ * txn_id: Transaction identifier.
+ * req_id: FE client request identifier.
+ * clients: Bitmask of clients to send get-tree to.
+ * ds_id: datastore ID.
+ * result_type: LYD_FORMAT result format.
+ * flags: option flags for the request.
+ * wd_options: LYD_PRINT_WD_* flags for the result.
+ * simple_xpath: true if xpath is simple (only key predicates).
+ * xpath: The xpath to get the tree from.
+ *
+ * Return:
+ * 0 on success.
+ */
+extern int mgmt_txn_send_get_tree_oper(uint64_t txn_id, uint64_t req_id,
+ uint64_t clients,
+ Mgmtd__DatastoreId ds_id,
+ LYD_FORMAT result_type, uint8_t flags,
+ uint32_t wd_options, bool simple_xpath,
+ const char *xpath);
+
/*
* Notifiy backend adapter on connection.
*/
@@ -206,8 +237,8 @@ mgmt_txn_notify_be_txn_reply(uint64_t txn_id, bool create, bool success,
* Reply to backend adapater with config data create request.
*/
extern int
-mgmt_txn_notify_be_cfgdata_reply(uint64_t txn_id, uint64_t batch_id,
- bool success, char *error_if_any,
+mgmt_txn_notify_be_cfgdata_reply(uint64_t txn_id, bool success,
+ char *error_if_any,
struct mgmt_be_client_adapter *adapter);
/*
@@ -223,10 +254,37 @@ extern int mgmt_txn_notify_be_cfg_validate_reply(
*/
extern int
mgmt_txn_notify_be_cfg_apply_reply(uint64_t txn_id, bool success,
- uint64_t batch_ids[],
- size_t num_batch_ids, char *error_if_any,
+ char *error_if_any,
struct mgmt_be_client_adapter *adapter);
+
+/**
+ * Process a reply from a backend client to our get-tree request
+ *
+ * Args:
+ * adapter: The adapter that received the result.
+ * txn_id: The transaction for this get-tree request.
+ * req_id: The request ID for this transaction.
+ * error: the integer error value (negative)
+ * errstr: the string description of the error.
+ */
+int mgmt_txn_notify_error(struct mgmt_be_client_adapter *adapter,
+ uint64_t txn_id, uint64_t req_id, int error,
+ const char *errstr);
+
+/**
+ * Process a reply from a backend client to our get-tree request
+ *
+ * Args:
+ * adapter: The adapter that received the result.
+ * data_msg: The message from the backend.
+ * msg_len: Total length of the message.
+ */
+
+extern int mgmt_txn_notify_tree_data_reply(struct mgmt_be_client_adapter *adapter,
+ struct mgmt_msg_tree_data *data_msg,
+ size_t msg_len);
+
/*
* Dump transaction status to vty.
*/
diff --git a/mgmtd/mgmt_vty.c b/mgmtd/mgmt_vty.c
index b49bf80..bbc1077 100644
--- a/mgmtd/mgmt_vty.c
+++ b/mgmtd/mgmt_vty.c
@@ -8,10 +8,13 @@
#include <zebra.h>
+#include "affinitymap.h"
#include "command.h"
+#include "filter.h"
#include "json.h"
#include "network.h"
#include "northbound_cli.h"
+#include "routemap.h"
#include "mgmtd/mgmt.h"
#include "mgmtd/mgmt_be_adapter.h"
@@ -20,6 +23,10 @@
#include "mgmtd/mgmt_history.h"
#include "mgmtd/mgmt_vty_clippy.c"
+#include "ripd/rip_nb.h"
+#include "ripngd/ripng_nb.h"
+#include "staticd/static_vty.h"
+#include "zebra/zebra_cli.h"
extern struct frr_daemon_info *mgmt_daemon_info;
@@ -144,6 +151,23 @@ DEFPY(mgmt_commit,
return CMD_SUCCESS;
}
+DEFPY(mgmt_create_config_data, mgmt_create_config_data_cmd,
+ "mgmt create-config WORD$path VALUE",
+ MGMTD_STR
+ "Create configuration data\n"
+ "XPath expression specifying the YANG data path\n"
+ "Value of the data to create\n")
+{
+ strlcpy(vty->cfg_changes[0].xpath, path,
+ sizeof(vty->cfg_changes[0].xpath));
+ vty->cfg_changes[0].value = value;
+ vty->cfg_changes[0].operation = NB_OP_CREATE_EXCL;
+ vty->num_cfg_changes = 1;
+
+ vty_mgmt_send_config_data(vty, NULL, false);
+ return CMD_SUCCESS;
+}
+
DEFPY(mgmt_set_config_data, mgmt_set_config_data_cmd,
"mgmt set-config WORD$path VALUE",
MGMTD_STR
@@ -154,10 +178,10 @@ DEFPY(mgmt_set_config_data, mgmt_set_config_data_cmd,
strlcpy(vty->cfg_changes[0].xpath, path,
sizeof(vty->cfg_changes[0].xpath));
vty->cfg_changes[0].value = value;
- vty->cfg_changes[0].operation = NB_OP_CREATE;
+ vty->cfg_changes[0].operation = NB_OP_MODIFY;
vty->num_cfg_changes = 1;
- vty_mgmt_send_config_data(vty, false);
+ vty_mgmt_send_config_data(vty, NULL, false);
return CMD_SUCCESS;
}
@@ -171,10 +195,45 @@ DEFPY(mgmt_delete_config_data, mgmt_delete_config_data_cmd,
strlcpy(vty->cfg_changes[0].xpath, path,
sizeof(vty->cfg_changes[0].xpath));
vty->cfg_changes[0].value = NULL;
+ vty->cfg_changes[0].operation = NB_OP_DELETE;
+ vty->num_cfg_changes = 1;
+
+ vty_mgmt_send_config_data(vty, NULL, false);
+ return CMD_SUCCESS;
+}
+
+DEFPY(mgmt_remove_config_data, mgmt_remove_config_data_cmd,
+ "mgmt remove-config WORD$path",
+ MGMTD_STR
+ "Remove configuration data\n"
+ "XPath expression specifying the YANG data path\n")
+{
+
+ strlcpy(vty->cfg_changes[0].xpath, path,
+ sizeof(vty->cfg_changes[0].xpath));
+ vty->cfg_changes[0].value = NULL;
vty->cfg_changes[0].operation = NB_OP_DESTROY;
vty->num_cfg_changes = 1;
- vty_mgmt_send_config_data(vty, false);
+ vty_mgmt_send_config_data(vty, NULL, false);
+ return CMD_SUCCESS;
+}
+
+DEFPY(mgmt_replace_config_data, mgmt_replace_config_data_cmd,
+ "mgmt replace-config WORD$path VALUE",
+ MGMTD_STR
+ "Replace configuration data\n"
+ "XPath expression specifying the YANG data path\n"
+ "Value of the data to set\n")
+{
+
+ strlcpy(vty->cfg_changes[0].xpath, path,
+ sizeof(vty->cfg_changes[0].xpath));
+ vty->cfg_changes[0].value = value;
+ vty->cfg_changes[0].operation = NB_OP_REPLACE;
+ vty->num_cfg_changes = 1;
+
+ vty_mgmt_send_config_data(vty, NULL, false);
return CMD_SUCCESS;
}
@@ -199,22 +258,69 @@ DEFPY(show_mgmt_get_config, show_mgmt_get_config_cmd,
}
DEFPY(show_mgmt_get_data, show_mgmt_get_data_cmd,
- "show mgmt get-data [candidate|operational|running]$dsname WORD$path",
- SHOW_STR MGMTD_STR
- "Get data from a specific datastore\n"
+ "show mgmt get-data WORD$path [datastore <candidate|running|operational>$ds] [with-config|only-config]$content [exact]$exact [with-defaults <trim|all-tag|all>$wd] [json|xml]$fmt",
+ SHOW_STR
+ MGMTD_STR
+ "Get a data from the operational datastore\n"
+ "XPath expression specifying the YANG data root\n"
+ "Specify datastore to get data from (operational by default)\n"
"Candidate datastore\n"
- "Operational datastore (default)\n"
"Running datastore\n"
- "XPath expression specifying the YANG data path\n")
+ "Operational datastore\n"
+ "Include \"config true\" data\n"
+ "Get only \"config true\" data\n"
+ "Get exact node instead of the whole data tree\n"
+ "Configure 'with-defaults' mode per RFC 6243 (\"explicit\" mode by default)\n"
+ "Use \"trim\" mode\n"
+ "Use \"report-all-tagged\" mode\n"
+ "Use \"report-all\" mode\n"
+ "JSON output format\n"
+ "XML output format\n")
{
- const char *xpath_list[VTY_MAXCFGCHANGES] = {0};
- Mgmtd__DatastoreId datastore = MGMTD_DS_OPERATIONAL;
+ LYD_FORMAT format = (fmt && fmt[0] == 'x') ? LYD_XML : LYD_JSON;
+ int plen = strlen(path);
+ char *xpath = NULL;
+ uint8_t flags = content ? GET_DATA_FLAG_CONFIG : GET_DATA_FLAG_STATE;
+ uint8_t defaults = GET_DATA_DEFAULTS_EXPLICIT;
+ uint8_t datastore = MGMT_MSG_DATASTORE_OPERATIONAL;
+
+ if (content && content[0] == 'w')
+ flags |= GET_DATA_FLAG_STATE;
+
+ if (exact)
+ flags |= GET_DATA_FLAG_EXACT;
+
+ if (wd) {
+ if (wd[0] == 't')
+ defaults = GET_DATA_DEFAULTS_TRIM;
+ else if (wd[3] == '-')
+ defaults = GET_DATA_DEFAULTS_ALL_ADD_TAG;
+ else
+ defaults = GET_DATA_DEFAULTS_ALL;
+ }
- if (dsname)
- datastore = mgmt_ds_name2id(dsname);
+ if (ds) {
+ if (ds[0] == 'c')
+ datastore = MGMT_MSG_DATASTORE_CANDIDATE;
+ else if (ds[0] == 'r')
+ datastore = MGMT_MSG_DATASTORE_RUNNING;
+ }
+
+ /* get rid of extraneous trailing slash-* or single '/' unless root */
+ if (plen > 2 && ((path[plen - 2] == '/' && path[plen - 1] == '*') ||
+ (path[plen - 2] != '/' && path[plen - 1] == '/'))) {
+ plen = path[plen - 1] == '/' ? plen - 1 : plen - 2;
+ xpath = XSTRDUP(MTYPE_TMP, path);
+ xpath[plen] = 0;
+ path = xpath;
+ }
+
+ vty_mgmt_send_get_data_req(vty, datastore, format, flags, defaults,
+ path);
+
+ if (xpath)
+ XFREE(MTYPE_TMP, xpath);
- xpath_list[0] = path;
- vty_mgmt_send_get_req(vty, false, datastore, xpath_list, 1);
return CMD_SUCCESS;
}
@@ -273,7 +379,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;
}
@@ -379,7 +485,7 @@ DEFPY(mgmt_rollback,
int config_write_mgmt_debug(struct vty *vty);
static struct cmd_node debug_node = {
- .name = "debug",
+ .name = "mgmt debug",
.node = DEBUG_NODE,
.prompt = "",
.config_write = config_write_mgmt_debug,
@@ -438,12 +544,18 @@ DEFPY(debug_mgmt, debug_mgmt_cmd,
{
uint32_t mode = DEBUG_NODE2MODE(vty->node);
- if (be)
+ if (be) {
DEBUG_MODE_SET(&mgmt_debug_be, mode, !no);
+ mgmt_be_adapter_toggle_client_debug(
+ DEBUG_MODE_CHECK(&mgmt_debug_be, DEBUG_MODE_ALL));
+ }
if (ds)
DEBUG_MODE_SET(&mgmt_debug_ds, mode, !no);
- if (fe)
+ if (fe) {
DEBUG_MODE_SET(&mgmt_debug_fe, mode, !no);
+ mgmt_fe_adapter_toggle_client_debug(
+ DEBUG_MODE_CHECK(&mgmt_debug_fe, DEBUG_MODE_ALL));
+ }
if (txn)
DEBUG_MODE_SET(&mgmt_debug_txn, mode, !no);
@@ -452,19 +564,57 @@ DEFPY(debug_mgmt, debug_mgmt_cmd,
static void mgmt_config_read_in(struct event *event)
{
- mgmt_vty_read_configs();
+ if (vty_mgmt_fe_enabled())
+ mgmt_vty_read_configs();
+ else {
+ zlog_warn("%s: no connection to front-end server, retry in 1s",
+ __func__);
+ event_add_timer(mm->master, mgmt_config_read_in, NULL, 1,
+ &mgmt_daemon_info->read_in);
+ }
+}
+
+static int mgmtd_config_write(struct vty *vty)
+{
+ struct lyd_node *root;
+
+ LY_LIST_FOR (running_config->dnode, root) {
+ nb_cli_show_dnode_cmds(vty, root, false);
+ }
+
+ return 1;
}
+static struct cmd_node mgmtd_node = {
+ .name = "mgmtd",
+ .node = MGMTD_NODE,
+ .prompt = "",
+ .config_write = mgmtd_config_write,
+};
+
void mgmt_vty_init(void)
{
/*
+ * Library based CLI handlers
+ */
+ filter_cli_init();
+ route_map_cli_init();
+ affinity_map_init();
+
+ /*
* Initialize command handling from VTYSH connection.
* Call command initialization routines defined by
* backend components that are moved to new MGMTD infra
* here one by one.
*/
-#if HAVE_STATICD
- extern void static_vty_init(void);
+ zebra_cli_init();
+#ifdef HAVE_RIPD
+ rip_cli_init();
+#endif
+#ifdef HAVE_RIPNGD
+ ripng_cli_init();
+#endif
+#ifdef HAVE_STATICD
static_vty_init();
#endif
@@ -472,6 +622,7 @@ void mgmt_vty_init(void)
&mgmt_daemon_info->read_in);
install_node(&debug_node);
+ install_node(&mgmtd_node);
install_element(VIEW_NODE, &show_mgmt_be_adapter_cmd);
install_element(VIEW_NODE, &show_mgmt_be_xpath_reg_cmd);
@@ -485,8 +636,11 @@ void mgmt_vty_init(void)
install_element(VIEW_NODE, &show_mgmt_cmt_hist_cmd);
install_element(CONFIG_NODE, &mgmt_commit_cmd);
+ install_element(CONFIG_NODE, &mgmt_create_config_data_cmd);
install_element(CONFIG_NODE, &mgmt_set_config_data_cmd);
install_element(CONFIG_NODE, &mgmt_delete_config_data_cmd);
+ install_element(CONFIG_NODE, &mgmt_remove_config_data_cmd);
+ install_element(CONFIG_NODE, &mgmt_replace_config_data_cmd);
install_element(CONFIG_NODE, &mgmt_load_config_cmd);
install_element(CONFIG_NODE, &mgmt_save_config_cmd);
install_element(CONFIG_NODE, &mgmt_rollback_cmd);
diff --git a/mgmtd/subdir.am b/mgmtd/subdir.am
index 67b45d5..1624c6e 100644
--- a/mgmtd/subdir.am
+++ b/mgmtd/subdir.am
@@ -15,6 +15,9 @@ clippy_scan += \
# end
lib_LTLIBRARIES += mgmtd/libmgmt_be_nb.la
+mgmtd_libmgmt_be_nb_la_SOURCES = \
+ zebra/zebra_cli.c \
+ # end
nodist_mgmtd_libmgmt_be_nb_la_SOURCES = \
# end
mgmtd_libmgmt_be_nb_la_CFLAGS = $(AM_CFLAGS) -DINCLUDE_MGMTD_CMDDEFS_ONLY
@@ -33,11 +36,6 @@ mgmtd_libmgmtd_a_SOURCES = \
mgmtd/mgmt_vty.c \
# end
-mgmtdheaderdir = $(pkgincludedir)/mgmtd
-mgmtdheader_HEADERS = \
- mgmtd/mgmt_defines.h \
- # end
-
noinst_HEADERS += \
mgmtd/mgmt.h \
mgmtd/mgmt_be_adapter.h \
@@ -46,23 +44,64 @@ noinst_HEADERS += \
mgmtd/mgmt_history.h \
mgmtd/mgmt_memory.h \
mgmtd/mgmt_txn.h \
+ zebra/zebra_cli.h \
# end
sbin_PROGRAMS += mgmtd/mgmtd
+if MGMTD_TESTC
+sbin_PROGRAMS += mgmtd/mgmtd_testc
+mgmtd_mgmtd_testc_SOURCES = mgmtd/mgmt_testc.c
+mgmtd_mgmtd_testc_LDADD = lib/libfrr.la
+endif
+
mgmtd_mgmtd_SOURCES = \
mgmtd/mgmt_main.c \
# end
nodist_mgmtd_mgmtd_SOURCES = \
+ yang/frr-zebra.yang.c \
+ yang/frr-zebra-route-map.yang.c \
+ yang/ietf/ietf-netconf-acm.yang.c \
+ yang/ietf/ietf-netconf.yang.c \
+ yang/ietf/ietf-netconf-with-defaults.yang.c \
# nothing
mgmtd_mgmtd_CFLAGS = $(AM_CFLAGS) -I ./
mgmtd_mgmtd_LDADD = mgmtd/libmgmtd.a lib/libfrr.la $(LIBCAP) $(LIBM) $(LIBYANG_LIBS) $(UST_LIBS)
mgmtd_mgmtd_LDADD += mgmtd/libmgmt_be_nb.la
+
+if STATICD
+nodist_mgmtd_mgmtd_SOURCES += yang/frr-bfdd.yang.c
+else
+if RIPD
+nodist_mgmtd_mgmtd_SOURCES += yang/frr-bfdd.yang.c
+endif
+endif
+
+if RIPD
+nodist_mgmtd_mgmtd_SOURCES += \
+ yang/frr-ripd.yang.c \
+ # end
+mgmtd_libmgmt_be_nb_la_SOURCES += \
+ ripd/rip_cli.c \
+ # end
+endif
+
+if RIPNGD
+nodist_mgmtd_mgmtd_SOURCES += \
+ yang/frr-ripngd.yang.c \
+ # end
+mgmtd_libmgmt_be_nb_la_SOURCES += \
+ ripngd/ripng_cli.c \
+ # end
+endif
+
if STATICD
nodist_mgmtd_mgmtd_SOURCES += \
yang/frr-staticd.yang.c \
- yang/frr-bfdd.yang.c \
# end
-nodist_mgmtd_libmgmt_be_nb_la_SOURCES += staticd/static_vty.c
+nodist_mgmtd_libmgmt_be_nb_la_SOURCES += \
+ staticd/static_vty.c \
+ # end
endif
+