From 13d6b9c1343a1f925e3ffd7be0938bf1f395b461 Mon Sep 17 00:00:00 2001 From: Renato Westphal Date: Mon, 27 Apr 2020 13:13:57 -0300 Subject: [PATCH] lib: introduce the northbound context structure The new northbound context structure contains information about the client performing a configuration transaction. This information will be made available to all configuration callbacks through the args->context parameter. The usefulness of this structure comes from the fact that it can be used as a communication channel (both input and output) between the northbound callbacks and the northbound clients. This can be done through its "client_data" field which contains client-specific data. This should cover some very specific scenarios where a northbound callback should perform an action only if the configuration change is coming from a given client. An example would be sending a PCEP response to a PCE when an SR-TE policy is created or modified through the PCEP northbound client (for that to happen, the northbound callbacks need to have access to the PCEP request ID, which needs to be available). Signed-off-by: Renato Westphal --- lib/libfrr.c | 8 ++-- lib/northbound.c | 93 ++++++++++++++++++++++++---------------- lib/northbound.h | 75 ++++++++++++++++++++++++-------- lib/northbound_cli.c | 32 ++++++++++---- lib/northbound_confd.c | 6 ++- lib/northbound_db.c | 2 +- lib/northbound_grpc.cpp | 12 ++++-- lib/northbound_sysrepo.c | 10 +++-- lib/vty.c | 9 ++-- 9 files changed, 168 insertions(+), 79 deletions(-) diff --git a/lib/libfrr.c b/lib/libfrr.c index ac165f254..d52cef3fe 100644 --- a/lib/libfrr.c +++ b/lib/libfrr.c @@ -902,11 +902,13 @@ static int frr_config_read_in(struct thread *t) * reading the configuration file. */ if (frr_get_cli_mode() == FRR_CLI_TRANSACTIONAL) { + struct nb_context context = {}; int ret; - ret = nb_candidate_commit(vty_shared_candidate_config, - NB_CLIENT_CLI, NULL, true, - "Read configuration file", NULL); + context.client = NB_CLIENT_CLI; + ret = nb_candidate_commit(&context, vty_shared_candidate_config, + true, "Read configuration file", + NULL); if (ret != NB_OK && ret != NB_ERR_NO_CHANGES) zlog_err("%s: failed to read configuration file.", __func__); diff --git a/lib/northbound.c b/lib/northbound.c index c49aff70b..e5349ad4e 100644 --- a/lib/northbound.c +++ b/lib/northbound.c @@ -62,14 +62,15 @@ static struct { */ static bool transaction_in_progress; -static int nb_callback_pre_validate(const struct nb_node *nb_node, +static int nb_callback_pre_validate(struct nb_context *context, + const struct nb_node *nb_node, const struct lyd_node *dnode); -static int nb_callback_configuration(const enum nb_event event, +static int nb_callback_configuration(struct nb_context *context, + const enum nb_event event, struct nb_config_change *change); -static struct nb_transaction *nb_transaction_new(struct nb_config *config, +static struct nb_transaction *nb_transaction_new(struct nb_context *context, + struct nb_config *config, struct nb_config_cbs *changes, - enum nb_client client, - const void *user, const char *comment); static void nb_transaction_free(struct nb_transaction *transaction); static int nb_transaction_process(enum nb_event event, @@ -592,7 +593,8 @@ static int nb_candidate_validate_yang(struct nb_config *candidate) } /* Perform code-level validation using the northbound callbacks. */ -static int nb_candidate_validate_code(struct nb_config *candidate, +static int nb_candidate_validate_code(struct nb_context *context, + struct nb_config *candidate, struct nb_config_cbs *changes) { struct nb_config_cb *cb; @@ -608,7 +610,7 @@ static int nb_candidate_validate_code(struct nb_config *candidate, if (!nb_node->cbs.pre_validate) goto next; - ret = nb_callback_pre_validate(nb_node, child); + ret = nb_callback_pre_validate(context, nb_node, child); if (ret != NB_OK) return NB_ERR_VALIDATION; @@ -621,7 +623,8 @@ static int nb_candidate_validate_code(struct nb_config *candidate, RB_FOREACH (cb, nb_config_cbs, changes) { struct nb_config_change *change = (struct nb_config_change *)cb; - ret = nb_callback_configuration(NB_EV_VALIDATE, change); + ret = nb_callback_configuration(context, NB_EV_VALIDATE, + change); if (ret != NB_OK) return NB_ERR_VALIDATION; } @@ -629,7 +632,8 @@ static int nb_candidate_validate_code(struct nb_config *candidate, return NB_OK; } -int nb_candidate_validate(struct nb_config *candidate) +int nb_candidate_validate(struct nb_context *context, + struct nb_config *candidate) { struct nb_config_cbs changes; int ret; @@ -639,14 +643,14 @@ int nb_candidate_validate(struct nb_config *candidate) RB_INIT(nb_config_cbs, &changes); nb_config_diff(running_config, candidate, &changes); - ret = nb_candidate_validate_code(candidate, &changes); + ret = nb_candidate_validate_code(context, candidate, &changes); nb_config_diff_del_changes(&changes); return ret; } -int nb_candidate_commit_prepare(struct nb_config *candidate, - enum nb_client client, const void *user, +int nb_candidate_commit_prepare(struct nb_context *context, + struct nb_config *candidate, const char *comment, struct nb_transaction **transaction) { @@ -664,7 +668,7 @@ int nb_candidate_commit_prepare(struct nb_config *candidate, if (RB_EMPTY(nb_config_cbs, &changes)) return NB_ERR_NO_CHANGES; - if (nb_candidate_validate_code(candidate, &changes) != NB_OK) { + if (nb_candidate_validate_code(context, candidate, &changes) != NB_OK) { flog_warn(EC_LIB_NB_CANDIDATE_INVALID, "%s: failed to validate candidate configuration", __func__); @@ -673,7 +677,7 @@ int nb_candidate_commit_prepare(struct nb_config *candidate, } *transaction = - nb_transaction_new(candidate, &changes, client, user, comment); + nb_transaction_new(context, candidate, &changes, comment); if (*transaction == NULL) { flog_warn(EC_LIB_NB_TRANSACTION_CREATION_FAILED, "%s: failed to create transaction", __func__); @@ -709,14 +713,14 @@ void nb_candidate_commit_apply(struct nb_transaction *transaction, nb_transaction_free(transaction); } -int nb_candidate_commit(struct nb_config *candidate, enum nb_client client, - const void *user, bool save_transaction, - const char *comment, uint32_t *transaction_id) +int nb_candidate_commit(struct nb_context *context, struct nb_config *candidate, + bool save_transaction, const char *comment, + uint32_t *transaction_id) { struct nb_transaction *transaction = NULL; int ret; - ret = nb_candidate_commit_prepare(candidate, client, user, comment, + ret = nb_candidate_commit_prepare(context, candidate, comment, &transaction); /* * Apply the changes if the preparation phase succeeded. Otherwise abort @@ -801,7 +805,8 @@ static void nb_log_config_callback(const enum nb_event event, value); } -static int nb_callback_create(const struct nb_node *nb_node, +static int nb_callback_create(struct nb_context *context, + const struct nb_node *nb_node, enum nb_event event, const struct lyd_node *dnode, union nb_resource *resource) { @@ -809,13 +814,15 @@ static int nb_callback_create(const struct nb_node *nb_node, nb_log_config_callback(event, NB_OP_CREATE, dnode); + args.context = context; args.event = event; args.dnode = dnode; args.resource = resource; return nb_node->cbs.create(&args); } -static int nb_callback_modify(const struct nb_node *nb_node, +static int nb_callback_modify(struct nb_context *context, + const struct nb_node *nb_node, enum nb_event event, const struct lyd_node *dnode, union nb_resource *resource) { @@ -823,13 +830,15 @@ static int nb_callback_modify(const struct nb_node *nb_node, nb_log_config_callback(event, NB_OP_MODIFY, dnode); + args.context = context; args.event = event; args.dnode = dnode; args.resource = resource; return nb_node->cbs.modify(&args); } -static int nb_callback_destroy(const struct nb_node *nb_node, +static int nb_callback_destroy(struct nb_context *context, + const struct nb_node *nb_node, enum nb_event event, const struct lyd_node *dnode) { @@ -837,24 +846,28 @@ static int nb_callback_destroy(const struct nb_node *nb_node, nb_log_config_callback(event, NB_OP_DESTROY, dnode); + args.context = context; args.event = event; args.dnode = dnode; return nb_node->cbs.destroy(&args); } -static int nb_callback_move(const struct nb_node *nb_node, enum nb_event event, +static int nb_callback_move(struct nb_context *context, + const struct nb_node *nb_node, enum nb_event event, const struct lyd_node *dnode) { struct nb_cb_move_args args = {}; nb_log_config_callback(event, NB_OP_MOVE, dnode); + args.context = context; args.event = event; args.dnode = dnode; return nb_node->cbs.move(&args); } -static int nb_callback_pre_validate(const struct nb_node *nb_node, +static int nb_callback_pre_validate(struct nb_context *context, + const struct nb_node *nb_node, const struct lyd_node *dnode) { struct nb_cb_pre_validate_args args = {}; @@ -865,13 +878,15 @@ static int nb_callback_pre_validate(const struct nb_node *nb_node, return nb_node->cbs.pre_validate(&args); } -static void nb_callback_apply_finish(const struct nb_node *nb_node, +static void nb_callback_apply_finish(struct nb_context *context, + const struct nb_node *nb_node, const struct lyd_node *dnode) { struct nb_cb_apply_finish_args args = {}; nb_log_config_callback(NB_EV_APPLY, NB_OP_APPLY_FINISH, dnode); + args.context = context; args.dnode = dnode; nb_node->cbs.apply_finish(&args); } @@ -952,7 +967,8 @@ int nb_callback_rpc(const struct nb_node *nb_node, const char *xpath, * Call the northbound configuration callback associated to a given * configuration change. */ -static int nb_callback_configuration(const enum nb_event event, +static int nb_callback_configuration(struct nb_context *context, + const enum nb_event event, struct nb_config_change *change) { enum nb_operation operation = change->cb.operation; @@ -969,16 +985,18 @@ static int nb_callback_configuration(const enum nb_event event, switch (operation) { case NB_OP_CREATE: - ret = nb_callback_create(nb_node, event, dnode, resource); + ret = nb_callback_create(context, nb_node, event, dnode, + resource); break; case NB_OP_MODIFY: - ret = nb_callback_modify(nb_node, event, dnode, resource); + ret = nb_callback_modify(context, nb_node, event, dnode, + resource); break; case NB_OP_DESTROY: - ret = nb_callback_destroy(nb_node, event, dnode); + ret = nb_callback_destroy(context, nb_node, event, dnode); break; case NB_OP_MOVE: - ret = nb_callback_move(nb_node, event, dnode); + ret = nb_callback_move(context, nb_node, event, dnode); break; default: yang_dnode_get_path(dnode, xpath, sizeof(xpath)); @@ -1027,13 +1045,14 @@ static int nb_callback_configuration(const enum nb_event event, return ret; } -static struct nb_transaction * -nb_transaction_new(struct nb_config *config, struct nb_config_cbs *changes, - enum nb_client client, const void *user, const char *comment) +static struct nb_transaction *nb_transaction_new(struct nb_context *context, + struct nb_config *config, + struct nb_config_cbs *changes, + const char *comment) { struct nb_transaction *transaction; - if (nb_running_lock_check(client, user)) { + if (nb_running_lock_check(context->client, context->user)) { flog_warn( EC_LIB_NB_TRANSACTION_CREATION_FAILED, "%s: running configuration is locked by another client", @@ -1051,7 +1070,7 @@ nb_transaction_new(struct nb_config *config, struct nb_config_cbs *changes, transaction_in_progress = true; transaction = XCALLOC(MTYPE_TMP, sizeof(*transaction)); - transaction->client = client; + transaction->context = context; if (comment) strlcpy(transaction->comment, comment, sizeof(transaction->comment)); @@ -1086,7 +1105,8 @@ static int nb_transaction_process(enum nb_event event, break; /* Call the appropriate callback. */ - ret = nb_callback_configuration(event, change); + ret = nb_callback_configuration(transaction->context, event, + change); switch (event) { case NB_EV_PREPARE: if (ret != NB_OK) @@ -1199,7 +1219,8 @@ static void nb_transaction_apply_finish(struct nb_transaction *transaction) /* Call the 'apply_finish' callbacks, sorted by their priorities. */ RB_FOREACH (cb, nb_config_cbs, &cbs) - nb_callback_apply_finish(cb->nb_node, cb->dnode); + nb_callback_apply_finish(transaction->context, cb->nb_node, + cb->dnode); /* Release memory. */ while (!RB_EMPTY(nb_config_cbs, &cbs)) { diff --git a/lib/northbound.h b/lib/northbound.h index 44727ca0d..caa7a9f82 100644 --- a/lib/northbound.h +++ b/lib/northbound.h @@ -91,6 +91,9 @@ union nb_resource { */ struct nb_cb_create_args { + /* Context of the configuration transaction. */ + struct nb_context *context; + /* * The transaction phase. Refer to the documentation comments of * nb_event for more details. @@ -110,6 +113,9 @@ struct nb_cb_create_args { }; struct nb_cb_modify_args { + /* Context of the configuration transaction. */ + struct nb_context *context; + /* * The transaction phase. Refer to the documentation comments of * nb_event for more details. @@ -129,6 +135,9 @@ struct nb_cb_modify_args { }; struct nb_cb_destroy_args { + /* Context of the configuration transaction. */ + struct nb_context *context; + /* * The transaction phase. Refer to the documentation comments of * nb_event for more details. @@ -140,6 +149,9 @@ struct nb_cb_destroy_args { }; struct nb_cb_move_args { + /* Context of the configuration transaction. */ + struct nb_context *context; + /* * The transaction phase. Refer to the documentation comments of * nb_event for more details. @@ -151,11 +163,17 @@ struct nb_cb_move_args { }; struct nb_cb_pre_validate_args { + /* Context of the configuration transaction. */ + struct nb_context *context; + /* libyang data node associated with the 'pre_validate' callback. */ const struct lyd_node *dnode; }; struct nb_cb_apply_finish_args { + /* Context of the configuration transaction. */ + struct nb_context *context; + /* libyang data node associated with the 'apply_finish' callback. */ const struct lyd_node *dnode; }; @@ -538,6 +556,29 @@ enum nb_client { NB_CLIENT_GRPC, }; +/* Northbound context. */ +struct nb_context { + /* Northbound client. */ + enum nb_client client; + + /* Northbound user (can be NULL). */ + const void *user; + + /* Client-specific data. */ +#if 0 + union { + struct { + } cli; + struct { + } confd; + struct { + } sysrepo; + struct { + } grpc; + } client_data; +#endif +}; + /* Northbound configuration. */ struct nb_config { struct lyd_node *dnode; @@ -564,7 +605,7 @@ struct nb_config_change { /* Northbound configuration transaction. */ struct nb_transaction { - enum nb_client client; + struct nb_context *context; char comment[80]; struct nb_config *config; struct nb_config_cbs changes; @@ -762,28 +803,29 @@ extern int nb_candidate_update(struct nb_config *candidate); * WARNING: the candidate can be modified as part of the validation process * (e.g. add default nodes). * + * context + * Context of the northbound transaction. + * * candidate * Candidate configuration to validate. * * Returns: * NB_OK on success, NB_ERR_VALIDATION otherwise. */ -extern int nb_candidate_validate(struct nb_config *candidate); +extern int nb_candidate_validate(struct nb_context *context, + struct nb_config *candidate); /* * Create a new configuration transaction but do not commit it yet. Only * validate the candidate and prepare all resources required to apply the * configuration changes. * + * context + * Context of the northbound transaction. + * * candidate * Candidate configuration to commit. * - * client - * Northbound client performing the commit. - * - * user - * Northbound user performing the commit (can be NULL). - * * comment * Optional comment describing the commit. * @@ -803,8 +845,8 @@ extern int nb_candidate_validate(struct nb_config *candidate); * the candidate configuration. * - NB_ERR for other errors. */ -extern int nb_candidate_commit_prepare(struct nb_config *candidate, - enum nb_client client, const void *user, +extern int nb_candidate_commit_prepare(struct nb_context *context, + struct nb_config *candidate, const char *comment, struct nb_transaction **transaction); @@ -842,16 +884,13 @@ extern void nb_candidate_commit_apply(struct nb_transaction *transaction, * take into account the results of the preparation phase of multiple managed * entities. * + * context + * Context of the northbound transaction. + * * candidate * Candidate configuration to commit. It's preserved regardless if the commit * operation fails or not. * - * client - * Northbound client performing the commit. - * - * user - * Northbound user performing the commit (can be NULL). - * * save_transaction * Specify whether the transaction should be recorded in the transactions log * or not. @@ -872,8 +911,8 @@ extern void nb_candidate_commit_apply(struct nb_transaction *transaction, * the candidate configuration. * - NB_ERR for other errors. */ -extern int nb_candidate_commit(struct nb_config *candidate, - enum nb_client client, const void *user, +extern int nb_candidate_commit(struct nb_context *context, + struct nb_config *candidate, bool save_transaction, const char *comment, uint32_t *transaction_id); diff --git a/lib/northbound_cli.c b/lib/northbound_cli.c index d4467faca..544b2434e 100644 --- a/lib/northbound_cli.c +++ b/lib/northbound_cli.c @@ -169,8 +169,12 @@ int nb_cli_apply_changes(struct vty *vty, const char *xpath_base_fmt, ...) /* Do an implicit "commit" when using the classic CLI mode. */ if (frr_get_cli_mode() == FRR_CLI_CLASSIC) { - ret = nb_candidate_commit(vty->candidate_config, NB_CLIENT_CLI, - vty, false, NULL, NULL); + struct nb_context context = {}; + + context.client = NB_CLIENT_CLI; + context.user = vty; + ret = nb_candidate_commit(&context, vty->candidate_config, + false, NULL, NULL); if (ret != NB_OK && ret != NB_ERR_NO_CHANGES) { vty_out(vty, "%% Configuration failed: %s.\n\n", nb_err_name(ret)); @@ -217,12 +221,16 @@ void nb_cli_confirmed_commit_clean(struct vty *vty) int nb_cli_confirmed_commit_rollback(struct vty *vty) { + struct nb_context context = {}; uint32_t transaction_id; int ret; + /* Perform the rollback. */ + context.client = NB_CLIENT_CLI; + context.user = vty; ret = nb_candidate_commit( - vty->confirmed_commit_rollback, NB_CLIENT_CLI, vty, true, + &context, vty->confirmed_commit_rollback, true, "Rollback to previous configuration - confirmed commit has timed out", &transaction_id); if (ret == NB_OK) @@ -252,6 +260,7 @@ static int nb_cli_confirmed_commit_timeout(struct thread *thread) static int nb_cli_commit(struct vty *vty, bool force, unsigned int confirmed_timeout, char *comment) { + struct nb_context context = {}; uint32_t transaction_id = 0; int ret; @@ -295,8 +304,10 @@ static int nb_cli_commit(struct vty *vty, bool force, &vty->t_confirmed_commit_timeout); } - ret = nb_candidate_commit(vty->candidate_config, NB_CLIENT_CLI, vty, - true, comment, &transaction_id); + context.client = NB_CLIENT_CLI; + context.user = vty; + ret = nb_candidate_commit(&context, vty->candidate_config, true, + comment, &transaction_id); /* Map northbound return code to CLI return code. */ switch (ret) { @@ -690,9 +701,12 @@ DEFPY (config_commit_check, "Commit changes into the running configuration\n" "Check if the configuration changes are valid\n") { + struct nb_context context = {}; int ret; - ret = nb_candidate_validate(vty->candidate_config); + context.client = NB_CLIENT_CLI; + context.user = vty; + ret = nb_candidate_validate(&context, vty->candidate_config); if (ret != NB_OK) { vty_out(vty, "%% Failed to validate candidate configuration.\n\n"); @@ -1530,6 +1544,7 @@ DEFPY (show_yang_module_translator, static int nb_cli_rollback_configuration(struct vty *vty, uint32_t transaction_id) { + struct nb_context context = {}; struct nb_config *candidate; char comment[80]; int ret; @@ -1544,8 +1559,9 @@ static int nb_cli_rollback_configuration(struct vty *vty, snprintf(comment, sizeof(comment), "Rollback to transaction %u", transaction_id); - ret = nb_candidate_commit(candidate, NB_CLIENT_CLI, vty, true, comment, - NULL); + context.client = NB_CLIENT_CLI; + context.user = vty; + ret = nb_candidate_commit(&context, candidate, true, comment, NULL); nb_config_free(candidate); switch (ret) { case NB_OK: diff --git a/lib/northbound_confd.c b/lib/northbound_confd.c index 2fc3c81cf..50daa62e5 100644 --- a/lib/northbound_confd.c +++ b/lib/northbound_confd.c @@ -285,6 +285,7 @@ frr_confd_cdb_diff_iter(confd_hkeypath_t *kp, enum cdb_iter_op cdb_op, static int frr_confd_cdb_read_cb_prepare(int fd, int *subp, int reslen) { + struct nb_context context = {}; struct nb_config *candidate; struct cdb_iter_args iter_args; int ret; @@ -321,8 +322,9 @@ static int frr_confd_cdb_read_cb_prepare(int fd, int *subp, int reslen) * required to apply them. */ transaction = NULL; - ret = nb_candidate_commit_prepare(candidate, NB_CLIENT_CONFD, NULL, - NULL, &transaction); + context.client = NB_CLIENT_CONFD; + ret = nb_candidate_commit_prepare(&context, candidate, NULL, + &transaction); if (ret != NB_OK && ret != NB_ERR_NO_CHANGES) { enum confd_errcode errcode; const char *errmsg; diff --git a/lib/northbound_db.c b/lib/northbound_db.c index 598805b96..244e760b2 100644 --- a/lib/northbound_db.c +++ b/lib/northbound_db.c @@ -86,7 +86,7 @@ int nb_db_transaction_save(const struct nb_transaction *transaction, if (!ss) goto exit; - client_name = nb_client_name(transaction->client); + client_name = nb_client_name(transaction->context->client); /* Always record configurations in the XML format. */ if (lyd_print_mem(&config_str, transaction->config->dnode, LYD_XML, LYP_FORMAT | LYP_WITHSIBLINGS) diff --git a/lib/northbound_grpc.cpp b/lib/northbound_grpc.cpp index 2962a977e..b038d1011 100644 --- a/lib/northbound_grpc.cpp +++ b/lib/northbound_grpc.cpp @@ -672,13 +672,17 @@ class NorthboundImpl // Execute the user request. + struct nb_context context = {}; + context.client = NB_CLIENT_GRPC; + switch (phase) { case frr::CommitRequest::VALIDATE: - ret = nb_candidate_validate(candidate->config); + ret = nb_candidate_validate(&context, + candidate->config); break; case frr::CommitRequest::PREPARE: ret = nb_candidate_commit_prepare( - candidate->config, NB_CLIENT_GRPC, NULL, + &context, candidate->config, comment.c_str(), &candidate->transaction); break; @@ -693,8 +697,8 @@ class NorthboundImpl break; case frr::CommitRequest::ALL: ret = nb_candidate_commit( - candidate->config, NB_CLIENT_GRPC, NULL, - true, comment.c_str(), &transaction_id); + &context, candidate->config, true, + comment.c_str(), &transaction_id); break; } diff --git a/lib/northbound_sysrepo.c b/lib/northbound_sysrepo.c index b94c93976..4d15c80a2 100644 --- a/lib/northbound_sysrepo.c +++ b/lib/northbound_sysrepo.c @@ -245,6 +245,7 @@ static int frr_sr_config_change_cb_verify(sr_session_ctx_t *session, sr_change_oper_t sr_op; sr_val_t *sr_old_val, *sr_new_val; char xpath[XPATH_MAXLEN]; + struct nb_context context = {}; struct nb_config *candidate; snprintf(xpath, sizeof(xpath), "/%s:*", module_name); @@ -276,21 +277,22 @@ static int frr_sr_config_change_cb_verify(sr_session_ctx_t *session, } transaction = NULL; + context.client = NB_CLIENT_SYSREPO; if (startup_config) { /* * sysrepod sends the entire startup configuration using a * single event (SR_EV_ENABLED). This means we need to perform * the full two-phase commit protocol in one go here. */ - ret = nb_candidate_commit(candidate, NB_CLIENT_SYSREPO, NULL, - true, NULL, NULL); + ret = nb_candidate_commit(&context, candidate, true, NULL, + NULL); } else { /* * Validate the configuration changes and allocate all resources * required to apply them. */ - ret = nb_candidate_commit_prepare(candidate, NB_CLIENT_SYSREPO, - NULL, NULL, &transaction); + ret = nb_candidate_commit_prepare(&context, candidate, NULL, + &transaction); } /* Map northbound return code to sysrepo return code. */ diff --git a/lib/vty.c b/lib/vty.c index 784f9cf2a..146666ec6 100644 --- a/lib/vty.c +++ b/lib/vty.c @@ -2349,9 +2349,12 @@ static void vty_read_file(struct nb_config *config, FILE *confp) * reading the configuration file. */ if (config == NULL) { - ret = nb_candidate_commit(vty->candidate_config, NB_CLIENT_CLI, - vty, true, "Read configuration file", - NULL); + struct nb_context context = {}; + + context.client = NB_CLIENT_CLI; + context.user = vty; + ret = nb_candidate_commit(&context, vty->candidate_config, true, + "Read configuration file", NULL); if (ret != NB_OK && ret != NB_ERR_NO_CHANGES) zlog_err("%s: failed to read configuration file.", __func__); -- 2.39.5