#!/usr/bin/env python # # Copyright (C) 2013 Nippon Telegraph and Telephone Corporation. # Copyright (C) 2013 YAMAMOTO Takashi # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or # implied. # See the License for the specific language governing permissions and # limitations under the License. # a simple command line OF-CONFIG client # # a usage example: # % PYTHONPATH=. ./bin/of_config_cli \ # --peers=sw1=localhost:1830:username:password # (Cmd) raw_get sw1 import ryu.contrib ryu.contrib.update_module_path() from ryu import cfg import cmd import sys import lxml.etree as ET from ryu.lib import of_config from ryu.lib.of_config import capable_switch from ncclient.operations.rpc import RPCError import ryu.lib.of_config.classes as ofc CONF = cfg.CONF CONF.register_cli_opts([ cfg.ListOpt('peers', default=[], help='list of peers') ]) class Peer(capable_switch.OFCapableSwitch): def __init__(self, name, host, port, username, password): self._name = name super(Peer, self).__init__( host=host, port=port, username=username, password=password, unknown_host_cb=lambda host, fingeprint: True) peers = {} def add_peer(name, host, port, username, password): peers[name] = Peer(name, host, port, username, password) def et_tostring_pp(tree): # pretty_print is an lxml feature, not available in ElementTree try: return ET.tostring(tree, pretty_print=True) except TypeError: return ET.tostring(tree) def validate(tree): schema = ET.XMLSchema(file=of_config.OF_CONFIG_1_1_1_XSD) if not schema(tree): print(schema.error_log) class Cmd(cmd.Cmd): def __init__(self, *args, **kwargs): self._in_onecmd = False cmd.Cmd.__init__(self, *args, **kwargs) def _request(self, line, f): args = line.split() try: peer = args[0] except: print("argument error") return try: p = peers[peer] except KeyError: print("unknown peer %s" % peer) return try: f(p, args[1:]) except RPCError as e: print("RPC Error %s" % e) except EOFError: print("disconnected") def _complete_peer(self, text, line, _begidx, _endidx): if len((line + 'x').split()) >= 3: return [] return [name for name in peers if name.startswith(text)] def do_list_cap(self, line): """list_cap """ def f(p, args): for i in p.netconf.server_capabilities: print(i) self._request(line, f) def do_raw_get(self, line): """raw_get """ def f(p, args): result = p.raw_get() tree = ET.fromstring(result) validate(tree) print(et_tostring_pp(tree)) self._request(line, f) def do_raw_get_config(self, line): """raw_get_config """ def f(p, args): try: source = args[0] except: print("argument error") return result = p.raw_get_config(source) tree = ET.fromstring(result) validate(tree) print(et_tostring_pp(tree)) self._request(line, f) def do_get(self, line): """get eg. get sw1 """ def f(p, args): print(p.get()) self._request(line, f) def do_commit(self, line): """commit eg. commit sw1 """ def f(p, args): print(p.commit()) self._request(line, f) def do_discard(self, line): """discard eg. discard sw1 """ def f(p, args): print(p.discard_changes()) self._request(line, f) def do_get_config(self, line): """get_config eg. get_config sw1 startup """ def f(p, args): try: source = args[0] except: print("argument error") return print(p.get_config(source)) self._request(line, f) def do_delete_config(self, line): """delete_config eg. delete_config sw1 startup """ def f(p, args): try: source = args[0] except: print("argument error") return print(p.delete_config(source)) self._request(line, f) def do_copy_config(self, line): """copy_config eg. copy_config sw1 running startup """ def f(p, args): try: source, target = args except: print("argument error") return print(p.copy_config(source, target)) self._request(line, f) def do_list_port(self, line): """list_port """ def f(p, args): o = p.get() for p in o.resources.port: print('%s %s %s' % (p.resource_id, p.name, p.number)) self._request(line, f) _port_settings = [ 'admin-state', 'no-forward', 'no-packet-in', 'no-receive', ] def do_get_port_config(self, line): """get_config_port eg. get_port_config sw1 running LogicalSwitch7-Port2 """ def f(p, args): try: source, port = args except: print("argument error") return o = p.get_config(source) for p in o.resources.port: if p.resource_id != port: continue print(p.resource_id) conf = p.configuration for k in self._port_settings: try: v = getattr(conf, k) except AttributeError: continue print('%s %s' % (k, v)) self._request(line, f) def do_set_port_config(self, line): """set_port_config eg. set_port_config sw1 running LogicalSwitch7-Port2 admin-state down eg. set_port_config sw1 running LogicalSwitch7-Port2 no-forward false """ def f(p, args): try: target, port, key, value = args except: print("argument error") print(args) return # get switch id o = p.get() capable_switch_id = o.id try: capable_switch = ofc.OFCapableSwitchType( id=capable_switch_id, resources=ofc.OFCapableSwitchResourcesType( port=[ ofc.OFPortType( resource_id=port, configuration=ofc.OFPortConfigurationType( **{key: value})) ] ) ) except TypeError: print("argument error") return try: p.edit_config(target, capable_switch) except Exception as e: print(e) self._request(line, f) def do_list_queue(self, line): """list_queue """ def f(p, args): o = p.get() if o.resources.queue: for q in o.resources.queue: print('%s %s' % (q.resource_id, q.port)) self._request(line, f) _queue_settings = [ 'max-rate', 'min-rate', 'experimenter', ] def do_get_queue_config(self, line): """get_queue_port eg. get_queue_config sw1 running LogicalSwitch7-Port1-Queue922 """ def f(p, args): try: source, queue = args except: print("argument error") return o = p.get_config(source) for q in o.resources.queue: if q.resource_id != queue: continue print(q.resource_id) conf = q.properties for k in self._queue_settings: try: v = getattr(conf, k) except AttributeError: continue print('%s %s' % (k, v)) self._request(line, f) def do_set_queue_config(self, line): """set_queue_config eg. set_queue_config sw1 running LogicalSwitch7-Port1-Queue922 \ max-rate 100 """ def f(p, args): try: target, queue, key, value = args except: print("argument error") print(args) return # get switch id o = p.get() capable_switch_id = o.id try: capable_switch = ofc.OFCapableSwitchType( id=capable_switch_id, resources=ofc.OFCapableSwitchResourcesType( queue=[ ofc.OFQueueType( resource_id=queue, properties=ofc.OFQueuePropertiesType( **{key: value})), ] ) ) except TypeError: print("argument error") return try: p.edit_config(target, capable_switch) except Exception as e: print(e) self._request(line, f) def do_add_queue(self, line): """add_queue eg. add_queue sw1 running LogicalSwitch7 NameOfNewQueue """ def f(p, args): try: target, lsw, queue = args except: print("argument error") print(args) return # get switch id o = p.get() capable_switch_id = o.id try: capable_switch = ofc.OFCapableSwitchType( id=capable_switch_id, resources=ofc.OFCapableSwitchResourcesType( queue=[ ofc.OFQueueType(resource_id=queue) ] ), logical_switches=ofc.OFCapableSwitchLogicalSwitchesType( switch=[ofc.OFLogicalSwitchType( id=lsw, resources=ofc.OFLogicalSwitchResourcesType( queue=[queue]) )] ) ) except TypeError: print("argument error") return try: p.edit_config(target, capable_switch) except Exception as e: print(e) self._request(line, f) def do_list_logical_switch(self, line): """list_logical_switch """ def f(p, args): o = p.get() for s in o.logical_switches.switch: print('%s %s' % (s.id, s.datapath_id)) self._request(line, f) def do_show_logical_switch(self, line): """show_logical_switch """ def f(p, args): try: (lsw,) = args except: print("argument error") return o = p.get() for s in o.logical_switches.switch: if s.id != lsw: continue print(s.id) print('datapath-id %s' % s.datapath_id) if s.resources.queue: print('queues:') for q in s.resources.queue: print('\t %s' % q) if s.resources.port: print('ports:') for p in s.resources.port: print('\t %s' % p) self._request(line, f) _lsw_settings = [ 'lost-connection-behavior', ] def do_get_logical_switch_config(self, line): """get_logical_switch_config """ def f(p, args): try: source, lsw = args except: print("argument error") return o = p.get_config(source) for l in o.logical_switches.switch: if l.id != lsw: continue print(l.id) for k in self._lsw_settings: try: v = getattr(l, k) except AttributeError: continue print('%s %s' % (k, v)) self._request(line, f) def do_set_logical_switch_config(self, line): """set_logical_switch_config eg. set_logical_switch_config sw1 running LogicalSwitch7 \ lost-connection-behavior failStandaloneMode """ def f(p, args): try: target, lsw, key, value = args except: print("argument error") return # get switch id o = p.get_config(target) capable_switch_id = o.id try: capable_switch = ofc.OFCapableSwitchType( id=capable_switch_id, logical_switches=ofc.OFCapableSwitchLogicalSwitchesType( switch=[ofc.OFLogicalSwitchType( id=lsw, **{key: value} )] ) ) except TypeError: print("argument error") return try: p.edit_config(target, capable_switch) except Exception as e: print(e) self._request(line, f) completedefault = _complete_peer def complete_EOF(self, _text, _line, _begidx, _endidx): return [] def do_EOF(self, _line): sys.exit(0) def onecmd(self, string): self._in_onecmd = True try: return cmd.Cmd.onecmd(self, string) finally: self._in_onecmd = False def main(args=None, prog=None): CONF(args=args, prog=prog, project='of-config-cli', version='of-config-cli') for p_str in CONF.peers: name, addr = p_str.split('=') host, port, username, password = addr.rsplit(':', 3) add_peer(name, host, port, username, password) Cmd().cmdloop() if __name__ == "__main__": main()