From 09d5b2533ce2df3e042415ffeedf62795c3cdbe7 Mon Sep 17 00:00:00 2001 From: IWASE Yusuke Date: Fri, 6 Oct 2017 10:35:00 +0900 Subject: [PATCH] controller: APIs to register switch address dynamically This patch introduces APIs to register/unregister switch address after Ryu (ofp_handler) starting. Signed-off-by: IWASE Yusuke Signed-off-by: FUJITA Tomonori --- ryu/controller/controller.py | 14 ++++++- ryu/controller/ofp_api.py | 73 +++++++++++++++++++++++++++++++++++ ryu/controller/ofp_event.py | 3 ++ ryu/controller/ofp_handler.py | 6 ++- 4 files changed, 93 insertions(+), 3 deletions(-) create mode 100644 ryu/controller/ofp_api.py diff --git a/ryu/controller/controller.py b/ryu/controller/controller.py index 84e0e05c..2de14a75 100644 --- a/ryu/controller/controller.py +++ b/ryu/controller/controller.py @@ -66,7 +66,7 @@ CONF.register_cli_opts([ cfg.StrOpt('ca-certs', default=None, help='CA certificates'), cfg.ListOpt('ofp-switch-address-list', item_type=str, default=[], help='list of IP address and port pairs (default empty). ' - 'e.g., "127.0.0.1:6653,127.0.0.1:6633"'), + 'e.g., "127.0.0.1:6653,[::1]:6653"'), cfg.IntOpt('ofp-switch-connect-interval', default=DEFAULT_OFP_SW_CON_INTERVAL, help='interval in seconds to connect to switches ' @@ -133,6 +133,12 @@ class OpenFlowController(object): self.ofp_tcp_listen_port = CONF.ofp_tcp_listen_port self.ofp_ssl_listen_port = CONF.ofp_ssl_listen_port + # Example: + # self._clients = { + # ('127.0.0.1', 6653): , + # } + self._clients = {} + # entry point def __call__(self): # LOG.debug('call') @@ -147,6 +153,12 @@ class OpenFlowController(object): interval = interval or CONF.ofp_switch_connect_interval client = hub.StreamClient(addr) hub.spawn(client.connect_loop, datapath_connection_factory, interval) + self._clients[addr] = client + + def stop_client_loop(self, addr): + client = self._clients.get(addr, None) + if client is not None: + client.stop() def server_loop(self, ofp_tcp_listen_port, ofp_ssl_listen_port): if CONF.ctl_privkey is not None and CONF.ctl_cert is not None: diff --git a/ryu/controller/ofp_api.py b/ryu/controller/ofp_api.py new file mode 100644 index 00000000..088f140d --- /dev/null +++ b/ryu/controller/ofp_api.py @@ -0,0 +1,73 @@ +# Copyright (C) 2017 Nippon Telegraph and Telephone Corporation. +# +# 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. + +""" +OpenFlow related APIs of ryu.controller module. +""" + +import netaddr + +from ryu.base import app_manager +from ryu.lib import hub +from . import ofp_event + + +_TMP_ADDRESSES = {} + + +def register_switch_address(addr, interval=None): + """ + Registers a new address to initiate connection to switch. + + Registers a new IP address and port pair of switch to let + ryu.controller.controller.OpenFlowController to try to initiate + connection to switch. + + :param addr: A tuple of (host, port) pair of switch. + :param interval: Interval in seconds to try to connect to switch + """ + assert len(addr) == 2 + assert netaddr.valid_ipv4(addr[0]) or netaddr.valid_ipv6(addr[0]) + ofp_handler = app_manager.lookup_service_brick(ofp_event.NAME) + _TMP_ADDRESSES[addr] = interval + + def _retry_loop(): + # Delays registration if ofp_handler is not started yet + while True: + if ofp_handler.controller is not None: + for a, i in _TMP_ADDRESSES.items(): + ofp_handler.controller.spawn_client_loop(a, i) + hub.sleep(1) + break + hub.sleep(1) + + hub.spawn(_retry_loop) + + +def unregister_switch_address(addr): + """ + Unregister the given switch address. + + Unregisters the given switch address to let + ryu.controller.controller.OpenFlowController stop trying to initiate + connection to switch. + + :param addr: A tuple of (host, port) pair of switch. + """ + ofp_handler = app_manager.lookup_service_brick(ofp_event.NAME) + # Do nothing if ofp_handler is not started yet + if ofp_handler.controller is None: + return + ofp_handler.controller.stop_client_loop(addr) diff --git a/ryu/controller/ofp_event.py b/ryu/controller/ofp_event.py index 6eb8e5f8..7640b41f 100644 --- a/ryu/controller/ofp_event.py +++ b/ryu/controller/ofp_event.py @@ -26,6 +26,9 @@ from ryu import ofproto from . import event +NAME = 'ofp_event' + + class EventOFPMsgBase(event.EventBase): """ The base class of OpenFlow event class. diff --git a/ryu/controller/ofp_handler.py b/ryu/controller/ofp_handler.py index 7b4bfd11..4f439c2e 100644 --- a/ryu/controller/ofp_handler.py +++ b/ryu/controller/ofp_handler.py @@ -51,11 +51,13 @@ from ryu.ofproto import ofproto_parser class OFPHandler(ryu.base.app_manager.RyuApp): def __init__(self, *args, **kwargs): super(OFPHandler, self).__init__(*args, **kwargs) - self.name = 'ofp_event' + self.name = ofp_event.NAME + self.controller = None def start(self): super(OFPHandler, self).start() - return hub.spawn(OpenFlowController()) + self.controller = OpenFlowController() + return hub.spawn(self.controller) def _hello_failed(self, datapath, error_desc): self.logger.error(error_desc)