]> git.puffer.fish Git - matthieu/frr.git/commitdiff
mgmtd, lib: implement CREATE_EXCL operation
authorIgor Ryzhov <iryzhov@nfware.com>
Thu, 5 Oct 2023 23:58:58 +0000 (02:58 +0300)
committerIgor Ryzhov <iryzhov@nfware.com>
Thu, 11 Jan 2024 13:06:53 +0000 (15:06 +0200)
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 <iryzhov@nfware.com>
lib/mgmt.proto
lib/mgmt_be_client.c
lib/northbound.c
lib/northbound.h
lib/vty.c
mgmtd/mgmt_txn.c
mgmtd/mgmt_vty.c

index 087d96a6ee25c4842cc1399ddcb21d0468cbbe02..9a39789c82e552689984d07d64ca53c9948f24a4 100644 (file)
@@ -56,6 +56,7 @@ enum CfgDataReqType {
   REQ_TYPE_NONE = 0;
   SET_DATA = 1;
   DELETE_DATA = 2;
+  CREATE_DATA = 3;
 }
 
 message YangCfgDataReq {
index c3fb34a7a4d4362548c705d71b6f32d728aa0fce..dd2613f132b45230b11e309faa2802cdfc6412a8 100644 (file)
@@ -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));
index 34f7d4f09adea2b6e5460dd1b3e61079cdaa303a..f7e0d698b3d7cdbdec06fde22c396b3f44a262d1 100644 (file)
@@ -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:
index b8e2c4fa4b33743762f6338353a346ba184e7a7b..e11958c77d01601a8abc8f509d7f092666448a2d 100644 (file)
@@ -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,
index 546392ba7fa2da0ad0d5a40df4319f107127ac70..69df0a024505a9c2cc315027b3f99c9049a58529 100644 (file)
--- 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:
index d25302ab6ac0fea5a3a1d4d4de483ca278eab060..abae2a6a53b13981ed8ad06437b933fb0f75d7eb 100644 (file)
@@ -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,
index 64abb462c3fa960c1a50aeec06bf5e5e26f0a43d..aa46d5c783633bbf16b6fd3aa81627d7dc830fc4 100644 (file)
@@ -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);