1 # Copyright (C) 2011 Nippon Telegraph and Telephone Corporation.
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
7 # http://www.apache.org/licenses/LICENSE-2.0
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
13 # See the License for the specific language governing permissions and
14 # limitations under the License.
16 from ryu
.base
import app_manager
17 from ryu
.controller
import ofp_event
18 from ryu
.controller
.handler
import CONFIG_DISPATCHER
, MAIN_DISPATCHER
19 from ryu
.controller
.handler
import set_ev_cls
20 from ryu
.ofproto
import ofproto_v1_3
21 from ryu
.lib
.packet
import packet
22 from ryu
.lib
.packet
import ethernet
23 from ryu
.lib
.packet
import ether_types
24 from ryu
.topology
.event
import EventSwitchEnter
, EventSwitchLeave
, EventSwitchReconnected
26 class SimpleSwitch13(app_manager
.RyuApp
):
27 OFP_VERSIONS
= [ofproto_v1_3
.OFP_VERSION
]
29 def __init__(self
, *args
, **kwargs
):
30 super(SimpleSwitch13
, self
).__init
__(*args
, **kwargs
)
33 @set_ev_cls(ofp_event
.EventOFPSwitchFeatures
, CONFIG_DISPATCHER
)
34 def switch_features_handler(self
, ev
):
35 datapath
= ev
.msg
.datapath
36 ofproto
= datapath
.ofproto
37 parser
= datapath
.ofproto_parser
39 # install table-miss flow entry
41 # We specify NO BUFFER to max_len of the output action due to
42 # OVS bug. At this moment, if we specify a lesser number, e.g.,
43 # 128, OVS will send Packet-In with invalid buffer_id and
44 # truncated packet data. In that case, we cannot output packets
45 # correctly. The bug has been fixed in OVS v2.1.0.
46 match
= parser
.OFPMatch()
47 #actions = [parser.OFPActionOutput(ofproto.OFPP_CONTROLLER,
48 # ofproto.OFPCML_NO_BUFFER)]
49 actions
= [parser
.OFPActionOutput(ofproto
.OFPCML_NO_BUFFER
)]
50 self
.add_flow(datapath
, 0, match
, actions
)
52 def add_flow(self
, datapath
, priority
, match
, actions
, buffer_id
=None, table_id
=0):
53 ofproto
= datapath
.ofproto
54 parser
= datapath
.ofproto_parser
56 inst
= [parser
.OFPInstructionActions(ofproto
.OFPIT_APPLY_ACTIONS
,
59 mod
= parser
.OFPFlowMod(datapath
=datapath
, buffer_id
=buffer_id
,
60 priority
=priority
, match
=match
,
61 instructions
=inst
, table_id
=table_id
)
63 mod
= parser
.OFPFlowMod(datapath
=datapath
, priority
=priority
,
64 match
=match
, instructions
=inst
, table_id
=table_id
)
65 datapath
.send_msg(mod
)
69 @set_ev_cls([EventSwitchEnter
, EventSwitchReconnected
])
70 def _ev_switch_enter_handler(self
, ev
):
71 datapath
= ev
.switch
.dp
72 self
.logger
.info('registered OF switch id: %s' % datapath
.id)
73 ofproto
= datapath
.ofproto
74 self
.logger
.info('OF version: {0}'.format(ofproto
))
75 # send NORMAL action for all undefined flows
76 ofp_parser
= datapath
.ofproto_parser
77 actions
= [ofp_parser
.OFPActionOutput(ofproto_v1_3
.OFPP_NORMAL
)]
78 self
.add_flow(datapath
, 0, None, actions
, table_id
=0)
81 @set_ev_cls(ofp_event
.EventOFPPacketIn
, MAIN_DISPATCHER
)
82 def _packet_in_handler(self
, ev
):
83 # If you hit this you might want to increase
84 # the "miss_send_length" of your switch
85 if ev
.msg
.msg_len
< ev
.msg
.total_len
:
86 self
.logger
.debug("packet truncated: only %s of %s bytes",
87 ev
.msg
.msg_len
, ev
.msg
.total_len
)
89 datapath
= msg
.datapath
90 ofproto
= datapath
.ofproto
91 parser
= datapath
.ofproto_parser
92 in_port
= msg
.match
['in_port']
94 pkt
= packet
.Packet(msg
.data
)
95 eth
= pkt
.get_protocols(ethernet
.ethernet
)[0]
97 if eth
.ethertype
== ether_types
.ETH_TYPE_LLDP
:
104 self
.mac_to_port
.setdefault(dpid
, {})
106 self
.logger
.info("packet in %s %s %s %s", dpid
, src
, dst
, in_port
)
108 # learn a mac address to avoid FLOOD next time.
109 self
.mac_to_port
[dpid
][src
] = in_port
111 if dst
in self
.mac_to_port
[dpid
]:
112 out_port
= self
.mac_to_port
[dpid
][dst
]
114 out_port
= ofproto
.OFPP_FLOOD
116 actions
= [parser
.OFPActionOutput(out_port
)]
118 # install a flow to avoid packet_in next time
119 if out_port
!= ofproto
.OFPP_FLOOD
:
120 match
= parser
.OFPMatch(in_port
=in_port
, eth_dst
=dst
)
121 # verify if we have a valid buffer_id, if yes avoid to send both
122 # flow_mod & packet_out
123 if msg
.buffer_id
!= ofproto
.OFP_NO_BUFFER
:
124 self
.add_flow(datapath
, 1, match
, actions
, msg
.buffer_id
)
127 self
.add_flow(datapath
, 1, match
, actions
)
129 if msg
.buffer_id
== ofproto
.OFP_NO_BUFFER
:
132 out
= parser
.OFPPacketOut(datapath
=datapath
, buffer_id
=msg
.buffer_id
,
133 in_port
=in_port
, actions
=actions
, data
=data
)
134 datapath
.send_msg(out
)