0

Fat tree topology

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)
mkrieger1
24.2k7 gold badges68 silver badges84 bronze badges
asked Oct 29, 2023 at 21:48
3
  • 2
    What exactly is wrong with the controller you have so far? Commented Oct 29, 2023 at 21:55
  • 1
    I can't establish a connection between any of the hosts. Get all X's from 'pingall', nothing gets sent or recieved when setting up and iperf server then sending data to it etc. Commented Oct 29, 2023 at 21:59
  • Maybe fat tree topology needs STP to avoid broadcast storm? ryu.app provides simple_switch_stp_13.py, but I have not test that application. Commented Sep 3, 2024 at 10:52

0

Know someone who can answer? Share a link to this question via email, Twitter, or Facebook.

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.