mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-08-13 17:40:04 +00:00
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 <chopps@labn.net>
This commit is contained in:
parent
be2424a875
commit
8df542b219
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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");
|
||||
|
@ -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);
|
||||
|
336
mgmtd/mgmt_txn.c
336
mgmtd/mgmt_txn.c
@ -7,9 +7,12 @@
|
||||
*/
|
||||
|
||||
#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"
|
||||
@ -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,
|
||||
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;
|
||||
|
@ -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.
|
||||
*/
|
||||
|
Loading…
Reference in New Issue
Block a user