1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
|
# Copyright (C) 2011 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.
from ryu.base import app_manager
from ryu.controller import ofp_event
from ryu.controller.handler import MAIN_DISPATCHER
from ryu.controller.handler import set_ev_cls
from ryu.ofproto import ofproto_v1_3
from ryu.lib.packet import packet
from ryu.lib.packet import ethernet
from ryu.lib import hub
import time
class SimpleSwitch13(app_manager.RyuApp):
OFP_VERSIONS = [ofproto_v1_3.OFP_VERSION]
def __init__(self, *args, **kwargs):
super(SimpleSwitch13, self).__init__(*args, **kwargs)
self.datapaths = {}
self.detector_thread = hub.spawn(self._measure)
# 处理交换机连接
@set_ev_cls(ofp_event.EventOFPStateChange, MAIN_DISPATCHER)
def switch_features_handler(self, ev):
datapath = ev.datapath
ofproto = datapath.ofproto
parser = datapath.ofproto_parser
# 交换机新连接
if ev.state == MAIN_DISPATCHER:
# 断言dpid存在
assert datapath.id is not None
print("Switch Coming", datapath.id)
self.datapaths[datapath.id] = datapath
# 为交换机的流表新增Table-miss Flow Entry项 用于在无法匹配到流表项后与之匹配
# match表示匹配约束 为空则说明可以匹配所有封包
# action表示匹配成功后执行的操作为向Controller端口发送最大数据长度的封包
# OFPCML_NO_BUFFER表示不需要在交换机上缓存封包将封包整体发给controller
# 优先级为0 即最低的优先权
match = parser.OFPMatch()
actions = [parser.OFPActionOutput(ofproto.OFPP_CONTROLLER,
ofproto.OFPCML_NO_BUFFER)]
self.add_flow(datapath, 0, match, actions)
# 每隔3秒进行控制器向交换机发送一次Echo报文以获取往返时延
def _measure(self):
SLEEP_PERIOD = 3
while True:
self._send_echo_request()
hub.sleep(SLEEP_PERIOD)
def _send_echo_request(self):
for datapath in self.datapaths.values():
parser = datapath.ofproto_parser
data = bytes("%.12f" % time.time(), encoding="utf8")
echo_req = parser.OFPEchoRequest(datapath, data=data)
datapath.send_msg(echo_req)
hub.sleep(0.5)
@set_ev_cls(ofp_event.EventOFPEchoReply, MAIN_DISPATCHER)
def echo_reply_handler(self, ev):
latency = time.time() - eval(ev.msg.data)
latency = latency * 1000
print("Delay of", ev.msg.datapath.id, "is", latency, "ms")
# 用于添加流表项的工具函数
def add_flow(self, datapath, priority, match, actions, buffer_id=None):
ofproto = datapath.ofproto
parser = datapath.ofproto_parser
inst = [parser.OFPInstructionActions(ofproto.OFPIT_APPLY_ACTIONS,
actions)]
if buffer_id:
mod = parser.OFPFlowMod(datapath=datapath,
buffer_id=buffer_id,
priority=priority,
match=match,
instructions=inst)
else:
mod = parser.OFPFlowMod(datapath=datapath,
priority=priority,
match=match,
instructions=inst)
datapath.send_msg(mod)
# 控制器接收到Packet-In消息
@set_ev_cls(ofp_event.EventOFPPacketIn, MAIN_DISPATCHER)
def packet_in_handler(self, ev):
msg = ev.msg
datapath = msg.datapath
in_port = msg.match['in_port']
# print("Recv PACKET_IN", datapath.id,"from",in_port)
pkt = packet.Packet(msg.data)
eth = pkt.get_protocols(ethernet.ethernet)[0]
# print("Eth pkt: {0}".format(eth))
|