Ryu of_config library doesn't use namespace, compatible with ofc-server (howewer, it obtains it with get_config), in edit_config request. Instead of this, Ryu send request in its own hardcoded 'urn:onf:of111:config:yang' namespace.
Signed-off-by: Raman Budny <raman_bu...@epam.com> --- This is "improved" version of previous patch with implemented proposals from Yamamoto Takashi. Unfortunately, I haven't found any pointers in of-config specifications (v1.1.1, v1.2), what namespace for elements of of-config messages should be used. > > I try to setup OVS with OF-Config. > > I think, that it's possible with openvswitch/of-config project > > (https://github.com/openvswitch/of-config), and Ryu of_config library. > > > > However, when I'm trying to test them by simple get_config/set_config > > requests, I got this error: > > Traceback (most recent call last): > > File "test_ovs_ofconfig.py", line 23, in <module> > > client.get_set() > > File "test_ovs_ofconfig.py", line 19, in get_set > > self.switch.edit_config('running', csw) > > File > > "/usr/local/lib/python2.7/dist-packages/ryu/lib/of_config/capable_switch.py", > > line 118, in edit_config > > self.raw_edit_config(target, xml, default_operation) > > File > > "/usr/local/lib/python2.7/dist-packages/ryu/lib/of_config/capable_switch.py", > > line 108, in raw_edit_config > > default_operation, test_option, error_option) > > File > > "/usr/local/lib/python2.7/dist-packages/ryu/contrib/ncclient/manager.py", > > line 78, in wrapper > > return self.execute(op_cls, *args, **kwds) > > File > > "/usr/local/lib/python2.7/dist-packages/ryu/contrib/ncclient/manager.py", > > line 132, in execute > > raise_mode=self._raise_mode).request(*args, **kwds) > > File > > "/usr/local/lib/python2.7/dist-packages/ryu/contrib/ncclient/operations/edit.py", > > line 58, in request > > return self._request(node) > > File > > "/usr/local/lib/python2.7/dist-packages/ryu/contrib/ncclient/operations/rpc.py", > > line 289, in _request > > raise self._reply.error > > ncclient.operations.rpc.RPCError: Some unspecified error occurred. > > > > Maintainer of openvswitch/of-config project has figured out, that this > > error appear due to hardcoded namespace sent by Ryu in edit_config > > request. > > > > For more detailed information, see > > https://github.com/openvswitch/of-config/issues/3 > > https://github.com/openvswitch/of-config/issues/5 > > reading the spec, i'm not sure what's the right way to negotiate > the version. i commented on the issue #5. > > > > > Patch body: > > diff --git a/ryu/lib/of_config/__init__.py b/ryu/lib/of_config/__init__.py > > index b2dbd05..0f47e97 100644 > > --- a/ryu/lib/of_config/__init__.py > > +++ b/ryu/lib/of_config/__init__.py > > @@ -47,7 +47,11 @@ OFCONFIG_1_1_YANG = 'urn:onf:of12:config:yang' > > # LINC specific? > > OFCONFIG_1_1_1_YANG = 'urn:onf:of111:config:yang' > > > > +# OVS OF-Config specific? > > +OFCONFIG_OFC_YANG = 'urn:onf:config:yang' > > + > > OFCONFIG_YANG_NAMESPACES = { > > '1.1': OFCONFIG_1_1_YANG, > > '1.1.1': OFCONFIG_1_1_1_YANG, > > + 'ofc': OFCONFIG_OFC_YANG, > > } > > diff --git a/ryu/lib/of_config/base.py b/ryu/lib/of_config/base.py > > index c657b10..8122152 100644 > > --- a/ryu/lib/of_config/base.py > > +++ b/ryu/lib/of_config/base.py > > @@ -51,11 +51,20 @@ class _ct(_e): > > > > > > class _Base(stringify.StringifyMixin): > > - _M = objectify.ElementMaker(annotate=False, > > - namespace=_ns_of111, > > - nsmap=_nsmap) > > - > > you can remove _nsmap as it's now unused. > > > def __init__(self, **kwargs): > > + ns_of = _ns_of111 > > + if 'namespace' in kwargs: > > + ns_of = kwargs.pop('namespace') > > + > > + nsmap = { > > + 'of': ns_of, > > + 'nc': _ns_netconf, > > + } > > + > > + self._m = objectify.ElementMaker(annotate=False, > > + namespace=ns_of, > > + nsmap=nsmap) > > + > > for e in self._ELEMENTS: > > k = _pythonify(e.name) > > try: > > @@ -81,7 +90,7 @@ class _Base(stringify.StringifyMixin): > > elif isinstance(v, objectify.ObjectifiedElement): > > assert ET.QName(v.tag).localname == itag > > return v > > - return self._M(itag, v) > > + return self._m(itag, v) > > > > args = [] > > for e in self._ELEMENTS: > > @@ -97,25 +106,27 @@ class _Base(stringify.StringifyMixin): > > assert not e.is_list > > ele = [convert(v)] > > args.extend(ele) > > - return self._M(tag, *args) > > + return self._m(tag, *args) > > > > def to_xml(self, tag): > > e = self.to_et(tag) > > return ET.tostring(e, pretty_print=True) > > > > @classmethod > > - def from_xml(cls, xmlstring): > > + def from_xml(cls, xmlstring, namespace=_ns_of111): > > et = objectify.fromstring(xmlstring) > > - return cls.from_et(et) > > + return cls.from_et(et, namespace) > > > > @classmethod > > - def from_et(cls, et): > > + def from_et(cls, et, namespace=_ns_of111): > > def convert(v): > > if e.cls is not None: > > - return e.cls.from_et(v) > > + return e.cls.from_et(v, namespace) > > return v > > > > - kwargs = {} > > + kwargs = { > > + 'namespace': namespace, > > + } > > for e in cls._ELEMENTS: > > try: > > v = et[e.name] > > diff --git a/ryu/lib/of_config/capable_switch.py > > b/ryu/lib/of_config/capable_switch.py > > index 91f4013..11ff202 100644 > > --- a/ryu/lib/of_config/capable_switch.py > > +++ b/ryu/lib/of_config/capable_switch.py > > @@ -108,13 +108,13 @@ class OFCapableSwitch(object): > > default_operation, test_option, > > error_option) > > > > def get(self): > > - return ofc.OFCapableSwitchType.from_xml(self.raw_get()) > > + return ofc.OFCapableSwitchType.from_xml(self.raw_get(), > > self.namespace) > > > > def get_config(self, source): > > - return > > ofc.OFCapableSwitchType.from_xml(self.raw_get_config(source)) > > + return > > ofc.OFCapableSwitchType.from_xml(self.raw_get_config(source), > > self.namespace) > > > > def edit_config(self, target, capable_switch, default_operation=None): > > - xml = ofc.NETCONF_Config(capable_switch=capable_switch).to_xml() > > + xml = ofc.NETCONF_Config(namespace=self.namespace, > > capable_switch=capable_switch).to_xml() > > self.raw_edit_config(target, xml, default_operation) > > self.namespace might be set if this is the first operation. > how about: > if self.namespace is None: > self.raw_get() # dummy GET to find out the namespace to use. > > > > > def delete_config(self, source): Actual patch: diff --git a/ryu/lib/of_config/__init__.py b/ryu/lib/of_config/__init__.py index b2dbd05..0f47e97 100644 --- a/ryu/lib/of_config/__init__.py +++ b/ryu/lib/of_config/__init__.py @@ -47,7 +47,11 @@ OFCONFIG_1_1_YANG = 'urn:onf:of12:config:yang' # LINC specific? OFCONFIG_1_1_1_YANG = 'urn:onf:of111:config:yang' +# OVS OF-Config specific? +OFCONFIG_OFC_YANG = 'urn:onf:config:yang' + OFCONFIG_YANG_NAMESPACES = { '1.1': OFCONFIG_1_1_YANG, '1.1.1': OFCONFIG_1_1_1_YANG, + 'ofc': OFCONFIG_OFC_YANG, } diff --git a/ryu/lib/of_config/base.py b/ryu/lib/of_config/base.py index c657b10..05ecab3 100644 --- a/ryu/lib/of_config/base.py +++ b/ryu/lib/of_config/base.py @@ -26,10 +26,6 @@ import lxml.etree as ET _ns_of111 = 'urn:onf:of111:config:yang' _ns_netconf = 'urn:ietf:params:xml:ns:netconf:base:1.0' -_nsmap = { - 'of111': _ns_of111, - 'nc': _ns_netconf, -} def _pythonify(name): @@ -51,11 +47,20 @@ class _ct(_e): class _Base(stringify.StringifyMixin): - _M = objectify.ElementMaker(annotate=False, - namespace=_ns_of111, - nsmap=_nsmap) - def __init__(self, **kwargs): + ns_of = _ns_of111 + if 'namespace' in kwargs: + ns_of = kwargs.pop('namespace') + + nsmap = { + 'of': ns_of, + 'nc': _ns_netconf, + } + + self._m = objectify.ElementMaker(annotate=False, + namespace=ns_of, + nsmap=nsmap) + for e in self._ELEMENTS: k = _pythonify(e.name) try: @@ -81,7 +86,7 @@ class _Base(stringify.StringifyMixin): elif isinstance(v, objectify.ObjectifiedElement): assert ET.QName(v.tag).localname == itag return v - return self._M(itag, v) + return self._m(itag, v) args = [] for e in self._ELEMENTS: @@ -97,25 +102,27 @@ class _Base(stringify.StringifyMixin): assert not e.is_list ele = [convert(v)] args.extend(ele) - return self._M(tag, *args) + return self._m(tag, *args) def to_xml(self, tag): e = self.to_et(tag) return ET.tostring(e, pretty_print=True) @classmethod - def from_xml(cls, xmlstring): + def from_xml(cls, xmlstring, namespace=_ns_of111): et = objectify.fromstring(xmlstring) - return cls.from_et(et) + return cls.from_et(et, namespace) @classmethod - def from_et(cls, et): + def from_et(cls, et, namespace=_ns_of111): def convert(v): if e.cls is not None: - return e.cls.from_et(v) + return e.cls.from_et(v, namespace) return v - kwargs = {} + kwargs = { + 'namespace': namespace, + } for e in cls._ELEMENTS: try: v = et[e.name] diff --git a/ryu/lib/of_config/capable_switch.py b/ryu/lib/of_config/capable_switch.py index 91f4013..fa74dfe 100644 --- a/ryu/lib/of_config/capable_switch.py +++ b/ryu/lib/of_config/capable_switch.py @@ -108,13 +108,16 @@ class OFCapableSwitch(object): default_operation, test_option, error_option) def get(self): - return ofc.OFCapableSwitchType.from_xml(self.raw_get()) + return ofc.OFCapableSwitchType.from_xml(self.raw_get(), self.namespace) def get_config(self, source): - return ofc.OFCapableSwitchType.from_xml(self.raw_get_config(source)) + return ofc.OFCapableSwitchType.from_xml(self.raw_get_config(source), self.namespace) def edit_config(self, target, capable_switch, default_operation=None): - xml = ofc.NETCONF_Config(capable_switch=capable_switch).to_xml() + if self.namespace is None: + self.raw_get() + + xml = ofc.NETCONF_Config(namespace=self.namespace, capable_switch=capable_switch).to_xml() self.raw_edit_config(target, xml, default_operation) def delete_config(self, source): ------------------------------------------------------------------------------ Dive into the World of Parallel Programming The Go Parallel Website, sponsored by Intel and developed in partnership with Slashdot Media, is your hub for all things parallel software development, from weekly thought leadership blogs to news, videos, case studies, tutorials and more. Take a look and join the conversation now. http://goparallel.sourceforge.net/ _______________________________________________ Ryu-devel mailing list Ryu-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/ryu-devel