From: Christian Hopps Date: Fri, 7 Jul 2023 03:23:24 +0000 (-0400) Subject: mgmtd: step 5: add get-tree txn functionality X-Git-Tag: base_10.0~171^2~18 X-Git-Url: https://git.puffer.fish/?a=commitdiff_plain;h=8df542b219c5680f744047033f7876a9ff0530d2;p=mirror%2Ffrr.git mgmtd: step 5: add get-tree txn functionality Adds the guts of the get-tree functionality that is called by or calls the FE and BE code for get-tree processing. Signed-off-by: Christian Hopps --- diff --git a/mgmtd/mgmt_be_adapter.c b/mgmtd/mgmt_be_adapter.c index cf6c848793..6b2f9026db 100644 --- a/mgmtd/mgmt_be_adapter.c +++ b/mgmtd/mgmt_be_adapter.c @@ -103,8 +103,7 @@ mgmt_be_adapter_sched_init_event(struct mgmt_be_client_adapter *adapter); static bool be_is_client_interested(const char *xpath, enum mgmt_be_client_id id, bool config); - -static const char *mgmt_be_client_id2name(enum mgmt_be_client_id id) +const char *mgmt_be_client_id2name(enum mgmt_be_client_id id) { if (id > MGMTD_BE_CLIENT_ID_MAX) return "invalid client id"; @@ -528,10 +527,37 @@ 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_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; + MGMTD_BE_ADAPTER_DBG("Got ERROR from '%s' txn-id %" PRIx64, + adapter->name, msg->txn_id); + + /* Forward the reply to the txn module */ + mgmt_txn_notify_error(adapter, msg->txn_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; + MGMTD_BE_ADAPTER_DBG("Got TREE_DATA from '%s' txn-id %" PRIx64, + adapter->name, msg->txn_id); + + /* Forward the reply to the txn module */ + mgmt_txn_notify_tree_data_reply(adapter, tree_msg, msg_len); + break; default: - MGMTD_BE_ADAPTER_ERR("unknown native message code %u to BE adapter %s", - msg->code, adapter->name); + MGMTD_BE_ADAPTER_ERR("unknown native message txn-id %" PRIu64 + " req-id %" PRIu64 + " code %u from BE client for adapter %s", + msg->txn_id, msg->req_id, msg->code, + adapter->name); break; } } diff --git a/mgmtd/mgmt_be_adapter.h b/mgmtd/mgmt_be_adapter.h index 9f62f87d6d..b8abd016e6 100644 --- a/mgmtd/mgmt_be_adapter.h +++ b/mgmtd/mgmt_be_adapter.h @@ -149,6 +149,9 @@ 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); diff --git a/mgmtd/mgmt_fe_adapter.c b/mgmtd/mgmt_fe_adapter.c index 9c7f070668..11262df863 100644 --- a/mgmtd/mgmt_fe_adapter.c +++ b/mgmtd/mgmt_fe_adapter.c @@ -258,15 +258,11 @@ void mgmt_fe_adapter_toggle_client_debug(bool set) static struct mgmt_fe_session_ctx *fe_adapter_session_by_txn_id(uint64_t txn_id) { -#if 0 /* allow commit to compile */ 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); -#else - return NULL; -#endif } static struct mgmt_fe_session_ctx * @@ -1193,12 +1189,8 @@ static void fe_adapter_handle_get_tree(struct mgmt_fe_session_ctx *session, session->txn_id, session->session_id); /* Create a GET-TREE request under the transaction */ -#if 0 /* allow commit to compile */ ret = mgmt_txn_send_get_tree_oper(session->txn_id, req_id, clients, msg->result_type, msg->xpath); -#else - ret = NB_OK; -#endif if (ret) { /* destroy the just created txn */ mgmt_destroy_txn(&session->txn_id); diff --git a/mgmtd/mgmt_memory.c b/mgmtd/mgmt_memory.c index b2a0f0e848..0fce61aa97 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 06518e3838..d5b6aa632e 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_txn.c b/mgmtd/mgmt_txn.c index c2dca2aea1..af782f1dc3 100644 --- a/mgmtd/mgmt_txn.c +++ b/mgmtd/mgmt_txn.c @@ -7,9 +7,12 @@ */ #include +#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" @@ -27,7 +30,9 @@ enum mgmt_txn_event { MGMTD_TXN_PROC_COMMITCFG, MGMTD_TXN_PROC_GETCFG, MGMTD_TXN_PROC_GETDATA, + MGMTD_TXN_PROC_GETTREE, MGMTD_TXN_COMMITCFG_TIMEOUT, + MGMTD_TXN_GETTREE_TIMEOUT, MGMTD_TXN_CLEANUP }; @@ -166,6 +171,16 @@ struct mgmt_get_data_req { int total_reply; }; + +struct txn_req_get_tree { + char *xpath; /* xpath of tree to get */ + uint8_t result_type; /* LYD_FORMAT for results */ + 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 */ + struct lyd_node *client_results; /* result tree from clients */ +}; + struct mgmt_txn_req { struct mgmt_txn_ctx *txn; enum mgmt_txn_event req_event; @@ -173,6 +188,7 @@ 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; @@ -196,7 +212,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 */ @@ -206,6 +224,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 @@ -228,6 +250,10 @@ struct mgmt_txn_ctx { */ struct mgmt_txn_reqs_head get_data_reqs; struct mgmt_txn_reqs_head pending_get_datas; + /* + * List of pending get-tree requests. + */ + 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. @@ -396,7 +422,16 @@ static struct mgmt_txn_req *mgmt_txn_req_alloc(struct mgmt_txn_ctx *txn, " txn-id: %" PRIu64 " session-id: %" PRIu64, txn_req->req_id, txn->txn_id, txn->session_id); break; + 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); + MGMTD_TXN_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_GETTREE_TIMEOUT: case MGMTD_TXN_CLEANUP: break; } @@ -513,7 +548,17 @@ static void mgmt_txn_req_free(struct mgmt_txn_req **txn_req) (*txn_req)->req.get_data->reply); XFREE(MTYPE_MGMTD_TXN_GETDATA_REQ, (*txn_req)->req.get_data); break; + case MGMTD_TXN_PROC_GETTREE: + MGMTD_TXN_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_GETTREE_TIMEOUT: case MGMTD_TXN_CLEANUP: break; } @@ -1260,6 +1305,66 @@ 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; + int ret = 0; + + /* cancel timer and send reply onward */ + EVENT_OFF(txn->get_tree_timeout); + + ret = mgmt_fe_adapter_send_tree_data(txn->session_id, txn->txn_id, + txn_req->req_id, + get_tree->result_type, + get_tree->client_results, + get_tree->partial_error, false); + + /* we're done with the request */ + mgmt_txn_req_free(&txn_req); + + if (ret) { + MGMTD_TXN_ERR("Error saving the results of GETTREE for txn-id %" PRIu64 + " req_id %" PRIu64 " to requested type %u", + txn->txn_id, txn_req->req_id, + get_tree->result_type); + + (void)mgmt_fe_adapter_txn_error(txn->txn_id, txn_req->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); + + + MGMTD_TXN_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. * @@ -1488,6 +1593,8 @@ static void mgmt_txn_send_getcfg_reply_data(struct mgmt_txn_req *txn_req, 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); @@ -1500,10 +1607,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; @@ -1581,7 +1686,7 @@ 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]); @@ -1733,7 +1838,7 @@ static struct mgmt_txn_ctx *mgmt_txn_create_new(uint64_t session_id, /* * For 'CONFIG' transaction check if one is already created - * or not. + * or not. TODO: figure out what code counts on this and fix it. */ if (type == MGMTD_TXN_TYPE_CONFIG && mgmt_txn_mm->cfg_txn) { if (mgmt_config_txn_in_progress() == session_id) @@ -1749,10 +1854,12 @@ 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) @@ -1834,6 +1941,13 @@ 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++; @@ -1859,6 +1973,7 @@ 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); @@ -1927,14 +2042,23 @@ static void mgmt_txn_register_event(struct mgmt_txn_ctx *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_CLEANUP: tv.tv_usec = MGMTD_TXN_CLEANUP_DELAY_USEC; event_add_timer_tv(mgmt_txn_tm, mgmt_txn_cleanup, txn, &tv, &txn->clnup); + break; + case MGMTD_TXN_PROC_GETTREE: + assert(!"code bug do not register this event"); + break; } } @@ -2333,6 +2457,202 @@ 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, LYD_FORMAT result_type, + 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; + size_t mlen = sizeof(*msg) + strlen(xpath) + 1; + 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->xpath = XSTRDUP(MTYPE_MGMTD_XPATH, xpath); + + msg = XCALLOC(MTYPE_MSG_NATIVE_MSG, mlen); + msg->txn_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, mlen - sizeof(*msg)); + + assert(clients); + FOREACH_BE_CLIENT_BITS (id, clients) { + ret = mgmt_be_send_native(id, msg, mlen); + if (ret) { + MGMTD_TXN_ERR("Could not send get-tree message to backend client %s", + mgmt_be_client_id2name(id)); + continue; + } + + MGMTD_TXN_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); + } + + XFREE(MTYPE_MSG_NATIVE_MSG, msg); + + /* 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) { + MGMTD_TXN_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) { + MGMTD_TXN_ERR("Error reply from %s for txn-id %" PRIu64 + " cannot find req_id %" PRIu64, + adapter->name, txn_id, req_id); + return -1; + } + + MGMTD_TXN_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_PROC_GETDATA: + case MGMTD_TXN_COMMITCFG_TIMEOUT: + case MGMTD_TXN_GETTREE_TIMEOUT: + case MGMTD_TXN_CLEANUP: + 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->txn_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) { + MGMTD_TXN_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) { + MGMTD_TXN_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) { + MGMTD_TXN_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) { + MGMTD_TXN_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); + + 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; diff --git a/mgmtd/mgmt_txn.h b/mgmtd/mgmt_txn.h index a89d5fb939..4aa0677755 100644 --- a/mgmtd/mgmt_txn.h +++ b/mgmtd/mgmt_txn.h @@ -9,21 +9,19 @@ #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 @@ -80,6 +78,12 @@ extern void mgmt_txn_destroy(void); */ extern uint64_t 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. * @@ -190,6 +194,23 @@ 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. + * result_type: LYD_FORMAT result format. + * 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, LYD_FORMAT result_type, + const char *xpath); + /* * Notifiy backend adapter on connection. */ @@ -228,6 +249,34 @@ mgmt_txn_notify_be_cfg_apply_reply(uint64_t txn_id, bool success, 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. */