I'm studing about a ring topology of network in mininet. There are 3 access point, in a triangle configuration: ap1, ap2 and ap3 that are connected each other. There is a station (sta1) that isn't mobile (always connected to ap3) and there is a mobile station (sta2) that moves randomly betweeen ap1 and ap2. The scope is to ping sta2 from sta1. I used a stp ryu-controller to avoid broadcast storm. It doesn't work well beacause for example I can ping sta2 when it is connected to ap1, but when it moves to ap2, I can't ping it anymore. How can I solve this problem? I attach my ryu-code:
<---sta2--->
ap1---------ap2
- -
- -
- ap3 -
sta1
from ryu.base import app_manager
from ryu.controller import ofp_event
from ryu.controller.handler import CONFIG_DISPATCHER, MAIN_DISPATCHER
from ryu.controller.handler import set_ev_cls
from ryu.ofproto import ofproto_v1_3
from ryu.lib import dpid as dpid_lib
from ryu.lib import stplib
from ryu.lib.packet import packet
from ryu.lib.packet import ethernet
from ryu.app import simple_switch_13
class SimpleSwitch13(simple_switch_13.SimpleSwitch13):
OFP_VERSIONS = [ofproto_v1_3.OFP_VERSION]
_CONTEXTS = {'stplib': stplib.Stp}
def __init__(self, *args, **kwargs):
super(SimpleSwitch13, self).__init__(*args, **kwargs)
self.mac_to_port = {}
self.stp = kwargs['stplib']
# Sample of stplib config.
# please refer to stplib.Stp.set_config() for details.
config = {dpid_lib.str_to_dpid('0000000000000001'):
{'bridge': {'priority': 0x8000}},
dpid_lib.str_to_dpid('0000000000000002'):
{'bridge': {'priority': 0x9000}},
dpid_lib.str_to_dpid('0000000000000003'):
{'bridge': {'priority': 0xa000}}}
self.stp.set_config(config)
def delete_flow(self, datapath):
ofproto = datapath.ofproto
parser = datapath.ofproto_parser
for dst in self.mac_to_port[datapath.id].keys():
match = parser.OFPMatch(eth_dst=dst)
mod = parser.OFPFlowMod(
datapath, command=ofproto.OFPFC_DELETE,
out_port=ofproto.OFPP_ANY, out_group=ofproto.OFPG_ANY,
priority=1, match=match)
datapath.send_msg(mod)
@set_ev_cls(stplib.EventPacketIn, MAIN_DISPATCHER)
def _packet_in_handler(self, ev):
msg = ev.msg
datapath = msg.datapath
ofproto = datapath.ofproto
parser = datapath.ofproto_parser
in_port = msg.match['in_port']
pkt = packet.Packet(msg.data)
eth = pkt.get_protocols(ethernet.ethernet)[0]
dst = eth.dst
src = eth.src
dpid = datapath.id
self.mac_to_port.setdefault(dpid, {})
self.logger.info("packet in %s %s %s %s", dpid, src, dst, in_port)
# learn a mac address to avoid FLOOD next time.
self.mac_to_port[dpid][src] = 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 = [parser.OFPActionOutput(out_port)]
# install a flow to avoid packet_in next time
if out_port != ofproto.OFPP_FLOOD:
match = parser.OFPMatch(in_port=in_port, eth_dst=dst)
self.add_flow(datapath, 1, match, actions)
data = None
if msg.buffer_id == ofproto.OFP_NO_BUFFER:
data = msg.data
out = parser.OFPPacketOut(datapath=datapath, buffer_id=msg.buffer_id,
in_port=in_port, actions=actions, data=data)
datapath.send_msg(out)
@set_ev_cls(stplib.EventTopologyChange, MAIN_DISPATCHER)
def _topology_change_handler(self, ev):
dp = ev.dp
dpid_str = dpid_lib.dpid_to_str(dp.id)
msg = 'Receive topology change event. Flush MAC table.'
self.logger.debug("[dpid=%s] %s", dpid_str, msg)
if dp.id in self.mac_to_port:
self.delete_flow(dp)
del self.mac_to_port[dp.id]
@set_ev_cls(stplib.EventPortStateChange, MAIN_DISPATCHER)
def _port_state_change_handler(self, ev):
dpid_str = dpid_lib.dpid_to_str(ev.dp.id)
of_state = {stplib.PORT_STATE_DISABLE: 'DISABLE',
stplib.PORT_STATE_BLOCK: 'BLOCK',
stplib.PORT_STATE_LISTEN: 'LISTEN',
stplib.PORT_STATE_LEARN: 'LEARN',
stplib.PORT_STATE_FORWARD: 'FORWARD'}
self.logger.debug("[dpid=%s][port=%d] state=%s",
dpid_str, ev.port_no, of_state[ev.port_state])
What I believe is causing the issue
I believe that the reason as to why
sta2
is able to pingsta1
initially is because the flow tables in the OpenFlow Switch are empty. Whensta2
pingssta1
, the controller adds the flow into theOVSSwitch
, and thus creates a flow entry in the flow table.Due to this entry in the flow table, the two stations are able to ping each other since the location is known and a route is set. Once the station migrates to
ap2
, there is no new flow entry created and attached to the flow table. Why? Because the controller believes that the flow entry in the flow table is accurate and as such does not need to query the network for the path again.A method to verify this claim
This can be verified by using the
dpctl
functionality provided by the mininet console. I'm using a slightly different network architecture below, but my theory still holds.sta5 migrates to ap1 from ap3
In this case,
sta5
was initially present inap3
, and we could pingsta3
, which is present inap2
in the initial state of mobility whensta5
is still associated with `ap3``.sta5 pings sta3
Running
dpctl dump-flows
allows us to see that the flows have been added after the initial ping has been made.dpctl dump-flows response
Now, once
sta5
migrates toap1
, you'll notice that the ping fails and that the flows have not been altered, thus proving my statement above.sta5 has migrated to ap1 and fails to ping sta3
Possible solutions
Coming to what can be done to alleviate this problem, there are a few methods,
dpctl del-flows
the station which is migrating.I realize that this is a pretty late response, but hope that it helps out the people that end up facing this issue later on.