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
, EventSwitchReconnected
27 class SimpleSwitch13(app_manager
.RyuApp
):
28 OFP_VERSIONS
= [ofproto_v1_3
.OFP_VERSION
]
30 def __init__(self
, *args
, **kwargs
):
31 super(SimpleSwitch13
, self
).__init
__(*args
, **kwargs
)
34 @set_ev_cls(ofp_event
.EventOFPSwitchFeatures
, CONFIG_DISPATCHER
)
35 def switch_features_handler(self
, ev
):
36 datapath
= ev
.msg
.datapath
37 ofproto
= datapath
.ofproto
38 parser
= datapath
.ofproto_parser
40 # install table-miss flow entry
42 # We specify NO BUFFER to max_len of the output action due to
43 # OVS bug. At this moment, if we specify a lesser number, e.g.,
44 # 128, OVS will send Packet-In with invalid buffer_id and
45 # truncated packet data. In that case, we cannot output packets
46 # correctly. The bug has been fixed in OVS v2.1.0.
47 match
= parser
.OFPMatch()
48 # actions = [parser.OFPActionOutput(ofproto.OFPP_CONTROLLER,
49 # ofproto.OFPCML_NO_BUFFER)]
50 actions
= [parser
.OFPActionOutput(ofproto
.OFPCML_NO_BUFFER
)]
51 self
.add_flow(datapath
, 0, match
, actions
)
53 def add_flow(self
, datapath
, priority
, match
,
54 actions
, buffer_id
=None, table_id
=0):
55 ofproto
= datapath
.ofproto
56 parser
= datapath
.ofproto_parser
58 inst
= [parser
.OFPInstructionActions(ofproto
.OFPIT_APPLY_ACTIONS
,
61 mod
= parser
.OFPFlowMod(datapath
=datapath
, buffer_id
=buffer_id
,
62 priority
=priority
, match
=match
,
63 instructions
=inst
, table_id
=table_id
)
65 mod
= parser
.OFPFlowMod(datapath
=datapath
, priority
=priority
,
66 match
=match
, instructions
=inst
, table_id
=table_id
)
67 datapath
.send_msg(mod
)
71 @set_ev_cls([EventSwitchEnter
, EventSwitchReconnected
])
72 def _ev_switch_enter_handler(self
, ev
):
73 datapath
= ev
.switch
.dp
74 self
.logger
.info('registered OF switch id: %s' % datapath
.id)
75 ofproto
= datapath
.ofproto
76 self
.logger
.info('OF version: {0}'.format(ofproto
))
77 # send NORMAL action for all undefined flows
78 ofp_parser
= datapath
.ofproto_parser
79 actions
= [ofp_parser
.OFPActionOutput(ofproto_v1_3
.OFPP_NORMAL
)]
80 self
.add_flow(datapath
, 0, None, actions
, table_id
=0)
82 @set_ev_cls(ofp_event
.EventOFPPacketIn
, MAIN_DISPATCHER
)
83 def _packet_in_handler(self
, ev
):
84 # If you hit this you might want to increase
85 # the "miss_send_length" of your switch
86 if ev
.msg
.msg_len
< ev
.msg
.total_len
:
87 self
.logger
.debug("packet truncated: only %s of %s bytes",
88 ev
.msg
.msg_len
, ev
.msg
.total_len
)
90 datapath
= msg
.datapath
91 ofproto
= datapath
.ofproto
92 parser
= datapath
.ofproto_parser
93 in_port
= msg
.match
['in_port']
95 pkt
= packet
.Packet(msg
.data
)
96 eth
= pkt
.get_protocols(ethernet
.ethernet
)[0]
98 if eth
.ethertype
== ether_types
.ETH_TYPE_LLDP
:
105 self
.mac_to_port
.setdefault(dpid
, {})
107 self
.logger
.info("packet in %s %s %s %s", dpid
, src
, dst
, in_port
)
109 # learn a mac address to avoid FLOOD next time.
110 self
.mac_to_port
[dpid
][src
] = in_port
112 if dst
in self
.mac_to_port
[dpid
]:
113 out_port
= self
.mac_to_port
[dpid
][dst
]
115 out_port
= ofproto
.OFPP_FLOOD
117 actions
= [parser
.OFPActionOutput(out_port
)]
119 # install a flow to avoid packet_in next time
120 if out_port
!= ofproto
.OFPP_FLOOD
:
121 match
= parser
.OFPMatch(in_port
=in_port
, eth_dst
=dst
)
122 # verify if we have a valid buffer_id, if yes avoid to send both
123 # flow_mod & packet_out
124 if msg
.buffer_id
!= ofproto
.OFP_NO_BUFFER
:
125 self
.add_flow(datapath
, 1, match
, actions
, msg
.buffer_id
)
128 self
.add_flow(datapath
, 1, match
, actions
)
130 if msg
.buffer_id
== ofproto
.OFP_NO_BUFFER
:
133 out
= parser
.OFPPacketOut(datapath
=datapath
, buffer_id
=msg
.buffer_id
,
134 in_port
=in_port
, actions
=actions
, data
=data
)
135 datapath
.send_msg(out
)