From 76e4eb84dd815ddee7d7e46bb5a2635bfe2501f5 Mon Sep 17 00:00:00 2001 From: Igor Ryzhov Date: Fri, 6 Oct 2023 02:58:58 +0300 Subject: [PATCH] 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(-) diff --git a/lib/mgmt.proto b/lib/mgmt.proto index 087d96a6ee..9a39789c82 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 c3fb34a7a4..dd2613f132 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 34f7d4f09a..f7e0d698b3 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 b8e2c4fa4b..e11958c77d 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 546392ba7f..69df0a0245 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 d25302ab6a..abae2a6a53 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 64abb462c3..aa46d5c783 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); -- 2.39.5