-
Notifications
You must be signed in to change notification settings - Fork 199
privcand UPDATE add private candidate datastore support #1805
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
Ardival
wants to merge
1
commit into
CESNET:devel
Choose a base branch
from
Ardival:devel
base: devel
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,111 @@ | ||
| module ietf-netconf-private-candidate { | ||
| yang-version 1.1; | ||
| namespace "urn:ietf:params:xml:ns:yang:ietf-netconf-private-candidate"; | ||
| prefix pc; | ||
|
|
||
|
|
||
| organization | ||
| "IETF NETCONF (Network Configuration) Working Group"; | ||
| contact | ||
| "WG Web: <http://tools.ietf.org/wg/netconf/> | ||
| WG List: <netconf@ietf.org> | ||
|
|
||
| Editor: James Cumming | ||
| <james.cumming@nokia.com> | ||
|
|
||
| Editor: Robert Wills | ||
| <rowills@cisco.com>"; | ||
| description | ||
| "NETCONF private candidate support. | ||
|
|
||
| Copyright (c) 2026 IETF Trust and the persons identified as | ||
| authors of the code. All rights reserved. | ||
|
|
||
| Redistribution and use in source and binary forms, with or | ||
| without modification, is permitted pursuant to, and subject to | ||
| the license terms contained in, the Revised BSD License set | ||
| forth in Section 4.c of the IETF Trust's Legal Provisions | ||
| Relating to IETF Documents | ||
| (https://trustee.ietf.org/license-info). | ||
|
|
||
| This version of this YANG module is part of RFC XXXX | ||
| (https://www.rfc-editor.org/info/rfcXXXX); see the RFC itself | ||
| for full legal notices. | ||
|
|
||
| The key words 'MUST', 'MUST NOT', 'REQUIRED', 'SHALL', 'SHALL | ||
| NOT', 'SHOULD', 'SHOULD NOT', 'RECOMMENDED', 'NOT RECOMMENDED', | ||
| 'MAY', and 'OPTIONAL' in this document are to be interpreted as | ||
| described in BCP 14 (RFC 2119) (RFC 8174) when, and only when, | ||
| they appear in all capitals, as shown here."; | ||
|
|
||
| revision 2026-02-03 { | ||
| description | ||
| "Introduce private candidate support"; | ||
| reference | ||
| "draft-ietf-netconf-privcand: | ||
| Netconf Private Candidates"; | ||
| } | ||
| revision 2025-10-30 { | ||
| description | ||
| "Introduce private candidate support"; | ||
| reference | ||
| "draft-ietf-netconf-privcand: | ||
| Netconf Private Candidates"; | ||
| } | ||
| revision 2024-09-12 { | ||
| description | ||
| "Introduce private candidate support"; | ||
| reference | ||
| "draft-ietf-netconf-privcand: | ||
| Netconf Private Candidates"; | ||
| } | ||
|
|
||
| feature private-candidate { | ||
| description | ||
| "NETCONF :private-candidate capability; | ||
| If the server advertises the :private-candidate | ||
| capability for a session, then this feature must | ||
| also be enabled for that session. Otherwise, | ||
| this feature must not be enabled."; | ||
| reference | ||
| "draft-ietf-netconf-privcand"; | ||
| } | ||
|
|
||
| rpc update { | ||
| if-feature "private-candidate"; | ||
| description | ||
| "Updates the private candidate from the running | ||
| configuration."; | ||
| reference | ||
| "draft-ietf-netconf-privcand"; | ||
| input { | ||
| leaf resolution-mode { | ||
| type enumeration { | ||
| enum revert-on-conflict { | ||
| description | ||
| "Reject update when any conflicting | ||
| node is found and revert the private | ||
| candidate configuration datastore to its | ||
| state prior to issuing the update."; | ||
| } | ||
| enum prefer-candidate { | ||
| description | ||
| "Resolve conflicted node by selecting | ||
| the private candidate configuration | ||
| datastore version."; | ||
| } | ||
| enum prefer-running { | ||
| description | ||
| "Resolve conflicted node by selecting | ||
| the running configuration datastore | ||
| version."; | ||
| } | ||
| } | ||
| default "revert-on-conflict"; | ||
| description | ||
| "Mode to resolve conflicts between running and | ||
| private-candidate configurations."; | ||
| } | ||
| } | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -740,6 +740,9 @@ np_new_session_cb(const char *UNUSED(client_name), struct nc_session *new_sessio | |
| goto error; | ||
| } | ||
|
|
||
| user_sess->use_private_cand = nc_session_cpblt(new_session, | ||
| "urn:ietf:params:netconf:capability:private-candidate:1.0") ? 1 : 0; | ||
|
|
||
| /* generate ietf-netconf-notification's netconf-session-start event for sysrepo */ | ||
| np_send_notif_session_start(new_session, np2srv.sr_sess, np2srv.sr_timeout); | ||
|
|
||
|
|
@@ -1240,8 +1243,8 @@ np_op_filter_data_ignored_mod(struct lyd_node **data, const char *ignored_mod) | |
| } | ||
|
|
||
| struct nc_server_reply * | ||
| np_op_filter_data_get(sr_session_ctx_t *session, uint32_t max_depth, uint32_t get_opts, const char *xp_filter, | ||
| struct lyd_node **data) | ||
| np_op_filter_data_get(struct np_user_sess *user_sess, sr_datastore_t ds, uint32_t max_depth, uint32_t get_opts, | ||
| const char *xp_filter, struct lyd_node **data) | ||
| { | ||
| sr_data_t *sr_data = NULL, *sr_ln2_nc_server = NULL; | ||
| struct lyd_node *e, *ignored_mod; | ||
|
|
@@ -1255,22 +1258,31 @@ np_op_filter_data_get(sr_session_ctx_t *session, uint32_t max_depth, uint32_t ge | |
| return NULL; | ||
| } | ||
|
|
||
| /* get the selected data */ | ||
| r = sr_get_data(session, xp_filter, max_depth, np2srv.sr_timeout, get_opts, &sr_data); | ||
| /* update sysrepo session datastore */ | ||
| sr_session_switch_ds(user_sess->sess, ds); | ||
|
|
||
| if (user_sess->use_private_cand && (ds == SR_DS_CANDIDATE)) { | ||
| /* use private candidate if supported and requested */ | ||
| r = sr_pc_get_data(user_sess->sess, xp_filter, max_depth, get_opts, user_sess->private_ds, &sr_data); | ||
| } else { | ||
| /* get the selected data */ | ||
| r = sr_get_data(user_sess->sess, xp_filter, max_depth, np2srv.sr_timeout, get_opts, &sr_data); | ||
| } | ||
|
|
||
| if (r && (r != SR_ERR_NOT_FOUND)) { | ||
| ERR("Getting data \"%s\" from sysrepo failed (%s).", xp_filter, sr_strerror(r)); | ||
|
|
||
| sr_session_get_error(session, &err_info); | ||
| sr_session_get_error(user_sess->sess, &err_info); | ||
| err = &err_info->err[0]; | ||
| if (strstr(err->message, " result is not a node set.")) { | ||
| /* invalid-value */ | ||
| e = nc_err(sr_session_acquire_context(session), NC_ERR_INVALID_VALUE, NC_ERR_TYPE_APP); | ||
| sr_session_release_context(session); | ||
| e = nc_err(sr_session_acquire_context(user_sess->sess), NC_ERR_INVALID_VALUE, NC_ERR_TYPE_APP); | ||
| sr_session_release_context(user_sess->sess); | ||
| nc_err_set_msg(e, err->message, "en"); | ||
| reply = nc_server_reply_err(e); | ||
| } else { | ||
| /* other error */ | ||
| reply = np_reply_err_sr(session, "get"); | ||
| reply = np_reply_err_sr(user_sess->sess, "get"); | ||
| } | ||
| goto cleanup; | ||
| } | ||
|
|
@@ -1302,7 +1314,7 @@ np_op_filter_data_get(sr_session_ctx_t *session, uint32_t max_depth, uint32_t ge | |
| sr_release_data(sr_data); | ||
| if (r) { | ||
| /* other error */ | ||
| reply = np_reply_err_op_failed(session, NULL, ly_last_logmsg()); | ||
| reply = np_reply_err_op_failed(user_sess->sess, NULL, ly_last_logmsg()); | ||
| goto cleanup; | ||
| } | ||
| } | ||
|
|
@@ -1881,3 +1893,138 @@ sub_ntf_ds2ident(sr_datastore_t ds) | |
|
|
||
| return NULL; | ||
| } | ||
|
|
||
| /** | ||
| * @brief Convert private candidate conflict type to string. | ||
| * | ||
| * @param[in] type Conflict type to convert. | ||
| * @return String representation of the conflict type. | ||
| */ | ||
| static const char * | ||
| np_pc_conflict_type2str(sr_pc_conflict_type_t type) | ||
| { | ||
| switch (type) { | ||
| case SR_PC_CONFLICT_VALUE_CHANGE: | ||
| return "value-change"; | ||
| case SR_PC_CONFLICT_LIST_ENTRY: | ||
| return "list-entry"; | ||
| case SR_PC_CONFLICT_LIST_ORDER: | ||
| return "list-order"; | ||
| case SR_PC_CONFLICT_PRESENCE_CONTAINER: | ||
| return "presence-container"; | ||
| case SR_PC_CONFLICT_LEAFLIST_ITEM: | ||
| return "leaf-list-item"; | ||
| case SR_PC_CONFLICT_LEAFLIST_ORDER: | ||
| return "leaf-list-order"; | ||
| case SR_PC_CONFLICT_LEAF_EXISTENCE: | ||
| return "leaf-existence"; | ||
| } | ||
|
|
||
| return NULL; | ||
| } | ||
|
|
||
| /** | ||
| * @brief Get the value of the conflict node. | ||
| * | ||
| * @param[in] type Conflict node to get the value from. | ||
| * @return String value of node. In case of list the keys are returned. | ||
| */ | ||
| static char * | ||
| np_pc_conflict_value(const struct lyd_node *node) | ||
| { | ||
| char *full_path = NULL, *list_keys = NULL, *result = NULL; | ||
| const char *val; | ||
|
|
||
| switch (node->schema->nodetype) { | ||
| case LYS_CONTAINER: | ||
| /* container does not have value */ | ||
| return NULL; | ||
|
|
||
| case LYS_LIST: | ||
| full_path = lyd_path(node, LYD_PATH_STD, NULL, 0); | ||
| if (full_path) { | ||
| list_keys = strchr(full_path, '['); | ||
| if (list_keys) { | ||
| result = strdup(list_keys); | ||
| } | ||
| free(full_path); | ||
| } | ||
| return result; | ||
|
|
||
| default: | ||
| val = lyd_get_value(node); | ||
| return val ? strdup(val) : NULL; | ||
| } | ||
| } | ||
|
|
||
| struct nc_server_reply * | ||
| np_reply_err_conflict(const struct lyd_node *rpc, sr_pc_conflict_set_t *conflict_set) | ||
| { | ||
| struct lyd_node *err, *err_info_node; | ||
| char *run_val = NULL, *cand_val = NULL, *xpath = NULL; | ||
| uint32_t i; | ||
| LY_ERR r; | ||
|
|
||
| err = nc_err(LYD_CTX(rpc), NC_ERR_OP_FAILED, NC_ERR_TYPE_APP); | ||
| nc_err_set_msg(err, "Update failed due to conflicts between private candidate and running configuration.", NULL); | ||
|
|
||
| if (conflict_set) { | ||
| for (i = 0; i < conflict_set->conflict_count; i++) { | ||
| err_info_node = NULL; | ||
|
|
||
| /* conflict node */ | ||
| if ((r = lyd_new_opaq2(NULL, LYD_CTX(rpc), "conflict", NULL, NULL, | ||
| "urn:ietf:params:xml:ns:yang:ietf-netconf-private-candidate", &err_info_node))) { | ||
| goto cleanup; | ||
| } | ||
|
|
||
| /* xpath of the conflicting node */ | ||
| xpath = lyd_path(conflict_set->conflicts[i].run_diff, LYD_PATH_STD, NULL, 0); | ||
| if ((r = lyd_new_opaq2(err_info_node, LYD_CTX(rpc), "xpath", xpath, NULL, | ||
| "urn:ietf:params:xml:ns:yang:ietf-netconf-private-candidate", NULL))) { | ||
| goto cleanup; | ||
| } | ||
|
|
||
| /* conflict type */ | ||
| if ((r = lyd_new_opaq2(err_info_node, LYD_CTX(rpc), "conflict-type", | ||
| np_pc_conflict_type2str(conflict_set->conflicts[i].type), | ||
| NULL, "urn:ietf:params:xml:ns:yang:ietf-netconf-private-candidate", NULL))) { | ||
| goto cleanup; | ||
| } | ||
|
|
||
| /* values where the conflict occurs */ | ||
| run_val = np_pc_conflict_value(conflict_set->conflicts[i].run_diff); | ||
| if (run_val) { | ||
| r = lyd_new_opaq2(err_info_node, LYD_CTX(rpc), "value-running", | ||
| run_val, NULL, "urn:ietf:params:xml:ns:yang:ietf-netconf-private-candidate", NULL); | ||
| free(run_val); | ||
| if (r) { | ||
| goto cleanup; | ||
| } | ||
| } | ||
|
|
||
| cand_val = np_pc_conflict_value(conflict_set->conflicts[i].pc_diff); | ||
| if (cand_val) { | ||
| r = lyd_new_opaq2(err_info_node, LYD_CTX(rpc), "value-candidate", | ||
| cand_val, NULL, "urn:ietf:params:xml:ns:yang:ietf-netconf-private-candidate", NULL); | ||
| free(cand_val); | ||
| if (r) { | ||
| goto cleanup; | ||
| } | ||
|
|
||
| } | ||
|
|
||
| /* add conflict node into error msg*/ | ||
| nc_err_add_info_other(err, err_info_node); | ||
| } | ||
| } | ||
|
|
||
| cleanup: | ||
| free(xpath); | ||
| if (r) { | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. May be uninitialized (if |
||
| lyd_free_tree(err_info_node); | ||
| return np_reply_err_op_failed(NULL, LYD_CTX(rpc), "Failed to build conflict error message."); | ||
| } | ||
|
|
||
| return nc_server_reply_err(err); | ||
| } | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Clearer and more readable code would be to move
err_info_node = NULL;right after this line and also initializingerr_info_nodetoNULL. Thenlyd_free_tree(err_info_node)in the cleanup could be moved outside thercondition.