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:
Christian Hopps 2023-07-06 23:23:24 -04:00
parent be2424a875
commit 8df542b219
7 changed files with 418 additions and 26 deletions

View File

@ -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;
}
}

View File

@ -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);

View File

@ -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);

View File

@ -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");

View File

@ -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);

View File

@ -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;

View File

@ -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.
*/