Skip to content

Commit

Permalink
Use generic clixon code for shared yang-specs
Browse files Browse the repository at this point in the history
  • Loading branch information
olofhagsand committed Jun 7, 2024
1 parent eddd75c commit 5cbf0ec
Show file tree
Hide file tree
Showing 4 changed files with 54 additions and 98 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
Clixon controller:
The Clixon controller is an open-source manager of network devices based on NETCONF and YANG.

See [Install](INSTALL.md), [User guide](https://clixon-controller-docs.readthedocs.io/en/latest) and [FAQ](FAQ.md)
See [Install](INSTALL.md), [User guide](https://clixon-controller-docs.readthedocs.io/en/latest), [project page](https://www.clicon.org/#controller) and [FAQ](FAQ.md)

Clixon interaction is best done posting issues, pull requests, or joining the
[Matrix clixon forum](https://matrix.to/#/#clixonforum:matrix.org).
Expand Down
96 changes: 16 additions & 80 deletions src/controller_cli.c
Original file line number Diff line number Diff line change
Expand Up @@ -137,73 +137,15 @@ controller_cli_exit(clixon_handle h)
return retval;
}

/*! Check if there is another equivalent xyanglib and if so reuse that yspec
*
* Prereq: schema-list (xyanglib) is completely known.
* Look for an existing equivalent schema-list among other devices.
* If found, re-use that YANG-SPEC.
* @param[in] h Clixon handle
* @param[in] xdev0 XML device tree full state
* @param[in] xyanglib0 Yang-lib in XML format
* @param[out] yspec1 Yang-spec to use, new or shared with previously created
* @retval 0 OK
* @retval -1 Error
* ßee device_shared_yspec for backend code
*/
static int
device_shared_yspec_xml(clixon_handle h,
cxobj *xdev0,
cxobj *xdevs,
cxobj *xyanglib0,
yang_stmt **yspec1)
{
int retval = -1;
yang_stmt *yspec = NULL;
cxobj *xdev;
cxobj *xyanglib;
char *devname;

if (clicon_option_bool(h, "CLICON_YANG_SCHEMA_MOUNT_SHARE")) {
xdev = NULL;
while ((xdev = xml_child_each(xdevs, xdev, CX_ELMNT)) != NULL) {
if (strcmp(xml_find_body(xdev, "name"), xml_find_body(xdev0, "name")) == 0)
continue;
if ((xyanglib = xpath_first(xdev, 0, "config/yang-library")) == NULL)
continue;
if (xml_tree_equal(xyanglib0, xyanglib) != 0)
continue;
if ((devname = xml_find_body(xdev, "name")) == NULL)
continue;
if (controller_mount_yspec_get(h, devname, &yspec) < 0)
goto done;
if (yspec != NULL){
clixon_debug(CLIXON_DBG_CTRL, "shared");
yang_ref_inc(yspec); /* share */
break;
}
}
}
if (yspec1) {
if (yspec == NULL){
if ((yspec = yspec_new()) == NULL)
goto done;
}
*yspec1 = yspec;
}
retval = 0;
done:
return retval;
}

/*! Given device config, check yspec of moint-point, see if shared exists, or parse new
/*! Given device config, check yspec of mount-point, see if shared exists, or parse new
*
* Given device name and config, extract module-state (xyanglib)
* Check if yspec of mount-point exists,
* If not, check if there is another equivalent xyanglib and if so reuse that yspec
* and parse the yang modules and set yspec at mountpoint
* @param[in] h Clixon handle
* @param[in] xdev XML device tree full state
* @param[in] xdevs List of devices shallow tree
* @param[in] xdevsp List of devices shallow tree on the form <data><devices>..
* @param[in] xyanglib Yang-lib in XML format
* @param[in] devname Device name
* @param[in] treename Autocli treename
Expand All @@ -215,38 +157,30 @@ device_shared_yspec_xml(clixon_handle h,
*/
static int
check_mtpoint_yspec(clixon_handle h,
cxobj *xdevs,
cxobj *xdevsp,
char *devname,
char *treename,
yang_stmt **yspec1p)
{
int retval = -1;
yang_stmt *yspec1 = NULL;
cxobj *xdevs;
cxobj *xdev;
cxobj *xyanglib;
int ret;
cxobj *xt;

clixon_debug(CLIXON_DBG_CTRL, "");
xdevs = xml_find(xdevsp, "devices");
if ((xdev = xpath_first(xdevs, 0, "device[name='%s']", devname)) == NULL)
goto skip;
if ((xyanglib = xpath_first(xdev, 0, "config/yang-library")) == NULL)
goto skip;
if (controller_mount_yspec_get(h, devname, &yspec1) < 0)
goto done;
if (yspec1 == NULL){
/* Check if there is another equivalent xyanglib and if so reuse that yspec */
if (device_shared_yspec_xml(h, xdev, xdevs, xyanglib, &yspec1) < 0)
goto done;
if (yspec1 == NULL){
clixon_err(OE_YANG, 0, "No yang spec");
goto done;
}
/* Parse YANGs locally from the yang specs */
if ((ret = yang_lib2yspec(h, xyanglib, yspec1)) < 0)
goto done;
if (controller_mount_yspec_set(h, devname, yspec1) < 0)
if ((xt = xml_find(xdev, "config")) != NULL){
if (yang_schema_yanglib_parse_mount(h, xt) < 0)
goto done;
}
if (controller_mount_yspec_get(h, devname, &yspec1) < 0)
goto done;
if (yspec1p)
*yspec1p = yspec1;
retval = 1;
Expand Down Expand Up @@ -340,7 +274,7 @@ controller_gentree_all(cligen_handle ch)
* But only for first match
*/
xdev0 = NULL;
while ((xdev0 = xml_child_each(xdevs0, xdev0, CX_ELMNT)) != NULL) {
while ((xdev0 = xml_child_each(xml_find(xdevs0, "devices"), xdev0, CX_ELMNT)) != NULL) {
if ((devname = xml_find_body(xdev0, "name")) == NULL)
continue;
if (pattern != NULL && fnmatch(pattern, devname, 0) != 0)
Expand All @@ -350,9 +284,10 @@ controller_gentree_all(cligen_handle ch)
newtree = cbuf_get(cb);
if ((ph = cligen_ph_find(ch, newtree)) == NULL){
/* No such cligen specs, query full modules once */
if (xdevs1 == NULL)
if (xdevs1 == NULL){
if (rpc_get_yanglib_mount_match(h, "*", 0, 1, &xdevs1) < 0)
goto done;
}
if (xdevs1 == NULL)
continue;
if ((ret = check_mtpoint_yspec(h, xdevs1, devname, newtree, &yspec1)) < 0)
Expand Down Expand Up @@ -432,7 +367,7 @@ controller_gentree_one(cligen_handle ch,
* But only for first match
*/
xdev0 = NULL;
while ((xdev0 = xml_child_each(xdevs0, xdev0, CX_ELMNT)) != NULL) {
while ((xdev0 = xml_child_each(xml_find(xdevs0, "devices"), xdev0, CX_ELMNT)) != NULL) {
if ((devname = xml_find_body(xdev0, "name")) == NULL)
continue;
if (pattern != NULL && fnmatch(pattern, devname, 0) != 0)
Expand All @@ -449,9 +384,10 @@ controller_gentree_one(cligen_handle ch,
if ((ph = cligen_ph_find(ch, newtree)) == NULL){
/* No such cligen specs, query full modules once
(* is optimization so you dont need to call again) */
if (xdevs1 == NULL)
if (xdevs1 == NULL){
if (rpc_get_yanglib_mount_match(h, "*", 0, 1, &xdevs1) < 0)
goto done;
}
if (xdevs1 == NULL)
continue;
if ((ret = check_mtpoint_yspec(h, xdevs1, devname, newtree, &yspec1)) < 0)
Expand Down
50 changes: 35 additions & 15 deletions src/controller_cli_callbacks.c
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ cli_apipath2xpath(clixon_handle h,
* @param[in] pattern Name glob pattern
* @param[in] single pattern is a single device that can be used in an xpath
* @param[in] yanglib 0: only device name, 1: Also include config/yang-librarylib
* @param[out] xdevsp XML on the form <devices><device><name>x</name>...
* @param[out] xdevsp XML on the form <data><devices><device><name>x</name>...</data>
* @retval 0 OK
* @retval -1 Error
* XXX: see https://github.com/clicon/clixon/issues/485
Expand All @@ -148,15 +148,19 @@ rpc_get_yanglib_mount_match(clixon_handle h,
int yanglib,
cxobj **xdevsp)
{
int retval = -1;
cbuf *cb = NULL;
cxobj *xtop = NULL;
cxobj *xrpc;
cxobj *xdevs = NULL;
cxobj *xdev;
char *devname;
cxobj *xret = NULL;
cxobj *xerr;
int retval = -1;
cbuf *cb = NULL;
cxobj *xtop = NULL;
cxobj *xrpc;
cxobj *xdevs = NULL;
cxobj *xdev;
char *devname;
cxobj *xret = NULL;
cxobj *xerr;
cxobj *xp;
yang_stmt *yspec;
int ret;


clixon_debug(CLIXON_DBG_CTRL, "");
if ((cb = cbuf_new()) == NULL){
Expand Down Expand Up @@ -197,7 +201,21 @@ rpc_get_yanglib_mount_match(clixon_handle h,
clixon_err_netconf(h, OE_XML, 0, xerr, "Get configuration");
goto done;
}

if ((xdevs = xpath_first(xret, NULL, "rpc-reply/data/devices")) != NULL){
if ((yspec = clicon_dbspec_yang(h)) == NULL){
clixon_err(OE_FATAL, 0, "No DB_SPEC");
goto done;
}
/* Populate XML with Yang spec. Binding is done in clicon_rpc_netconf of RPC only
* where <data> is ANYDATA
*/
if ((ret = xml_bind_yang0(h, xdevs, YB_MODULE, yspec, &xerr)) < 0)
goto done;
if (ret == 0){
clixon_err_netconf(h, OE_XML, 0, xerr, "Get devices config");
goto done;
}
xdev = NULL;
while ((xdev = xml_child_each(xdevs, xdev, CX_ELMNT)) != NULL) {
if ((devname = xml_find_body(xdev, "name")) == NULL ||
Expand All @@ -208,9 +226,11 @@ rpc_get_yanglib_mount_match(clixon_handle h,
if (xml_tree_prune_flagged_sub(xdevs, XML_FLAG_MARK, 1, NULL) < 0)
goto done;
/* Double check that there is at least one device */
if (xdevsp && xpath_first(xdevs, NULL, "device/name") != NULL){
*xdevsp = xdevs;
xml_rm(*xdevsp);
if (xdevsp && xpath_first(xdevs, NULL, "device/name") != NULL &&
(xp = xml_parent(xdevs))){
xml_rm(xp);
xml_spec_set(xp, NULL);
*xdevsp = xp;
}
}
retval = 0;
Expand Down Expand Up @@ -335,7 +355,7 @@ cli_show_auto_devs(clixon_handle h,
}
else {
xdev = NULL;
while ((xdev = xml_child_each(xdevs, xdev, CX_ELMNT)) != NULL) {
while ((xdev = xml_child_each(xml_find(xdevs, "devices"), xdev, CX_ELMNT)) != NULL) {
if ((devname = xml_find_body(xdev, "name")) == NULL)
continue;
cv_string_set(cv, devname); /* replace name */
Expand Down Expand Up @@ -2112,7 +2132,7 @@ cli_dbxml_devs(clixon_handle h,
}
else {
xdev = NULL;
while ((xdev = xml_child_each(xdevs, xdev, CX_ELMNT)) != NULL) {
while ((xdev = xml_child_each(xml_find(xdevs, "devices"), xdev, CX_ELMNT)) != NULL) {
if ((devname = xml_find_body(xdev, "name")) == NULL)
continue;
cv_string_set(cv, devname); /* replace name */
Expand Down
4 changes: 2 additions & 2 deletions src/controller_device_state.c
Original file line number Diff line number Diff line change
Expand Up @@ -1006,8 +1006,8 @@ device_state_check_sanity(device_handle dh,
char *rpcname)
{
if (tid == 0 || ct == NULL){
device_close_connection(dh, "Device %s not associated with transaction in state %s",
name, device_state_int2str(conn_state));
device_close_connection(dh, "Unexped rpc %s from device %s in state %s: device is not part of any transaction",
rpcname, name, device_state_int2str(conn_state));
return 0;
}
if (ct->ct_state != TS_INIT && ct->ct_state != TS_RESOLVED){
Expand Down

0 comments on commit 5cbf0ec

Please sign in to comment.