diff --git a/lib/mgmt.proto b/lib/mgmt.proto index 3c536838aa9d..f40ba557619f 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 50d86cb3e42b..c7300602029c 100644 --- a/lib/mgmt_be_client.c +++ b/lib/mgmt_be_client.c @@ -568,6 +568,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 eb188d433599..a74cf3bb43f3 100644 --- a/lib/northbound.c +++ b/lib/northbound.c @@ -680,7 +680,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; @@ -742,6 +742,42 @@ 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; + } else { + lyd_free_tree(old_dnode); + } + } + break; case NB_OP_MOVE: /* TODO: update configuration. */ break; @@ -764,6 +800,7 @@ static void nb_update_candidate_changes(struct nb_config *candidate, switch (oper) { case NB_OP_CREATE: case NB_OP_MODIFY: + case NB_OP_REPLACE: root = yang_dnode_get(candidate->dnode, xpath); break; case NB_OP_DESTROY: @@ -814,6 +851,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"; } @@ -825,7 +864,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 f749e32bed92..7b26248e1351 100644 --- a/lib/northbound.h +++ b/lib/northbound.h @@ -706,6 +706,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 436748222690..6ca0b156b0b5 100644 --- a/lib/vty.c +++ b/lib/vty.c @@ -3788,6 +3788,11 @@ int vty_mgmt_send_config_data(struct vty *vty, bool implicit_commit) 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_MODIFY: case NB_OP_MOVE: cfg_req[indx].req_type = diff --git a/mgmtd/mgmt_txn.c b/mgmtd/mgmt_txn.c index e3c75357edb7..41bbf82cab60 100644 --- a/mgmtd/mgmt_txn.c +++ b/mgmtd/mgmt_txn.c @@ -2241,6 +2241,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; 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 a7306c723b42..b73dd155e2cc 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, 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 @@ -523,6 +541,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);