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.
20 edit linc config file. LINC-Switch/rel/linc/releases/1.0/sys.config
21 You can find the sample config I used for the test below
23 For this following config to work, the network interface
24 linc-port and linc-port2 must be created before hand.
25 (Or edit the port name depending on your environment)
26 An easy way is to create them as follows
27 # ip link add linc-port type veth peer name linc-port-peer
28 # ip link set linc-port up
29 # ip link add linc-port2 type veth peer name linc-port-peer2
30 # ip link set linc-port2 up
33 # rel/linc/bin/linc console
36 # PYTHONPATH=. ./bin/ryu-manager --verbose \
37 ryu/tests/integrated/test_of_config.py
40 Here is my sys.config used for this test.
41 -->8-->8-->8-->8-->8-->8-->8-->8-->8-->8-->8-->8-->8---
55 {"Switch0-DefaultController", "localhost", 6633, tcp}
60 {port, 1, [{interface, "linc-port"}]},
61 {port, 2, [{interface, "linc-port2"}]}
64 {queues_status, disabled},
75 {capabilities, [{base, {1, 1}},
77 {'writable-running', {1, 0}}]},
78 {callback_module, linc_ofconfig},
91 {lager_console_backend, info},
94 {"log/error.log", error, 10485760, "$D0", 5},
95 {"log/console.log", info, 10485760, "$D0", 5}
102 {sasl_error_logger, {file, "log/sasl-error.log"}},
103 {errlog_type, error},
104 {error_logger_mf_dir, "log/sasl"}, % Log directory
105 {error_logger_mf_maxbytes, 10485760}, % 10 MB max file size
106 {error_logger_mf_maxfiles, 5} % 5 files max
109 -->8-->8-->8-->8-->8-->8-->8-->8-->8-->8-->8-->8-->8--
113 from __future__ import print_function
120 from ryu.base import app_manager
121 from ryu.lib.netconf import constants as nc_consts
122 from ryu.lib import hub
123 from ryu.lib import of_config
124 from ryu.lib.of_config import capable_switch
125 from ryu.lib.of_config import constants as ofc_consts
128 # Change those depending on switch configuration
134 CAPABLE_SWITCH_ID = 'CapableSwitch0'
135 LOGICAL_SWITCH = 'LogicalSwitch0'
136 PORT_ID = 'LogicalSwitch0-Port2'
137 CONTROLLER_ID = 'Switch0-DefaultController'
140 'capable_switch': CAPABLE_SWITCH_ID,
142 'logical_switch': LOGICAL_SWITCH,
143 'controller_id': CONTROLLER_ID,
147 SWITCH_PORT_DOWN = '''
148 <nc:config xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0">
149 <capable-switch xmlns="urn:onf:of111:config:yang">
150 <id>%(capable_switch)s</id>
153 <resource-id>%(port_id)s</resource-id>
154 <configuration operation="merge">
155 <admin-state>down</admin-state>
156 <no-receive>false</no-receive>
157 <no-forward>false</no-forward>
158 <no-packet-in>false</no-packet-in>
166 SWITCH_ADVERTISED = '''
167 <nc:config xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0">
168 <capable-switch xmlns="urn:onf:of111:config:yang">
169 <id>%(capable_switch)s</id>
172 <resource-id>%(port_id)s</resource-id>
174 <advertised operation="merge">
176 <auto-negotiate>true</auto-negotiate>
177 <medium>copper</medium>
178 <pause>unsupported</pause>
187 SWITCH_CONTROLLER = '''
188 <nc:config xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0">
189 <capable-switch xmlns="urn:onf:of111:config:yang">
190 <id>%(capable_switch)s</id>
193 <id>%(logical_switch)s</id>
195 <controller operation="merge">
196 <id>%(controller_id)s</id>
198 <ip-address>%(ip)s</ip-address>
200 <protocol>tcp</protocol>
211 # file_name = of_config.OF_CONFIG_1_0_XSD
212 # file_name = of_config.OF_CONFIG_1_1_XSD
213 file_name = of_config.OF_CONFIG_1_1_1_XSD
214 return lxml.etree.XMLSchema(file=file_name)
217 class OFConfigClient(app_manager.RyuApp):
218 def __init__(self, *args, **kwargs):
219 super(OFConfigClient, self).__init__(*args, **kwargs)
220 self.switch = capable_switch.OFCapableSwitch(
221 host=HOST, port=PORT, username=USERNAME, password=PASSWORD,
222 unknown_host_cb=lambda host, fingeprint: True)
223 hub.spawn(self._do_of_config)
225 def _validate(self, tree):
226 xmlschema = _get_schema()
228 xmlschema.assertValid(tree)
230 traceback.print_exc()
233 data_xml = self.switch.raw_get()
235 tree = lxml.etree.fromstring(data_xml)
236 # print(lxml.etree.tostring(tree, pretty_print=True))
240 for e in tree.getiterator():
241 name_spaces.add(capable_switch.get_ns_tag(e.tag)[0])
246 def _do_get_config(self, source):
247 print('source = %s' % source)
248 config_xml = self.switch.raw_get_config(source)
250 tree = lxml.etree.fromstring(config_xml)
251 # print(lxml.etree.tostring(tree, pretty_print=True))
254 def _do_edit_config(self, config):
255 tree = lxml.etree.fromstring(config)
257 self.switch.raw_edit_config(target='running', config=config)
259 def _print_ports(self, tree, ns):
260 for port in tree.findall('{%s}%s/{%s}%s' % (ns, ofc_consts.RESOURCES,
261 ns, ofc_consts.PORT)):
262 print(lxml.etree.tostring(port, pretty_print=True))
264 def _set_ports_down(self):
265 """try to set all ports down with etree operation"""
266 tree = self._do_get()
267 print(lxml.etree.tostring(tree, pretty_print=True))
269 qname = lxml.etree.QName(tree.tag)
271 self._print_ports(tree, ns)
273 switch_id = tree.find('{%s}%s' % (ns, ofc_consts.ID))
274 resources = tree.find('{%s}%s' % (ns, ofc_consts.RESOURCES))
275 configuration = tree.find(
276 '{%s}%s/{%s}%s/{%s}%s' % (ns, ofc_consts.RESOURCES,
278 ns, ofc_consts.CONFIGURATION))
279 admin_state = tree.find(
280 '{%s}%s/{%s}%s/{%s}%s/{%s}%s' % (ns, ofc_consts.RESOURCES,
282 ns, ofc_consts.CONFIGURATION,
283 ns, ofc_consts.ADMIN_STATE))
285 config_ = lxml.etree.Element(
286 '{%s}%s' % (ncclient.xml_.BASE_NS_1_0, nc_consts.CONFIG))
287 capable_switch_ = lxml.etree.SubElement(config_, tree.tag)
288 switch_id_ = lxml.etree.SubElement(capable_switch_, switch_id.tag)
289 switch_id_.text = switch_id.text
290 resources_ = lxml.etree.SubElement(capable_switch_,
292 for port in tree.findall(
293 '{%s}%s/{%s}%s' % (ns, ofc_consts.RESOURCES,
294 ns, ofc_consts.PORT)):
295 resource_id = port.find('{%s}%s' % (ns, ofc_consts.RESOURCE_ID))
297 port_ = lxml.etree.SubElement(resources_, port.tag)
298 resource_id_ = lxml.etree.SubElement(port_, resource_id.tag)
299 resource_id_.text = resource_id.text
300 configuration_ = lxml.etree.SubElement(port_, configuration.tag)
301 configuration_.set(ofc_consts.OPERATION, nc_consts.MERGE)
302 admin_state_ = lxml.etree.SubElement(configuration_,
304 admin_state_.text = ofc_consts.DOWN
305 self._do_edit_config(lxml.etree.tostring(config_, pretty_print=True))
307 tree = self._do_get()
308 self._print_ports(tree, ns)
310 def _do_of_config(self):
312 self._do_get_config('running')
313 self._do_get_config('startup')
315 # LINC doesn't support 'candidate' datastore
317 self._do_get_config('candidate')
318 except ncclient.NCClientError:
319 traceback.print_exc()
322 self._do_edit_config(SWITCH_PORT_DOWN)
323 self._do_edit_config(SWITCH_ADVERTISED)
324 self._do_edit_config(SWITCH_CONTROLLER)
326 self._set_ports_down()
328 self.switch.close_session()