1. 代码解析
ryu/app/simple_switch_rest_13.py:
import json from ryu.app import simple_switch_13 from ryu.controller import ofp_event from ryu.controller.handler import CONFIG_DISPATCHER from ryu.controller.handler import set_ev_cls from ryu.app.wsgi import ControllerBase from ryu.app.wsgi import Response from ryu.app.wsgi import route from ryu.app.wsgi import WSGIApplication from ryu.lib import dpid as dpid_lib simple_switch_instance_name = ‘simple_switch_api_app‘ url = ‘/simpleswitch/mactable/{dpid}‘ class SimpleSwitchRest13(simple_switch_13.SimpleSwitch13): _CONTEXTS = {‘wsgi‘: WSGIApplication} def __init__(self, *args, **kwargs): super(SimpleSwitchRest13, self).__init__(*args, **kwargs) self.switches = {} wsgi = kwargs[‘wsgi‘] wsgi.register(SimpleSwitchController, {simple_switch_instance_name: self}) @set_ev_cls(ofp_event.EventOFPSwitchFeatures, CONFIG_DISPATCHER) def switch_features_handler(self, ev): super(SimpleSwitchRest13, self).switch_features_handler(ev) datapath = ev.msg.datapath self.switches[datapath.id] = datapath self.mac_to_port.setdefault(datapath.id, {}) def set_mac_to_port(self, dpid, entry): mac_table = self.mac_to_port.setdefault(dpid, {}) datapath = self.switches.get(dpid) entry_port = entry[‘port‘] entry_mac = entry[‘mac‘] if datapath is not None: parser = datapath.ofproto_parser if entry_port not in mac_table.values(): for mac, port in mac_table.items(): # from known device to new device actions = [parser.OFPActionOutput(entry_port)] match = parser.OFPMatch(in_port=port, eth_dst=entry_mac) self.add_flow(datapath, 1, match, actions) # from new device to known device actions = [parser.OFPActionOutput(port)] match = parser.OFPMatch(in_port=entry_port, eth_dst=mac) self.add_flow(datapath, 1, match, actions) mac_table.update({entry_mac: entry_port}) return mac_table class SimpleSwitchController(ControllerBase): def __init__(self, req, link, data, **config): super(SimpleSwitchController, self).__init__(req, link, data, **config) self.simple_switch_app = data[simple_switch_instance_name] @route(‘simpleswitch‘, url, methods=[‘GET‘], requirements={‘dpid‘: dpid_lib.DPID_PATTERN}) def list_mac_table(self, req, **kwargs): simple_switch = self.simple_switch_app dpid = kwargs[‘dpid‘] if dpid not in simple_switch.mac_to_port: return Response(status=404) mac_table = simple_switch.mac_to_port.get(dpid, {}) body = json.dumps(mac_table) return Response(content_type=‘application/json‘, text=body) @route(‘simpleswitch‘, url, methods=[‘PUT‘], requirements={‘dpid‘: dpid_lib.DPID_PATTERN}) def put_mac_table(self, req, **kwargs): simple_switch = self.simple_switch_app dpid = kwargs[‘dpid‘] try: new_entry = req.json if req.body else {} except ValueError: raise Response(status=400) if dpid not in simple_switch.mac_to_port: return Response(status=404) try: mac_table = simple_switch.set_mac_to_port(dpid, new_entry) body = json.dumps(mac_table) return Response(content_type=‘application/json‘, text=body) except Exception as e: return Response(status=500)
2. 运行
# --topo sigle,3: 单个交换机,3个主机 # --mac: 自动设置主机的MAC地址 # --switch ovsk: 使用 ovs # --controller remote: 使用外部OpenFlow控制器 # -x: 启动xterm $ sudo mn --topo single,3 --mac --switch ovsk --controller remote -x
此时会启动5个xterm:h1~h3, switch, controller.
设置OpenFlow版本:switch: s1
# ovs-vsctl set Bridge s1 protocols=OpenFlow13
启动控制器:controller: c0
# ryu-manager --verbose ryu/app/simple_switch_rest_13.py
ping:
mininet> h1 ping -c1 h2
执行Rest API:
$ curl -X GET http://127.0.0.1:8080/simpleswitch/mactable/0000000000000001 $ curl -X PUT -d ‘{"mac" : "00:00:00:00:00:01", "port" : 1}‘ http://127.0.0.1:8080/simpleswitch/mactable/0000000000000001 $ curl -X PUT -d ‘{"mac" : "00:00:00:00:00:02", "port" : 2}‘ http://127.0.0.1:8080/simpleswitch/mactable/0000000000000001