]> git.proxmox.com Git - mirror_frr.git/commitdiff
lib: introduce a read-write lock for northbound configurations
authorRenato Westphal <renato@opensourcerouting.org>
Wed, 3 Apr 2019 19:31:18 +0000 (16:31 -0300)
committerRenato Westphal <renato@opensourcerouting.org>
Fri, 26 Apr 2019 21:04:22 +0000 (18:04 -0300)
The upcoming gRPC-based northbound plugin will run on a separate
pthread, and it will need to have access to the running configuration
global variable.  Introduce a rw-lock to control concurrent access
to the running configuration. Add the lock inside the "nb_config"
structure so that it can be used to protect candidate configurations
as well (this might be necessary depending on the threading scheme
of future northbound plugins).

Signed-off-by: Renato Westphal <renato@opensourcerouting.org>
isisd/isis_cli.c
lib/command.c
lib/if.c
lib/libfrr.c
lib/northbound.c
lib/northbound.h
lib/northbound_cli.c
lib/northbound_confd.c
lib/northbound_sysrepo.c
lib/vty.c

index 00948528259d56d158b297677134488c9bb7df98..0334b98a122fb71c54a0704b8d97cf068a266457 100644 (file)
@@ -188,10 +188,14 @@ DEFPY(ip_router_isis, ip_router_isis_cmd, "ip router isis WORD$tag",
        }
 
        /* check if the interface is a loopback and if so set it as passive */
-       ifp = nb_running_get_entry(NULL, VTY_CURR_XPATH, false);
-       if (ifp && if_is_loopback(ifp))
-               nb_cli_enqueue_change(vty, "./frr-isisd:isis/passive",
-                                     NB_OP_MODIFY, "true");
+       pthread_rwlock_rdlock(&running_config->lock);
+       {
+               ifp = nb_running_get_entry(NULL, VTY_CURR_XPATH, false);
+               if (ifp && if_is_loopback(ifp))
+                       nb_cli_enqueue_change(vty, "./frr-isisd:isis/passive",
+                                             NB_OP_MODIFY, "true");
+       }
+       pthread_rwlock_unlock(&running_config->lock);
 
        return nb_cli_apply_changes(vty, NULL);
 }
@@ -258,10 +262,14 @@ DEFPY(ip6_router_isis, ip6_router_isis_cmd, "ipv6 router isis WORD$tag",
        }
 
        /* check if the interface is a loopback and if so set it as passive */
-       ifp = nb_running_get_entry(NULL, VTY_CURR_XPATH, false);
-       if (ifp && if_is_loopback(ifp))
-               nb_cli_enqueue_change(vty, "./frr-isisd:isis/passive",
-                                     NB_OP_MODIFY, "true");
+       pthread_rwlock_rdlock(&running_config->lock);
+       {
+               ifp = nb_running_get_entry(NULL, VTY_CURR_XPATH, false);
+               if (ifp && if_is_loopback(ifp))
+                       nb_cli_enqueue_change(vty, "./frr-isisd:isis/passive",
+                                             NB_OP_MODIFY, "true");
+       }
+       pthread_rwlock_unlock(&running_config->lock);
 
        return nb_cli_apply_changes(vty, NULL);
 }
@@ -368,20 +376,26 @@ DEFPY(no_is_type, no_is_type_cmd,
       "Act as both a station router and an area router\n"
       "Act as an area router only\n")
 {
-       const char *value = NULL;
-       struct isis_area *area;
+       const char *value;
 
-       area = nb_running_get_entry(NULL, VTY_CURR_XPATH, false);
+       pthread_rwlock_rdlock(&running_config->lock);
+       {
+               struct isis_area *area;
+
+               area = nb_running_get_entry(NULL, VTY_CURR_XPATH, false);
+
+               /*
+                * Put the is-type back to defaults:
+                * - level-1-2 on first area
+                * - level-1 for the rest
+                */
+               if (area && listgetdata(listhead(isis->area_list)) == area)
+                       value = "level-1-2";
+               else
+                       value = NULL;
+       }
+       pthread_rwlock_unlock(&running_config->lock);
 
-       /*
-        * Put the is-type back to defaults:
-        * - level-1-2 on first area
-        * - level-1 for the rest
-        */
-       if (area && listgetdata(listhead(isis->area_list)) == area)
-               value = "level-1-2";
-       else
-               value = NULL;
        nb_cli_enqueue_change(vty, "./is-type", NB_OP_MODIFY, value);
 
        return nb_cli_apply_changes(vty, NULL);
@@ -1769,50 +1783,43 @@ DEFPY(no_isis_circuit_type, no_isis_circuit_type_cmd,
       "Level-1-2 adjacencies are formed\n"
       "Level-2 only adjacencies are formed\n")
 {
-       struct interface *ifp;
-       struct isis_circuit *circuit;
-       int is_type;
-       const char *circ_type;
+       const char *circ_type = NULL;
 
        /*
         * Default value depends on whether the circuit is part of an area,
         * and the is-type of the area if there is one. So we need to do this
         * here.
         */
-       ifp = nb_running_get_entry(NULL, VTY_CURR_XPATH, false);
-       if (!ifp)
-               goto def_val;
+       pthread_rwlock_rdlock(&running_config->lock);
+       {
+               struct interface *ifp;
+               struct isis_circuit *circuit;
 
-       circuit = circuit_scan_by_ifp(ifp);
-       if (!circuit)
-               goto def_val;
+               ifp = nb_running_get_entry(NULL, VTY_CURR_XPATH, false);
+               if (!ifp)
+                       goto unlock;
 
-       if (circuit->state == C_STATE_UP)
-               is_type = circuit->area->is_type;
-       else
-               goto def_val;
+               circuit = circuit_scan_by_ifp(ifp);
+               if (!circuit || circuit->state != C_STATE_UP)
+                       goto unlock;
 
-       switch (is_type) {
-       case IS_LEVEL_1:
-               circ_type = "level-1";
-               break;
-       case IS_LEVEL_2:
-               circ_type = "level-2";
-               break;
-       case IS_LEVEL_1_AND_2:
-               circ_type = "level-1-2";
-               break;
-       default:
-               return CMD_ERR_NO_MATCH;
+               switch (circuit->area->is_type) {
+               case IS_LEVEL_1:
+                       circ_type = "level-1";
+                       break;
+               case IS_LEVEL_2:
+                       circ_type = "level-2";
+                       break;
+               case IS_LEVEL_1_AND_2:
+                       circ_type = "level-1-2";
+                       break;
+               }
        }
-       nb_cli_enqueue_change(vty, "./frr-isisd:isis/circuit-type",
-                             NB_OP_MODIFY, circ_type);
-
-       return nb_cli_apply_changes(vty, NULL);
+unlock:
+       pthread_rwlock_unlock(&running_config->lock);
 
-def_val:
        nb_cli_enqueue_change(vty, "./frr-isisd:isis/circuit-type",
-                             NB_OP_MODIFY, NULL);
+                             NB_OP_MODIFY, circ_type);
 
        return nb_cli_apply_changes(vty, NULL);
 }
index 559457c11998ec0bbd968b734b5a6fbf826aeabd..b3ef028004f687dcf686c7669bc205f10a50548c 100644 (file)
@@ -1705,12 +1705,16 @@ static int vty_write_config(struct vty *vty)
        vty_out(vty, "frr defaults %s\n", DFLT_NAME);
        vty_out(vty, "!\n");
 
-       for (i = 0; i < vector_active(cmdvec); i++)
-               if ((node = vector_slot(cmdvec, i)) && node->func
-                   && (node->vtysh || vty->type != VTY_SHELL)) {
-                       if ((*node->func)(vty))
-                               vty_out(vty, "!\n");
-               }
+       pthread_rwlock_rdlock(&running_config->lock);
+       {
+               for (i = 0; i < vector_active(cmdvec); i++)
+                       if ((node = vector_slot(cmdvec, i)) && node->func
+                           && (node->vtysh || vty->type != VTY_SHELL)) {
+                               if ((*node->func)(vty))
+                                       vty_out(vty, "!\n");
+                       }
+       }
+       pthread_rwlock_unlock(&running_config->lock);
 
        if (vty->type == VTY_TERM) {
                vty_out(vty, "end\n");
index 86b850c059f785ab1926d957ab09c29156a7c34a..38f3f45ed1e020f079f4d85b4d6ae1c4a917f679 100644 (file)
--- a/lib/if.c
+++ b/lib/if.c
@@ -187,18 +187,21 @@ void if_update_to_new_vrf(struct interface *ifp, vrf_id_t vrf_id)
        if (yang_module_find("frr-interface")) {
                struct lyd_node *if_dnode;
 
-               if_dnode = yang_dnode_get(
-                       running_config->dnode,
-                       "/frr-interface:lib/interface[name='%s'][vrf='%s']/vrf",
-                       ifp->name, old_vrf->name);
-               if (if_dnode) {
-                       yang_dnode_change_leaf(if_dnode, vrf->name);
-                       running_config->version++;
+               pthread_rwlock_wrlock(&running_config->lock);
+               {
+                       if_dnode = yang_dnode_get(
+                               running_config->dnode,
+                               "/frr-interface:lib/interface[name='%s'][vrf='%s']/vrf",
+                               ifp->name, old_vrf->name);
+                       if (if_dnode) {
+                               yang_dnode_change_leaf(if_dnode, vrf->name);
+                               running_config->version++;
+                       }
                }
+               pthread_rwlock_unlock(&running_config->lock);
        }
 }
 
-
 /* Delete interface structure. */
 void if_delete_retain(struct interface *ifp)
 {
index 0d4c8d6c0f1b4200895491cc3ef28c7fb5aa2847..5970e70a6bd493230f9b7cb5091cb963277178c5 100644 (file)
@@ -830,7 +830,12 @@ static int frr_config_read_in(struct thread *t)
        /*
         * Update the shared candidate after reading the startup configuration.
         */
-       nb_config_replace(vty_shared_candidate_config, running_config, true);
+       pthread_rwlock_rdlock(&running_config->lock);
+       {
+               nb_config_replace(vty_shared_candidate_config, running_config,
+                                 true);
+       }
+       pthread_rwlock_unlock(&running_config->lock);
 
        return 0;
 }
index 58dcc02ac3fbcc18e714188ea18b6d02c5baf435..6c68772cf89ad8451b61b38eaf6bae79032b235d 100644 (file)
@@ -264,6 +264,7 @@ struct nb_config *nb_config_new(struct lyd_node *dnode)
        else
                config->dnode = yang_dnode_new(ly_native_ctx, true);
        config->version = 0;
+       pthread_rwlock_init(&config->lock, NULL);
 
        return config;
 }
@@ -272,6 +273,7 @@ void nb_config_free(struct nb_config *config)
 {
        if (config->dnode)
                yang_dnode_free(config->dnode);
+       pthread_rwlock_destroy(&config->lock);
        XFREE(MTYPE_NB_CONFIG, config);
 }
 
@@ -282,6 +284,7 @@ struct nb_config *nb_config_dup(const struct nb_config *config)
        dup = XCALLOC(MTYPE_NB_CONFIG, sizeof(*dup));
        dup->dnode = yang_dnode_dup(config->dnode);
        dup->version = config->version;
+       pthread_rwlock_init(&dup->lock, NULL);
 
        return dup;
 }
@@ -529,17 +532,28 @@ int nb_candidate_edit(struct nb_config *candidate,
 
 bool nb_candidate_needs_update(const struct nb_config *candidate)
 {
-       if (candidate->version < running_config->version)
-               return true;
+       bool ret = false;
+
+       pthread_rwlock_rdlock(&running_config->lock);
+       {
+               if (candidate->version < running_config->version)
+                       ret = true;
+       }
+       pthread_rwlock_unlock(&running_config->lock);
 
-       return false;
+       return ret;
 }
 
 int nb_candidate_update(struct nb_config *candidate)
 {
        struct nb_config *updated_config;
 
-       updated_config = nb_config_dup(running_config);
+       pthread_rwlock_rdlock(&running_config->lock);
+       {
+               updated_config = nb_config_dup(running_config);
+       }
+       pthread_rwlock_unlock(&running_config->lock);
+
        if (nb_config_merge(updated_config, candidate, true) != NB_OK)
                return NB_ERR;
 
@@ -591,9 +605,13 @@ int nb_candidate_validate(struct nb_config *candidate)
                return NB_ERR_VALIDATION;
 
        RB_INIT(nb_config_cbs, &changes);
-       nb_config_diff(running_config, candidate, &changes);
-       ret = nb_candidate_validate_changes(candidate, &changes);
-       nb_config_diff_del_changes(&changes);
+       pthread_rwlock_rdlock(&running_config->lock);
+       {
+               nb_config_diff(running_config, candidate, &changes);
+               ret = nb_candidate_validate_changes(candidate, &changes);
+               nb_config_diff_del_changes(&changes);
+       }
+       pthread_rwlock_unlock(&running_config->lock);
 
        return ret;
 }
@@ -613,26 +631,36 @@ int nb_candidate_commit_prepare(struct nb_config *candidate,
        }
 
        RB_INIT(nb_config_cbs, &changes);
-       nb_config_diff(running_config, candidate, &changes);
-       if (RB_EMPTY(nb_config_cbs, &changes))
-               return NB_ERR_NO_CHANGES;
+       pthread_rwlock_rdlock(&running_config->lock);
+       {
+               nb_config_diff(running_config, candidate, &changes);
+               if (RB_EMPTY(nb_config_cbs, &changes)) {
+                       pthread_rwlock_unlock(&running_config->lock);
+                       return NB_ERR_NO_CHANGES;
+               }
 
-       if (nb_candidate_validate_changes(candidate, &changes) != NB_OK) {
-               flog_warn(EC_LIB_NB_CANDIDATE_INVALID,
-                         "%s: failed to validate candidate configuration",
-                         __func__);
-               nb_config_diff_del_changes(&changes);
-               return NB_ERR_VALIDATION;
-       }
+               if (nb_candidate_validate_changes(candidate, &changes)
+                   != NB_OK) {
+                       flog_warn(
+                               EC_LIB_NB_CANDIDATE_INVALID,
+                               "%s: failed to validate candidate configuration",
+                               __func__);
+                       nb_config_diff_del_changes(&changes);
+                       pthread_rwlock_unlock(&running_config->lock);
+                       return NB_ERR_VALIDATION;
+               }
 
-       *transaction =
-               nb_transaction_new(candidate, &changes, client, user, comment);
-       if (*transaction == NULL) {
-               flog_warn(EC_LIB_NB_TRANSACTION_CREATION_FAILED,
-                         "%s: failed to create transaction", __func__);
-               nb_config_diff_del_changes(&changes);
-               return NB_ERR_LOCKED;
+               *transaction = nb_transaction_new(candidate, &changes, client,
+                                                 user, comment);
+               if (*transaction == NULL) {
+                       flog_warn(EC_LIB_NB_TRANSACTION_CREATION_FAILED,
+                                 "%s: failed to create transaction", __func__);
+                       nb_config_diff_del_changes(&changes);
+                       pthread_rwlock_unlock(&running_config->lock);
+                       return NB_ERR_LOCKED;
+               }
        }
+       pthread_rwlock_unlock(&running_config->lock);
 
        return nb_transaction_process(NB_EV_PREPARE, *transaction);
 }
@@ -651,7 +679,11 @@ void nb_candidate_commit_apply(struct nb_transaction *transaction,
 
        /* Replace running by candidate. */
        transaction->config->version++;
-       nb_config_replace(running_config, transaction->config, true);
+       pthread_rwlock_wrlock(&running_config->lock);
+       {
+               nb_config_replace(running_config, transaction->config, true);
+       }
+       pthread_rwlock_unlock(&running_config->lock);
 
        /* Record transaction. */
        if (save_transaction
@@ -931,40 +963,52 @@ static int nb_transaction_process(enum nb_event event,
 {
        struct nb_config_cb *cb;
 
-       RB_FOREACH (cb, nb_config_cbs, &transaction->changes) {
-               struct nb_config_change *change = (struct nb_config_change *)cb;
-               int ret;
-
-               /*
-                * Only try to release resources that were allocated
-                * successfully.
-                */
-               if (event == NB_EV_ABORT && change->prepare_ok == false)
-                       break;
+       /*
+        * Need to lock the running configuration since transaction->changes
+        * can contain pointers to data nodes from the running configuration.
+        */
+       pthread_rwlock_rdlock(&running_config->lock);
+       {
+               RB_FOREACH (cb, nb_config_cbs, &transaction->changes) {
+                       struct nb_config_change *change =
+                               (struct nb_config_change *)cb;
+                       int ret;
 
-               /* Call the appropriate callback. */
-               ret = nb_callback_configuration(event, change);
-               switch (event) {
-               case NB_EV_PREPARE:
-                       if (ret != NB_OK)
-                               return ret;
-                       change->prepare_ok = true;
-                       break;
-               case NB_EV_ABORT:
-               case NB_EV_APPLY:
                        /*
-                        * At this point it's not possible to reject the
-                        * transaction anymore, so any failure here can lead to
-                        * inconsistencies and should be treated as a bug.
-                        * Operations prone to errors, like validations and
-                        * resource allocations, should be performed during the
-                        * 'prepare' phase.
+                        * Only try to release resources that were allocated
+                        * successfully.
                         */
-                       break;
-               default:
-                       break;
+                       if (event == NB_EV_ABORT && change->prepare_ok == false)
+                               break;
+
+                       /* Call the appropriate callback. */
+                       ret = nb_callback_configuration(event, change);
+                       switch (event) {
+                       case NB_EV_PREPARE:
+                               if (ret != NB_OK) {
+                                       pthread_rwlock_unlock(
+                                               &running_config->lock);
+                                       return ret;
+                               }
+                               change->prepare_ok = true;
+                               break;
+                       case NB_EV_ABORT:
+                       case NB_EV_APPLY:
+                               /*
+                                * At this point it's not possible to reject the
+                                * transaction anymore, so any failure here can
+                                * lead to inconsistencies and should be treated
+                                * as a bug. Operations prone to errors, like
+                                * validations and resource allocations, should
+                                * be performed during the 'prepare' phase.
+                                */
+                               break;
+                       default:
+                               break;
+                       }
                }
        }
+       pthread_rwlock_unlock(&running_config->lock);
 
        return NB_OK;
 }
index dca33b905ff68baea078dfe5c9856a7195309d72..909bb08ebef1ffa4e42ac92e76f1817e311021b2 100644 (file)
@@ -422,8 +422,19 @@ enum nb_client {
 
 /* Northbound configuration. */
 struct nb_config {
+       /* Configuration data. */
        struct lyd_node *dnode;
+
+       /* Configuration version. */
        uint32_t version;
+
+       /*
+        * Lock protecting this structure. The use of this lock is always
+        * necessary when reading or modifying the global running configuration.
+        * For candidate configurations, use of this lock is optional depending
+        * on the threading scheme of the northbound plugin.
+        */
+       pthread_rwlock_t lock;
 };
 
 /* Northbound configuration callback. */
index cd79c0608e0c2a6c73dcd35bd992cd495227933b..ae1b0578a004ef473da89b2c97ea8c74a6a2a906 100644 (file)
@@ -193,8 +193,13 @@ int nb_cli_apply_changes(struct vty *vty, const char *xpath_base_fmt, ...)
                                "Please check the logs for more details.\n");
 
                        /* Regenerate candidate for consistency. */
-                       nb_config_replace(vty->candidate_config, running_config,
-                                         true);
+                       pthread_rwlock_rdlock(&running_config->lock);
+                       {
+                               nb_config_replace(vty->candidate_config,
+                                                 running_config, true);
+                       }
+                       pthread_rwlock_unlock(&running_config->lock);
+
                        return CMD_WARNING_CONFIG_FAILED;
                }
        }
@@ -302,7 +307,12 @@ static int nb_cli_commit(struct vty *vty, bool force,
 
        /* "confirm" parameter. */
        if (confirmed_timeout) {
-               vty->confirmed_commit_rollback = nb_config_dup(running_config);
+               pthread_rwlock_rdlock(&running_config->lock);
+               {
+                       vty->confirmed_commit_rollback =
+                               nb_config_dup(running_config);
+               }
+               pthread_rwlock_unlock(&running_config->lock);
 
                vty->t_confirmed_commit_timeout = NULL;
                thread_add_timer(master, nb_cli_confirmed_commit_timeout, vty,
@@ -316,8 +326,13 @@ static int nb_cli_commit(struct vty *vty, bool force,
        /* Map northbound return code to CLI return code. */
        switch (ret) {
        case NB_OK:
-               nb_config_replace(vty->candidate_config_base, running_config,
-                                 true);
+               pthread_rwlock_rdlock(&running_config->lock);
+               {
+                       nb_config_replace(vty->candidate_config_base,
+                                         running_config, true);
+               }
+               pthread_rwlock_unlock(&running_config->lock);
+
                vty_out(vty,
                        "%% Configuration committed successfully (Transaction ID #%u).\n\n",
                        transaction_id);
@@ -682,7 +697,12 @@ DEFPY (config_update,
                return CMD_WARNING;
        }
 
-       nb_config_replace(vty->candidate_config_base, running_config, true);
+       pthread_rwlock_rdlock(&running_config->lock);
+       {
+               nb_config_replace(vty->candidate_config_base, running_config,
+                                 true);
+       }
+       pthread_rwlock_unlock(&running_config->lock);
 
        vty_out(vty, "%% Candidate configuration updated successfully.\n\n");
 
@@ -782,8 +802,12 @@ DEFPY (show_config_running,
                }
        }
 
-       nb_cli_show_config(vty, running_config, format, translator,
-                          !!with_defaults);
+       pthread_rwlock_rdlock(&running_config->lock);
+       {
+               nb_cli_show_config(vty, running_config, format, translator,
+                                  !!with_defaults);
+       }
+       pthread_rwlock_unlock(&running_config->lock);
 
        return CMD_SUCCESS;
 }
@@ -897,57 +921,68 @@ DEFPY (show_config_compare,
        struct nb_config *config2, *config_transaction2 = NULL;
        int ret = CMD_WARNING;
 
-       if (c1_candidate)
-               config1 = vty->candidate_config;
-       else if (c1_running)
-               config1 = running_config;
-       else {
-               config_transaction1 = nb_db_transaction_load(c1_tid);
-               if (!config_transaction1) {
-                       vty_out(vty, "%% Transaction %u does not exist\n\n",
-                               (unsigned int)c1_tid);
-                       goto exit;
+       /*
+        * For simplicity, lock the running configuration regardless if it's
+        * going to be used or not.
+        */
+       pthread_rwlock_rdlock(&running_config->lock);
+       {
+               if (c1_candidate)
+                       config1 = vty->candidate_config;
+               else if (c1_running)
+                       config1 = running_config;
+               else {
+                       config_transaction1 = nb_db_transaction_load(c1_tid);
+                       if (!config_transaction1) {
+                               vty_out(vty,
+                                       "%% Transaction %u does not exist\n\n",
+                                       (unsigned int)c1_tid);
+                               goto exit;
+                       }
+                       config1 = config_transaction1;
                }
-               config1 = config_transaction1;
-       }
 
-       if (c2_candidate)
-               config2 = vty->candidate_config;
-       else if (c2_running)
-               config2 = running_config;
-       else {
-               config_transaction2 = nb_db_transaction_load(c2_tid);
-               if (!config_transaction2) {
-                       vty_out(vty, "%% Transaction %u does not exist\n\n",
-                               (unsigned int)c2_tid);
-                       goto exit;
+               if (c2_candidate)
+                       config2 = vty->candidate_config;
+               else if (c2_running)
+                       config2 = running_config;
+               else {
+                       config_transaction2 = nb_db_transaction_load(c2_tid);
+                       if (!config_transaction2) {
+                               vty_out(vty,
+                                       "%% Transaction %u does not exist\n\n",
+                                       (unsigned int)c2_tid);
+                               goto exit;
+                       }
+                       config2 = config_transaction2;
                }
-               config2 = config_transaction2;
-       }
 
-       if (json)
-               format = NB_CFG_FMT_JSON;
-       else if (xml)
-               format = NB_CFG_FMT_XML;
-       else
-               format = NB_CFG_FMT_CMDS;
+               if (json)
+                       format = NB_CFG_FMT_JSON;
+               else if (xml)
+                       format = NB_CFG_FMT_XML;
+               else
+                       format = NB_CFG_FMT_CMDS;
 
-       if (translator_family) {
-               translator = yang_translator_find(translator_family);
-               if (!translator) {
-                       vty_out(vty, "%% Module translator \"%s\" not found\n",
-                               translator_family);
-                       goto exit;
+               if (translator_family) {
+                       translator = yang_translator_find(translator_family);
+                       if (!translator) {
+                               vty_out(vty,
+                                       "%% Module translator \"%s\" not found\n",
+                                       translator_family);
+                               goto exit;
+                       }
                }
-       }
 
-       ret = nb_cli_show_config_compare(vty, config1, config2, format,
-                                        translator);
-exit:
-       if (config_transaction1)
-               nb_config_free(config_transaction1);
-       if (config_transaction2)
-               nb_config_free(config_transaction2);
+               ret = nb_cli_show_config_compare(vty, config1, config2, format,
+                                                translator);
+       exit:
+               if (config_transaction1)
+                       nb_config_free(config_transaction1);
+               if (config_transaction2)
+                       nb_config_free(config_transaction2);
+       }
+       pthread_rwlock_unlock(&running_config->lock);
 
        return ret;
 }
index 2fc3c81cf2a5987bfd0bb815bdc192a83abda8e7..e9669fc7e16c8d5cb6a313f022b0a5acb75c20e4 100644 (file)
@@ -289,7 +289,11 @@ static int frr_confd_cdb_read_cb_prepare(int fd, int *subp, int reslen)
        struct cdb_iter_args iter_args;
        int ret;
 
-       candidate = nb_config_dup(running_config);
+       pthread_rwlock_rdlock(&running_config->lock);
+       {
+               candidate = nb_config_dup(running_config);
+       }
+       pthread_rwlock_unlock(&running_config->lock);
 
        /* Iterate over all configuration changes. */
        iter_args.candidate = candidate;
index e21f57d37e79d81cd57c09cf71a8fb971bbbad2c..44a55137f82e23e93227c74369b1aaa7a5f52695 100644 (file)
@@ -256,7 +256,11 @@ static int frr_sr_config_change_cb_verify(sr_session_ctx_t *session,
                return ret;
        }
 
-       candidate = nb_config_dup(running_config);
+       pthread_rwlock_rdlock(&running_config->lock);
+       {
+               candidate = nb_config_dup(running_config);
+       }
+       pthread_rwlock_unlock(&running_config->lock);
 
        while ((ret = sr_get_change_next(session, it, &sr_op, &sr_old_val,
                                         &sr_new_val))
index da9bee6e108188ee9aa611b0dbdd72b5db64724c..0ee9b78b91f9afa77951178dbd734bd003396e08 100644 (file)
--- a/lib/vty.c
+++ b/lib/vty.c
@@ -2608,17 +2608,22 @@ int vty_config_enter(struct vty *vty, bool private_config, bool exclusive)
        vty->private_config = private_config;
        vty->xpath_index = 0;
 
-       if (private_config) {
-               vty->candidate_config = nb_config_dup(running_config);
-               vty->candidate_config_base = nb_config_dup(running_config);
-               vty_out(vty,
-                       "Warning: uncommitted changes will be discarded on exit.\n\n");
-       } else {
-               vty->candidate_config = vty_shared_candidate_config;
-               if (frr_get_cli_mode() == FRR_CLI_TRANSACTIONAL)
+       pthread_rwlock_rdlock(&running_config->lock);
+       {
+               if (private_config) {
+                       vty->candidate_config = nb_config_dup(running_config);
                        vty->candidate_config_base =
                                nb_config_dup(running_config);
+                       vty_out(vty,
+                               "Warning: uncommitted changes will be discarded on exit.\n\n");
+               } else {
+                       vty->candidate_config = vty_shared_candidate_config;
+                       if (frr_get_cli_mode() == FRR_CLI_TRANSACTIONAL)
+                               vty->candidate_config_base =
+                                       nb_config_dup(running_config);
+               }
        }
+       pthread_rwlock_unlock(&running_config->lock);
 
        return CMD_SUCCESS;
 }