I have successfully managed to generate the topology in mininet but I am struggling to create a controller that uses Round-Robin load balancing over all available links to send packets.
This is my topology file:
from mininet.topo import Topo
from mininet.net import Mininet
from mininet.log import setLogLevel
from mininet.cli import CLI
from mininet.node import RemoteController
class MyTopo(Topo):
def __init__(self):
super(MyTopo, self).__init__()
switches = []
for i in range(1, 20 + 1):
switch = self.addSwitch('s{}'.format(i))
switches.append(switch)
hosts = []
for i in range(1, 16 + 1):
host = self.addHost('h{}'.format(i))
hosts.append(host)
# Connect the first 8 switches to the first 16 hosts
for i, switch in enumerate(switches[:8]):
self.addLink(switch, hosts[i * 2])
self.addLink(switch, hosts[i * 2 + 1])
# Connect switches 9-16 to switches 1-8
for i in range(4):
for j in range(2):
self.addLink(switches[i * 2 + j], switches[i * 2 + 8])
self.addLink(switches[i * 2 + j], switches[i * 2 + 9])
# Connect switches 17-20 to switches 9-16
for i in range(2):
for j in range(4):
self.addLink(switches[16 + i], switches[2 * j + 8])
for j in range(4):
self.addLink(switches[18 + i], switches[2 * j + 9])
def main():
setLogLevel('info')
topo = MyTopo()
net = Mininet(topo=topo, controller=RemoteController)
net.start()
CLI(net)
net.stop()
if __name__ == '__main__':
main()
Tried editing the pre-existing SimpleSwitch13, but it is probably an abomination:
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.packet import packet
from ryu.lib.packet import ethernet
from ryu.lib.packet import ether_types
class SimpleSwitch13RR(app_manager.RyuApp):
OFP_VERSIONS = [ofproto_v1_3.OFP_VERSION]
def __init__(self, *args, **kwargs):
super(SimpleSwitch13RR, self).__init__(*args, **kwargs)
self.mac_to_port = {}
self.port_round_robin = {}
@set_ev_cls(ofp_event.EventOFPSwitchFeatures, CONFIG_DISPATCHER)
def switch_features_handler(self, ev):
datapath = ev.msg.datapath
ofproto = datapath.ofproto
parser = datapath.ofproto_parser
# install table-miss flow entry
match = parser.OFPMatch()
actions = [parser.OFPActionOutput(ofproto.OFPP_CONTROLLER, ofproto.OFPCML_NO_BUFFER)]
self.add_flow(datapath, 0, match, actions)
def add_flow(self, datapath, priority, match, actions, buffer_id=None):
ofproto = datapath.ofproto
parser = datapath.ofproto_parser
inst = [parser.OFPInstructionActions(ofproto.OFPIT_APPLY_ACTIONS, actions)]
if buffer_id:
mod = parser.OFPFlowMod(datapath=datapath, buffer_id=buffer_id, priority=priority, match=match, instructions=inst)
else:
mod = parser.OFPFlowMod(datapath=datapath, priority=priority, match=match, instructions=inst)
datapath.send_msg(mod)
@set_ev_cls(ofp_event.EventOFPPacketIn, MAIN_DISPATCHER)
def _packet_in_handler(self, ev):
if ev.msg.msg_len < ev.msg.total_len:
self.logger.debug("packet truncated: only %s of %s bytes", ev.msg.msg_len, ev.msg.total_len)
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]
if eth.ethertype == ether_types.ETH_TYPE_LLDP or eth.ethertype == ether_types.ETH_TYPE_IPV6:
return
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)
# Round Robin logic
available_ports = [port.port_no for port in datapath.ports.values()
if port.port_no not in [ofproto.OFPP_LOCAL, ofproto.OFPP_CONTROLLER]]
if (src, dst) not in self.port_round_robin:
self.port_round_robin[(src, dst)] = iter(available_ports)
try:
out_port = next(self.port_round_robin[(src, dst)])
except StopIteration:
self.port_round_robin[(src, dst)] = iter(available_ports)
out_port = next(self.port_round_robin[(src, dst)])
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, eth_src=src)
if msg.buffer_id != ofproto.OFP_NO_BUFFER:
self.add_flow(datapath, 1, match, actions, msg.buffer_id)
return
else:
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)