From d726114790464831b1d377eb3acc05c2933e3cd8 Mon Sep 17 00:00:00 2001 From: Igor Ryzhov Date: Mon, 9 Oct 2023 03:21:16 +0300 Subject: [PATCH] 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(-) diff --git a/lib/mgmt.proto b/lib/mgmt.proto index e0b6019d2b6c..5d83fca347ba 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 53df191b2c73..16aea249a430 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 1fd58cf8b0ef..efbf1bc4bc24 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 ef774fb476cb..3dd9d09d4a63 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 7e856e3741e2..5f9f0dc2435b 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 dee75e658659..76681e30762d 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 b12f54ccbe33..2591930e4a89 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);