Skip to content

Fix libyang backlinks issue: #9545

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
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
113 changes: 81 additions & 32 deletions src/sonic-yang-mgmt/sonic_yang.py
Original file line number Diff line number Diff line change
Expand Up @@ -348,6 +348,9 @@ def _find_data_node(self, data_xpath):
def _find_schema_node(self, schema_xpath):
try:
schema_set = self.ctx.find_path(schema_xpath)
if schema_set is None:
return None

for schema_node in schema_set.schema():
if (schema_xpath == schema_node.path()):
return schema_node
Expand Down Expand Up @@ -497,21 +500,45 @@ def _find_data_nodes(self, data_xpath):
- Exception if schema node not found
"""
def _find_schema_dependencies(self, schema_xpath):
ref_list = []
try:
schema_node = self._find_schema_node(schema_xpath)
except Exception as e:
self.sysLog(msg="Cound not find the schema node from xpath: " + str(schema_xpath), debug=syslog.LOG_ERR, doPrint=True)
self.fail(e)
return ref_list

schema_node = ly.Schema_Node_Leaf(schema_node)
backlinks = schema_node.backlinks()
if backlinks.number() > 0:
for link in backlinks.schema():
self.sysLog(msg="backlink schema: {}".format(link.path()), doPrint=True)
ref_list.append(link.path())
return ref_list
backlinks = []

modules = self.ctx.get_module_iter()
for module in modules:
instantiables = module.data_instantiables(0)
if len(instantiables) < 1:
continue

schema = instantiables[0]
# find all backlinks for this schema node
schema_list = schema.tree_dfs()
for elem in schema_list:
if ly.LYS_LEAF == elem.nodetype() or ly.LYS_LEAFLIST == elem.nodetype():
subtype = elem.subtype()
if subtype is None:
continue

base_type = subtype.type().base()
#union of leafref
if base_type == ly.LY_TYPE_UNION:
count = subtype.type().info().uni().count()
types = subtype.type().info().uni().types()
for i in range(count):
dertype = types[i]
if dertype.base() == ly.LY_TYPE_LEAFREF:
leafref_path = dertype.info().lref().path()

if leafref_path == schema_xpath:
backlinks.append(elem.path())
continue

if base_type != ly.LY_TYPE_LEAFREF:
continue

leafref_path = self._get_leafref_path(elem.path())

if leafref_path == schema_xpath:
backlinks.append(elem.path())
return backlinks

"""
find_data_dependencies(): find the data dependencies from data xpath
Expand All @@ -530,13 +557,13 @@ def find_data_dependencies(self, data_xpath):

try:
value = str(self._find_data_node_value(data_xpath))

schema_node = ly.Schema_Node_Leaf(data_node.schema())
backlinks = schema_node.backlinks()
if backlinks is not None and backlinks.number() > 0:
for link in backlinks.schema():
node_set = node.find_path(link.path())
for data_set in node_set.data():
#backlinks of this scheme node
backlinks = self._find_schema_dependencies(schema_node.path())
#data dependencies for this data node
for link in backlinks:
node_set = node.find_path(link)
for data_set in node_set.data():
data_set.schema()
casted = data_set.subtype()
if value == casted.value_str():
Expand Down Expand Up @@ -607,7 +634,8 @@ def _get_data_type(self, schema_xpath):
return None

if (schema_node is not None):
return schema_node.subtype().type().base()
if schema_node.subtype() != None:
return schema_node.subtype().type().base()

return ly.LY_TYPE_UNKNOWN

Expand All @@ -617,15 +645,15 @@ def _get_data_type(self, schema_xpath):
output: type of the node this leafref references to
"""
def _get_leafref_type(self, data_xpath):
data_node = self._find_data_node(data_xpath)
if (data_node is not None):
subtype = data_node.subtype()
if (subtype is not None):
if data_node.schema().subtype().type().base() != ly.LY_TYPE_LEAFREF:
self.sysLog(msg="get_leafref_type() node type for data xpath: {} is not LEAFREF".format(data_xpath), debug=syslog.LOG_ERR, doPrint=True)
return ly.LY_TYPE_UNKNOWN
else:
return subtype.value_type()
#get leafref's reference schema path
try:
data_node = self._find_data_node(data_xpath)
except Exception as e:
print("_get_leafref_type(): Failed to find data node from xpath: {}".format(data_xapth))
return ly.LY_TYPE_UNKNOWN

if data_node != None:
return self._get_leafref_type_schema(data_node.schema().path())

return ly.LY_TYPE_UNKNOWN

Expand All @@ -639,6 +667,15 @@ def _get_leafref_path(self, schema_xpath):
if (schema_node is not None):
subtype = schema_node.subtype()
if (subtype is not None):
base_type = subtype.type().base()
if base_type == ly.LY_TYPE_UNION:
count = subtype.type().info().uni().count()
types = subtype.type().info().uni().types()
for i in range(count):
dertype = types[i]
if dertype.base() == ly.LY_TYPE_LEAFREF:
return dertype.info().lref().path()

if subtype.type().base() != ly.LY_TYPE_LEAFREF:
return None
else:
Expand All @@ -656,10 +693,22 @@ def _get_leafref_type_schema(self, schema_xpath):
if (schema_node is not None):
subtype = schema_node.subtype()
if (subtype is not None):
base_type = subtype.type().base()
#union of leafref
if base_type == ly.LY_TYPE_UNION:
count = subtype.type().info().uni().count()
types = subtype.type().info().uni().types()
for i in range(count):
dertype = types[i]
if dertype.base() == ly.LY_TYPE_LEAFREF:
target = dertype.info().lref().target()
target_path = target.path()
target_type = self._get_data_type(target_path)
return target_type

if subtype.type().base() != ly.LY_TYPE_LEAFREF:
return None
else:
subtype.type().info().lref().path()
target = subtype.type().info().lref().target()
target_path = target.path()
target_type = self._get_data_type(target_path)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,12 @@
"vlanid": 111,
"port": "Ethernet6",
"tagging_mode": "tagged"
}
},
{
"vlanid": 111,
"port": "Ethernet8",
"tagging_mode": "tagged"
}
]
}
},
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
module test-vlan {

yang-version 1.1;

namespace "http://github.com/Azure/vlan";
prefix vlan;

Expand All @@ -21,6 +23,11 @@ module test-vlan {
revision-date 2019-07-01;
}

import test-portchannel {
prefix lag;
revision-date 2019-07-01;
}

revision 2019-07-01 {
description "First Revision";
}
Expand Down Expand Up @@ -125,9 +132,14 @@ module test-vlan {
leaf port {
/* key elements are mandatory by default */
mandatory true;
type leafref {
path /port:port/port:PORT/port:PORT_LIST/port:port_name;
}
type union {
type leafref {
path /port:port/port:PORT/port:PORT_LIST/port:port_name;
}
type leafref {
path /lag:portchannel/lag:PORTCHANNEL/lag:PORTCHANNEL_LIST/lag:portchannel_name;
}
}
}

leaf tagging_mode {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,8 @@
"dependencies" : [
"/test-acl:acl/ACL_TABLE/ACL_TABLE_LIST[ACL_TABLE_NAME='PACL-V6']/ports[.='Ethernet8']",
"/test-interface:interface/INTERFACE/INTERFACE_LIST[interface='Ethernet8'][ip-prefix='10.1.1.64/26']/interface",
"/test-interface:interface/INTERFACE/INTERFACE_LIST[interface='Ethernet8'][ip-prefix='2000:f500:40:a749::/126']/interface"
"/test-interface:interface/INTERFACE/INTERFACE_LIST[interface='Ethernet8'][ip-prefix='2000:f500:40:a749::/126']/interface",
"/test-vlan:vlan/VLAN_MEMBER/VLAN_MEMBER_LIST[vlanid='111'][port='Ethernet8']/port"
],
"xpath" : "/test-port:port/PORT/PORT_LIST[port_name='Ethernet8']/port_name"
},
Expand Down