2ca49a222b
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>
116 lines
4.2 KiB
Python
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, {})
|