From 5d1a31403832a069d1b655bc3410fcd770ad8313 Mon Sep 17 00:00:00 2001 From: Igor Ryzhov Date: Fri, 6 Oct 2023 00:13:16 +0300 Subject: lib: split nb_operation into two types Currently, nb_operation enum means two different things - edit operation type (frontend part), and callback type (backend part). These types overlap, but they are not identical. We need to add more operation types to support NETCONF/RESTCONF integration, so it's better to have separate enums to identify different entities. Signed-off-by: Igor Ryzhov --- lib/northbound.c | 188 ++++++++++++++++++++++++++++--------------------------- 1 file changed, 95 insertions(+), 93 deletions(-) (limited to 'lib/northbound.c') diff --git a/lib/northbound.c b/lib/northbound.c index 03d252ee5..34f7d4f09 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_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 */ @@ -748,27 +748,29 @@ int nb_candidate_edit(struct nb_config *candidate, 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: + return "create"; + case NB_OP_MODIFY: + return "modify"; + case NB_OP_DESTROY: + return "destroy"; + 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) return false; @@ -815,7 +817,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; @@ -1140,7 +1142,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 +1159,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 +1175,7 @@ static int nb_callback_create(struct nb_context *context, assert(!CHECK_FLAG(nb_node->flags, F_NB_NODE_IGNORE_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 +1226,7 @@ static int nb_callback_modify(struct nb_context *context, assert(!CHECK_FLAG(nb_node->flags, F_NB_NODE_IGNORE_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 +1277,7 @@ static int nb_callback_destroy(struct nb_context *context, assert(!CHECK_FLAG(nb_node->flags, F_NB_NODE_IGNORE_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 +1322,7 @@ static int nb_callback_move(struct nb_context *context, assert(!CHECK_FLAG(nb_node->flags, F_NB_NODE_IGNORE_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 +1368,7 @@ static int nb_callback_pre_validate(struct nb_context *context, if (CHECK_FLAG(nb_node->flags, F_NB_NODE_IGNORE_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 +1402,7 @@ static void nb_callback_apply_finish(struct nb_context *context, if (CHECK_FLAG(nb_node->flags, F_NB_NODE_IGNORE_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 +1554,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 +1570,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 +1608,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 +1777,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 +1828,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 +1858,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 +1876,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 +1912,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 +1926,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 +1948,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 +1962,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 +1975,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 +2177,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"; } -- cgit v1.2.3 From 76e4eb84dd815ddee7d7e46bb5a2635bfe2501f5 Mon Sep 17 00:00:00 2001 From: Igor Ryzhov Date: Fri, 6 Oct 2023 02:58:58 +0300 Subject: mgmtd, lib: implement CREATE_EXCL operation Currently, there's no difference between CREATE and MODIFY operations. To be compatible with NETCONF/RESTCONF, add new CREATE_EXCL operation that throws an error if the configuration data already exists. Signed-off-by: Igor Ryzhov --- lib/mgmt.proto | 1 + lib/mgmt_be_client.c | 2 +- lib/northbound.c | 9 +++++++-- lib/northbound.h | 1 + lib/vty.c | 5 +++++ mgmtd/mgmt_txn.c | 40 ++++++++++++++++++++++++++++------------ mgmtd/mgmt_vty.c | 20 +++++++++++++++++++- 7 files changed, 62 insertions(+), 16 deletions(-) (limited to 'lib/northbound.c') diff --git a/lib/mgmt.proto b/lib/mgmt.proto index 087d96a6e..9a39789c8 100644 --- a/lib/mgmt.proto +++ b/lib/mgmt.proto @@ -56,6 +56,7 @@ enum CfgDataReqType { REQ_TYPE_NONE = 0; SET_DATA = 1; DELETE_DATA = 2; + CREATE_DATA = 3; } message YangCfgDataReq { diff --git a/lib/mgmt_be_client.c b/lib/mgmt_be_client.c index c3fb34a7a..dd2613f13 100644 --- a/lib/mgmt_be_client.c +++ b/lib/mgmt_be_client.c @@ -569,7 +569,7 @@ static int mgmt_be_update_setcfg_in_batch(struct mgmt_be_client *client_ctx, == MGMTD__CFG_DATA_REQ_TYPE__DELETE_DATA) cfg_chg->operation = NB_OP_DESTROY; else - cfg_chg->operation = NB_OP_CREATE; + cfg_chg->operation = NB_OP_MODIFY; strlcpy(cfg_chg->xpath, cfg_req[index]->data->xpath, sizeof(cfg_chg->xpath)); diff --git a/lib/northbound.c b/lib/northbound.c index 34f7d4f09..f7e0d698b 100644 --- a/lib/northbound.c +++ b/lib/northbound.c @@ -668,6 +668,7 @@ int nb_candidate_edit(struct nb_config *candidate, struct lyd_node *dnode, *dep_dnode; 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,9 +681,11 @@ int nb_candidate_edit(struct nb_config *candidate, switch (operation) { case NB_OP_CREATE: case NB_OP_MODIFY: + options = LYD_NEW_PATH_UPDATE; + fallthrough; + case NB_OP_CREATE_EXCL: err = lyd_new_path(candidate->dnode, ly_native_ctx, xpath_edit, - (void *)data->value, LYD_NEW_PATH_UPDATE, - &dnode); + (void *)data->value, options, &dnode); if (err) { flog_warn(EC_LIB_LIBYANG, "%s: lyd_new_path(%s) failed: %d", __func__, @@ -756,6 +759,8 @@ int nb_candidate_edit(struct nb_config *candidate, const char *nb_operation_name(enum nb_operation operation) { switch (operation) { + case NB_OP_CREATE_EXCL: + return "create exclusive"; case NB_OP_CREATE: return "create"; case NB_OP_MODIFY: diff --git a/lib/northbound.h b/lib/northbound.h index b8e2c4fa4..e11958c77 100644 --- a/lib/northbound.h +++ b/lib/northbound.h @@ -718,6 +718,7 @@ struct nb_config { /* Northbound operations */ enum nb_operation { + NB_OP_CREATE_EXCL, NB_OP_CREATE, NB_OP_MODIFY, NB_OP_DESTROY, diff --git a/lib/vty.c b/lib/vty.c index 546392ba7..69df0a024 100644 --- a/lib/vty.c +++ b/lib/vty.c @@ -4001,6 +4001,11 @@ int vty_mgmt_send_config_data(struct vty *vty, const char *xpath_base, MGMTD__CFG_DATA_REQ_TYPE__DELETE_DATA; break; + case NB_OP_CREATE_EXCL: + cfg_req[indx].req_type = + MGMTD__CFG_DATA_REQ_TYPE__CREATE_DATA; + break; + case NB_OP_CREATE: case NB_OP_MODIFY: case NB_OP_MOVE: diff --git a/mgmtd/mgmt_txn.c b/mgmtd/mgmt_txn.c index d25302ab6..abae2a6a5 100644 --- a/mgmtd/mgmt_txn.c +++ b/mgmtd/mgmt_txn.c @@ -911,6 +911,11 @@ 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]; + /* + * 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; @@ -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,30 @@ 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_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__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..aa46d5c78 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); @@ -527,6 +544,7 @@ 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_load_config_cmd); -- cgit v1.2.3 From 3c2598a26ff01fc712d61233a6a627fdfa1a7b77 Mon Sep 17 00:00:00 2001 From: Igor Ryzhov Date: Fri, 6 Oct 2023 15:01:16 +0300 Subject: mgmt, lib: differentiate DELETE and REMOVE operations Currently, there's a single operation type which doesn't return error if the object doesn't exists. To be compatible with NETCONF/RESTCONF, we should support differentiate between DELETE (fails when object doesn't exist) and REMOVE (doesn't fail if the object doesn't exist). Signed-off-by: Igor Ryzhov --- .../retrofitting-configuration-commands.rst | 6 +++--- lib/mgmt.proto | 3 ++- lib/mgmt_be_client.c | 20 +++++++++++++++++--- lib/northbound.c | 20 ++++++++++++-------- lib/northbound.h | 2 +- lib/northbound_cli.h | 2 +- lib/northbound_sysrepo.c | 2 +- lib/vty.c | 7 ++++++- mgmtd/mgmt_txn.c | 5 ++++- mgmtd/mgmt_vty.c | 18 ++++++++++++++++++ 10 files changed, 65 insertions(+), 20 deletions(-) (limited to 'lib/northbound.c') 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 9a39789c8..e0b6019d2 100644 --- a/lib/mgmt.proto +++ b/lib/mgmt.proto @@ -55,8 +55,9 @@ message YangData { enum CfgDataReqType { REQ_TYPE_NONE = 0; SET_DATA = 1; - DELETE_DATA = 2; + REMOVE_DATA = 2; CREATE_DATA = 3; + DELETE_DATA = 4; } message YangCfgDataReq { diff --git a/lib/mgmt_be_client.c b/lib/mgmt_be_client.c index dd2613f13..53df191b2 100644 --- a/lib/mgmt_be_client.c +++ b/lib/mgmt_be_client.c @@ -565,11 +565,25 @@ 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 + break; + case MGMTD__CFG_DATA_REQ_TYPE__SET_DATA: + case MGMTD__CFG_DATA_REQ_TYPE__CREATE_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 f7e0d698b..01bb09185 100644 --- a/lib/northbound.c +++ b/lib/northbound.c @@ -731,13 +731,14 @@ int nb_candidate_edit(struct nb_config *candidate, } 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); @@ -767,6 +768,8 @@ const char *nb_operation_name(enum nb_operation operation) return "modify"; case NB_OP_DESTROY: return "destroy"; + case NB_OP_DELETE: + return "delete"; case NB_OP_MOVE: return "move"; } @@ -777,7 +780,8 @@ const char *nb_operation_name(enum nb_operation operation) 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) return false; } return true; @@ -842,7 +846,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]", diff --git a/lib/northbound.h b/lib/northbound.h index e11958c77..ef774fb47 100644 --- a/lib/northbound.h +++ b/lib/northbound.h @@ -722,6 +722,7 @@ enum nb_operation { NB_OP_CREATE, NB_OP_MODIFY, NB_OP_DESTROY, + NB_OP_DELETE, NB_OP_MOVE, }; @@ -953,7 +954,6 @@ extern bool nb_is_operation_allowed(struct nb_node *nb_node, * * 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, 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_sysrepo.c b/lib/northbound_sysrepo.c index 1a194935a..198d96e38 100644 --- a/lib/northbound_sysrepo.c +++ b/lib/northbound_sysrepo.c @@ -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 69df0a024..7e856e374 100644 --- a/lib/vty.c +++ b/lib/vty.c @@ -3996,11 +3996,16 @@ 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; diff --git a/mgmtd/mgmt_txn.c b/mgmtd/mgmt_txn.c index abae2a6a5..dee75e658 100644 --- a/mgmtd/mgmt_txn.c +++ b/mgmtd/mgmt_txn.c @@ -918,7 +918,7 @@ static int mgmt_txn_create_config_batches(struct mgmt_txn_req *txn_req, */ 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; @@ -2052,6 +2052,9 @@ int mgmt_txn_send_set_config_req(uint64_t txn_id, uint64_t req_id, 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; break; case MGMTD__CFG_DATA_REQ_TYPE__SET_DATA: diff --git a/mgmtd/mgmt_vty.c b/mgmtd/mgmt_vty.c index aa46d5c78..b12f54ccb 100644 --- a/mgmtd/mgmt_vty.c +++ b/mgmtd/mgmt_vty.c @@ -185,6 +185,23 @@ DEFPY(mgmt_delete_config_data, mgmt_delete_config_data_cmd, "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_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; @@ -547,6 +564,7 @@ void mgmt_vty_init(void) 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_load_config_cmd); install_element(CONFIG_NODE, &mgmt_save_config_cmd); install_element(CONFIG_NODE, &mgmt_rollback_cmd); -- cgit v1.2.3 From fe0d4dc2cb8fdf63524d92ab364157904327eb29 Mon Sep 17 00:00:00 2001 From: Igor Ryzhov Date: Mon, 9 Oct 2023 03:10:18 +0300 Subject: lib: move dnode creation into a separate function Signed-off-by: Igor Ryzhov --- lib/northbound.c | 61 ++++++++++++++++++++++++++++++-------------------------- 1 file changed, 33 insertions(+), 28 deletions(-) (limited to 'lib/northbound.c') diff --git a/lib/northbound.c b/lib/northbound.c index 01bb09185..1fd58cf8b 100644 --- a/lib/northbound.c +++ b/lib/northbound.c @@ -659,6 +659,32 @@ 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, @@ -684,22 +710,11 @@ int nb_candidate_edit(struct nb_config *candidate, options = LYD_NEW_PATH_UPDATE; fallthrough; case NB_OP_CREATE_EXCL: - err = lyd_new_path(candidate->dnode, ly_native_ctx, xpath_edit, - (void *)data->value, options, &dnode); + 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 * @@ -711,21 +726,11 @@ 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; } } } -- cgit v1.2.3 From d726114790464831b1d377eb3acc05c2933e3cd8 Mon Sep 17 00:00:00 2001 From: Igor Ryzhov Date: Mon, 9 Oct 2023 03:21:16 +0300 Subject: mgmt, lib: implement REPLACE operation Replace operation removes the current data node configuration and sets the provided value. As current northbound code works only with one xpath at a time, the operation only makes sense to clear the config of a container without deleting it itself. However, the next step is to allow passing JSON-encoded complex values to northbound operations which will make replace operation much more useful. Signed-off-by: Igor Ryzhov --- lib/mgmt.proto | 1 + lib/mgmt_be_client.c | 1 + lib/northbound.c | 41 +++++++++++++++++++++++++++++++++++++++-- lib/northbound.h | 1 + lib/vty.c | 5 +++++ mgmtd/mgmt_txn.c | 3 +++ mgmtd/mgmt_vty.c | 19 +++++++++++++++++++ 7 files changed, 69 insertions(+), 2 deletions(-) (limited to 'lib/northbound.c') diff --git a/lib/mgmt.proto b/lib/mgmt.proto index e0b6019d2..5d83fca34 100644 --- a/lib/mgmt.proto +++ b/lib/mgmt.proto @@ -58,6 +58,7 @@ enum CfgDataReqType { 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 53df191b2..16aea249a 100644 --- a/lib/mgmt_be_client.c +++ b/lib/mgmt_be_client.c @@ -577,6 +577,7 @@ static int mgmt_be_update_setcfg_in_batch(struct mgmt_be_client *client_ctx, 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: diff --git a/lib/northbound.c b/lib/northbound.c index 1fd58cf8b..efbf1bc4b 100644 --- a/lib/northbound.c +++ b/lib/northbound.c @@ -691,7 +691,7 @@ int nb_candidate_edit(struct nb_config *candidate, 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; @@ -754,6 +754,41 @@ 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; @@ -775,6 +810,8 @@ const char *nb_operation_name(enum nb_operation operation) return "destroy"; case NB_OP_DELETE: return "delete"; + case NB_OP_REPLACE: + return "replace"; case NB_OP_MOVE: return "move"; } @@ -786,7 +823,7 @@ 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 - || oper == NB_OP_DELETE) + || oper == NB_OP_DELETE || oper == NB_OP_REPLACE) return false; } return true; diff --git a/lib/northbound.h b/lib/northbound.h index ef774fb47..3dd9d09d4 100644 --- a/lib/northbound.h +++ b/lib/northbound.h @@ -723,6 +723,7 @@ enum nb_operation { NB_OP_MODIFY, NB_OP_DESTROY, NB_OP_DELETE, + NB_OP_REPLACE, NB_OP_MOVE, }; diff --git a/lib/vty.c b/lib/vty.c index 7e856e374..5f9f0dc24 100644 --- a/lib/vty.c +++ b/lib/vty.c @@ -4011,6 +4011,11 @@ int vty_mgmt_send_config_data(struct vty *vty, const char *xpath_base, 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: diff --git a/mgmtd/mgmt_txn.c b/mgmtd/mgmt_txn.c index dee75e658..76681e307 100644 --- a/mgmtd/mgmt_txn.c +++ b/mgmtd/mgmt_txn.c @@ -2072,6 +2072,9 @@ int mgmt_txn_send_set_config_req(uint64_t txn_id, uint64_t req_id, 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: diff --git a/mgmtd/mgmt_vty.c b/mgmtd/mgmt_vty.c index b12f54ccb..2591930e4 100644 --- a/mgmtd/mgmt_vty.c +++ b/mgmtd/mgmt_vty.c @@ -212,6 +212,24 @@ DEFPY(mgmt_remove_config_data, mgmt_remove_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 @@ -565,6 +583,7 @@ void mgmt_vty_init(void) 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); -- cgit v1.2.3