实际加入两个先前在「交換器(Switching Hub )」那个实验中说明过的 API。
- MAC 位址表取得 API
取得 Switching hub 中储存的 MAC 位址表内容。成对的 MAC 位址和连接符号将以 JSON 的形式回传。
- MAC 位址表注册 API
MAC 位址和连接符号成对的新增进 MAC 位址表,同时加到交换器的 Flow Entry 中。
simple_switch_rest_13.py 定义了两个类别:
SimpleSwitchRest13,用來扩充「交換器(Switching Hub )」让它得以更新MAC 位址表.。
SimpleSwitchController。控制器类 ,其中定义收到 HTTP request 时所需要回应的操作。
代码分析
_CONTEXT是用来建立Ryu中WSGI网页服务器所对应的类别,因此可通过wsgi Key来取得网页服务器的实体
# 通过上一步设置的_CONTEXTS成员变量,可以通过kwargs进行实例化一个WSGIApplication。
# 使用register方法注册该服务到controller类上
# 重写父类的switch_features_handler函数
# 存储datapath到switches
# 初始化MAC地址表
重写,這個方法會在 SwitchFeatures 事件發生時被触发,在ev得到datapath后存放到switches中。此時 MAC 位址的初始值將會設定為空白字典(empty dictionary )形態。
该方法将MAC地址和端口注册到指定的交换器。该方法主要被REST API的PUT方法所调用。
entry 用来存储已经注册的 MAC 位址和连接符号。
最后被加入到交换器当中的 Flow Entry将会如下所示。
- match 条件:in_port = 1, dst_mac = 00:00:00:00:00:02 action:output=2
- match 条件:in_port = 2, dst_mac = 00:00:00:00:00:01 action:output=1
Flow Entry 的加入是通过父类别的 add_flow 方法达成。最后经由参数 entry 传递的信息会被储存在 MAC 位址表中。
接下来是控制器类
#借助route装饰器关联方法和URL,
#第一个参数:任何自定义名称;
#第二个参数:指明URL;
#第三个参数:指定http方法;
#第四个参数:指明指定位置的格式,URL(/simpleswitch/mactable/{dpid} 匹配DPID_PATTERN的描述
#当使用GET方式访问到该REST API接口时,调用list_mac_table函数!!
# 获取{dpid} :data path ID
# 如果没有dpid,返回404
# 使用PUT方式设置mac_table
当 put_mac_table 方法产生例外的時候,回应码 500 会被回传。同样的,list_mac_table
方法在 Ryu 所连接的交换器使用未知的 data path ID 的话,回传404。
实验部分
安装Ryu
- 安装之前准备:
sudo apt-get install python-eventlet python-routes python-webob python-paramiko
- git clone git://github.com/osrg/ryu.git
- sudo pip inatall -r tools/pip-requires
- sudo python setup.py install
- 测试,ryu-manager
查看ryu路径
sudo pip show ryu
得到 Location: /usr/lib/python2.7/dist-packages
所以本实验路径为:Location: /usr/lib/python2.7/dist-packages/ryu/app
错误问题
问题一
hub: uncaught exception: Traceback (most recent call last):
File "/usr/lib/python2.7/dist-packages/ryu/lib/hub.py", line 60, in _launch
return func(*args, **kwargs)
File "/usr/lib/python2.7/dist-packages/ryu/controller/controller.py", line 123, in server_loop
datapath_connection_factory)
File "/usr/lib/python2.7/dist-packages/ryu/lib/hub.py", line 127, in __init__
self.server = eventlet.listen(listen_info)
File "/usr/lib/python2.7/dist-packages/eventlet/convenience.py", line 47, in listen
sock.listen(backlog)
File "/usr/lib/python2.7/socket.py", line 228, in meth
return getattr(self._sock,name)(*args)
error: [Errno 98] Address already in use
解决方法
kill 掉占用端口号6633的程序
首先查找出是哪个进程占用了该端口号命令为
sudo lsof -i :6633
比如我查出来是
显示ryu-manag这个进程占用了6633 那就kill掉这个进程。
kill -9 33707
Ryu
cd /usr/lib/python2.7/dist-packages/ryu/app
sudo ovs-vsctl set Bridge s1 protocols=OpenFlow13
ryu-manager --verbose ./simple_switch_rest_13.py
mininet
sudo mn --controller=remote,ip=127.0.0.1,port=6633
sudo mn -c 删除拓扑
h1 ping -c 1 h2
这时会发生三次往 Ryu 方向的 Packet-In
EVENT ofp_event->SimpleSwitchRest13 EventOFPPacketIn
packet in 1 e6:a9:0b:ac:5f:74 ff:ff:ff:ff:ff:ff 1
EVENT ofp_event->SimpleSwitchRest13 EventOFPPacketIn
packet in 1 02:14:c7:b4:ad:ec e6:a9:0b:ac:5f:74 2
EVENT ofp_event->SimpleSwitchRest13 EventOFPPacketIn
packet in 1 e6:a9:0b:ac:5f:74 02:14:c7:b4:ad:ec 1
然后我们使用 curl 指令来驱动 REST API,以便在 switching hub 中取得 MAC 位址表
curl -X GET http://127.0.0.1:8080/simpleswitch/mactable/0000000000000001
你会发现h1 和 h2 的 MAC 位址表已经学习并更新完毕。
这次 h1 和 h2 的 MAC 位址表提前在执行 ping 之前被设定好。暂时停止 switching hub 和 mininet 的执行。然後再次启动 mininet ,并将 OpenFlow 版本设定为 OpenFlow13 。
接着在每个 host 上呼叫 MAC 位址表更新的 REST API。REST API 呼叫的形式是 {"mac’’ : "MAC 位址’’, "port’’ : 连接符号}
curl -X PUT -d '{"mac" : "5e:5e:bb:cd:a0:9d", "port" : 1}' http://127.0.0.1:8080/simpleswitch/mactable/0000000000000001
curl -X PUT -d '{"mac" : "86:09:aa:00:ca:d0", "port" : 2}' http://127.0.0.1:8080/simpleswitch/mactable/0000000000000001
执行上述的指令,h1 和 h2 对应的 Flow Entry 就会被加入交换器中。
然后从 h1 对 h2 执行 ping 指令
h1 ping -c 1 h2
这时候交换器中已经存在着 Flow Entry。Packet-In只会发生在当 h1 到 h2 的 ARP 出现且沒有
接连发生的封包交换时。