diff options
Diffstat (limited to 'mgmtd/mgmt_fe_adapter.c')
-rw-r--r-- | mgmtd/mgmt_fe_adapter.c | 596 |
1 files changed, 454 insertions, 142 deletions
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; |