os-ken/ryu/app/simple_switch_lacp.py
Yuichi Ito 2ca49a222b add LACP application
this application provides the simple example of link aggregation using LACP.

the module "lacplib" controls exchange of LACP packets and watches the
status of the slave i/fs.  the status changes if the i/fs went into a
LAG or timeout to exchange LACP occurred.  the module sends a
"EventSlaveStateChanged" event when the status changed.

the module "simple_switch_lacp" is a variation of "simple_switch".
the switch receives the "EventPacketIn" event instead of the
"EventOFPPacketIn" event from the module "lacplib" in order to except
LACP.  when the module received "EventSlaveStateChanged" event, the
module resets flow entries.

to run:
ryu-manager ryu/app/simple_switch_lacp.py

Signed-off-by: Yuichi Ito <ito.yuichi0@gmal.com>
Signed-off-by: FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>
2013-08-29 10:22:00 +09:00

116 lines
4.2 KiB
Python

# Copyright (C) 2013 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.
import struct
from ryu.base import app_manager
from ryu.controller.handler import set_ev_cls
from ryu.ofproto import ofproto_v1_0
from ryu.lib import addrconv
from ryu.lib import lacplib
from ryu.lib.dpid import str_to_dpid
class SimpleSwitchLacp(app_manager.RyuApp):
OFP_VERSIONS = [ofproto_v1_0.OFP_VERSION]
_CONTEXTS = {'lacplib': lacplib.LacpLib}
def __init__(self, *args, **kwargs):
super(SimpleSwitchLacp, self).__init__(*args, **kwargs)
self.mac_to_port = {}
self._lacp = kwargs['lacplib']
# in this sample application, bonding i/fs of the switchs
# shall be set up as follows:
# - the port 1 and 2 of the datapath 1 face the slave i/fs.
# - the port 3, 4 and 5 of the datapath 1 face the others.
# - the port 1 and 2 of the datapath 2 face the others.
self._lacp.add(
dpid=str_to_dpid('0000000000000001'), ports=[1, 2])
self._lacp.add(
dpid=str_to_dpid('0000000000000001'), ports=[3, 4, 5])
self._lacp.add(
dpid=str_to_dpid('0000000000000002'), ports=[1, 2])
def add_flow(self, datapath, in_port, dst, actions):
ofproto = datapath.ofproto
parser = datapath.ofproto_parser
match = parser.OFPMatch(in_port=in_port,
dl_dst=addrconv.mac.text_to_bin(dst))
mod = parser.OFPFlowMod(
datapath=datapath, match=match, cookie=0,
command=ofproto.OFPFC_ADD, actions=actions)
datapath.send_msg(mod)
def del_flow(self, datapath, dst):
ofproto = datapath.ofproto
parser = datapath.ofproto_parser
match = parser.OFPMatch(dl_dst=addrconv.mac.text_to_bin(dst))
mod = parser.OFPFlowMod(
datapath=datapath, match=match, cookie=0,
command=ofproto.OFPFC_DELETE)
datapath.send_msg(mod)
@set_ev_cls(lacplib.EventPacketIn, lacplib.LAG_EV_DISPATCHER)
def _packet_in_handler(self, ev):
msg = ev.msg
datapath = msg.datapath
ofproto = datapath.ofproto
(dst_, src_, _eth_type) = struct.unpack_from(
'!6s6sH', buffer(msg.data), 0)
src = addrconv.mac.bin_to_text(src_)
dst = addrconv.mac.bin_to_text(dst_)
dpid = datapath.id
self.mac_to_port.setdefault(dpid, {})
self.logger.info("packet in %s %s %s %s",
dpid, src, dst, msg.in_port)
# learn a mac address to avoid FLOOD next time.
self.mac_to_port[dpid][src] = msg.in_port
if dst in self.mac_to_port[dpid]:
out_port = self.mac_to_port[dpid][dst]
else:
out_port = ofproto.OFPP_FLOOD
actions = [datapath.ofproto_parser.OFPActionOutput(out_port)]
# install a flow to avoid packet_in next time
if out_port != ofproto.OFPP_FLOOD:
self.add_flow(datapath, msg.in_port, dst, actions)
out = datapath.ofproto_parser.OFPPacketOut(
datapath=datapath, buffer_id=msg.buffer_id, in_port=msg.in_port,
actions=actions)
datapath.send_msg(out)
@set_ev_cls(lacplib.EventSlaveStateChanged, lacplib.LAG_EV_DISPATCHER)
def _slave_state_changed_handler(self, ev):
datapath = ev.datapath
dpid = datapath.id
port_no = ev.port
enabled = ev.enabled
self.logger.info("slave state changed port: %d enabled: %s",
port_no, enabled)
if dpid in self.mac_to_port:
for mac in self.mac_to_port[dpid]:
self.del_flow(datapath, mac)
del self.mac_to_port[dpid]
self.mac_to_port.setdefault(dpid, {})