Feature Request: Support RFC 6022 (NETCONF Monitoring)

* Added capabilities and schema state, and get-schema rpc
* New `clixon-config@2022-11-01.yang` revision
  * Added option:
    * `CLICON_NETCONF_MONITORING`
    * `CLICON_NETCONF_MONITORING_LOCATION`
This commit is contained in:
Olof hagsand 2022-11-22 13:56:20 +01:00
parent 8ebab16c4c
commit c94e9dad67
20 changed files with 1988 additions and 64 deletions

View file

@ -722,7 +722,7 @@ from_client_lock(clicon_handle h,
yang_stmt *yspec;
if ((yspec = clicon_dbspec_yang(h)) == NULL){
clicon_err(OE_YANG, ENOENT, "No yang spec9");
clicon_err(OE_YANG, ENOENT, "No yang spec");
goto done;
}
if ((db = netconf_db_find(xe, "target")) == NULL){
@ -1046,6 +1046,109 @@ from_client_create_subscription(clicon_handle h,
return retval;
}
/*! Retrieve a schema from the NETCONF server.
*
* @param[in] h Clicon handle
* @param[in] xe Request: <rpc><xn></rpc>
* @param[out] cbret Return xml tree, eg <rpc-reply>..., <rpc-error..
* @param[in] arg client-entry
* @param[in] regarg User argument given at rpc_callback_register()
* @retval 0 OK
* @retval -1 Error
* @see RFC6022, ietf-netconf-monitoring.yang
*/
static int
from_client_get_schema(clicon_handle h,
cxobj *xe,
cbuf *cbret,
void *arg,
void *regarg)
{
int retval = -1;
cxobj *x; /* Generic xml tree */
cvec *nsc = NULL;
char *identifier = NULL;
char *version = NULL;
char *format = NULL;
yang_stmt *yspec;
yang_stmt *ymod;
yang_stmt *ymatch;
yang_stmt *yrev;
cbuf *cbyang = NULL;
if ((yspec = clicon_dbspec_yang(h)) == NULL){
clicon_err(OE_YANG, ENOENT, "No yang spec");
goto done;
}
if ((nsc = xml_nsctx_init(NULL, NETCONF_MONITORING_NAMESPACE)) == NULL)
goto done;
if ((x = xpath_first(xe, nsc, "identifier")) == NULL){
if (netconf_missing_element(cbret, "protocol", "identifier", NULL) < 0)
goto done;
goto ok;
}
identifier = xml_body(x);
if ((x = xpath_first(xe, nsc, "version")) != NULL)
version = xml_body(x);
if ((x = xpath_first(xe, nsc, "format")) != NULL)
format = xml_body(x);
ymatch = NULL;
ymod = NULL;
while ((ymod = yn_each(yspec, ymod)) != NULL) {
if (yang_keyword_get(ymod) != Y_MODULE &&
yang_keyword_get(ymod) != Y_SUBMODULE)
continue;
if (strcmp(identifier, yang_argument_get(ymod)) != 0)
continue;
if (version){
if ((yrev = yang_find(ymod, Y_REVISION, NULL)) == NULL)
continue;
if (strcmp(version, yang_argument_get(yrev)) != 0)
continue;
ymatch = ymod;
break;
}
else if (ymatch){
/* If more than one schema matches the requested parameters, the
* <error-tag> is 'operation-failed', and <error-app-tag> is
* 'data-not-unique'.
*/
if (netconf_data_not_unique(cbret, NULL, NULL)< 0)
goto done;
goto ok;
}
else
ymatch = ymod;
}
if (ymatch == NULL){
if (netconf_invalid_value(cbret, "protocol", "No such schema") < 0)
goto done;
goto ok;
}
if (format && strcmp(format, "yang") != 0){
if (netconf_invalid_value(cbret, "protocol", "Format not supported") < 0)
goto done;
goto ok;
}
cprintf(cbret, "<rpc-reply xmlns=\"%s\"><data xmlns=\"%s\">",
NETCONF_BASE_NAMESPACE, NETCONF_MONITORING_NAMESPACE);
if ((cbyang = cbuf_new()) == NULL){
clicon_err(OE_UNIX, errno, "cbuf_new");
goto done;
}
yang_print_cbuf(cbyang, ymatch, 0, 0);
xml_chardata_cbuf_append(cbret, cbuf_get(cbyang));
cprintf(cbret, "</data></rpc-reply>");
ok:
retval = 0;
done:
if (cbyang)
cbuf_free(cbyang);
if (nsc)
xml_nsctx_free(nsc);
return retval;
}
/*! Set debug level.
* @param[in] h Clicon handle
* @param[in] xe Request: <rpc><xn></rpc>
@ -1388,6 +1491,10 @@ from_client_msg(clicon_handle h,
goto reply;
}
ce->ce_id = id;
/* As a side-effect, this expands xt with default values according to "report-all"
* This may not be correct, the RFC does not mention expanding default values for
* input RPC
*/
if ((ret = xml_yang_validate_rpc(h, x, 1, &xret)) < 0)
goto done;
if (ret == 0){
@ -1604,6 +1711,10 @@ backend_rpc_init(clicon_handle h)
if (rpc_callback_register(h, from_client_create_subscription, NULL,
EVENT_RFC5277_NAMESPACE, "create-subscription") < 0)
goto done;
/* RFC 6022 */
if (rpc_callback_register(h, from_client_get_schema, NULL,
NETCONF_MONITORING_NAMESPACE, "get-schema") < 0)
goto done;
/* Clixon RPC */
if (rpc_callback_register(h, from_client_debug, NULL,
CLIXON_LIB_NS, "debug") < 0)

View file

@ -251,6 +251,12 @@ get_client_statedata(clicon_handle h,
if (ret == 0)
goto fail;
}
if (clicon_option_bool(h, "CLICON_NETCONF_MONITORING")){
if ((ret = netconf_monitoring_state_get(h, yspec, xpath, nsc, 0, xret)) < 0)
goto done;
if (ret == 0)
goto fail;
}
/* Use plugin state callbacks */
if ((ret = clixon_plugin_statedata_all(h, yspec, nsc, xpath, xret)) < 0)
goto done;

View file

@ -470,7 +470,7 @@ netconf_notification_cb(int s,
clicon_err(OE_NETCONF, EFAULT, "Notification malformed");
goto done;
}
if ((nsc = xml_nsctx_init(NULL, NOTIFICATION_RFC5277_NAMESPACE)) == NULL)
if ((nsc = xml_nsctx_init(NULL, NETCONF_NOTIFICATION_NAMESPACE)) == NULL)
goto done;
if ((xn = xpath_first(xt, nsc, "notification")) == NULL)
goto ok;