In this recipe, we will monitor and notify when new links are added to the network. Listing 10.5 gives a simple monitoring for link changes:
#!/usr/bin/env python # Python Network Programming Cookbook, Second Edition -- Chapter - 10 # This program is optimized for Python 2.7.12. # It may run on any other version with/without modifications. # Adopted from https://github.com/osrg/ryu/blob/master/ryu/app/ws_topology.py from socket import error as SocketError from tinyrpc.exc import InvalidReplyError from ryu.app.wsgi import ( ControllerBase, WSGIApplication, websocket, WebSocketRPCClient ) from ryu.base import app_manager from ryu.topology import event, switches from ryu.controller.handler import set_ev_cls class WebSocketTopology(app_manager.RyuApp): _CONTEXTS = { 'wsgi': WSGIApplication, 'switches': switches.Switches, } def __init__(self, *args, **kwargs): super(WebSocketTopology, self).__init__(*args, **kwargs) self.rpc_clients = [] wsgi = kwargs['wsgi'] wsgi.register(WebSocketTopologyController, {'app': self}) # Monitor the events / topology changes # EventSwitchEnter and EventSwitchLeave for switches
entering and leaving. # EventLinkAdd and EventLinkDelete for links addition and deletion. # EventHostAdd for hosts addition. # Event - Link added @set_ev_cls(event.EventLinkAdd) def _event_link_add_handler(self, ev): msg = ev.link.to_dict() self._rpc_broadcall('event_link_add', msg) # Event - Link deleted @set_ev_cls(event.EventLinkDelete) def _event_link_delete_handler(self, ev): msg = ev.link.to_dict() self._rpc_broadcall('event_link_delete', msg) def _rpc_broadcall(self, func_name, msg): disconnected_clients = [] for rpc_client in self.rpc_clients: rpc_server = rpc_client.get_proxy() try: getattr(rpc_server, func_name)(msg) except SocketError: self.logger.debug('WebSocket disconnected: %s',
rpc_client.ws) disconnected_clients.append(rpc_client) except InvalidReplyError as e: self.logger.error(e) for client in disconnected_clients: self.rpc_clients.remove(client) class WebSocketTopologyController(ControllerBase): def __init__(self, req, link, data, **config): super(WebSocketTopologyController, self).__init__( req, link, data, **config) self.app = data['app'] @websocket('topology', '/v1.0/topology/ws') def _websocket_handler(self, ws): rpc_client = WebSocketRPCClient(ws) self.app.rpc_clients.append(rpc_client) rpc_client.serve_forever()
Run this recipe using ryu-manager:
$ ryu-manager --verbose --observe-links 10_5_sdn_ryu.py Registered VCS backend: git Registered VCS backend: hg Registered VCS backend: svn Registered VCS backend: bzr loading app 10_5_sdn_ryu.py loading app ryu.controller.ofp_handler instantiating app None of Switches creating context switches creating context wsgi instantiating app ryu.controller.ofp_handler of OFPHandler instantiating app 10_5_sdn_ryu.py of WebSocketTopology BRICK switches PROVIDES EventLinkDelete TO {'WebSocketTopology': set()} PROVIDES EventLinkAdd TO {'WebSocketTopology': set()} CONSUMES EventOFPPortStatus CONSUMES EventLinkRequest CONSUMES EventHostRequest CONSUMES EventOFPPacketIn CONSUMES EventOFPStateChange CONSUMES EventSwitchRequest BRICK ofp_event PROVIDES EventOFPPortStatus TO {'switches': {'main'}} PROVIDES EventOFPPacketIn TO {'switches': {'main'}} PROVIDES EventOFPStateChange TO {'switches': {'main',
'dead'}} CONSUMES EventOFPEchoReply CONSUMES EventOFPSwitchFeatures CONSUMES EventOFPHello CONSUMES EventOFPPortStatus CONSUMES EventOFPEchoRequest CONSUMES EventOFPErrorMsg CONSUMES EventOFPPortDescStatsReply BRICK WebSocketTopology CONSUMES EventLinkDelete CONSUMES EventLinkAdd (32456) wsgi starting up on http://0.0.0.0:8080 Next, run wscat: $ wscat -c ws://localhost:8080/v1.0/topology/ws connected (press CTRL+C to quit) This will print the below line to the ryu-manager in the previous window: (32456) accepted ('127.0.0.1', 60740). Now, start the network emulation with Mininet: $ sudo mn --controller=remote,ip=127.0.0.1 --topo tree,depth=3,fanout=2 [sudo] password for pradeeban: *** Creating network *** Adding controller Connecting to remote controller at 127.0.0.1:6653 *** Adding hosts and stations: h1 h2 h3 h4 h5 h6 h7 h8 *** Adding switches and access point(s): s1 s2 s3 s4 s5 s6 s7 *** Adding link(s): (s1, s2) (s1, s5) (s2, s3) (s2, s4) (s3, h1) (s3, h2) (s4, h3) (s4, h4) (s5, s6) (s5, s7) (s6, h5) (s6, h6) (s7, h7) (s7, h8) *** Configuring hosts *** Starting controller(s) c0 *** Starting switches and/or access points s1 s2 s3 s4 s5 s6 s7 ... *** Starting CLI: This will make the following event to be printed to the wscat: < {"id": 1, "method": "event_link_add", "jsonrpc": "2.0", "params": [{"dst": {"name": "s5-eth1", "dpid": "0000000000000005", "hw_addr": "ba:91:f4:f2:5f:0c", "port_no": "00000001"}, "src": {"name": "s6-eth3", "dpid": "0000000000000006", "hw_addr": "7a:95:e0:95:fb:34", "port_no": "00000003"}}]}
At the same time, ryu-manager will print lines of messages indicating the changes.
The following screenshot captures ryu-manager, wscat, and Mininet in action for this recipe:
SDN with Ryu