1 # Copyright (C) 2013 Nippon Telegraph and Telephone Corporation.
2 # Copyright (C) 2013 Isaku Yamahata <yamahata at private email ne jp>
4 # Licensed under the Apache License, Version 2.0 (the "License");
5 # you may not use this file except in compliance with the License.
6 # You may obtain a copy of the License at
8 # http://www.apache.org/licenses/LICENSE-2.0
10 # Unless required by applicable law or agreed to in writing, software
11 # distributed under the License is distributed on an "AS IS" BASIS,
12 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
14 # See the License for the specific language governing permissions and
15 # limitations under the License.
18 import ncclient.manager
21 from ryu import exception as ryu_exc
22 from ryu.lib import of_config
23 from ryu.lib.of_config import constants as ofc_consts
24 from ryu.lib.of_config import classes as ofc
27 # TODO: When we re-organize ncclient, its NCClientError will be
28 # subclass of RyuException.
29 class OFConfigCapableSwitchNotFound(ryu_exc.RyuException,
30 ncclient.NCClientError):
31 message = 'OpenFlow Capable Switch not found'
36 return tuple(tag[1:].split('}', 1))
40 class OFCapableSwitch(object):
41 def __init__(self, connect_method='connect_ssh', *args, **kwargs):
42 super(OFCapableSwitch, self).__init__()
43 self._connect_method = connect_method
44 self._connect_args = args
45 self._connect_kwargs = kwargs
49 connect = getattr(ncclient.manager, self._connect_method)
50 self.netconf = connect(*self._connect_args, **self._connect_kwargs)
52 def close_session(self):
54 self.netconf.close_session()
63 def client_capabilities(self):
64 return self.netconf.client_capabilities
66 def server_capabilities(self):
67 return self.netconf.server_capabilities
69 def _find_capable_switch(self, tree):
72 ns, tag = get_ns_tag(element.tag)
73 if tag != ofc_consts.CAPABLE_SWITCH:
76 # assumes that <get> returns only single capable switch
77 assert capable_switch is None
79 capable_switch = element
81 versions = [(version, ns_) for version, ns_ in
82 of_config.OFCONFIG_YANG_NAMESPACES.items()
85 assert len(versions) == 1
87 self.version, self.namespace = version
89 if not capable_switch:
90 raise OFConfigCapableSwitchNotFound()
94 def _find_capable_switch_xml(self, tree):
95 return ncclient.xml_.to_xml(self._find_capable_switch(tree))
97 def raw_get(self, filter=None):
98 reply = self.netconf.get(filter)
99 return self._find_capable_switch_xml(reply.data_ele)
101 def raw_get_config(self, source, filter=None):
102 reply = self.netconf.get_config(source, filter)
103 return self._find_capable_switch_xml(reply.data_ele)
105 def raw_edit_config(self, target, config, default_operation=None,
106 test_option=None, error_option=None):
107 self.netconf.edit_config(target, config,
108 default_operation, test_option, error_option)
111 return ofc.OFCapableSwitchType.from_xml(self.raw_get())
113 def get_config(self, source):
114 return ofc.OFCapableSwitchType.from_xml(self.raw_get_config(source))
116 def edit_config(self, target, capable_switch, default_operation=None):
117 xml = ofc.NETCONF_Config(capable_switch=capable_switch).to_xml()
118 self.raw_edit_config(target, xml, default_operation)
120 def delete_config(self, source):
121 self.netconf.delete_config(source)
123 def copy_config(self, source, target):
124 self.netconf.copy_config(source, target)
127 self.netconf.commit()
129 def discard_changes(self):
130 self.netconf.discard_changes()
132 # TODO: more netconf operations
133 # TODO: convinience(higher level) methods