summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristian Hopps <chopps@labn.net>2024-01-12 12:07:57 +0100
committerGitHub <noreply@github.com>2024-01-12 12:07:57 +0100
commit20d0d475cb41744f1ad4b65078fe5ecd176bb3bf (patch)
treefcb4b43f9698449d169e58c16252e77414dce2a4
parentMerge pull request #15136 from idryzhov/ignore-cbs (diff)
parentlib: explain semantics of northbound operations (diff)
downloadfrr-20d0d475cb41744f1ad4b65078fe5ecd176bb3bf.tar.xz
frr-20d0d475cb41744f1ad4b65078fe5ecd176bb3bf.zip
Merge pull request #14542 from idryzhov/nb-op-cb-split
Add more northbound operation types
-rw-r--r--doc/developer/northbound/retrofitting-configuration-commands.rst6
-rw-r--r--lib/mgmt.proto5
-rw-r--r--lib/mgmt_be_client.c23
-rw-r--r--lib/northbound.c313
-rw-r--r--lib/northbound.h95
-rw-r--r--lib/northbound_cli.h2
-rw-r--r--lib/northbound_confd.c2
-rw-r--r--lib/northbound_sysrepo.c12
-rw-r--r--lib/vty.c24
-rw-r--r--mgmtd/mgmt_txn.c50
-rw-r--r--mgmtd/mgmt_vty.c57
-rw-r--r--tools/gen_northbound_callbacks.c41
12 files changed, 413 insertions, 217 deletions
diff --git a/doc/developer/northbound/retrofitting-configuration-commands.rst b/doc/developer/northbound/retrofitting-configuration-commands.rst
index b40724604..41f9902b6 100644
--- a/doc/developer/northbound/retrofitting-configuration-commands.rst
+++ b/doc/developer/northbound/retrofitting-configuration-commands.rst
@@ -1005,7 +1005,7 @@ configuration. Here’s the declaration of this structure (taken from the
/*
* Operation to apply (either NB_OP_CREATE, NB_OP_MODIFY or
- * NB_OP_DELETE).
+ * NB_OP_DESTROY).
*/
enum nb_operation operation;
@@ -1205,7 +1205,7 @@ This example shows how to create a list entry:
},
{
.xpath = "./access-list",
- .operation = acl ? NB_OP_MODIFY : NB_OP_DELETE,
+ .operation = acl ? NB_OP_MODIFY : NB_OP_DESTROY,
.value = acl,
},
};
@@ -1242,7 +1242,7 @@ When deleting a list entry, all non-key leaves can be ignored:
struct cli_config_change changes[] = {
{
.xpath = ".",
- .operation = NB_OP_DELETE,
+ .operation = NB_OP_DESTROY,
},
};
diff --git a/lib/mgmt.proto b/lib/mgmt.proto
index 087d96a6e..5d83fca34 100644
--- a/lib/mgmt.proto
+++ b/lib/mgmt.proto
@@ -55,7 +55,10 @@ message YangData {
enum CfgDataReqType {
REQ_TYPE_NONE = 0;
SET_DATA = 1;
- DELETE_DATA = 2;
+ REMOVE_DATA = 2;
+ CREATE_DATA = 3;
+ DELETE_DATA = 4;
+ REPLACE_DATA = 5;
}
message YangCfgDataReq {
diff --git a/lib/mgmt_be_client.c b/lib/mgmt_be_client.c
index c3fb34a7a..16aea249a 100644
--- a/lib/mgmt_be_client.c
+++ b/lib/mgmt_be_client.c
@@ -565,11 +565,26 @@ static int mgmt_be_update_setcfg_in_batch(struct mgmt_be_client *client_ctx,
for (index = 0; index < num_req; index++) {
cfg_chg = &txn_req->req.set_cfg.cfg_changes[index];
- if (cfg_req[index]->req_type
- == MGMTD__CFG_DATA_REQ_TYPE__DELETE_DATA)
+ /*
+ * Treat all operations as destroy or modify, because we don't
+ * need additional existence checks on the backend. Everything
+ * is already checked by mgmtd.
+ */
+ switch (cfg_req[index]->req_type) {
+ case MGMTD__CFG_DATA_REQ_TYPE__DELETE_DATA:
+ case MGMTD__CFG_DATA_REQ_TYPE__REMOVE_DATA:
cfg_chg->operation = NB_OP_DESTROY;
- else
- cfg_chg->operation = NB_OP_CREATE;
+ break;
+ case MGMTD__CFG_DATA_REQ_TYPE__SET_DATA:
+ case MGMTD__CFG_DATA_REQ_TYPE__CREATE_DATA:
+ case MGMTD__CFG_DATA_REQ_TYPE__REPLACE_DATA:
+ cfg_chg->operation = NB_OP_MODIFY;
+ break;
+ case MGMTD__CFG_DATA_REQ_TYPE__REQ_TYPE_NONE:
+ case _MGMTD__CFG_DATA_REQ_TYPE_IS_INT_SIZE:
+ default:
+ continue;
+ }
strlcpy(cfg_chg->xpath, cfg_req[index]->data->xpath,
sizeof(cfg_chg->xpath));
diff --git a/lib/northbound.c b/lib/northbound.c
index c72a8dfbe..42e4ebbcc 100644
--- a/lib/northbound.c
+++ b/lib/northbound.c
@@ -209,12 +209,12 @@ bool nb_node_has_dependency(struct nb_node *node)
}
static int nb_node_validate_cb(const struct nb_node *nb_node,
- enum nb_operation operation,
+ enum nb_cb_operation operation,
int callback_implemented, bool optional)
{
bool valid;
- valid = nb_operation_is_valid(operation, nb_node->snode);
+ valid = nb_cb_operation_is_valid(operation, nb_node->snode);
/*
* Add an exception for operational data callbacks. A rw list usually
@@ -226,15 +226,15 @@ static int nb_node_validate_cb(const struct nb_node *nb_node,
* depends on context (e.g. some daemons might augment "frr-interface"
* while others don't).
*/
- if (!valid && callback_implemented && operation != NB_OP_GET_NEXT
- && operation != NB_OP_GET_KEYS && operation != NB_OP_LOOKUP_ENTRY)
+ if (!valid && callback_implemented && operation != NB_CB_GET_NEXT
+ && operation != NB_CB_GET_KEYS && operation != NB_CB_LOOKUP_ENTRY)
flog_warn(EC_LIB_NB_CB_UNNEEDED,
"unneeded '%s' callback for '%s'",
- nb_operation_name(operation), nb_node->xpath);
+ nb_cb_operation_name(operation), nb_node->xpath);
if (!optional && valid && !callback_implemented) {
flog_err(EC_LIB_NB_CB_MISSING, "missing '%s' callback for '%s'",
- nb_operation_name(operation), nb_node->xpath);
+ nb_cb_operation_name(operation), nb_node->xpath);
return 1;
}
@@ -253,27 +253,27 @@ static unsigned int nb_node_validate_cbs(const struct nb_node *nb_node)
if (CHECK_FLAG(nb_node->flags, F_NB_NODE_IGNORE_CFG_CBS))
return error;
- error += nb_node_validate_cb(nb_node, NB_OP_CREATE,
+ error += nb_node_validate_cb(nb_node, NB_CB_CREATE,
!!nb_node->cbs.create, false);
- error += nb_node_validate_cb(nb_node, NB_OP_MODIFY,
+ error += nb_node_validate_cb(nb_node, NB_CB_MODIFY,
!!nb_node->cbs.modify, false);
- error += nb_node_validate_cb(nb_node, NB_OP_DESTROY,
+ error += nb_node_validate_cb(nb_node, NB_CB_DESTROY,
!!nb_node->cbs.destroy, false);
- error += nb_node_validate_cb(nb_node, NB_OP_MOVE, !!nb_node->cbs.move,
+ error += nb_node_validate_cb(nb_node, NB_CB_MOVE, !!nb_node->cbs.move,
false);
- error += nb_node_validate_cb(nb_node, NB_OP_PRE_VALIDATE,
+ error += nb_node_validate_cb(nb_node, NB_CB_PRE_VALIDATE,
!!nb_node->cbs.pre_validate, true);
- error += nb_node_validate_cb(nb_node, NB_OP_APPLY_FINISH,
+ error += nb_node_validate_cb(nb_node, NB_CB_APPLY_FINISH,
!!nb_node->cbs.apply_finish, true);
- error += nb_node_validate_cb(nb_node, NB_OP_GET_ELEM,
+ error += nb_node_validate_cb(nb_node, NB_CB_GET_ELEM,
!!nb_node->cbs.get_elem, false);
- error += nb_node_validate_cb(nb_node, NB_OP_GET_NEXT,
+ error += nb_node_validate_cb(nb_node, NB_CB_GET_NEXT,
!!nb_node->cbs.get_next, false);
- error += nb_node_validate_cb(nb_node, NB_OP_GET_KEYS,
+ error += nb_node_validate_cb(nb_node, NB_CB_GET_KEYS,
!!nb_node->cbs.get_keys, false);
- error += nb_node_validate_cb(nb_node, NB_OP_LOOKUP_ENTRY,
+ error += nb_node_validate_cb(nb_node, NB_CB_LOOKUP_ENTRY,
!!nb_node->cbs.lookup_entry, false);
- error += nb_node_validate_cb(nb_node, NB_OP_RPC, !!nb_node->cbs.rpc,
+ error += nb_node_validate_cb(nb_node, NB_CB_RPC, !!nb_node->cbs.rpc,
false);
return error;
@@ -409,7 +409,7 @@ static inline int nb_config_cb_compare(const struct nb_config_cb *a,
RB_GENERATE(nb_config_cbs, nb_config_cb, entry, nb_config_cb_compare);
static void nb_config_diff_add_change(struct nb_config_cbs *changes,
- enum nb_operation operation,
+ enum nb_cb_operation operation,
uint32_t *seq,
const struct lyd_node *dnode)
{
@@ -449,7 +449,7 @@ void nb_config_diff_del_changes(struct nb_config_cbs *changes)
void nb_config_diff_created(const struct lyd_node *dnode, uint32_t *seq,
struct nb_config_cbs *changes)
{
- enum nb_operation operation;
+ enum nb_cb_operation operation;
struct lyd_node *child;
/* Ignore unimplemented nodes. */
@@ -462,10 +462,10 @@ void nb_config_diff_created(const struct lyd_node *dnode, uint32_t *seq,
if (lyd_is_default(dnode))
break;
- if (nb_operation_is_valid(NB_OP_CREATE, dnode->schema))
- operation = NB_OP_CREATE;
- else if (nb_operation_is_valid(NB_OP_MODIFY, dnode->schema))
- operation = NB_OP_MODIFY;
+ if (nb_cb_operation_is_valid(NB_CB_CREATE, dnode->schema))
+ operation = NB_CB_CREATE;
+ else if (nb_cb_operation_is_valid(NB_CB_MODIFY, dnode->schema))
+ operation = NB_CB_MODIFY;
else
return;
@@ -473,8 +473,8 @@ void nb_config_diff_created(const struct lyd_node *dnode, uint32_t *seq,
break;
case LYS_CONTAINER:
case LYS_LIST:
- if (nb_operation_is_valid(NB_OP_CREATE, dnode->schema))
- nb_config_diff_add_change(changes, NB_OP_CREATE, seq,
+ if (nb_cb_operation_is_valid(NB_CB_CREATE, dnode->schema))
+ nb_config_diff_add_change(changes, NB_CB_CREATE, seq,
dnode);
/* Process child nodes recursively. */
@@ -494,8 +494,8 @@ static void nb_config_diff_deleted(const struct lyd_node *dnode, uint32_t *seq,
if (!dnode->schema->priv)
return;
- if (nb_operation_is_valid(NB_OP_DESTROY, dnode->schema))
- nb_config_diff_add_change(changes, NB_OP_DESTROY, seq, dnode);
+ if (nb_cb_operation_is_valid(NB_CB_DESTROY, dnode->schema))
+ nb_config_diff_add_change(changes, NB_CB_DESTROY, seq, dnode);
else if (CHECK_FLAG(dnode->schema->nodetype, LYS_CONTAINER)) {
struct lyd_node *child;
@@ -644,7 +644,7 @@ void nb_config_diff(const struct nb_config *config1,
/* either moving an entry or changing a value */
target = yang_dnode_get(config2->dnode, path);
assert(target);
- nb_config_diff_add_change(changes, NB_OP_MODIFY,
+ nb_config_diff_add_change(changes, NB_CB_MODIFY,
&seq, target);
break;
case 'n': /* none */
@@ -659,15 +659,42 @@ void nb_config_diff(const struct nb_config *config1,
lyd_free_all(diff);
}
+static int dnode_create(struct nb_config *candidate, const char *xpath,
+ const char *value, uint32_t options,
+ struct lyd_node **new_dnode)
+{
+ struct lyd_node *dnode;
+ LY_ERR err;
+
+ err = lyd_new_path(candidate->dnode, ly_native_ctx, xpath, value,
+ options, &dnode);
+ if (err) {
+ flog_warn(EC_LIB_LIBYANG, "%s: lyd_new_path(%s) failed: %d",
+ __func__, xpath, err);
+ return NB_ERR;
+ } else if (dnode) {
+ err = lyd_new_implicit_tree(dnode, LYD_IMPLICIT_NO_STATE, NULL);
+ if (err) {
+ flog_warn(EC_LIB_LIBYANG,
+ "%s: lyd_new_implicit_all failed: %d",
+ __func__, err);
+ }
+ }
+ if (new_dnode)
+ *new_dnode = dnode;
+ return NB_OK;
+}
+
int nb_candidate_edit(struct nb_config *candidate,
const struct nb_node *nb_node,
enum nb_operation operation, const char *xpath,
const struct yang_data *previous,
const struct yang_data *data)
{
- struct lyd_node *dnode, *dep_dnode;
+ struct lyd_node *dnode, *dep_dnode, *old_dnode, *parent;
char xpath_edit[XPATH_MAXLEN];
char dep_xpath[XPATH_MAXLEN];
+ uint32_t options = 0;
LY_ERR err;
/* Use special notation for leaf-lists (RFC 6020, section 9.13.5). */
@@ -680,23 +707,14 @@ int nb_candidate_edit(struct nb_config *candidate,
switch (operation) {
case NB_OP_CREATE:
case NB_OP_MODIFY:
- err = lyd_new_path(candidate->dnode, ly_native_ctx, xpath_edit,
- (void *)data->value, LYD_NEW_PATH_UPDATE,
+ options = LYD_NEW_PATH_UPDATE;
+ fallthrough;
+ case NB_OP_CREATE_EXCL:
+ err = dnode_create(candidate, xpath_edit, data->value, options,
&dnode);
if (err) {
- flog_warn(EC_LIB_LIBYANG,
- "%s: lyd_new_path(%s) failed: %d", __func__,
- xpath_edit, err);
- return NB_ERR;
+ return err;
} else if (dnode) {
- /* Create default nodes */
- LY_ERR err = lyd_new_implicit_tree(
- dnode, LYD_IMPLICIT_NO_STATE, NULL);
- if (err) {
- flog_warn(EC_LIB_LIBYANG,
- "%s: lyd_new_implicit_all failed: %d",
- __func__, err);
- }
/*
* create dependency
*
@@ -708,33 +726,24 @@ int nb_candidate_edit(struct nb_config *candidate,
nb_node->dep_cbs.get_dependency_xpath(
dnode, dep_xpath);
- err = lyd_new_path(candidate->dnode,
- ly_native_ctx, dep_xpath,
- NULL, LYD_NEW_PATH_UPDATE,
- &dep_dnode);
- /* Create default nodes */
- if (!err && dep_dnode)
- err = lyd_new_implicit_tree(
- dep_dnode,
- LYD_IMPLICIT_NO_STATE, NULL);
+ err = dnode_create(candidate, dep_xpath, NULL,
+ LYD_NEW_PATH_UPDATE, NULL);
if (err) {
- flog_warn(
- EC_LIB_LIBYANG,
- "%s: dependency: lyd_new_path(%s) failed: %d",
- __func__, dep_xpath, err);
- return NB_ERR;
+ lyd_free_tree(dnode);
+ return err;
}
}
}
break;
case NB_OP_DESTROY:
+ case NB_OP_DELETE:
dnode = yang_dnode_get(candidate->dnode, xpath_edit);
- if (!dnode)
- /*
- * Return a special error code so the caller can choose
- * whether to ignore it or not.
- */
- return NB_ERR_NOT_FOUND;
+ if (!dnode) {
+ if (operation == NB_OP_DELETE)
+ return NB_ERR;
+ else
+ return NB_OK;
+ }
/* destroy dependant */
if (nb_node->dep_cbs.get_dependant_xpath) {
nb_node->dep_cbs.get_dependant_xpath(dnode, dep_xpath);
@@ -745,32 +754,76 @@ int nb_candidate_edit(struct nb_config *candidate,
}
lyd_free_tree(dnode);
break;
+ case NB_OP_REPLACE:
+ old_dnode = yang_dnode_get(candidate->dnode, xpath_edit);
+ if (old_dnode) {
+ parent = lyd_parent(old_dnode);
+ lyd_unlink_tree(old_dnode);
+ }
+ err = dnode_create(candidate, xpath_edit, data->value, options,
+ &dnode);
+ if (!err && dnode && !old_dnode) {
+ /* create dependency if the node didn't exist */
+ nb_node = dnode->schema->priv;
+ if (nb_node->dep_cbs.get_dependency_xpath) {
+ nb_node->dep_cbs.get_dependency_xpath(
+ dnode, dep_xpath);
+
+ err = dnode_create(candidate, dep_xpath, NULL,
+ LYD_NEW_PATH_UPDATE, NULL);
+ if (err)
+ lyd_free_tree(dnode);
+ }
+ }
+ if (old_dnode) {
+ /* restore original node on error, free it otherwise */
+ if (err) {
+ if (parent)
+ lyd_insert_child(parent, old_dnode);
+ else
+ lyd_insert_sibling(candidate->dnode,
+ old_dnode, NULL);
+ return err;
+ }
+
+ lyd_free_tree(old_dnode);
+ }
+ break;
case NB_OP_MOVE:
/* TODO: update configuration. */
break;
- case NB_OP_PRE_VALIDATE:
- case NB_OP_APPLY_FINISH:
- case NB_OP_GET_ELEM:
- case NB_OP_GET_NEXT:
- case NB_OP_GET_KEYS:
- case NB_OP_LOOKUP_ENTRY:
- case NB_OP_RPC:
- flog_warn(EC_LIB_DEVELOPMENT,
- "%s: unknown operation (%u) [xpath %s]", __func__,
- operation, xpath_edit);
- return NB_ERR;
}
return NB_OK;
}
-static bool nb_is_operation_allowed(struct nb_node *nb_node,
- struct nb_cfg_change *change)
+const char *nb_operation_name(enum nb_operation operation)
{
- enum nb_operation oper = change->operation;
+ switch (operation) {
+ case NB_OP_CREATE_EXCL:
+ return "create exclusive";
+ case NB_OP_CREATE:
+ return "create";
+ case NB_OP_MODIFY:
+ return "modify";
+ case NB_OP_DESTROY:
+ return "destroy";
+ case NB_OP_DELETE:
+ return "delete";
+ case NB_OP_REPLACE:
+ return "replace";
+ case NB_OP_MOVE:
+ return "move";
+ }
+
+ assert(!"Reached end of function we should never hit");
+}
+bool nb_is_operation_allowed(struct nb_node *nb_node, enum nb_operation oper)
+{
if (lysc_is_key(nb_node->snode)) {
- if (oper == NB_OP_MODIFY || oper == NB_OP_DESTROY)
+ if (oper == NB_OP_MODIFY || oper == NB_OP_DESTROY
+ || oper == NB_OP_DELETE || oper == NB_OP_REPLACE)
return false;
}
return true;
@@ -815,7 +868,7 @@ void nb_candidate_edit_config_changes(
continue;
}
/* Find if the node to be edited is not a key node */
- if (!nb_is_operation_allowed(nb_node, change)) {
+ if (!nb_is_operation_allowed(nb_node, change->operation)) {
zlog_err(" Xpath %s points to key node", xpath);
if (error)
*error = true;
@@ -835,7 +888,7 @@ void nb_candidate_edit_config_changes(
ret = nb_candidate_edit(candidate_config, nb_node,
change->operation, xpath, NULL, data);
yang_data_free(data);
- if (ret != NB_OK && ret != NB_ERR_NOT_FOUND) {
+ if (ret != NB_OK) {
flog_warn(
EC_LIB_NB_CANDIDATE_EDIT_ERROR,
"%s: failed to edit candidate configuration: operation [%s] xpath [%s]",
@@ -1140,7 +1193,7 @@ int nb_running_lock_check(enum nb_client client, const void *user)
}
static void nb_log_config_callback(const enum nb_event event,
- enum nb_operation operation,
+ enum nb_cb_operation operation,
const struct lyd_node *dnode)
{
const char *value;
@@ -1157,7 +1210,7 @@ static void nb_log_config_callback(const enum nb_event event,
zlog_debug(
"northbound callback: event [%s] op [%s] xpath [%s] value [%s]",
- nb_event_name(event), nb_operation_name(operation), xpath,
+ nb_event_name(event), nb_cb_operation_name(operation), xpath,
value);
}
@@ -1173,7 +1226,7 @@ static int nb_callback_create(struct nb_context *context,
assert(!CHECK_FLAG(nb_node->flags, F_NB_NODE_IGNORE_CFG_CBS));
- nb_log_config_callback(event, NB_OP_CREATE, dnode);
+ nb_log_config_callback(event, NB_CB_CREATE, dnode);
args.context = context;
args.event = event;
@@ -1224,7 +1277,7 @@ static int nb_callback_modify(struct nb_context *context,
assert(!CHECK_FLAG(nb_node->flags, F_NB_NODE_IGNORE_CFG_CBS));
- nb_log_config_callback(event, NB_OP_MODIFY, dnode);
+ nb_log_config_callback(event, NB_CB_MODIFY, dnode);
args.context = context;
args.event = event;
@@ -1275,7 +1328,7 @@ static int nb_callback_destroy(struct nb_context *context,
assert(!CHECK_FLAG(nb_node->flags, F_NB_NODE_IGNORE_CFG_CBS));
- nb_log_config_callback(event, NB_OP_DESTROY, dnode);
+ nb_log_config_callback(event, NB_CB_DESTROY, dnode);
args.context = context;
args.event = event;
@@ -1320,7 +1373,7 @@ static int nb_callback_move(struct nb_context *context,
assert(!CHECK_FLAG(nb_node->flags, F_NB_NODE_IGNORE_CFG_CBS));
- nb_log_config_callback(event, NB_OP_MOVE, dnode);
+ nb_log_config_callback(event, NB_CB_MOVE, dnode);
args.context = context;
args.event = event;
@@ -1366,7 +1419,7 @@ static int nb_callback_pre_validate(struct nb_context *context,
if (CHECK_FLAG(nb_node->flags, F_NB_NODE_IGNORE_CFG_CBS))
return 0;
- nb_log_config_callback(NB_EV_VALIDATE, NB_OP_PRE_VALIDATE, dnode);
+ nb_log_config_callback(NB_EV_VALIDATE, NB_CB_PRE_VALIDATE, dnode);
args.dnode = dnode;
args.errmsg = errmsg;
@@ -1400,7 +1453,7 @@ static void nb_callback_apply_finish(struct nb_context *context,
if (CHECK_FLAG(nb_node->flags, F_NB_NODE_IGNORE_CFG_CBS))
return;
- nb_log_config_callback(NB_EV_APPLY, NB_OP_APPLY_FINISH, dnode);
+ nb_log_config_callback(NB_EV_APPLY, NB_CB_APPLY_FINISH, dnode);
args.context = context;
args.dnode = dnode;
@@ -1552,7 +1605,7 @@ static int nb_callback_configuration(struct nb_context *context,
struct nb_config_change *change,
char *errmsg, size_t errmsg_len)
{
- enum nb_operation operation = change->cb.operation;
+ enum nb_cb_operation operation = change->cb.operation;
char xpath[XPATH_MAXLEN];
const struct nb_node *nb_node = change->cb.nb_node;
const struct lyd_node *dnode = change->cb.dnode;
@@ -1568,29 +1621,29 @@ static int nb_callback_configuration(struct nb_context *context,
resource = &change->resource;
switch (operation) {
- case NB_OP_CREATE:
+ case NB_CB_CREATE:
ret = nb_callback_create(context, nb_node, event, dnode,
resource, errmsg, errmsg_len);
break;
- case NB_OP_MODIFY:
+ case NB_CB_MODIFY:
ret = nb_callback_modify(context, nb_node, event, dnode,
resource, errmsg, errmsg_len);
break;
- case NB_OP_DESTROY:
+ case NB_CB_DESTROY:
ret = nb_callback_destroy(context, nb_node, event, dnode,
errmsg, errmsg_len);
break;
- case NB_OP_MOVE:
+ case NB_CB_MOVE:
ret = nb_callback_move(context, nb_node, event, dnode, errmsg,
errmsg_len);
break;
- case NB_OP_PRE_VALIDATE:
- case NB_OP_APPLY_FINISH:
- case NB_OP_GET_ELEM:
- case NB_OP_GET_NEXT:
- case NB_OP_GET_KEYS:
- case NB_OP_LOOKUP_ENTRY:
- case NB_OP_RPC:
+ case NB_CB_PRE_VALIDATE:
+ case NB_CB_APPLY_FINISH:
+ case NB_CB_GET_ELEM:
+ case NB_CB_GET_NEXT:
+ case NB_CB_GET_KEYS:
+ case NB_CB_LOOKUP_ENTRY:
+ case NB_CB_RPC:
yang_dnode_get_path(dnode, xpath, sizeof(xpath));
flog_err(EC_LIB_DEVELOPMENT,
"%s: unknown operation (%u) [xpath %s]", __func__,
@@ -1606,28 +1659,28 @@ static int nb_callback_configuration(struct nb_context *context,
flog_warn(EC_LIB_NB_CB_CONFIG_VALIDATE,
"error processing configuration change: error [%s] event [%s] operation [%s] xpath [%s]%s%s",
nb_err_name(ret), nb_event_name(event),
- nb_operation_name(operation), xpath,
+ nb_cb_operation_name(operation), xpath,
errmsg[0] ? " message: " : "", errmsg);
break;
case NB_EV_PREPARE:
flog_warn(EC_LIB_NB_CB_CONFIG_PREPARE,
"error processing configuration change: error [%s] event [%s] operation [%s] xpath [%s]%s%s",
nb_err_name(ret), nb_event_name(event),
- nb_operation_name(operation), xpath,
+ nb_cb_operation_name(operation), xpath,
errmsg[0] ? " message: " : "", errmsg);
break;
case NB_EV_ABORT:
flog_warn(EC_LIB_NB_CB_CONFIG_ABORT,
"error processing configuration change: error [%s] event [%s] operation [%s] xpath [%s]%s%s",
nb_err_name(ret), nb_event_name(event),
- nb_operation_name(operation), xpath,
+ nb_cb_operation_name(operation), xpath,
errmsg[0] ? " message: " : "", errmsg);
break;
case NB_EV_APPLY:
flog_err(EC_LIB_NB_CB_CONFIG_APPLY,
"error processing configuration change: error [%s] event [%s] operation [%s] xpath [%s]%s%s",
nb_err_name(ret), nb_event_name(event),
- nb_operation_name(operation), xpath,
+ nb_cb_operation_name(operation), xpath,
errmsg[0] ? " message: " : "", errmsg);
break;
default:
@@ -1775,7 +1828,7 @@ static void nb_transaction_apply_finish(struct nb_transaction *transaction,
* (the 'apply_finish' callbacks from the node ancestors should
* be called though).
*/
- if (change->cb.operation == NB_OP_DESTROY) {
+ if (change->cb.operation == NB_CB_DESTROY) {
char xpath[XPATH_MAXLEN];
dnode = lyd_parent(dnode);
@@ -1826,15 +1879,15 @@ static void nb_transaction_apply_finish(struct nb_transaction *transaction,
}
}
-bool nb_operation_is_valid(enum nb_operation operation,
- const struct lysc_node *snode)
+bool nb_cb_operation_is_valid(enum nb_cb_operation operation,
+ const struct lysc_node *snode)
{
struct nb_node *nb_node = snode->priv;
struct lysc_node_container *scontainer;
struct lysc_node_leaf *sleaf;
switch (operation) {
- case NB_OP_CREATE:
+ case NB_CB_CREATE:
if (!CHECK_FLAG(snode->flags, LYS_CONFIG_W))
return false;
@@ -1856,7 +1909,7 @@ bool nb_operation_is_valid(enum nb_operation operation,
return false;
}
return true;
- case NB_OP_MODIFY:
+ case NB_CB_MODIFY:
if (!CHECK_FLAG(snode->flags, LYS_CONFIG_W))
return false;
@@ -1874,7 +1927,7 @@ bool nb_operation_is_valid(enum nb_operation operation,
return false;
}
return true;
- case NB_OP_DESTROY:
+ case NB_CB_DESTROY:
if (!CHECK_FLAG(snode->flags, LYS_CONFIG_W))
return false;
@@ -1910,7 +1963,7 @@ bool nb_operation_is_valid(enum nb_operation operation,
return false;
}
return true;
- case NB_OP_MOVE:
+ case NB_CB_MOVE:
if (!CHECK_FLAG(snode->flags, LYS_CONFIG_W))
return false;
@@ -1924,12 +1977,12 @@ bool nb_operation_is_valid(enum nb_operation operation,
return false;
}
return true;
- case NB_OP_PRE_VALIDATE:
- case NB_OP_APPLY_FINISH:
+ case NB_CB_PRE_VALIDATE:
+ case NB_CB_APPLY_FINISH:
if (!CHECK_FLAG(snode->flags, LYS_CONFIG_W))
return false;
return true;
- case NB_OP_GET_ELEM:
+ case NB_CB_GET_ELEM:
if (!CHECK_FLAG(snode->flags, LYS_CONFIG_R))
return false;
@@ -1946,7 +1999,7 @@ bool nb_operation_is_valid(enum nb_operation operation,
return false;
}
return true;
- case NB_OP_GET_NEXT:
+ case NB_CB_GET_NEXT:
switch (snode->nodetype) {
case LYS_LIST:
if (CHECK_FLAG(nb_node->flags, F_NB_NODE_CONFIG_ONLY))
@@ -1960,8 +2013,8 @@ bool nb_operation_is_valid(enum nb_operation operation,
return false;
}
return true;
- case NB_OP_GET_KEYS:
- case NB_OP_LOOKUP_ENTRY:
+ case NB_CB_GET_KEYS:
+ case NB_CB_LOOKUP_ENTRY:
switch (snode->nodetype) {
case LYS_LIST:
if (CHECK_FLAG(nb_node->flags, F_NB_NODE_CONFIG_ONLY))
@@ -1973,7 +2026,7 @@ bool nb_operation_is_valid(enum nb_operation operation,
return false;
}
return true;
- case NB_OP_RPC:
+ case NB_CB_RPC:
if (CHECK_FLAG(snode->flags, LYS_CONFIG_W | LYS_CONFIG_R))
return false;
@@ -2175,30 +2228,30 @@ const char *nb_event_name(enum nb_event event)
assert(!"Reached end of function we should never hit");
}
-const char *nb_operation_name(enum nb_operation operation)
+const char *nb_cb_operation_name(enum nb_cb_operation operation)
{
switch (operation) {
- case NB_OP_CREATE:
+ case NB_CB_CREATE:
return "create";
- case NB_OP_MODIFY:
+ case NB_CB_MODIFY:
return "modify";
- case NB_OP_DESTROY:
+ case NB_CB_DESTROY:
return "destroy";
- case NB_OP_MOVE:
+ case NB_CB_MOVE:
return "move";
- case NB_OP_PRE_VALIDATE:
+ case NB_CB_PRE_VALIDATE:
return "pre_validate";
- case NB_OP_APPLY_FINISH:
+ case NB_CB_APPLY_FINISH:
return "apply_finish";
- case NB_OP_GET_ELEM:
+ case NB_CB_GET_ELEM:
return "get_elem";
- case NB_OP_GET_NEXT:
+ case NB_CB_GET_NEXT:
return "get_next";
- case NB_OP_GET_KEYS:
+ case NB_CB_GET_KEYS:
return "get_keys";
- case NB_OP_LOOKUP_ENTRY:
+ case NB_CB_LOOKUP_ENTRY:
return "lookup_entry";
- case NB_OP_RPC:
+ case NB_CB_RPC:
return "rpc";
}
diff --git a/lib/northbound.h b/lib/northbound.h
index 2c238f3bc..4f9ab565d 100644
--- a/lib/northbound.h
+++ b/lib/northbound.h
@@ -83,28 +83,22 @@ enum nb_event {
};
/*
- * Northbound operations.
+ * Northbound callback operations.
*
* Refer to the documentation comments of nb_callbacks for more details.
*/
-enum nb_operation {
- NB_OP_CREATE,
- NB_OP_MODIFY,
- NB_OP_DESTROY,
- NB_OP_MOVE,
- NB_OP_PRE_VALIDATE,
- NB_OP_APPLY_FINISH,
- NB_OP_GET_ELEM,
- NB_OP_GET_NEXT,
- NB_OP_GET_KEYS,
- NB_OP_LOOKUP_ENTRY,
- NB_OP_RPC,
-};
-
-struct nb_cfg_change {
- char xpath[XPATH_MAXLEN];
- enum nb_operation operation;
- const char *value;
+enum nb_cb_operation {
+ NB_CB_CREATE,
+ NB_CB_MODIFY,
+ NB_CB_DESTROY,
+ NB_CB_MOVE,
+ NB_CB_PRE_VALIDATE,
+ NB_CB_APPLY_FINISH,
+ NB_CB_GET_ELEM,
+ NB_CB_GET_NEXT,
+ NB_CB_GET_KEYS,
+ NB_CB_LOOKUP_ENTRY,
+ NB_CB_RPC,
};
union nb_resource {
@@ -694,7 +688,7 @@ struct nb_context {
/* Northbound configuration callback. */
struct nb_config_cb {
RB_ENTRY(nb_config_cb) entry;
- enum nb_operation operation;
+ enum nb_cb_operation operation;
uint32_t seq;
const struct nb_node *nb_node;
const struct lyd_node *dnode;
@@ -723,6 +717,26 @@ struct nb_config {
uint32_t version;
};
+/*
+ * Northbound operations. The semantics of operations is explained in RFC 8072,
+ * section 2.5: https://datatracker.ietf.org/doc/html/rfc8072#section-2.5.
+ */
+enum nb_operation {
+ NB_OP_CREATE_EXCL, /* "create" */
+ NB_OP_CREATE, /* "merge" - kept for backward compatibility */
+ NB_OP_MODIFY, /* "merge" */
+ NB_OP_DESTROY, /* "remove" */
+ NB_OP_DELETE, /* "delete" */
+ NB_OP_REPLACE, /* "replace" */
+ NB_OP_MOVE, /* "move" */
+};
+
+struct nb_cfg_change {
+ char xpath[XPATH_MAXLEN];
+ enum nb_operation operation;
+ const char *value;
+};
+
/* Callback function used by nb_oper_data_iterate(). */
typedef int (*nb_oper_data_cb)(const struct lysc_node *snode,
struct yang_translator *translator,
@@ -896,6 +910,32 @@ extern void nb_config_replace(struct nb_config *config_dst,
bool preserve_source);
/*
+ * Return a human-readable string representing a northbound operation.
+ *
+ * operation
+ * Northbound operation.
+ *
+ * Returns:
+ * String representation of the given northbound operation.
+ */
+extern const char *nb_operation_name(enum nb_operation operation);
+
+/*
+ * Validate if the northbound operation is allowed for the given node.
+ *
+ * nb_node
+ * Northbound node.
+ *
+ * operation
+ * Operation we want to check.
+ *
+ * Returns:
+ * true if the operation is allowed, false otherwise.
+ */
+extern bool nb_is_operation_allowed(struct nb_node *nb_node,
+ enum nb_operation oper);
+
+/*
* Edit a candidate configuration.
*
* candidate
@@ -919,7 +959,6 @@ extern void nb_config_replace(struct nb_config *config_dst,
*
* Returns:
* - NB_OK on success.
- * - NB_ERR_NOT_FOUND when the element to be deleted was not found.
* - NB_ERR for other errors.
*/
extern int nb_candidate_edit(struct nb_config *candidate,
@@ -1369,7 +1408,7 @@ extern void nb_oper_cancel_walk(void *walk);
extern void nb_oper_cancel_all_walks(void);
/*
- * Validate if the northbound operation is valid for the given node.
+ * Validate if the northbound callback operation is valid for the given node.
*
* operation
* Operation we want to check.
@@ -1380,8 +1419,8 @@ extern void nb_oper_cancel_all_walks(void);
* Returns:
* true if the operation is valid, false otherwise.
*/
-extern bool nb_operation_is_valid(enum nb_operation operation,
- const struct lysc_node *snode);
+extern bool nb_cb_operation_is_valid(enum nb_cb_operation operation,
+ const struct lysc_node *snode);
/*
* Send a YANG notification. This is a no-op unless the 'nb_notification_send'
@@ -1505,15 +1544,15 @@ extern void *nb_running_get_entry_non_rec(const struct lyd_node *dnode,
extern const char *nb_event_name(enum nb_event event);
/*
- * Return a human-readable string representing a northbound operation.
+ * Return a human-readable string representing a northbound callback operation.
*
* operation
- * Northbound operation.
+ * Northbound callback operation.
*
* Returns:
- * String representation of the given northbound operation.
+ * String representation of the given northbound callback operation.
*/
-extern const char *nb_operation_name(enum nb_operation operation);
+extern const char *nb_cb_operation_name(enum nb_cb_operation operation);
/*
* Return a human-readable string representing a northbound error.
diff --git a/lib/northbound_cli.h b/lib/northbound_cli.h
index c8f8a8481..1a45794d4 100644
--- a/lib/northbound_cli.h
+++ b/lib/northbound_cli.h
@@ -32,7 +32,7 @@ extern struct nb_config *vty_shared_candidate_config;
* XPath (absolute or relative) of the configuration option being edited.
*
* operation
- * Operation to apply (either NB_OP_CREATE, NB_OP_MODIFY or NB_OP_DELETE).
+ * Operation to apply (either NB_OP_CREATE, NB_OP_MODIFY or NB_OP_DESTROY).
*
* value
* New value of the configuration option. Should be NULL for typeless YANG
diff --git a/lib/northbound_confd.c b/lib/northbound_confd.c
index 34406a110..8503d1800 100644
--- a/lib/northbound_confd.c
+++ b/lib/northbound_confd.c
@@ -221,7 +221,7 @@ frr_confd_cdb_diff_iter(confd_hkeypath_t *kp, enum cdb_iter_op cdb_op,
nb_op = NB_OP_DESTROY;
break;
case MOP_VALUE_SET:
- if (nb_operation_is_valid(NB_OP_MODIFY, nb_node->snode))
+ if (nb_is_operation_allowed(nb_node, NB_OP_MODIFY))
nb_op = NB_OP_MODIFY;
else
/* Ignore list keys modifications. */
diff --git a/lib/northbound_sysrepo.c b/lib/northbound_sysrepo.c
index 535c8b637..198d96e38 100644
--- a/lib/northbound_sysrepo.c
+++ b/lib/northbound_sysrepo.c
@@ -186,12 +186,12 @@ static int frr_sr_process_change(struct nb_config *candidate,
/* Map operation values. */
switch (sr_op) {
case SR_OP_CREATED:
+ nb_op = NB_OP_CREATE;
+ break;
case SR_OP_MODIFIED:
- if (nb_operation_is_valid(NB_OP_CREATE, nb_node->snode))
- nb_op = NB_OP_CREATE;
- else if (nb_operation_is_valid(NB_OP_MODIFY, nb_node->snode)) {
+ if (nb_is_operation_allowed(nb_node, NB_OP_MODIFY))
nb_op = NB_OP_MODIFY;
- } else
+ else
/* Ignore list keys modifications. */
return NB_OK;
break;
@@ -201,7 +201,7 @@ static int frr_sr_process_change(struct nb_config *candidate,
* notified about the removal of all of its leafs, even the ones
* that are non-optional. We need to ignore these notifications.
*/
- if (!nb_operation_is_valid(NB_OP_DESTROY, nb_node->snode))
+ if (!nb_is_operation_allowed(nb_node, NB_OP_DESTROY))
return NB_OK;
nb_op = NB_OP_DESTROY;
@@ -221,7 +221,7 @@ static int frr_sr_process_change(struct nb_config *candidate,
ret = nb_candidate_edit(candidate, nb_node, nb_op, xpath, NULL, data);
yang_data_free(data);
- if (ret != NB_OK && ret != NB_ERR_NOT_FOUND) {
+ if (ret != NB_OK) {
flog_warn(
EC_LIB_NB_CANDIDATE_EDIT_ERROR,
"%s: failed to edit candidate configuration: operation [%s] xpath [%s]",
diff --git a/lib/vty.c b/lib/vty.c
index c7029bdcb..5f9f0dc24 100644
--- a/lib/vty.c
+++ b/lib/vty.c
@@ -3996,24 +3996,32 @@ int vty_mgmt_send_config_data(struct vty *vty, const char *xpath_base,
mgmt_yang_cfg_data_req_init(&cfg_req[indx]);
cfg_req[indx].data = &cfg_data[indx];
switch (vty->cfg_changes[indx].operation) {
- case NB_OP_DESTROY:
+ case NB_OP_DELETE:
cfg_req[indx].req_type =
MGMTD__CFG_DATA_REQ_TYPE__DELETE_DATA;
break;
+ case NB_OP_DESTROY:
+ cfg_req[indx].req_type =
+ MGMTD__CFG_DATA_REQ_TYPE__REMOVE_DATA;
+ break;
+
+ case NB_OP_CREATE_EXCL:
+ cfg_req[indx].req_type =
+ MGMTD__CFG_DATA_REQ_TYPE__CREATE_DATA;
+ break;
+
+ case NB_OP_REPLACE:
+ cfg_req[indx].req_type =
+ MGMTD__CFG_DATA_REQ_TYPE__REPLACE_DATA;
+ break;
+
case NB_OP_CREATE:
case NB_OP_MODIFY:
case NB_OP_MOVE:
- case NB_OP_PRE_VALIDATE:
- case NB_OP_APPLY_FINISH:
cfg_req[indx].req_type =
MGMTD__CFG_DATA_REQ_TYPE__SET_DATA;
break;
- case NB_OP_GET_ELEM:
- case NB_OP_GET_NEXT:
- case NB_OP_GET_KEYS:
- case NB_OP_LOOKUP_ENTRY:
- case NB_OP_RPC:
default:
assertf(false,
"Invalid operation type for send config: %d",
diff --git a/mgmtd/mgmt_txn.c b/mgmtd/mgmt_txn.c
index 998e5a383..76ea5c63c 100644
--- a/mgmtd/mgmt_txn.c
+++ b/mgmtd/mgmt_txn.c
@@ -909,9 +909,14 @@ static int mgmt_txn_create_config_batches(struct mgmt_txn_req *txn_req,
batch->cfg_datap[batch->num_cfg_data] =
&batch->cfg_data[batch->num_cfg_data];
- if (chg->cb.operation == NB_OP_DESTROY)
+ /*
+ * On the backend, we don't really care if it's CREATE
+ * or MODIFY, because the existence was already checked
+ * on the frontend. Therefore we use SET for both.
+ */
+ if (chg->cb.operation == NB_CB_DESTROY)
batch->cfg_data[batch->num_cfg_data].req_type =
- MGMTD__CFG_DATA_REQ_TYPE__DELETE_DATA;
+ MGMTD__CFG_DATA_REQ_TYPE__REMOVE_DATA;
else
batch->cfg_data[batch->num_cfg_data].req_type =
MGMTD__CFG_DATA_REQ_TYPE__SET_DATA;
@@ -2026,6 +2031,7 @@ int mgmt_txn_send_set_config_req(uint64_t txn_id, uint64_t req_id,
size_t indx;
uint16_t *num_chgs;
struct nb_cfg_change *cfg_chg;
+ struct nb_node *node;
txn = mgmt_txn_id2ctx(txn_id);
if (!txn)
@@ -2044,20 +2050,36 @@ int mgmt_txn_send_set_config_req(uint64_t txn_id, uint64_t req_id,
for (indx = 0; indx < num_req; indx++) {
cfg_chg = &txn_req->req.set_cfg->cfg_changes[*num_chgs];
- if (cfg_req[indx]->req_type ==
- MGMTD__CFG_DATA_REQ_TYPE__DELETE_DATA)
+ switch (cfg_req[indx]->req_type) {
+ case MGMTD__CFG_DATA_REQ_TYPE__DELETE_DATA:
+ cfg_chg->operation = NB_OP_DELETE;
+ break;
+ case MGMTD__CFG_DATA_REQ_TYPE__REMOVE_DATA:
cfg_chg->operation = NB_OP_DESTROY;
- else if (cfg_req[indx]->req_type ==
- MGMTD__CFG_DATA_REQ_TYPE__SET_DATA)
- cfg_chg->operation =
- mgmt_ds_find_data_node_by_xpath(ds_ctx,
- cfg_req[indx]
- ->data
- ->xpath)
- ? NB_OP_MODIFY
- : NB_OP_CREATE;
- else
+ break;
+ case MGMTD__CFG_DATA_REQ_TYPE__SET_DATA:
+ /*
+ * For backward compatibility, we need to allow creating
+ * *new* list keys with SET_DATA operation. NB_OP_MODIFY
+ * is not allowed for keys, so use NB_OP_CREATE_EXCL.
+ */
+ node = nb_node_find(cfg_req[indx]->data->xpath);
+ if (node && lysc_is_key(node->snode))
+ cfg_chg->operation = NB_OP_CREATE_EXCL;
+ else
+ cfg_chg->operation = NB_OP_MODIFY;
+ break;
+ case MGMTD__CFG_DATA_REQ_TYPE__CREATE_DATA:
+ cfg_chg->operation = NB_OP_CREATE_EXCL;
+ break;
+ case MGMTD__CFG_DATA_REQ_TYPE__REPLACE_DATA:
+ cfg_chg->operation = NB_OP_REPLACE;
+ break;
+ case MGMTD__CFG_DATA_REQ_TYPE__REQ_TYPE_NONE:
+ case _MGMTD__CFG_DATA_REQ_TYPE_IS_INT_SIZE:
+ default:
continue;
+ }
MGMTD_TXN_DBG("XPath: '%s', Value: '%s'",
cfg_req[indx]->data->xpath,
diff --git a/mgmtd/mgmt_vty.c b/mgmtd/mgmt_vty.c
index 64abb462c..2591930e4 100644
--- a/mgmtd/mgmt_vty.c
+++ b/mgmtd/mgmt_vty.c
@@ -144,6 +144,23 @@ DEFPY(mgmt_commit,
return CMD_SUCCESS;
}
+DEFPY(mgmt_create_config_data, mgmt_create_config_data_cmd,
+ "mgmt create-config WORD$path VALUE",
+ MGMTD_STR
+ "Create configuration data\n"
+ "XPath expression specifying the YANG data path\n"
+ "Value of the data to create\n")
+{
+ strlcpy(vty->cfg_changes[0].xpath, path,
+ sizeof(vty->cfg_changes[0].xpath));
+ vty->cfg_changes[0].value = value;
+ vty->cfg_changes[0].operation = NB_OP_CREATE_EXCL;
+ vty->num_cfg_changes = 1;
+
+ vty_mgmt_send_config_data(vty, NULL, false);
+ return CMD_SUCCESS;
+}
+
DEFPY(mgmt_set_config_data, mgmt_set_config_data_cmd,
"mgmt set-config WORD$path VALUE",
MGMTD_STR
@@ -154,7 +171,7 @@ DEFPY(mgmt_set_config_data, mgmt_set_config_data_cmd,
strlcpy(vty->cfg_changes[0].xpath, path,
sizeof(vty->cfg_changes[0].xpath));
vty->cfg_changes[0].value = value;
- vty->cfg_changes[0].operation = NB_OP_CREATE;
+ vty->cfg_changes[0].operation = NB_OP_MODIFY;
vty->num_cfg_changes = 1;
vty_mgmt_send_config_data(vty, NULL, false);
@@ -171,6 +188,23 @@ DEFPY(mgmt_delete_config_data, mgmt_delete_config_data_cmd,
strlcpy(vty->cfg_changes[0].xpath, path,
sizeof(vty->cfg_changes[0].xpath));
vty->cfg_changes[0].value = NULL;
+ vty->cfg_changes[0].operation = NB_OP_DELETE;
+ vty->num_cfg_changes = 1;
+
+ vty_mgmt_send_config_data(vty, NULL, false);
+ return CMD_SUCCESS;
+}
+
+DEFPY(mgmt_remove_config_data, mgmt_remove_config_data_cmd,
+ "mgmt remove-config WORD$path",
+ MGMTD_STR
+ "Remove configuration data\n"
+ "XPath expression specifying the YANG data path\n")
+{
+
+ strlcpy(vty->cfg_changes[0].xpath, path,
+ sizeof(vty->cfg_changes[0].xpath));
+ vty->cfg_changes[0].value = NULL;
vty->cfg_changes[0].operation = NB_OP_DESTROY;
vty->num_cfg_changes = 1;
@@ -178,6 +212,24 @@ DEFPY(mgmt_delete_config_data, mgmt_delete_config_data_cmd,
return CMD_SUCCESS;
}
+DEFPY(mgmt_replace_config_data, mgmt_replace_config_data_cmd,
+ "mgmt replace-config WORD$path VALUE",
+ MGMTD_STR
+ "Replace configuration data\n"
+ "XPath expression specifying the YANG data path\n"
+ "Value of the data to set\n")
+{
+
+ strlcpy(vty->cfg_changes[0].xpath, path,
+ sizeof(vty->cfg_changes[0].xpath));
+ vty->cfg_changes[0].value = value;
+ vty->cfg_changes[0].operation = NB_OP_REPLACE;
+ vty->num_cfg_changes = 1;
+
+ vty_mgmt_send_config_data(vty, NULL, false);
+ return CMD_SUCCESS;
+}
+
DEFPY(show_mgmt_get_config, show_mgmt_get_config_cmd,
"show mgmt get-config [candidate|operational|running]$dsname WORD$path",
SHOW_STR MGMTD_STR
@@ -527,8 +579,11 @@ void mgmt_vty_init(void)
install_element(VIEW_NODE, &show_mgmt_cmt_hist_cmd);
install_element(CONFIG_NODE, &mgmt_commit_cmd);
+ install_element(CONFIG_NODE, &mgmt_create_config_data_cmd);
install_element(CONFIG_NODE, &mgmt_set_config_data_cmd);
install_element(CONFIG_NODE, &mgmt_delete_config_data_cmd);
+ install_element(CONFIG_NODE, &mgmt_remove_config_data_cmd);
+ install_element(CONFIG_NODE, &mgmt_replace_config_data_cmd);
install_element(CONFIG_NODE, &mgmt_load_config_cmd);
install_element(CONFIG_NODE, &mgmt_save_config_cmd);
install_element(CONFIG_NODE, &mgmt_rollback_cmd);
diff --git a/tools/gen_northbound_callbacks.c b/tools/gen_northbound_callbacks.c
index 993aa3420..550058bfe 100644
--- a/tools/gen_northbound_callbacks.c
+++ b/tools/gen_northbound_callbacks.c
@@ -31,62 +31,62 @@ static struct nb_callback_info {
char arguments[128];
} nb_callbacks[] = {
{
- .operation = NB_OP_CREATE,
+ .operation = NB_CB_CREATE,
.return_type = "int ",
.return_value = "NB_OK",
.arguments = "struct nb_cb_create_args *args",
},
{
- .operation = NB_OP_MODIFY,
+ .operation = NB_CB_MODIFY,
.return_type = "int ",
.return_value = "NB_OK",
.arguments = "struct nb_cb_modify_args *args",
},
{
- .operation = NB_OP_DESTROY,
+ .operation = NB_CB_DESTROY,
.return_type = "int ",
.return_value = "NB_OK",
.arguments = "struct nb_cb_destroy_args *args",
},
{
- .operation = NB_OP_MOVE,
+ .operation = NB_CB_MOVE,
.return_type = "int ",
.return_value = "NB_OK",
.arguments = "struct nb_cb_move_args *args",
},
{
- .operation = NB_OP_APPLY_FINISH,
+ .operation = NB_CB_APPLY_FINISH,
.optional = true,
.return_type = "void ",
.return_value = "",
.arguments = "struct nb_cb_apply_finish_args *args",
},
{
- .operation = NB_OP_GET_ELEM,
+ .operation = NB_CB_GET_ELEM,
.return_type = "struct yang_data *",
.return_value = "NULL",
.arguments = "struct nb_cb_get_elem_args *args",
},
{
- .operation = NB_OP_GET_NEXT,
+ .operation = NB_CB_GET_NEXT,
.return_type = "const void *",
.return_value = "NULL",
.arguments = "struct nb_cb_get_next_args *args",
},
{
- .operation = NB_OP_GET_KEYS,
+ .operation = NB_CB_GET_KEYS,
.return_type = "int ",
.return_value = "NB_OK",
.arguments = "struct nb_cb_get_keys_args *args",
},
{
- .operation = NB_OP_LOOKUP_ENTRY,
+ .operation = NB_CB_LOOKUP_ENTRY,
.return_type = "const void *",
.return_value = "NULL",
.arguments = "struct nb_cb_lookup_entry_args *args",
},
{
- .operation = NB_OP_RPC,
+ .operation = NB_CB_RPC,
.return_type = "int ",
.return_value = "NB_OK",
.arguments = "struct nb_cb_rpc_args *args",
@@ -107,7 +107,7 @@ static void replace_hyphens_by_underscores(char *str)
}
static void generate_callback_name(const struct lysc_node *snode,
- enum nb_operation operation, char *buffer,
+ enum nb_cb_operation operation, char *buffer,
size_t size)
{
struct list *snodes;
@@ -129,7 +129,7 @@ static void generate_callback_name(const struct lysc_node *snode,
strlcat(buffer, snode->name, size);
strlcat(buffer, "_", size);
}
- strlcat(buffer, nb_operation_name(operation), size);
+ strlcat(buffer, nb_cb_operation_name(operation), size);
list_delete(&snodes);
replace_hyphens_by_underscores(buffer);
@@ -160,7 +160,7 @@ static int generate_prototypes(const struct lysc_node *snode, void *arg)
char cb_name[BUFSIZ];
if (cb->optional
- || !nb_operation_is_valid(cb->operation, snode))
+ || !nb_cb_operation_is_valid(cb->operation, snode))
continue;
generate_callback_name(snode, cb->operation, cb_name,
@@ -178,10 +178,10 @@ static void generate_callback(const struct nb_callback_info *ncinfo,
ncinfo->return_type, cb_name, ncinfo->arguments);
switch (ncinfo->operation) {
- case NB_OP_CREATE:
- case NB_OP_MODIFY:
- case NB_OP_DESTROY:
- case NB_OP_MOVE:
+ case NB_CB_CREATE:
+ case NB_CB_MODIFY:
+ case NB_CB_DESTROY:
+ case NB_CB_MOVE:
printf("\tswitch (args->event) {\n"
"\tcase NB_EV_VALIDATE:\n"
"\tcase NB_EV_PREPARE:\n"
@@ -222,7 +222,7 @@ static int generate_callbacks(const struct lysc_node *snode, void *arg)
char cb_name[BUFSIZ];
if (cb->optional
- || !nb_operation_is_valid(cb->operation, snode))
+ || !nb_cb_operation_is_valid(cb->operation, snode))
continue;
if (first) {
@@ -267,7 +267,7 @@ static int generate_nb_nodes(const struct lysc_node *snode, void *arg)
char cb_name[BUFSIZ];
if (cb->optional
- || !nb_operation_is_valid(cb->operation, snode))
+ || !nb_cb_operation_is_valid(cb->operation, snode))
continue;
if (first) {
@@ -285,7 +285,8 @@ static int generate_nb_nodes(const struct lysc_node *snode, void *arg)
generate_callback_name(snode, cb->operation, cb_name,
sizeof(cb_name));
- printf("\t\t\t\t.%s = %s,\n", nb_operation_name(cb->operation),
+ printf("\t\t\t\t.%s = %s,\n",
+ nb_cb_operation_name(cb->operation),
cb_name);
}