├── .gitignore ├── .gitreview ├── README.md ├── __init__.py ├── bgprouter_deploy.py ├── bgprouter_dev.py ├── dec14demo.py ├── mcast.py ├── onoslib.py ├── onsdemo.py ├── routinglib.py ├── simple.py ├── trellis ├── README.md ├── Vagrantfile ├── bgpdbgp1.conf ├── bgpdbgp2.conf ├── bgpdr1.conf ├── bgpdr2.conf ├── cleanup ├── dhcpd.conf ├── dhcpd6.conf ├── dhcpd_hybrid_v4.conf ├── docker │ ├── Dockerfile │ ├── entrypoint.sh │ └── m ├── trellis.json ├── trellis.py ├── trellis_double_tagged.json ├── trellis_double_tagged.py ├── trellis_dualhome.json ├── trellis_dualhome.py ├── trellis_dualhome_lacp.json ├── trellis_dualhome_lacp.py ├── trellis_duallink.json ├── trellis_duallink.py ├── trellis_hag.json ├── trellis_hag.py ├── trellis_hybrid.json ├── trellis_hybrid.py ├── trellis_hybrid_v4.json ├── trellis_hybrid_v4.py ├── trellis_mcast.json ├── trellis_mcast.py ├── trellis_mcast_netcfg_gen.json ├── trellis_mcast_netcfg_gen.py ├── trellis_remote_dhcp.json ├── trellis_remote_dhcp.py ├── trellis_vlan.json ├── trellis_vlan.py ├── trellislib.py ├── trellisp4.json └── trellisp4.py └── vrouter.py /.gitignore: -------------------------------------------------------------------------------- 1 | *~ 2 | \#*\# 3 | *.pyc 4 | *.project 5 | *.pydevproject 6 | .idea 7 | 8 | # vagrant 9 | trellis/.vagrant/ 10 | # virtualbox 11 | trellis/*.log 12 | # patch 13 | *.txt 14 | 15 | trellis/zebradbgp1.conf 16 | trellis/zebradbgp2.conf 17 | -------------------------------------------------------------------------------- /.gitreview: -------------------------------------------------------------------------------- 1 | [gerrit] 2 | host=gerrit.onosproject.org 3 | port=29418 4 | project=routing.git 5 | defaultremote=origin 6 | defaultbranch=master 7 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Routing libraries and topologies for Mininet 2 | ======================================================== 3 | 4 | This repository contains a set of libraries and scripts that build on 5 | top of Mininet to construct topologies that include L3 routing elements. 6 | Quagga is used to construct routes that support a variety of routing 7 | protocols. 8 | 9 | ### Dependencies 10 | 11 | - Mininet: `sudo apt-get install mininet` 12 | - Quagga: `sudo apt-get install quagga` 13 | - ipaddress: `sudo pip install ipaddress` (if that doesn't work use `sudo apt-get install python-pip`) 14 | 15 | 16 | -------------------------------------------------------------------------------- /__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opennetworkinglab/routing/6374a34ada78d07eff793d2c026aebe399c90e35/__init__.py -------------------------------------------------------------------------------- /bgprouter_deploy.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | from mininet.topo import Topo 4 | from mininet.net import Mininet 5 | from mininet.cli import CLI 6 | from mininet.log import setLogLevel, info 7 | from mininet.node import RemoteController, OVSSwitch 8 | from routinglib import BgpRouter 9 | 10 | class BgpRouterDeployTopo( Topo ): 11 | "Sets up control plane components for BgpRouter deployment" 12 | 13 | def __init__( self, *args, **kwargs ): 14 | Topo.__init__( self, *args, **kwargs ) 15 | s1 = self.addSwitch('s1', dpid='0000000000000001') 16 | 17 | sdnAs = 65000 18 | 19 | # Set up BGP speakers 20 | bgp1eth0 = { 'ipAddrs' : ['1.1.1.11/24'] } 21 | 22 | bgp1eth1 = [ 23 | { 'vlan': 1, 24 | 'mac':'00:00:00:00:00:01', 25 | 'ipAddrs' : ['192.168.10.101/24'] }, 26 | { 'vlan': 2, 27 | 'mac':'00:00:00:00:00:02', 28 | 'ipAddrs' : ['192.168.20.101/24'] } 29 | ] 30 | 31 | bgp1Intfs = { 'bgp1-eth0' : bgp1eth0, 32 | 'bgp1-eth1' : bgp1eth1 } 33 | 34 | neighbors = [{'address':'192.168.10.1', 'as':65001}, 35 | {'address':'192.168.20.1', 'as':65001}, 36 | {'address':'192.168.30.1', 'as':65002}, 37 | {'address':'192.168.40.1', 'as':65003}, 38 | {'address':'1.1.1.1', 'as':sdnAs, 'port': 2000}] 39 | 40 | bgp1 = self.addHost( "bgp1", interfaces=bgp1Intfs, asNum=sdnAs, 41 | neighbors=neighbors, routes=[], cls=BgpRouter) 42 | 43 | root = self.addHost('root', ip='1.1.1.1/24', inNamespace=False) 44 | 45 | self.addLink( bgp1, root ) 46 | self.addLink( bgp1, s1 ) 47 | 48 | if __name__ == "__main__": 49 | setLogLevel('debug') 50 | topo = BgpRouterDeployTopo() 51 | 52 | net = Mininet(topo=topo, controller=RemoteController, switch=OVSSwitch) 53 | 54 | net.start() 55 | 56 | CLI(net) 57 | 58 | net.stop() 59 | 60 | info("done\n") 61 | -------------------------------------------------------------------------------- /bgprouter_dev.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | from mininet.topo import Topo 4 | from mininet.net import Mininet 5 | from mininet.cli import CLI 6 | from mininet.log import setLogLevel, info 7 | from mininet.node import RemoteController, OVSBridge 8 | from routinglib import BasicAutonomousSystem 9 | from routinglib import SdnAutonomousSystem, AutonomousSystem 10 | from routinglib import generateRoutes 11 | 12 | 13 | class BgpRouterTopo( Topo ): 14 | "Single switch topology for testing the BgpRouter" 15 | 16 | def __init__( self, *args, **kwargs ): 17 | Topo.__init__( self, *args, **kwargs ) 18 | # Router switch 19 | s1 = self.addSwitch('s1', dpid='00000000000000a1') 20 | 21 | # Control plane switch for BGP daemon 22 | s7 = self.addSwitch('s7', dpid='00000000000000a7') 23 | 24 | # SDN AS 25 | onosIps = ['192.168.56.11'] 26 | sdnAs = SdnAutonomousSystem(onosIps, numBgpSpeakers=1, asNum=65000) 27 | 28 | numRoutesPerAs = 1 29 | 30 | # Normal ASes 31 | as1 = BasicAutonomousSystem(1, 32 | generateRoutes(u'10.1.0.0/16', numRoutesPerAs)) 33 | AutonomousSystem.addPeering(as1, sdnAs, useVlans=True) 34 | as1.addLink(s1) 35 | as1.build(self) 36 | 37 | as2 = BasicAutonomousSystem(2, 38 | generateRoutes(u'10.2.0.0/16', numRoutesPerAs)) 39 | AutonomousSystem.addPeering(as2, sdnAs, useVlans=True) 40 | as2.addLink(s1) 41 | as2.build(self) 42 | 43 | as3 = BasicAutonomousSystem(3, 44 | generateRoutes(u'10.3.0.0/16', numRoutesPerAs)) 45 | AutonomousSystem.addPeering(as3, sdnAs, useVlans=True) 46 | as3.addLink(s1) 47 | as3.build(self) 48 | 49 | as4 = BasicAutonomousSystem(4, 50 | generateRoutes(u'10.4.0.0/16', numRoutesPerAs)) 51 | AutonomousSystem.addPeering(as4, sdnAs, useVlans=False) 52 | as4.addLink(s1) 53 | as4.build(self) 54 | 55 | # SDN AS (internal BGP speaker) connects to control plane switch 56 | cs0 = self.addSwitch('cs0', cls=OVSBridge) 57 | sdnAs.build(self, s7, cs0) 58 | 59 | if __name__ == "__main__": 60 | setLogLevel('debug') 61 | topo = BgpRouterTopo() 62 | 63 | net = Mininet(topo=topo, controller=None) 64 | net.addController(RemoteController('c0', ip='192.168.56.11')) 65 | 66 | net.start() 67 | 68 | CLI(net) 69 | 70 | net.stop() 71 | 72 | info("done\n") 73 | -------------------------------------------------------------------------------- /dec14demo.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | from mininet.topo import Topo 4 | from mininet.node import RemoteController, OVSSwitch, OVSBridge 5 | from mininet.log import setLogLevel, info 6 | from mininet.net import Mininet 7 | from routinglib import RoutingCli as CLI 8 | from routinglib import AutonomousSystem, BasicAutonomousSystem, SdnAutonomousSystem 9 | from routinglib import generateRoutes 10 | 11 | onoses = [ '192.168.56.11', '192.168.56.12', '192.168.56.13' ] 12 | 13 | class Dec14DemoTopo( Topo ): 14 | 15 | "Topology from the Dec 14 SDN-IP demo" 16 | 17 | def __init__( self, **kwargs ): 18 | Topo.__init__( self, **kwargs ) 19 | coreMesh = [] 20 | 21 | for i in range( 1, 5 ): 22 | coreMesh.append( self.addSwitch( 's%s' %i ) ) 23 | 24 | # create full mesh between middle 4 switches 25 | remaining = list( coreMesh ) 26 | while True: 27 | first = remaining[ 0 ] 28 | for switch in tuple( remaining ): 29 | if switch is not first: 30 | self.addLink( switch, first ) 31 | remaining.remove( first ) 32 | if not remaining: 33 | break 34 | 35 | 36 | s5 = self.addSwitch( 's5', dpid='00:00:00:00:00:00:00:05' ) 37 | s6 = self.addSwitch( 's6', dpid='00:00:00:00:00:00:00:06' ) 38 | s7 = self.addSwitch( 's7', dpid='00:00:00:00:00:00:00:07' ) 39 | self.addLink( s5, s6 ) 40 | self.addLink( s6, s7 ) 41 | 42 | s8 = self.addSwitch( 's8', dpid='00:00:00:00:00:00:00:08' ) 43 | s9 = self.addSwitch( 's9', dpid='00:00:00:00:00:00:00:09' ) 44 | s10 = self.addSwitch( 's10', dpid='00:00:00:00:00:00:00:10' ) 45 | self.addLink( s8, s9 ) 46 | self.addLink( s9, s10 ) 47 | 48 | self.addLink( s5, s8 ) 49 | 50 | # add links between core mesh and satellite switches 51 | self.addLink( coreMesh[ 0 ], s5 ) 52 | self.addLink( coreMesh[ 0 ], s6 ) 53 | self.addLink( coreMesh[ 0 ], s7 ) 54 | self.addLink( coreMesh[ 1 ], s8 ) 55 | self.addLink( coreMesh[ 1 ], s9 ) 56 | self.addLink( coreMesh[ 1 ], s10 ) 57 | self.addLink( coreMesh[ 2 ], s7 ) 58 | self.addLink( coreMesh[ 3 ], s10 ) 59 | 60 | # SDN AS 61 | sdnAs = SdnAutonomousSystem(onoses, numBgpSpeakers=3, asNum=65000, externalOnos=True) 62 | cs0 = self.addSwitch('cs0', cls=OVSBridge) 63 | 64 | numRoutesPerAs = 32 65 | 66 | # Add external ASes 67 | as1 = BasicAutonomousSystem(1, generateRoutes(u'192.168.1.0/24', numRoutesPerAs)) 68 | AutonomousSystem.addPeering(as1, sdnAs) 69 | AutonomousSystem.addPeering(as1, sdnAs, router2=3, intf1=2) 70 | as1.addLink(s5) 71 | as1.addLink(s6) 72 | as1.build(self) 73 | 74 | as2 = BasicAutonomousSystem(2, generateRoutes(u'192.168.2.0/24', numRoutesPerAs)) 75 | AutonomousSystem.addPeering(as2, sdnAs) 76 | AutonomousSystem.addPeering(as2, sdnAs, router2=2) 77 | as2.addLink(s7) 78 | as2.build(self) 79 | 80 | as3 = BasicAutonomousSystem(3, generateRoutes(u'192.168.3.0/24', numRoutesPerAs)) 81 | AutonomousSystem.addPeering(as3, sdnAs, router2=2) 82 | AutonomousSystem.addPeering(as3, sdnAs, router2=3) 83 | as3.addLink(s8) 84 | as3.build(self) 85 | 86 | as4 = BasicAutonomousSystem(4, generateRoutes(u'192.168.4.0/24', numRoutesPerAs), numRouters=2) 87 | AutonomousSystem.addPeering(as4, sdnAs) 88 | AutonomousSystem.addPeering(as4, sdnAs, router1=2, router2=3) 89 | as4.addLink(s9) 90 | as4.addLink(s10, router=2) 91 | as4.build(self) 92 | 93 | # add links between nets 94 | #self.addLink( BGP1, coreMesh[ 0 ], port2=10 ) 95 | #self.addLink( BGP2, coreMesh[ 1 ], port2=10 ) 96 | #self.addLink( BGP3, coreMesh[ 2 ], port2=10 ) 97 | 98 | sdnAs.build(self, coreMesh[0], cs0) 99 | # TODO multihome the BGP speakers to different switches 100 | 101 | def run(): 102 | topo = Dec14DemoTopo( ) 103 | net = Mininet( topo=topo, switch=OVSSwitch, controller=None ) 104 | 105 | for i in range(len(onoses)): 106 | net.addController( RemoteController( 'c%s' % (i+1), ip=onoses[i], checkListening=False ) ) 107 | 108 | net.start() 109 | 110 | CLI( net ) 111 | 112 | net.stop() 113 | info( 'done\n' ) 114 | 115 | if __name__ == '__main__': 116 | setLogLevel( 'debug' ) 117 | run() 118 | 119 | 120 | -------------------------------------------------------------------------------- /mcast.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | from mininet.topo import Topo 4 | from mininet.net import Mininet 5 | from mininet.cli import CLI 6 | from mininet.log import setLogLevel 7 | from mininet.node import RemoteController, OVSSwitch, UserSwitch 8 | from mininet.nodelib import NAT 9 | from routinglib import QuaggaRouter 10 | from routinglib import BgpProtocol, OspfProtocol 11 | from routinglib import RoutedNetwork, RoutedHost, Router 12 | from ipaddress import ip_network 13 | from routinglib import PimProtocol 14 | 15 | #onosIps = ['192.168.56.11'] 16 | 17 | cordOnos = '192.168.56.12' 18 | fabricOnos = '192.168.56.11' 19 | 20 | c0 = RemoteController( 'c0', ip=fabricOnos ) 21 | c1 = RemoteController( 'c1', ip=cordOnos ) 22 | 23 | cmap = { 's1': c0, 's2': c1 } 24 | 25 | class MultiSwitch( UserSwitch ): 26 | "Custom Switch() subclass that connects to different controllers" 27 | def start( self, controllers ): 28 | return UserSwitch.start( self, [ cmap[ self.name ] ] ) 29 | 30 | class MulticastTopo( Topo ): 31 | """Topology for testing multicast in CORD. 32 | Contains two switches: 33 | (1) stand-in for the OLT, where the IGMP snooping will happen 34 | (2) vRouter/fabric leaf where the PIM to upstream happens""" 35 | 36 | def __init__( self, *args, **kwargs ): 37 | Topo.__init__( self, *args, **kwargs ) 38 | 39 | QuaggaRouter.binDir='/home/jono/shared/quagga/build/bin' 40 | 41 | # vRouter switch 42 | s1 = self.addSwitch('s1', dpid='1') 43 | # IGMP switch 44 | s2 = self.addSwitch('s2', dpid='2') 45 | 46 | eth0 = { 'ipAddrs' : ['10.0.3.1/24'] } 47 | eth1 = { 'ipAddrs' : ['10.0.2.254/24']} 48 | intfs = {'r1-eth0' : eth0, 49 | 'r1-eth1' : eth1} 50 | 51 | pim = PimProtocol(configFile='configs/pim.conf') 52 | #bgp = BgpProtocol(asNum=65001, neighbors=[{'address' : '10.0.3.2', 'as' : 65000}], routes=['10.0.2.0/24']) 53 | ospf = OspfProtocol() 54 | r1 = self.addHost('r1', interfaces=intfs, cls=QuaggaRouter, 55 | protocols=[pim, ospf]) 56 | 57 | self.addLink(r1, s1) 58 | 59 | RoutedNetwork.build(self, r1, 'h1', [ip_network(u'10.0.2.0/24')]) 60 | 61 | 62 | cpintfs = {'cp1-eth0' : { 'mac' : '00:00:00:00:00:01', 'ipAddrs' : ['10.0.3.2/24', '10.0.1.100/24'] }, 63 | 'cp1-eth1' : { 'ipAddrs' : ['1.1.1.1/24']} } 64 | #bgp = BgpProtocol(asNum=65000, neighbors=[{'address' : '10.0.3.1', 'as': 65001}]) 65 | ospf = OspfProtocol() 66 | cp1 = self.addHost('cp1', cls=QuaggaRouter, interfaces=cpintfs, protocols=[ospf], 67 | fpm=fabricOnos, defaultRoute='1.1.1.254') 68 | #cp1 = self.addHost('cp1', cls=Router, ips=['10.0.3.2/24'], mac='00:00:00:00:00:01') 69 | 70 | nat = self.addHost('nat', cls=NAT, 71 | ip='1.1.1.254/24', 72 | subnet='1.1.1.0/24', inNamespace=False); 73 | self.addLink(cp1, s1) 74 | self.addLink(cp1, nat) 75 | 76 | h2 = self.addHost('h2', ip="10.0.1.1/24", defaultRoute="via 10.0.1.254", mac="00:00:00:00:00:02", inNamespace=True) 77 | self.addLink(h2, s2) 78 | self.addLink(s2, s1) 79 | 80 | if __name__ == "__main__": 81 | setLogLevel('debug') 82 | topo = MulticastTopo() 83 | 84 | net = Mininet(topo=topo, switch=MultiSwitch, controller=None) 85 | 86 | net.addController(c0) 87 | net.addController(c1) 88 | 89 | h2 = net.get('h2') 90 | h2.cmd('ethtool --offload h2-eth0 tx off') 91 | r1 = net.get('r1') 92 | r1.cmd('ethtool --offload r1-eth0 tx off') 93 | cp1 = net.get('cp1') 94 | cp1.cmd('ethtool --offload cp1-eth0 tx off') 95 | 96 | net.start() 97 | 98 | CLI(net) 99 | 100 | net.stop() 101 | -------------------------------------------------------------------------------- /onoslib.py: -------------------------------------------------------------------------------- 1 | """ 2 | Libraries for using ONOS from within Mininet. 3 | """ 4 | 5 | from mininet.node import OVSBridge 6 | from mininet.util import netParse, ipStr 7 | import os, sys, imp 8 | 9 | # Import the ONOS classes from onos.py in the ONOS repository 10 | if not 'ONOS_ROOT' in os.environ: 11 | print 'ONOS_ROOT is not set.' 12 | print 'Try running the script with \'sudo -E\' to pass your environment in.' 13 | sys.exit(1) 14 | 15 | onos_path = os.path.join(os.path.abspath(os.environ['ONOS_ROOT']), 'tools/test/topos/onos.py') 16 | onos = imp.load_source('onos', onos_path) 17 | from onos import ONOS 18 | 19 | class ONOSHostCluster(object): 20 | def __init__(self, controlSubnet='192.168.1.0/24', numInstances=1, basename='ONOS', 21 | features=[]): 22 | self.controlSubnet = controlSubnet 23 | self.numInstances = numInstances 24 | self.basename = basename 25 | self.instances = [] 26 | self.features = features 27 | 28 | def create(self, topology): 29 | cs0 = topology.addSwitch('cs0', cls=OVSBridge) 30 | 31 | ctrlIp, ctrlPrefixLen = netParse(self.controlSubnet) 32 | 33 | for i in range(1, self.numInstances + 1): 34 | strCtrlIp = '%s/%i' % (ipStr(ctrlIp + i), ctrlPrefixLen) 35 | 36 | c = topology.addHost('%s%s' % (self.basename, i), cls=ONOS, inNamespace=True, 37 | ip=strCtrlIp, 38 | features=['onos-app-config', 'onos-app-proxyarp', 39 | 'onos-core'] + self.features, 40 | reactive=False) 41 | 42 | topology.addLink(c, cs0, params1={ 'ip' : strCtrlIp }) 43 | 44 | self.instances.append(c) 45 | 46 | # Connect switch to root namespace so that data network 47 | # switches will be able to talk to us 48 | highestIp = '%s/%i' % (ipStr(ctrlIp + (2 ** (32 - ctrlPrefixLen)) - 2), ctrlPrefixLen) 49 | root = topology.addHost('root', inNamespace=False, ip=highestIp) 50 | topology.addLink(root, cs0) 51 | 52 | class ONOSHostSdnipCluster(ONOSHostCluster): 53 | 54 | def __init__(self, dataSubnet='10.0.0.0/24', features=['onos-app-sdnip'], **kwargs): 55 | super(ONOSHostSdnipCluster, self).__init__(features=features, **kwargs) 56 | 57 | self.dataSubnet = dataSubnet 58 | 59 | def create(self, topology): 60 | super(ONOSHostSdnipCluster, self).create(topology) 61 | 62 | cs1 = topology.addSwitch('cs1', cls=OVSBridge) 63 | 64 | dataIp, dataPrefixLen = netParse(self.dataSubnet) 65 | for i in range(1, len(self.instances) + 1): 66 | c = self.instances[i-1] 67 | strDataIp = '%s/%i' % (ipStr(dataIp + i), dataPrefixLen) 68 | topology.addLink(c, cs1, params1={ 'ip' : strDataIp }) 69 | 70 | return cs1 -------------------------------------------------------------------------------- /onsdemo.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | from mininet.topo import Topo 4 | from mininet.net import Mininet 5 | from mininet.node import RemoteController 6 | from mininet.cli import CLI 7 | from mininet.log import setLogLevel, info 8 | from mininet.node import OVSBridge 9 | from routinglib import BgpRouter, RoutedHost 10 | from onoslib import ONOSHostSdnipCluster 11 | 12 | onoses = [ '192.168.56.11', '192.168.56.12' ] 13 | 14 | class BgpRouterDeployTopo( Topo ): 15 | "Our familiar ONS demo topology" 16 | 17 | def __init__( self, *args, **kwargs ): 18 | Topo.__init__( self, *args, **kwargs ) 19 | sw1 = self.addSwitch('sw1', dpid='00000000000000a1') 20 | sw2 = self.addSwitch('sw2', dpid='00000000000000a2') 21 | sw3 = self.addSwitch('sw3', dpid='00000000000000a3') 22 | sw4 = self.addSwitch('sw4', dpid='00000000000000a4') 23 | sw5 = self.addSwitch('sw5', dpid='00000000000000a5') 24 | sw6 = self.addSwitch('sw6', dpid='00000000000000a6') 25 | 26 | #Note this switch isn't part of the SDN topology 27 | as6sw = self.addSwitch('as6sw', dpid='00000000000000a7', cls=OVSBridge) 28 | 29 | #AS2 host 30 | host3eth0 = { 'mac':'00:00:00:00:02:01', 'ipAddrs' : [ '192.168.10.1/24' ] } 31 | host3eth1 = { 'mac':'00:00:00:00:02:02', 'ipAddrs' : [ '192.168.20.1/24' ] } 32 | host3eth2 = { 'ipAddrs' : [ '172.16.20.254/24' ] } 33 | host3Intfs = {'host3-eth0' : host3eth0, 34 | 'host3-eth1' : host3eth1, 35 | 'host3-eth2' : host3eth2 } 36 | host3neigh = [{'address':'192.168.10.101', 'as':64513}, 37 | {'address':'192.168.20.101', 'as':64513}] 38 | host3routes = ['127.16.10.0/24'] 39 | 40 | host3 = self.addHost( 'host3', interfaces=host3Intfs, asNum=65001, 41 | neighbors=host3neigh, routes=host3routes, 42 | cls=BgpRouter) 43 | 44 | as2host = self.addHost( 'as2host', cls=RoutedHost, ip='172.16.20.1/24', 45 | route='172.16.20.254' ) 46 | 47 | 48 | #AS3 host 49 | host4eth0 = { 'mac':'00:00:00:00:03:01', 'ipAddrs' : [ '192.168.30.1/24' ] } 50 | host4eth1 = { 'ipAddrs' : [ '172.16.30.254/24' ] } 51 | host4Intfs = {'host4-eth0' : host4eth0, 52 | 'host4-eth1' : host4eth1 } 53 | host4neigh = [{'address':'192.168.30.101', 'as':64513}] 54 | host4routes = ['172.16.30.0/24'] 55 | host4 = self.addHost( 'host4', interfaces=host4Intfs, asNum=65002, 56 | neighbors=host4neigh, routes=host4routes, 57 | cls=BgpRouter) 58 | 59 | as3host = self.addHost( 'as3host', cls=RoutedHost, ip='172.16.30.1/24', 60 | route='172.16.30.254' ) 61 | 62 | 63 | #AS4 host 64 | host5eth0 = { 'mac':'00:00:00:00:04:01', 'ipAddrs' : [ '192.168.40.1/24' ] } 65 | host5eth1 = { 'ipAddrs' : [ '172.16.40.254/24' ] } 66 | host5Intfs = {'host5-eth0' : host5eth0, 67 | 'host5-eth1' : host5eth1 } 68 | host5neigh = [{'address':'192.168.40.101', 'as':64513}] 69 | host5routes = ['172.16.40.0/24'] 70 | host5 = self.addHost( 'host5', interfaces=host5Intfs, asNum=65003, 71 | neighbors=host5neigh, routes=host5routes, 72 | cls=BgpRouter) 73 | 74 | as4host = self.addHost( 'as4host', cls=RoutedHost, ip='172.16.40.1/24', 75 | route='172.16.40.254' ) 76 | 77 | #AS6 host 78 | #as6rs = self.addHost( 'as6rs' ) 79 | #as6rs2 = self.addHost( 'as6rs2' ) 80 | #as6router = self.addHost( 'as6router' ) 81 | #as6host = self.addHost( 'as6host' ) 82 | 83 | # Create a control network 84 | onosCluster = ONOSHostSdnipCluster(controlSubnet='192.168.50.0/24', 85 | dataSubnet='1.1.1.0/24', numInstances=2) 86 | cs1 = onosCluster.create(self) 87 | #cs0 = self.createControlNet((u'192.168.50.0/24'), (u'1.1.1.0/24'), numOnos=2) 88 | 89 | # Set up BGP speakers 90 | bgp1eth0 = { 'ipAddrs' : ['1.1.1.11/24'] } 91 | bgp1eth1 = { 'mac':'00:00:00:00:00:01', 92 | 'ipAddrs' : ['192.168.10.101/24', 93 | '192.168.20.101/24', 94 | '192.168.30.101/24', 95 | '192.168.40.101/24',] } 96 | bgp1Intfs = { 'BGP1-eth0' : bgp1eth0, 97 | 'BGP1-eth1' : bgp1eth1 } 98 | bgp1neigh = [{'address':'192.168.10.1', 'as':65001}, 99 | {'address':'192.168.20.1', 'as':65001}, 100 | {'address':'192.168.30.1', 'as':65002}, 101 | {'address':'192.168.40.1', 'as':65003}, 102 | {'address':'1.1.1.1', 'as':64513}, 103 | {'address':'1.1.1.2', 'as':64513}, 104 | {'address':'1.1.1.12', 'as':64513}] 105 | 106 | bgp1 = self.addHost( "BGP1", interfaces=bgp1Intfs, asNum=64513, 107 | neighbors=bgp1neigh, routes=[], cls=BgpRouter) 108 | 109 | self.addLink( bgp1, cs1 ) 110 | self.addLink( bgp1, sw1 ) 111 | 112 | #bgp2eth0 = { 'ipAddrs' : ['1.1.1.12/24'] } 113 | #bgp2eth1 = { 'mac':'00:00:00:00:00:02', 114 | # 'ipAddrs' : ['192.168.10.102/24', 115 | # '192.168.20.102/24', 116 | # '192.168.30.102/24', 117 | # '192.168.40.102/24',] } 118 | #bgp2Intfs = { 'BGP2-eth0' : bgp2eth0, 119 | # 'BGP2-eth1' : bgp2eth1 } 120 | 121 | #bgp2 = self.addHost( "BGP2", cls=BgpRouter, 122 | # quaggaConfFile = '../onsdemo/quagga-sdn2.conf', 123 | # zebraConfFile = zebraConf, 124 | # interfaces=bgp2Intfs ) 125 | 126 | #self.addLink( bgp2, cs0 ) 127 | #self.addLink( bgp2, sw4 ) 128 | 129 | #Links to the multihomed AS 130 | self.addLink( host3, sw3 ) 131 | self.addLink( host3, sw5 ) 132 | self.addLink( as2host, host3 ) 133 | #Single links to the remaining two ASes 134 | self.addLink( host4, sw2 ) 135 | self.addLink( as3host, host4 ) 136 | self.addLink( host5, sw6 ) 137 | self.addLink( as4host, host5 ) 138 | #AS3-AS4 link 139 | #self.addLink( host4, host5) 140 | #Add new AS6 to its bridge 141 | #self.addLink( as6rs, as6sw ) 142 | #self.addLink( as6rs2, as6sw ) 143 | #self.addLink( as6router, as6sw ) 144 | #self.addLink( as6host, as6router ) 145 | #for i in range(1, 10): 146 | # host = self.addHost('as6host%d' % i) 147 | # self.addLink(host, as6router) 148 | 149 | self.addLink( sw1, sw2 ) 150 | self.addLink( sw1, sw3 ) 151 | self.addLink( sw2, sw4 ) 152 | self.addLink( sw3, sw4 ) 153 | self.addLink( sw3, sw5 ) 154 | self.addLink( sw4, sw6 ) 155 | self.addLink( sw5, sw6 ) 156 | self.addLink( as6sw, sw4 ) 157 | 158 | if __name__ == "__main__": 159 | setLogLevel('debug') 160 | topo = BgpRouterDeployTopo() 161 | 162 | net = Mininet(topo=topo, controller=None) 163 | for i in range(len(onoses)): 164 | net.addController( RemoteController( 'c%s' % (i+1), ip=onoses[i], checkListening=False ) ) 165 | 166 | net.start() 167 | 168 | CLI(net) 169 | 170 | net.stop() 171 | 172 | info("done\n") 173 | -------------------------------------------------------------------------------- /simple.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | from mininet.topo import Topo 4 | from mininet.net import Mininet 5 | from mininet.node import RemoteController, OVSBridge 6 | from mininet.cli import CLI 7 | from mininet.log import setLogLevel, info 8 | from routinglib import BasicAutonomousSystem, RouteServerAutonomousSystem 9 | from routinglib import SdnAutonomousSystem, AutonomousSystem 10 | from ipaddress import ip_network 11 | 12 | onoses = [ '192.168.56.11' ] 13 | 14 | class SdnTopo( Topo ): 15 | "Topology built using higher-level abstractions (ASes)" 16 | 17 | def __init__( self, *args, **kwargs ): 18 | Topo.__init__( self, *args, **kwargs ) 19 | sw1 = self.addSwitch('sw1', dpid='00000000000000a1') 20 | sw2 = self.addSwitch('sw2', dpid='00000000000000a2') 21 | sw3 = self.addSwitch('sw3', dpid='00000000000000a3') 22 | sw4 = self.addSwitch('sw4', dpid='00000000000000a4') 23 | sw5 = self.addSwitch('sw5', dpid='00000000000000a5') 24 | sw6 = self.addSwitch('sw6', dpid='00000000000000a6') 25 | 26 | # SDN AS 27 | sdnAs = SdnAutonomousSystem(onoses, numBgpSpeakers=1, asNum=65000) 28 | 29 | # Normal ASes 30 | as1 = BasicAutonomousSystem(1, [ip_network(u'172.16.10.0/24')]) 31 | 32 | AutonomousSystem.addPeering(as1, sdnAs) 33 | as1.addLink(sw3) 34 | as1.build(self) 35 | 36 | as2 = BasicAutonomousSystem(2, [ip_network(u'172.16.20.0/24')]) 37 | 38 | AutonomousSystem.addPeering(as2, sdnAs) 39 | as2.addLink(sw2) 40 | as2.build(self) 41 | 42 | as3 = BasicAutonomousSystem(3, [ip_network(u'172.16.30.0/24')]) 43 | 44 | AutonomousSystem.addPeering(as3, sdnAs) 45 | as3.addLink(sw6) 46 | as3.build(self) 47 | 48 | # AS containing a route server 49 | #as4 = RouteServerAutonomousSystem('192.168.60.2/24', 4, '192.168.60.1/24', 50 | # [ip_network(u'172.16.60.0/24')]) 51 | #as4.build(self, sw4); 52 | 53 | cs0 = self.addSwitch('cs0', cls=OVSBridge) 54 | 55 | sdnAs.build(self, sw1, cs0) 56 | 57 | self.addLink( sw1, sw2 ) 58 | self.addLink( sw1, sw3 ) 59 | self.addLink( sw2, sw4 ) 60 | self.addLink( sw3, sw4 ) 61 | self.addLink( sw3, sw5 ) 62 | self.addLink( sw4, sw6 ) 63 | self.addLink( sw5, sw6 ) 64 | 65 | if __name__ == "__main__": 66 | setLogLevel('debug') 67 | topo = SdnTopo() 68 | 69 | net = Mininet(topo=topo, controller=None) 70 | for i in range(len(onoses)): 71 | net.addController( RemoteController( 'c%s' % (i+1), ip=onoses[i], checkListening=False ) ) 72 | 73 | net.start() 74 | 75 | CLI(net) 76 | 77 | net.stop() 78 | 79 | info("done\n") 80 | -------------------------------------------------------------------------------- /trellis/README.md: -------------------------------------------------------------------------------- 1 | Trellis Leaf-Spine Fabric 2 | ========================= 3 | 4 | # Introduction 5 | This folder contains Mininet scripts and corresponding config files that 6 | can be used to emulate Trellis leaf-spine fabric, vRouter and DHCP relay. 7 | Current Mininet setup only works with ONOS 1.12 and above. We recommend you use the tip of 1.12 branch. 8 | 9 | # Download 10 | `git clone https://gerrit.onosproject.org/routing` 11 | 12 | # Manual Installation 13 | 14 | ## Ubuntu 16.04 LTS 15 | Some dependencies need to be installed for a fresh Ubuntu. 16 | ``` 17 | sudo apt-get update 18 | sudo apt-get install -y gawk texinfo python-pip build-essential iptables automake autoconf libtool 19 | sudo pip install -U pip 20 | sudo pip install ipaddress 21 | ``` 22 | 23 | ## Mininet 24 | `sudo apt-get install mininet` 25 | 26 | ## OpenvSwitch 27 | Mininet should install OVS for you. 28 | Please run `sudo ovs-vsctl --version` and make sure the OVS version is above 2.5.0+. 29 | 30 | ## DHCP server 31 | `sudo apt-get install isc-dhcp-server` 32 | 33 | ## Quagga 34 | Trellis needs a special FPM patch for Quagga. 35 | 36 | In order to start the quagga related daemons, you should create a user `quagga` 37 | and set the correct read/write permission to local state directory(`--localstatedir`) 38 | and configuration directory(`--sysconfdir`). 39 | 40 | ``` 41 | git clone -b onos-1.11 https://gerrit.opencord.org/quagga 42 | cd quagga 43 | ./bootstrap.sh 44 | ./configure --enable-fpm --sbindir=/usr/lib/quagga enable_user=root enable_group=root 45 | make 46 | sudo make install 47 | cd .. 48 | sudo ldconfig 49 | ``` 50 | 51 | ## ONOS - Installation 52 | Learn about how to setup ONOS at: https://wiki.onosproject.org/. 53 | After installation, the following ONOS apps need to be activated. 54 | 55 | `export ONOS_APPS=drivers,openflow,segmentrouting,fpm,dhcprelay,netcfghostprovider,routeradvertisement,mcast` 56 | 57 | ## ONOS - Network Config 58 | `onos-netcfg routing/trellis/trellis.json` 59 | 60 | ## Disable/Modify AppArmor 61 | The apparmor will set dhcpd in enforce mode. We will need to disable the profile. 62 | ``` 63 | sudo ln -s /etc/apparmor.d/usr.sbin.dhcpd /etc/apparmor.d/disable/ 64 | sudo apparmor_parser -R /etc/apparmor.d/usr.sbin.dhcpd 65 | ``` 66 | 67 | The apparmor rules of dhclient will restrict the dhclient to write files to directory /var/lib/. 68 | We need to modify the rules of dhclient profile and restart the apparmor. 69 | ``` 70 | sudo /etc/init.d/apparmor stop 71 | sudo sed -i '30i /var/lib/dhcp{,3}/dhcpclient* lrw,' /etc/apparmor.d/sbin.dhclient 72 | sudo /etc/init.d/apparmor start 73 | ``` 74 | 75 | ## Start Mininet Emulation 76 | ``` 77 | cd routing/trellis 78 | sudo ./trellis.py --controllers ONOS_CONTROLLER_IP1,ONOS_CONTROLLER_IP2,...,ONOS_CONTROLLER_IPN 79 | ``` 80 | 81 | ## Verify Network Connectivity 82 | In Mininet, run 83 | - `h1 ping 10.0.99.2` to check IPv4 connectivity 84 | - `h1v6 ping6 2000::9902` to check IPv6 connectivity 85 | 86 | # Vagrant 87 | We also provide a mininet VM image supported by Vagrant file. 88 | In that VM environment, you only need to modify the IP address of ONOS controller for 89 | `trellis.py` and `zebradbgp*.conf`. 90 | 91 | In order to use the Vagrant, make sure you have already installed the Vagrant in your environment. 92 | 93 | ## Start the VM 94 | ``` 95 | vagrant up 96 | ``` 97 | 98 | ## Start the ONOS 99 | Start the ONOS controller and set the config via `onos-netcfg` on the other host. 100 | 101 | ## Operate the VM 102 | Type the following command to ssh into the VM environment. 103 | ``` 104 | vagrant ssh 105 | ``` 106 | 107 | Now start mininet to test 108 | ``` 109 | cd routing/trellis 110 | sudo ./trellis.py --controllers ONOS_CONTROLLER_IP1,ONOS_CONTROLLER_IP2,...,ONOS_CONTROLLER_IPN 111 | ``` 112 | 113 | # Troubleshooting 114 | - Services in the emulated hosts may still be alive if Mininet is not terminated properly. 115 | In that case, simply run the following command to clean up. 116 | ``` 117 | sudo killall -9 dhclient dhcpd zebra bgpd 118 | sudo mn -c 119 | ``` 120 | -------------------------------------------------------------------------------- /trellis/Vagrantfile: -------------------------------------------------------------------------------- 1 | # -*- mode: ruby -*- 2 | # vi: set ft=ruby : 3 | 4 | Vagrant.configure("2") do |config| 5 | config.vm.box = "bento/ubuntu-18.04" 6 | config.vm.box_version = "201807.12.0" 7 | config.vm.hostname = 'trellis-dev' 8 | config.ssh.forward_agent = true 9 | config.ssh.forward_x11 = true 10 | 11 | config.vm.provision "shell", privileged: false, inline: <<-SHELL 12 | set -e -x -u 13 | sudo apt-get update 14 | sudo DEBIAN_FRONTEND=noninteractive apt-get -yq install gawk texinfo python-pip build-essential iptables automake autoconf libtool mininet isc-dhcp-server wireshark 15 | sudo pip install -U pip 16 | sudo pip install ipaddress 17 | git clone -b onos-1.11 https://gerrit.opencord.org/quagga 18 | cd quagga 19 | ./bootstrap.sh 20 | ./configure --enable-fpm --sbindir=/usr/lib/quagga enable_user=root enable_group=root 21 | make 22 | sudo make install 23 | cd .. 24 | 25 | sudo /etc/init.d/apparmor stop 26 | sudo ln -s /etc/apparmor.d/usr.sbin.dhcpd /etc/apparmor.d/disable/ 27 | sudo apparmor_parser -R /etc/apparmor.d/usr.sbin.dhcpd 28 | sudo sed -i '30i /var/lib/dhcp{,3}/dhcpclient* lrw,' /etc/apparmor.d/sbin.dhclient 29 | sudo /etc/init.d/apparmor start 30 | 31 | git clone https://gerrit.onosproject.org/routing 32 | 33 | sudo ldconfig 34 | 35 | sudo ovs-vsctl set Open_vSwitch . other_config:vlan-limit=2 36 | SHELL 37 | 38 | config.vm.provider :virtualbox do |v| 39 | v.customize ["modifyvm", :id, "--cpus", 2] 40 | # enable this when you want to have more memory 41 | # v.customize ["modifyvm", :id, "--memory", 4096] 42 | v.customize ['modifyvm', :id, '--nicpromisc1', 'allow-all'] 43 | end 44 | end 45 | -------------------------------------------------------------------------------- /trellis/bgpdbgp1.conf: -------------------------------------------------------------------------------- 1 | log file /var/log/quagga/bgpdbgp1.log 2 | hostname bgp1 3 | password quagga 4 | ! 5 | ! Different next hop for IPv4 6 | ! 7 | ip prefix-list 1 seq 10 permit 10.0.2.0/24 8 | ip prefix-list 1 seq 20 permit 10.1.2.0/24 9 | ip prefix-list 1 seq 30 permit 10.0.3.0/24 10 | ip prefix-list 1 seq 40 permit 10.0.4.0/24 11 | ip prefix-list 1 seq 50 permit 10.5.6.0/24 12 | ip prefix-list 1 seq 60 permit 10.11.1.0/24 13 | ip prefix-list 1 seq 70 permit 10.11.2.0/24 14 | ! 15 | route-map NEXTHOP41 permit 10 16 | match ip address prefix-list 1 17 | set ip next-hop 10.0.1.254 18 | ! 19 | ! 20 | route-map NEXTHOP47 permit 10 21 | match ip address prefix-list 1 22 | set ip next-hop 10.0.7.254 23 | ! 24 | ! Different next hop for IPv6 25 | ! 26 | ipv6 prefix-list 2 seq 10 permit 2000::200/120 27 | ipv6 prefix-list 2 seq 20 permit 2000::300/120 28 | ipv6 prefix-list 2 seq 30 permit 2000::a00/120 29 | ipv6 prefix-list 2 seq 40 permit 2000::b00/120 30 | 31 | ! 32 | route-map NEXTHOP61 permit 10 33 | match ipv6 address prefix-list 2 34 | set ipv6 next-hop global 2000::1ff 35 | set ipv6 next-hop local 2000::1ff 36 | ! 37 | ! 38 | route-map NEXTHOP67 permit 10 39 | match ipv6 address prefix-list 2 40 | set ipv6 next-hop global 2000::7ff 41 | set ipv6 next-hop local 2000::7ff 42 | ! 43 | ! Basic router config 44 | ! 45 | router bgp 65003 46 | bgp router-id 172.16.0.3 47 | timers bgp 3 9 48 | ! 49 | ! IPv4 50 | ! 51 | neighbor 10.0.1.1 remote-as 65001 52 | neighbor 10.0.1.1 ebgp-multihop 53 | neighbor 10.0.1.1 timers connect 5 54 | neighbor 10.0.1.1 advertisement-interval 5 55 | neighbor 10.0.1.1 route-map NEXTHOP41 out 56 | ! 57 | neighbor 2000::101 remote-as 65001 58 | neighbor 2000::101 timers connect 5 59 | neighbor 2000::101 advertisement-interval 1 60 | no neighbor 2000::101 activate 61 | ! 62 | neighbor 10.0.7.1 remote-as 65002 63 | neighbor 10.0.7.1 ebgp-multihop 64 | neighbor 10.0.7.1 timers connect 5 65 | neighbor 10.0.7.1 advertisement-interval 5 66 | neighbor 10.0.7.1 route-map NEXTHOP47 out 67 | ! 68 | neighbor 2000::701 remote-as 65002 69 | neighbor 2000::701 timers connect 5 70 | neighbor 2000::701 advertisement-interval 1 71 | no neighbor 2000::701 activate 72 | ! 73 | network 10.0.2.0/24 74 | network 10.1.2.0/24 75 | network 10.0.3.0/24 76 | network 10.0.4.0/24 77 | network 10.5.6.0/24 78 | network 10.11.1.0/24 79 | network 10.11.2.0/24 80 | ! 81 | ! IPv6 82 | ! 83 | address-family ipv6 84 | network 2000::200/120 85 | network 2000::300/120 86 | network 2000::a00/120 87 | network 2000::b00/120 88 | neighbor 2000::101 activate 89 | neighbor 2000::101 route-map NEXTHOP61 out 90 | neighbor 2000::701 activate 91 | neighbor 2000::701 route-map NEXTHOP67 out 92 | exit-address-family 93 | -------------------------------------------------------------------------------- /trellis/bgpdbgp2.conf: -------------------------------------------------------------------------------- 1 | log file /var/log/quagga/bgpdbgp2.log 2 | hostname bgp2 3 | password quagga 4 | ! 5 | ! Different next hop for IPv4 6 | ! 7 | ip prefix-list 1 seq 10 permit 10.0.2.0/24 8 | ip prefix-list 1 seq 20 permit 10.1.2.0/24 9 | ip prefix-list 1 seq 30 permit 10.0.3.0/24 10 | ip prefix-list 1 seq 40 permit 10.0.4.0/24 11 | ip prefix-list 1 seq 50 permit 10.5.6.0/24 12 | ip prefix-list 1 seq 60 permit 10.11.1.0/24 13 | ip prefix-list 1 seq 70 permit 10.11.2.0/24 14 | ! 15 | route-map NEXTHOP45 permit 10 16 | match ip address prefix-list 1 17 | set ip next-hop 10.0.5.254 18 | ! 19 | ! 20 | route-map NEXTHOP46 permit 10 21 | match ip address prefix-list 1 22 | set ip next-hop 10.0.6.254 23 | ! 24 | ! Different next hop for IPv6 25 | ! 26 | ipv6 prefix-list 2 seq 10 permit 2000::200/120 27 | ipv6 prefix-list 2 seq 20 permit 2000::300/120 28 | ipv6 prefix-list 2 seq 30 permit 2000::a00/120 29 | ipv6 prefix-list 2 seq 40 permit 2000::b00/120 30 | ! 31 | route-map NEXTHOP65 permit 10 32 | match ipv6 address prefix-list 2 33 | set ipv6 next-hop global 2000::5ff 34 | set ipv6 next-hop local 2000::5ff 35 | ! 36 | ! 37 | route-map NEXTHOP66 permit 10 38 | match ipv6 address prefix-list 2 39 | set ipv6 next-hop global 2000::6ff 40 | set ipv6 next-hop local 2000::6ff 41 | ! 42 | ! Basic router config 43 | ! 44 | router bgp 65003 45 | bgp router-id 172.16.0.4 46 | timers bgp 3 9 47 | ! 48 | ! IPv4 49 | ! 50 | neighbor 10.0.5.1 remote-as 65001 51 | neighbor 10.0.5.1 ebgp-multihop 52 | neighbor 10.0.5.1 timers connect 5 53 | neighbor 10.0.5.1 advertisement-interval 5 54 | neighbor 10.0.5.1 route-map NEXTHOP45 out 55 | ! 56 | neighbor 2000::501 remote-as 65001 57 | neighbor 2000::501 timers connect 5 58 | neighbor 2000::501 advertisement-interval 1 59 | no neighbor 2000::501 activate 60 | ! 61 | neighbor 10.0.6.1 remote-as 65002 62 | neighbor 10.0.6.1 ebgp-multihop 63 | neighbor 10.0.6.1 timers connect 5 64 | neighbor 10.0.6.1 advertisement-interval 5 65 | neighbor 10.0.6.1 route-map NEXTHOP46 out 66 | ! 67 | neighbor 2000::601 remote-as 65002 68 | neighbor 2000::601 timers connect 5 69 | neighbor 2000::601 advertisement-interval 1 70 | no neighbor 2000::601 activate 71 | ! 72 | network 10.0.2.0/24 73 | network 10.1.2.0/24 74 | network 10.0.3.0/24 75 | network 10.0.4.0/24 76 | network 10.5.6.0/24 77 | network 10.11.1.0/24 78 | network 10.11.2.0/24 79 | ! 80 | ! IPv6 81 | ! 82 | address-family ipv6 83 | network 2000::200/120 84 | network 2000::300/120 85 | network 2000::a00/120 86 | network 2000::b00/120 87 | neighbor 2000::501 activate 88 | neighbor 2000::501 route-map NEXTHOP65 out 89 | neighbor 2000::601 activate 90 | neighbor 2000::601 route-map NEXTHOP66 out 91 | exit-address-family 92 | -------------------------------------------------------------------------------- /trellis/bgpdr1.conf: -------------------------------------------------------------------------------- 1 | log file /var/log/quagga/bgpdr1.log 2 | hostname r1 3 | password quagga 4 | ! 5 | ! Basic router config 6 | ! 7 | router bgp 65001 8 | bgp router-id 10.0.1.1 9 | timers bgp 3 9 10 | ! 11 | ! IPv4 12 | ! 13 | neighbor 10.0.1.2 remote-as 65003 14 | neighbor 10.0.1.2 ebgp-multihop 15 | neighbor 10.0.1.2 timers connect 5 16 | neighbor 10.0.1.2 advertisement-interval 5 17 | ! 18 | neighbor 2000::102 remote-as 65003 19 | neighbor 2000::102 timers connect 5 20 | neighbor 2000::102 advertisement-interval 1 21 | no neighbor 2000::102 activate 22 | ! 23 | neighbor 10.0.5.2 remote-as 65003 24 | neighbor 10.0.5.2 ebgp-multihop 25 | neighbor 10.0.5.2 timers connect 5 26 | neighbor 10.0.5.2 advertisement-interval 5 27 | ! 28 | neighbor 2000::502 remote-as 65003 29 | neighbor 2000::502 timers connect 5 30 | neighbor 2000::502 advertisement-interval 1 31 | no neighbor 2000::502 activate 32 | ! 33 | network 10.0.99.0/24 34 | ! 35 | ! IPv6 36 | ! 37 | address-family ipv6 38 | network 2000::7700/120 39 | network 2000::9900/120 40 | neighbor 2000::102 activate 41 | neighbor 2000::502 activate 42 | exit-address-family 43 | -------------------------------------------------------------------------------- /trellis/bgpdr2.conf: -------------------------------------------------------------------------------- 1 | log file /var/log/quagga/bgpdr2.log 2 | hostname r2 3 | password quagga 4 | ! 5 | ! Basic router config 6 | ! 7 | router bgp 65002 8 | bgp router-id 10.0.6.1 9 | timers bgp 3 9 10 | ! 11 | ! IPv4 12 | ! 13 | neighbor 10.0.6.2 remote-as 65003 14 | neighbor 10.0.6.2 ebgp-multihop 15 | neighbor 10.0.6.2 timers connect 5 16 | neighbor 10.0.6.2 advertisement-interval 5 17 | ! 18 | neighbor 2000::602 remote-as 65003 19 | neighbor 2000::602 timers connect 5 20 | neighbor 2000::602 advertisement-interval 1 21 | no neighbor 2000::602 activate 22 | ! 23 | neighbor 10.0.7.2 remote-as 65003 24 | neighbor 10.0.7.2 ebgp-multihop 25 | neighbor 10.0.7.2 timers connect 5 26 | neighbor 10.0.7.2 advertisement-interval 5 27 | ! 28 | neighbor 2000::702 remote-as 65003 29 | neighbor 2000::702 timers connect 5 30 | neighbor 2000::702 advertisement-interval 1 31 | no neighbor 2000::702 activate 32 | ! 33 | network 10.0.99.0/24 34 | ! 35 | ! IPv6 36 | ! 37 | address-family ipv6 38 | network 2000::8800/120 39 | network 2000::9900/120 40 | neighbor 2000::602 activate 41 | neighbor 2000::702 activate 42 | exit-address-family 43 | -------------------------------------------------------------------------------- /trellis/cleanup: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [[ $EUID -ne 0 ]]; then 4 | echo "This script must be run as root" 5 | exit 1 6 | fi 7 | 8 | mn -c 9 | killall dhcpd dhclient zebra bgpd 10 | -------------------------------------------------------------------------------- /trellis/dhcpd.conf: -------------------------------------------------------------------------------- 1 | ddns-update-style none; 2 | 3 | default-lease-time 600; 4 | max-lease-time 7200; 5 | 6 | option domain-name-servers 8.8.8.8, 8.8.4.4; 7 | option domain-name "trellis.local"; 8 | 9 | subnet 10.0.2.0 netmask 255.255.255.0 { 10 | range 10.0.2.100 10.0.2.240; 11 | option routers 10.0.2.254; 12 | } 13 | 14 | subnet 10.1.2.0 netmask 255.255.255.0 { 15 | range 10.1.2.100 10.1.2.240; 16 | option routers 10.1.2.254; 17 | } 18 | 19 | subnet 10.0.3.0 netmask 255.255.255.0 { 20 | range 10.0.3.100 10.0.3.240; 21 | option routers 10.0.3.254; 22 | } 23 | 24 | subnet 10.0.4.0 netmask 255.255.255.0 { 25 | range 10.0.4.100 10.0.4.240; 26 | option routers 10.0.4.254; 27 | } 28 | 29 | subnet 10.0.99.3 netmask 255.255.255.255 { 30 | } 31 | 32 | subnet 10.5.6.0 netmask 255.255.255.0 { 33 | range 10.5.6.100 10.5.6.240; 34 | option routers 10.5.6.254; 35 | } 36 | 37 | subnet 10.11.1.0 netmask 255.255.255.0 { 38 | range 10.11.1.100 10.11.1.240; 39 | option routers 10.11.1.254; 40 | } 41 | 42 | subnet 10.11.2.0 netmask 255.255.255.0 { 43 | range 10.11.2.100 10.11.2.240; 44 | option routers 10.11.2.254; 45 | } 46 | 47 | subnet 10.100.1.0 netmask 255.255.255.0 { 48 | range 10.100.1.100 10.100.1.240; 49 | option routers 10.100.1.254; 50 | } 51 | 52 | subnet 10.100.2.0 netmask 255.255.255.0 { 53 | range 10.100.2.100 10.100.2.240; 54 | option routers 10.100.2.254; 55 | } 56 | 57 | subnet 10.100.3.0 netmask 255.255.255.0 { 58 | range 10.100.3.100 10.100.3.240; 59 | option routers 10.100.3.254; 60 | } 61 | 62 | subnet 10.100.4.0 netmask 255.255.255.0 { 63 | range 10.100.4.100 10.100.4.240; 64 | option routers 10.100.4.254; 65 | } 66 | 67 | host h1 { 68 | hardware ethernet 00:aa:00:00:00:01; 69 | fixed-address 10.0.2.1; 70 | } 71 | 72 | host h2 { 73 | hardware ethernet 00:aa:00:00:00:02; 74 | fixed-address 10.0.2.2; 75 | } 76 | 77 | host h3 { 78 | hardware ethernet 00:aa:00:00:00:03; 79 | fixed-address 10.0.3.1; 80 | } 81 | 82 | host h4 { 83 | hardware ethernet 00:aa:00:00:00:04; 84 | fixed-address 10.0.3.2; 85 | } 86 | 87 | host h5 { 88 | hardware ethernet 00:aa:00:00:00:05; 89 | fixed-address 10.0.4.1; 90 | } 91 | 92 | host dh1 { 93 | hardware ethernet 00:cc:00:00:00:01; 94 | fixed-address 10.1.2.1; 95 | } 96 | 97 | host dh2 { 98 | hardware ethernet 00:cc:00:00:00:02; 99 | fixed-address 10.5.6.1; 100 | } 101 | 102 | host rpd5 { 103 | hardware ethernet 00:dd:00:00:00:01; 104 | fixed-address 10.11.1.5; 105 | } 106 | 107 | host rpd6 { 108 | hardware ethernet 00:dd:00:00:00:02; 109 | fixed-address 10.11.2.15; 110 | } -------------------------------------------------------------------------------- /trellis/dhcpd6.conf: -------------------------------------------------------------------------------- 1 | default-lease-time 600; 2 | max-lease-time 7200; 3 | 4 | option dhcp6.next-hop code 242 = ip6-address; 5 | 6 | subnet6 2000::200/120 { 7 | range6 2000::260 2000::2fe; 8 | option dhcp6.next-hop 2000::02ff; 9 | } 10 | 11 | subnet6 2000::300/120 { 12 | range6 2000::360 2000::3fe; 13 | option dhcp6.next-hop 2000::03ff; 14 | } 15 | 16 | subnet6 2000::400/120 { 17 | range6 2000::460 2000::4fe; 18 | option dhcp6.next-hop 2000::04ff; 19 | } 20 | 21 | subnet6 2001::200/120 { 22 | range6 2001::260 2001::2fe; 23 | option dhcp6.next-hop 2001::02ff; 24 | } 25 | 26 | subnet6 2000::9903/128 { 27 | } 28 | 29 | subnet6 2000::a00/120 { 30 | range6 2000::a60 2000::afe; 31 | option dhcp6.next-hop 2000::aff; 32 | } 33 | 34 | subnet6 2000::b00/120 { 35 | range6 2000::b60 2000::bfe; 36 | option dhcp6.next-hop 2000::bff; 37 | } 38 | 39 | subnet6 2002::100/120 { 40 | range6 2002::160 2002::1fe; 41 | option dhcp6.next-hop 2002::1ff; 42 | } 43 | 44 | subnet6 2002::200/120 { 45 | range6 2002::260 2002::2fe; 46 | option dhcp6.next-hop 2002::2ff; 47 | } 48 | 49 | subnet6 2002::300/120 { 50 | range6 2002::360 2002::3fe; 51 | option dhcp6.next-hop 2002::3ff; 52 | } 53 | 54 | subnet6 2002::400/120 { 55 | range6 2002::460 2002::4fe; 56 | option dhcp6.next-hop 2002::4ff; 57 | } 58 | 59 | host h1v6 { 60 | hardware ethernet 00:bb:00:00:00:01; 61 | fixed-address6 2000::201; 62 | } 63 | 64 | host h2v6 { 65 | hardware ethernet 00:bb:00:00:00:02; 66 | fixed-address6 2000::202; 67 | } 68 | 69 | host h3v6 { 70 | hardware ethernet 00:bb:00:00:00:03; 71 | fixed-address6 2000::301; 72 | } 73 | 74 | host h4v6 { 75 | hardware ethernet 00:bb:00:00:00:04; 76 | fixed-address6 2000::302; 77 | } 78 | 79 | host h5v6 { 80 | hardware ethernet 00:bb:00:00:00:05; 81 | fixed-address6 2000::401; 82 | } 83 | 84 | host dh1 { 85 | hardware ethernet 00:cc:00:00:00:01; 86 | fixed-address6 2001::202; 87 | } 88 | 89 | host rpd5v6 { 90 | hardware ethernet 00:ee:00:00:00:01; 91 | fixed-address6 2000::a0a; 92 | } 93 | 94 | host rpd6v6 { 95 | hardware ethernet 00:ee:00:00:00:02; 96 | fixed-address6 2000::b0b; 97 | } 98 | -------------------------------------------------------------------------------- /trellis/dhcpd_hybrid_v4.conf: -------------------------------------------------------------------------------- 1 | ddns-update-style none; 2 | 3 | default-lease-time 600; 4 | max-lease-time 7200; 5 | 6 | option domain-name-servers 8.8.8.8, 8.8.4.4; 7 | option domain-name "trellis.local"; 8 | 9 | subnet 10.0.2.0 netmask 255.255.255.0 { 10 | range 10.0.2.100 10.0.2.240; 11 | option routers 10.0.2.254; 12 | } 13 | 14 | subnet 10.1.2.0 netmask 255.255.255.0 { 15 | range 10.1.2.100 10.1.2.240; 16 | option routers 10.1.2.254; 17 | } 18 | 19 | subnet 10.0.3.0 netmask 255.255.255.0 { 20 | range 10.0.3.100 10.0.3.240; 21 | option routers 10.0.3.254; 22 | } 23 | 24 | subnet 10.0.4.0 netmask 255.255.255.0 { 25 | range 10.0.4.100 10.0.4.240; 26 | option routers 10.0.4.254; 27 | } 28 | 29 | subnet 10.0.99.3 netmask 255.255.255.255 { 30 | } 31 | 32 | subnet 10.5.6.0 netmask 255.255.255.0 { 33 | range 10.5.6.100 10.5.6.240; 34 | option routers 10.5.6.254; 35 | } 36 | 37 | subnet 10.11.1.0 netmask 255.255.255.0 { 38 | range 10.11.1.100 10.11.1.240; 39 | option routers 10.11.1.254; 40 | } 41 | 42 | subnet 10.11.2.0 netmask 255.255.255.0 { 43 | range 10.11.2.100 10.11.2.240; 44 | option routers 10.11.2.254; 45 | } 46 | 47 | 48 | host h1 { 49 | hardware ethernet 00:aa:00:00:00:01; 50 | fixed-address 10.11.1.5; 51 | } 52 | 53 | host h2 { 54 | hardware ethernet 00:aa:00:00:00:02; 55 | fixed-address 10.11.2.15; 56 | } 57 | 58 | host h3 { 59 | hardware ethernet 00:aa:00:00:00:03; 60 | fixed-address 10.0.4.1; 61 | } 62 | 63 | host h4 { 64 | hardware ethernet 00:aa:00:00:00:04; 65 | fixed-address 10.0.2.2; 66 | } 67 | 68 | host h5 { 69 | hardware ethernet 00:aa:00:00:00:05; 70 | fixed-address 10.0.3.1; 71 | } 72 | 73 | host h6 { 74 | hardware ethernet 00:aa:00:00:00:06; 75 | fixed-address 10.0.3.2; 76 | } 77 | 78 | host dh1 { 79 | hardware ethernet 00:cc:00:00:00:01; 80 | fixed-address 10.1.2.1; 81 | } 82 | 83 | host dh2 { 84 | hardware ethernet 00:cc:00:00:00:02; 85 | fixed-address 10.5.6.1; 86 | } 87 | -------------------------------------------------------------------------------- /trellis/docker/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:18.04 2 | MAINTAINER Charles Chan 3 | 4 | ENV HOME /root 5 | 6 | # Install dependencies 7 | WORKDIR $HOME 8 | RUN apt-get update && \ 9 | DEBIAN_FRONTEND=noninteractive apt-get -yq --no-install-recommends install git gawk texinfo python-pip build-essential iptables automake autoconf libtool openvswitch-switch mininet \ 10 | isc-dhcp-server isc-dhcp-client iputils-ping net-tools curl iproute2 ethtool && \ 11 | pip install ipaddress && \ 12 | rm -rf /var/lib/apt/lists/* 13 | 14 | # Install Quagga 15 | RUN git clone --depth 1 -b onos-1.11 https://gerrit.opencord.org/quagga 16 | WORKDIR $HOME/quagga 17 | RUN ./bootstrap.sh 18 | RUN ./configure --enable-fpm --sbindir=/usr/lib/quagga enable_user=root enable_group=root 19 | RUN make 20 | RUN make install 21 | 22 | # Clone Trellis simulation repo 23 | WORKDIR $HOME 24 | RUN git clone --depth 1 https://gerrit.onosproject.org/routing 25 | 26 | # Update dynamic linker 27 | RUN ldconfig 28 | 29 | # Fetch ONOS netcfg tools 30 | WORKDIR $HOME 31 | RUN curl -o /usr/local/bin/onos-netcfg https://raw.githubusercontent.com/opennetworkinglab/onos/onos-1.12/tools/package/runtime/bin/onos-netcfg 32 | RUN curl -o /usr/local/bin/_rest-port https://raw.githubusercontent.com/opennetworkinglab/onos/onos-1.12/tools/package/runtime/bin/_rest-port 33 | RUN curl -o /usr/local/bin/_find-node https://raw.githubusercontent.com/opennetworkinglab/onos/onos-1.12/tools/package/runtime/bin/_find-node 34 | RUN curl -o /usr/local/bin/_check-json https://raw.githubusercontent.com/opennetworkinglab/onos/onos-1.12/tools/package/runtime/bin/_check-json 35 | RUN chmod a+x /usr/local/bin/onos-netcfg /usr/local/bin/_rest-port /usr/local/bin/_find-node /usr/local/bin/_check-json 36 | 37 | # Copy useful Mininet utility 38 | COPY m $HOME 39 | 40 | # Copy start script 41 | COPY entrypoint.sh $HOME 42 | 43 | # Requirement for Mininet NAT class 44 | RUN touch /etc/network/interfaces 45 | -------------------------------------------------------------------------------- /trellis/docker/entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Select topology to emulate 4 | TOPO=${TOPO:-trellis} 5 | ONOS_HOST=${ONOS_HOST:-localhost} 6 | 7 | # Resolve ONOS IP 8 | ONOS_IP=`getent hosts $ONOS_HOSTNAME | awk '{ print $1 }'` 9 | 10 | # Start and configure OVS 11 | # Avoid using Linux service since it will attempt but fail the kernel module check 12 | /usr/share/openvswitch/scripts/ovs-ctl --no-ovs-vswitchd --no-monitor --system-id=random start 13 | /usr/sbin/ovs-vswitchd --detach 14 | ovs-vsctl set Open_vSwitch . other_config:vlan-limit=2 15 | 16 | cd routing/trellis 17 | NETCFG=${EXTERNAL_VOLUME}/${NETCFG_FILE} 18 | echo "Check custom config, ${NETCFG}" 19 | 20 | # Use custom file if ${NETCFG_FILE} be set 21 | if [[ ${NETCFG_FILE} ]]; then 22 | if [ -f ${NETCFG} ]; then 23 | echo "Detected custom cfg ${NETCFG}, use it" 24 | onos-netcfg ${ONOS_IP} ${NETCFG} || exit 0 25 | else 26 | echo "${NETCFG} does not exist" 27 | exit 0 28 | fi 29 | else 30 | onos-netcfg ${ONOS_IP} ${TOPO}.json || exit 0 31 | fi 32 | 33 | # Start mininet 34 | ./${TOPO}.py -c ${ONOS_IP} 35 | -------------------------------------------------------------------------------- /trellis/docker/m: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Attach to a Mininet host and run a command 4 | 5 | if [ -z $1 ]; then 6 | echo "usage: $0 host cmd [args...]" 7 | exit 1 8 | else 9 | host=$1 10 | fi 11 | 12 | pid=`ps ax | grep "mininet:$host$" | grep bash | grep -v mnexec | awk '{print $1};'` 13 | 14 | if echo $pid | grep -q ' '; then 15 | echo "Error: found multiple mininet:$host processes" 16 | exit 2 17 | fi 18 | 19 | if [ "$pid" == "" ]; then 20 | echo "Could not find Mininet host $host" 21 | exit 3 22 | fi 23 | 24 | if [ -z $2 ]; then 25 | cmd='bash' 26 | else 27 | shift 28 | cmd=$* 29 | fi 30 | 31 | cgroup=/sys/fs/cgroup/cpu/$host 32 | if [ -d "$cgroup" ]; then 33 | cg="-g $host" 34 | fi 35 | 36 | # Check whether host should be running in a chroot dir 37 | rootdir="/var/run/mn/$host/root" 38 | if [ -d $rootdir -a -x $rootdir/bin/bash ]; then 39 | cmd="'cd `pwd`; exec $cmd'" 40 | cmd="chroot $rootdir /bin/bash -c $cmd" 41 | fi 42 | 43 | cmd="exec mnexec $cg -a $pid $cmd" 44 | eval $cmd 45 | -------------------------------------------------------------------------------- /trellis/trellis.json: -------------------------------------------------------------------------------- 1 | { 2 | "ports" : { 3 | "of:0000000000000204/3" : { 4 | "interfaces" : [ 5 | { 6 | "ips" : [ "10.0.2.254/24" ], 7 | "vlan-untagged": 20 8 | } 9 | ] 10 | }, 11 | "of:0000000000000204/4" : { 12 | "interfaces" : [ 13 | { 14 | "ips" : [ "10.0.2.254/24" ], 15 | "vlan-untagged": 20 16 | } 17 | ] 18 | }, 19 | "of:0000000000000204/5" : { 20 | "interfaces" : [ 21 | { 22 | "ips" : [ "2000::2ff/120" ], 23 | "vlan-untagged": 40 24 | } 25 | ] 26 | }, 27 | "of:0000000000000204/6" : { 28 | "interfaces" : [ 29 | { 30 | "ips" : [ "2000::2ff/120" ], 31 | "vlan-untagged": 40 32 | } 33 | ] 34 | }, 35 | "of:0000000000000205/3" : { 36 | "interfaces" : [ 37 | { 38 | "ips" : [ "10.0.3.254/24" ], 39 | "vlan-untagged": 30 40 | } 41 | ] 42 | }, 43 | "of:0000000000000205/4" : { 44 | "interfaces" : [ 45 | { 46 | "ips" : [ "10.0.3.254/24" ], 47 | "vlan-untagged": 30 48 | } 49 | ] 50 | }, 51 | "of:0000000000000205/5" : { 52 | "interfaces" : [ 53 | { 54 | "ips" : [ "2000::3ff/120" ], 55 | "vlan-untagged": 50 56 | } 57 | ] 58 | }, 59 | "of:0000000000000205/6" : { 60 | "interfaces" : [ 61 | { 62 | "ips" : [ "2000::3ff/120" ], 63 | "vlan-untagged": 50 64 | } 65 | ] 66 | }, 67 | "of:0000000000000205/7" : { 68 | "interfaces" : [ 69 | { 70 | "ips" : [ "10.0.3.254/24", "2000::3ff/120" ], 71 | "vlan-untagged": 30 72 | } 73 | ] 74 | }, 75 | "of:0000000000000205/8" : { 76 | "interfaces" : [ 77 | { 78 | "ips" : [ "10.0.1.254/24", "2000::1ff/120" ], 79 | "vlan-untagged": 10 80 | } 81 | ] 82 | }, 83 | "of:0000000000000205/9" : { 84 | "interfaces" : [ 85 | { 86 | "ips" : [ "10.0.1.254/24", "2000::1ff/120" ], 87 | "vlan-untagged": 10 88 | } 89 | ] 90 | } 91 | }, 92 | "devices" : { 93 | "of:0000000000000204" : { 94 | "segmentrouting" : { 95 | "name" : "s204", 96 | "ipv4NodeSid" : 204, 97 | "ipv4Loopback" : "192.168.0.204", 98 | "ipv6NodeSid" : 214, 99 | "ipv6Loopback" : "2000::c0a8:0204", 100 | "routerMac" : "00:00:00:00:02:04", 101 | "isEdgeRouter" : true, 102 | "adjacencySids" : [] 103 | }, 104 | "basic" : { 105 | "name": "s204", 106 | "driver" : "ofdpa-ovs" 107 | } 108 | }, 109 | "of:0000000000000205" : { 110 | "segmentrouting" : { 111 | "name" : "s205", 112 | "ipv4NodeSid" : 205, 113 | "ipv4Loopback" : "192.168.0.205", 114 | "ipv6NodeSid" : 215, 115 | "ipv6Loopback" : "2000::c0a8:0205", 116 | "routerMac" : "00:00:00:00:02:05", 117 | "isEdgeRouter" : true, 118 | "adjacencySids" : [] 119 | }, 120 | "basic" : { 121 | "name": "s205", 122 | "driver" : "ofdpa-ovs" 123 | } 124 | }, 125 | "of:0000000000000226" : { 126 | "segmentrouting" : { 127 | "name" : "s226", 128 | "ipv4NodeSid" : 226, 129 | "ipv4Loopback" : "192.168.0.226", 130 | "ipv6NodeSid" : 236, 131 | "ipv6Loopback" : "2000::c0a8:0226", 132 | "routerMac" : "00:00:00:00:02:26", 133 | "isEdgeRouter" : false, 134 | "adjacencySids" : [] 135 | }, 136 | "basic" : { 137 | "name": "s226", 138 | "driver" : "ofdpa-ovs" 139 | } 140 | }, 141 | "of:0000000000000227" : { 142 | "segmentrouting" : { 143 | "name" : "s227", 144 | "ipv4NodeSid" : 227, 145 | "ipv4Loopback" : "192.168.0.227", 146 | "ipv6NodeSid" : 237, 147 | "ipv6Loopback" : "2000::c0a8:0227", 148 | "routerMac" : "00:00:00:00:02:27", 149 | "isEdgeRouter" : false, 150 | "adjacencySids" : [] 151 | }, 152 | "basic" : { 153 | "name": "s227", 154 | "driver" : "ofdpa-ovs" 155 | } 156 | } 157 | }, 158 | "apps" : { 159 | "org.onosproject.dhcprelay" : { 160 | "default": [ 161 | { 162 | "dhcpServerConnectPoint": "of:0000000000000205/7", 163 | "serverIps": ["10.0.3.253", "2000::3fd"] 164 | } 165 | ] 166 | } 167 | } 168 | } 169 | -------------------------------------------------------------------------------- /trellis/trellis.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | import sys 4 | sys.path.append('..') 5 | from mininet.topo import Topo 6 | from mininet.net import Mininet 7 | from mininet.cli import CLI 8 | from mininet.log import setLogLevel 9 | from mininet.node import RemoteController, OVSBridge, Host, OVSSwitch 10 | from ipaddress import ip_network 11 | from routinglib import BgpRouter 12 | from routinglib import RoutedHost, RoutedHost6, UserNAT 13 | from trellislib import DhcpClient, Dhcp6Client, DhcpRelay, DhcpServer, Dhcp6Server 14 | from trellislib import get_mininet, parse_trellis_args, set_up_zebra_config 15 | from functools import partial 16 | 17 | class Trellis( Topo ): 18 | "Trellis basic topology" 19 | 20 | def __init__( self, *args, **kwargs ): 21 | Topo.__init__( self, *args, **kwargs ) 22 | 23 | # Spines 24 | s226 = self.addSwitch('s226', dpid='226') 25 | s227 = self.addSwitch('s227', dpid='227') 26 | 27 | # Leaves 28 | s204 = self.addSwitch('s204', dpid='204') 29 | s205 = self.addSwitch('s205', dpid='205') 30 | 31 | # Switch Links 32 | self.addLink(s226, s204) 33 | self.addLink(s226, s205) 34 | self.addLink(s227, s204) 35 | self.addLink(s227, s205) 36 | 37 | # NOTE avoid using 10.0.1.0/24 which is the default subnet of quaggas 38 | # NOTE avoid using 00:00:00:00:00:xx which is the default mac of host behind upstream router 39 | # IPv4 Hosts 40 | h1 = self.addHost('h1', cls=DhcpClient, mac='00:aa:00:00:00:01') 41 | h2 = self.addHost('h2', cls=DhcpClient, mac='00:aa:00:00:00:02') 42 | h3 = self.addHost('h3', cls=DhcpClient, mac='00:aa:00:00:00:03') 43 | h4 = self.addHost('h4', cls=DhcpClient, mac='00:aa:00:00:00:04') 44 | self.addLink(h1, s204) 45 | self.addLink(h2, s204) 46 | self.addLink(h3, s205) 47 | self.addLink(h4, s205) 48 | 49 | # IPv6 Hosts 50 | h1v6 = self.addHost('h1v6', cls=Dhcp6Client, mac='00:bb:00:00:00:01') 51 | h2v6 = self.addHost('h2v6', cls=Dhcp6Client, mac='00:bb:00:00:00:02') 52 | h3v6 = self.addHost('h3v6', cls=Dhcp6Client, mac='00:bb:00:00:00:03') 53 | h4v6 = self.addHost('h4v6', cls=Dhcp6Client, mac='00:bb:00:00:00:04') 54 | self.addLink(h1v6, s204) 55 | self.addLink(h2v6, s204) 56 | self.addLink(h3v6, s205) 57 | self.addLink(h4v6, s205) 58 | 59 | # DHCP server 60 | dhcp = self.addHost('dhcp', cls=DhcpServer, mac='00:99:00:00:00:01', ips=['10.0.3.253/24'], gateway='10.0.3.254') 61 | 62 | # DHCPv6 server 63 | dhcp6 = self.addHost('dhcp6', cls=Dhcp6Server, mac='00:99:66:00:00:01', ips=['2000::3fd/120'], gateway='2000::3ff') 64 | 65 | # Control plane switch (for DHCP servers) 66 | cs1 = self.addSwitch('cs1', cls=OVSBridge, datapath='user') 67 | self.addLink(cs1, s205) 68 | self.addLink(dhcp, cs1) 69 | self.addLink(dhcp6, cs1) 70 | 71 | # Control plane switch (for quagga fpm) 72 | cs0 = self.addSwitch('cs0', cls=OVSBridge, datapath='user') 73 | 74 | # Control plane NAT (for quagga fpm) 75 | nat = self.addHost('nat', cls=UserNAT, 76 | ip='172.16.0.1/24', 77 | subnet=str(ip_network(u'172.16.0.0/24')), inNamespace=False) 78 | self.addLink(cs0, nat) 79 | 80 | # Internal Quagga bgp1 81 | intfs = {'bgp1-eth0': {'ipAddrs': ['10.0.1.2/24', '2000::102/120'], 'mac': '00:88:00:00:00:02'}, 82 | 'bgp1-eth1': {'ipAddrs': ['172.16.0.2/24']}} 83 | bgp1 = self.addHost('bgp1', cls=BgpRouter, 84 | interfaces=intfs, 85 | quaggaConfFile='./bgpdbgp1.conf', 86 | zebraConfFile='./zebradbgp1.conf') 87 | self.addLink(bgp1, s205) 88 | self.addLink(bgp1, cs0) 89 | 90 | # External Quagga r1 91 | intfs = {'r1-eth0': {'ipAddrs': ['10.0.1.1/24', '2000::101/120'], 'mac': '00:88:00:00:00:01'}, 92 | 'r1-eth1': {'ipAddrs': ['10.0.99.1/16']}, 93 | 'r1-eth2': {'ipAddrs': ['2000::9901/120']}} 94 | r1 = self.addHost('r1', cls=BgpRouter, 95 | interfaces=intfs, 96 | quaggaConfFile='./bgpdr1.conf') 97 | self.addLink(r1, s205) 98 | 99 | # External IPv4 Host behind r1 100 | rh1 = self.addHost('rh1', cls=RoutedHost, ips=['10.0.99.2/24'], gateway='10.0.99.1') 101 | self.addLink(r1, rh1) 102 | 103 | # External IPv6 Host behind r1 104 | rh1v6 = self.addHost('rh1v6', cls=RoutedHost, ips=['2000::9902/120'], gateway='2000::9901') 105 | self.addLink(r1, rh1v6) 106 | 107 | topos = { 'trellis' : Trellis } 108 | 109 | if __name__ == "__main__": 110 | setLogLevel('debug') 111 | topo = Trellis() 112 | switch = partial(OVSSwitch, protocols='OpenFlow13', datapath='user') 113 | arguments = parse_trellis_args() 114 | set_up_zebra_config(arguments.controllers) 115 | net = get_mininet(arguments, topo, switch) 116 | 117 | net.start() 118 | CLI(net) 119 | net.stop() 120 | -------------------------------------------------------------------------------- /trellis/trellis_double_tagged.json: -------------------------------------------------------------------------------- 1 | { 2 | "ports" : { 3 | "of:0000000000000204/3" : { 4 | "interfaces" : [ 5 | { 6 | "ips" : [ "10.0.2.254/24" ], 7 | "vlan-untagged": 20 8 | } 9 | ] 10 | }, 11 | "of:0000000000000204/4" : { 12 | "interfaces" : [ 13 | { 14 | "ips" : [ "10.0.2.254/24" ], 15 | "vlan-untagged": 20 16 | } 17 | ] 18 | }, 19 | "of:0000000000000204/5" : { 20 | "interfaces" : [ 21 | { 22 | "ips" : [ "10.0.2.254/24" ] 23 | } 24 | ] 25 | }, 26 | "of:0000000000000204/6" : { 27 | "interfaces" : [ 28 | { 29 | "ips" : [ "2000::2ff/120" ], 30 | "vlan-untagged": 40 31 | } 32 | ] 33 | }, 34 | "of:0000000000000204/7" : { 35 | "interfaces" : [ 36 | { 37 | "ips" : [ "2000::2ff/120" ], 38 | "vlan-untagged": 40 39 | } 40 | ] 41 | }, 42 | "of:0000000000000205/3" : { 43 | "interfaces" : [ 44 | { 45 | "ips" : [ "10.0.3.254/24" ], 46 | "vlan-untagged": 30 47 | } 48 | ] 49 | }, 50 | "of:0000000000000205/4" : { 51 | "interfaces" : [ 52 | { 53 | "ips" : [ "10.0.3.254/24" ], 54 | "vlan-untagged": 30 55 | } 56 | ] 57 | }, 58 | "of:0000000000000205/5" : { 59 | "interfaces" : [ 60 | { 61 | "ips" : [ "2000::3ff/120" ], 62 | "vlan-untagged": 50 63 | } 64 | ] 65 | }, 66 | "of:0000000000000205/6" : { 67 | "interfaces" : [ 68 | { 69 | "ips" : [ "2000::3ff/120" ], 70 | "vlan-untagged": 50 71 | } 72 | ] 73 | }, 74 | "of:0000000000000205/7" : { 75 | "interfaces" : [ 76 | { 77 | "ips" : [ "10.0.3.254/24", "2000::3ff/120" ], 78 | "vlan-untagged": 30 79 | } 80 | ] 81 | }, 82 | "of:0000000000000205/8" : { 83 | "interfaces" : [ 84 | { 85 | "ips" : [ "10.0.1.254/24", "2000::1ff/120" ], 86 | "vlan-untagged": 10 87 | } 88 | ] 89 | }, 90 | "of:0000000000000205/9" : { 91 | "interfaces" : [ 92 | { 93 | "ips" : [ "10.0.1.254/24", "2000::1ff/120" ], 94 | "vlan-untagged": 10 95 | } 96 | ] 97 | } 98 | }, 99 | "devices" : { 100 | "of:0000000000000204" : { 101 | "segmentrouting" : { 102 | "name" : "s204", 103 | "ipv4NodeSid" : 204, 104 | "ipv4Loopback" : "192.168.0.204", 105 | "ipv6NodeSid" : 214, 106 | "ipv6Loopback" : "2000::c0a8:0204", 107 | "routerMac" : "00:00:00:00:02:04", 108 | "isEdgeRouter" : true, 109 | "adjacencySids" : [] 110 | }, 111 | "basic" : { 112 | "name": "s204", 113 | "driver" : "ofdpa-ovs" 114 | } 115 | }, 116 | "of:0000000000000205" : { 117 | "segmentrouting" : { 118 | "name" : "s205", 119 | "ipv4NodeSid" : 205, 120 | "ipv4Loopback" : "192.168.0.205", 121 | "ipv6NodeSid" : 215, 122 | "ipv6Loopback" : "2000::c0a8:0205", 123 | "routerMac" : "00:00:00:00:02:05", 124 | "isEdgeRouter" : true, 125 | "adjacencySids" : [] 126 | }, 127 | "basic" : { 128 | "name": "s205", 129 | "driver" : "ofdpa-ovs" 130 | } 131 | }, 132 | "of:0000000000000226" : { 133 | "segmentrouting" : { 134 | "name" : "s226", 135 | "ipv4NodeSid" : 226, 136 | "ipv4Loopback" : "192.168.0.226", 137 | "ipv6NodeSid" : 236, 138 | "ipv6Loopback" : "2000::c0a8:0226", 139 | "routerMac" : "00:00:00:00:02:26", 140 | "isEdgeRouter" : false, 141 | "adjacencySids" : [] 142 | }, 143 | "basic" : { 144 | "name": "s226", 145 | "driver" : "ofdpa-ovs" 146 | } 147 | }, 148 | "of:0000000000000227" : { 149 | "segmentrouting" : { 150 | "name" : "s227", 151 | "ipv4NodeSid" : 227, 152 | "ipv4Loopback" : "192.168.0.227", 153 | "ipv6NodeSid" : 237, 154 | "ipv6Loopback" : "2000::c0a8:0227", 155 | "routerMac" : "00:00:00:00:02:27", 156 | "isEdgeRouter" : false, 157 | "adjacencySids" : [] 158 | }, 159 | "basic" : { 160 | "name": "s227", 161 | "driver" : "ofdpa-ovs" 162 | } 163 | } 164 | }, 165 | "apps" : { 166 | "org.onosproject.dhcprelay" : { 167 | "default": [ 168 | { 169 | "dhcpServerConnectPoint": "of:0000000000000205/7", 170 | "serverIps": ["10.0.3.253", "2000::3fd"] 171 | } 172 | ] 173 | } 174 | }, 175 | "hosts": { 176 | "00:aa:00:00:00:05/100": { 177 | "basic": { 178 | "ips": ["10.0.2.3"], 179 | "locations": ["of:0000000000000204/5"], 180 | "innerVlan": 200, 181 | "outerTpid": "0x88a8" 182 | } 183 | } 184 | } 185 | } 186 | -------------------------------------------------------------------------------- /trellis/trellis_double_tagged.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | import sys 4 | 5 | sys.path.append('..') 6 | from mininet.topo import Topo 7 | from mininet.net import Mininet 8 | from mininet.cli import CLI 9 | from mininet.log import setLogLevel 10 | from mininet.node import RemoteController, OVSBridge, Host, OVSSwitch 11 | from ipaddress import ip_network 12 | from routinglib import BgpRouter 13 | from routinglib import RoutedHost, RoutedHost6, UserNAT 14 | from trellislib import DhcpClient, Dhcp6Client, DhcpRelay, DhcpServer, Dhcp6Server, DoubleTaggedRoutedHost 15 | from trellislib import get_mininet, parse_trellis_args, set_up_zebra_config 16 | from functools import partial 17 | from time import sleep 18 | 19 | class Trellis( Topo ): 20 | "Trellis basic topology" 21 | 22 | def __init__( self, *args, **kwargs ): 23 | Topo.__init__( self, *args, **kwargs ) 24 | 25 | # Spines 26 | s226 = self.addSwitch('s226', dpid='226') 27 | s227 = self.addSwitch('s227', dpid='227') 28 | 29 | # Leaves 30 | s204 = self.addSwitch('s204', dpid='204') 31 | s205 = self.addSwitch('s205', dpid='205') 32 | 33 | # Switch Links 34 | self.addLink(s226, s204) 35 | self.addLink(s226, s205) 36 | self.addLink(s227, s204) 37 | self.addLink(s227, s205) 38 | 39 | # NOTE avoid using 10.0.1.0/24 which is the default subnet of quaggas 40 | # NOTE avoid using 00:00:00:00:00:xx which is the default mac of host behind upstream router 41 | # IPv4 Hosts 42 | h1 = self.addHost('h1', cls=DhcpClient, mac='00:aa:00:00:00:01') 43 | h2 = self.addHost('h2', cls=DhcpClient, mac='00:aa:00:00:00:02') 44 | h3 = self.addHost('h3', cls=DhcpClient, mac='00:aa:00:00:00:03') 45 | h4 = self.addHost('h4', cls=DhcpClient, mac='00:aa:00:00:00:04') 46 | dth5 = self.addHost('dth5', cls=DoubleTaggedRoutedHost, mac='00:aa:00:00:00:05', ips=['10.0.2.3/24'], gateway='10.0.2.254', outerVlan=100, innerVlan=200) 47 | self.addLink(h1, s204) 48 | self.addLink(h2, s204) 49 | self.addLink(h3, s205) 50 | self.addLink(h4, s205) 51 | self.addLink(dth5, s204) 52 | 53 | # IPv6 Hosts 54 | h1v6 = self.addHost('h1v6', cls=Dhcp6Client, mac='00:bb:00:00:00:01') 55 | h2v6 = self.addHost('h2v6', cls=Dhcp6Client, mac='00:bb:00:00:00:02') 56 | h3v6 = self.addHost('h3v6', cls=Dhcp6Client, mac='00:bb:00:00:00:03') 57 | h4v6 = self.addHost('h4v6', cls=Dhcp6Client, mac='00:bb:00:00:00:04') 58 | self.addLink(h1v6, s204) 59 | self.addLink(h2v6, s204) 60 | self.addLink(h3v6, s205) 61 | self.addLink(h4v6, s205) 62 | 63 | # DHCP server 64 | dhcp = self.addHost('dhcp', cls=DhcpServer, mac='00:99:00:00:00:01', ips=['10.0.3.253/24'], gateway='10.0.3.254') 65 | 66 | # DHCPv6 server 67 | dhcp6 = self.addHost('dhcp6', cls=Dhcp6Server, mac='00:99:66:00:00:01', ips=['2000::3fd/120'], gateway='2000::3ff') 68 | 69 | # Control plane switch (for DHCP servers) 70 | cs1 = self.addSwitch('cs1', cls=OVSBridge, datapath='user') 71 | self.addLink(cs1, s205) 72 | self.addLink(dhcp, cs1) 73 | self.addLink(dhcp6, cs1) 74 | 75 | # Control plane switch (for quagga fpm) 76 | cs0 = self.addSwitch('cs0', cls=OVSBridge, datapath='user') 77 | 78 | # Control plane NAT (for quagga fpm) 79 | nat = self.addHost('nat', cls=UserNAT, 80 | ip='172.16.0.1/24', 81 | subnet=str(ip_network(u'172.16.0.0/24')), inNamespace=False) 82 | self.addLink(cs0, nat) 83 | 84 | # Internal Quagga bgp1 85 | intfs = {'bgp1-eth0': {'ipAddrs': ['10.0.1.2/24', '2000::102/120'], 'mac': '00:88:00:00:00:02'}, 86 | 'bgp1-eth1': {'ipAddrs': ['172.16.0.2/24']}} 87 | bgp1 = self.addHost('bgp1', cls=BgpRouter, 88 | interfaces=intfs, 89 | quaggaConfFile='./bgpdbgp1.conf', 90 | zebraConfFile='./zebradbgp1.conf') 91 | self.addLink(bgp1, s205) 92 | self.addLink(bgp1, cs0) 93 | 94 | # External Quagga r1 95 | intfs = {'r1-eth0': {'ipAddrs': ['10.0.1.1/24', '2000::101/120'], 'mac': '00:88:00:00:00:01'}, 96 | 'r1-eth1': {'ipAddrs': ['10.0.99.1/16']}, 97 | 'r1-eth2': {'ipAddrs': ['2000::9901/120']}} 98 | r1 = self.addHost('r1', cls=BgpRouter, 99 | interfaces=intfs, 100 | quaggaConfFile='./bgpdr1.conf') 101 | self.addLink(r1, s205) 102 | 103 | # External IPv4 Host behind r1 104 | rh1 = self.addHost('rh1', cls=RoutedHost, ips=['10.0.99.2/24'], gateway='10.0.99.1') 105 | self.addLink(r1, rh1) 106 | 107 | # External IPv6 Host behind r1 108 | rh1v6 = self.addHost('rh1v6', cls=RoutedHost, ips=['2000::9902/120'], gateway='2000::9901') 109 | self.addLink(r1, rh1v6) 110 | 111 | topos = { 'trellis' : Trellis } 112 | 113 | if __name__ == "__main__": 114 | setLogLevel('debug') 115 | topo = Trellis() 116 | switch = partial(OVSSwitch, protocols='OpenFlow13', datapath='user') 117 | arguments = parse_trellis_args() 118 | set_up_zebra_config(arguments.controllers) 119 | net = get_mininet(arguments, topo, switch) 120 | 121 | net.start() 122 | sleep(3) 123 | print 'ping %s' % net.get('h1').IP() 124 | net.get('dth5').cmd('ping -c 1 %s'% net.get('h1').IP()) 125 | CLI(net) 126 | net.stop() 127 | -------------------------------------------------------------------------------- /trellis/trellis_dualhome.json: -------------------------------------------------------------------------------- 1 | { 2 | "ports" : { 3 | "of:0000000000000203/5" : { 4 | "interfaces" : [ 5 | { 6 | "ips" : [ "10.1.2.254/24", "2001::2ff/120" ], 7 | "vlan-tagged": [20, 21] 8 | } 9 | ] 10 | }, 11 | "of:0000000000000203/6" : { 12 | "interfaces" : [ 13 | { 14 | "ips" : [ "10.1.2.254/24", "2001::2ff/120" ], 15 | "vlan-untagged": 21 16 | } 17 | ] 18 | }, 19 | "of:0000000000000204/5" : { 20 | "interfaces" : [ 21 | { 22 | "ips" : [ "10.1.2.254/24", "2001::2ff/120" ], 23 | "vlan-tagged": [20, 21] 24 | } 25 | ] 26 | }, 27 | "of:0000000000000204/6" : { 28 | "interfaces" : [ 29 | { 30 | "ips" : [ "10.0.2.254/24" ], 31 | "vlan-untagged": 20 32 | } 33 | ] 34 | }, 35 | "of:0000000000000204/7" : { 36 | "interfaces" : [ 37 | { 38 | "ips" : [ "10.0.2.254/24" ], 39 | "vlan-untagged": 20 40 | } 41 | ] 42 | }, 43 | "of:0000000000000204/8" : { 44 | "interfaces" : [ 45 | { 46 | "ips" : [ "2000::2ff/120" ], 47 | "vlan-untagged": 40 48 | } 49 | ] 50 | }, 51 | "of:0000000000000204/9" : { 52 | "interfaces" : [ 53 | { 54 | "ips" : [ "2000::2ff/120" ], 55 | "vlan-untagged": 40 56 | } 57 | ] 58 | }, 59 | "of:0000000000000204/10" : { 60 | "interfaces" : [ 61 | { 62 | "ips" : [ "10.1.2.254/24", "2001::2ff/120" ], 63 | "vlan-untagged": 21 64 | } 65 | ] 66 | }, 67 | "of:0000000000000205/6" : { 68 | "interfaces" : [ 69 | { 70 | "ips" : [ "10.0.3.254/24" ], 71 | "vlan-untagged": 30 72 | } 73 | ] 74 | }, 75 | "of:0000000000000205/7" : { 76 | "interfaces" : [ 77 | { 78 | "ips" : [ "10.0.3.254/24" ], 79 | "vlan-untagged": 30 80 | } 81 | ] 82 | }, 83 | "of:0000000000000205/8" : { 84 | "interfaces" : [ 85 | { 86 | "ips" : [ "2000::3ff/120" ], 87 | "vlan-untagged": 50 88 | } 89 | ] 90 | }, 91 | "of:0000000000000205/9" : { 92 | "interfaces" : [ 93 | { 94 | "ips" : [ "2000::3ff/120" ], 95 | "vlan-untagged": 50 96 | } 97 | ] 98 | }, 99 | "of:0000000000000205/10" : { 100 | "interfaces" : [ 101 | { 102 | "ips" : [ "10.0.3.254/24", "2000::3ff/120" ], 103 | "vlan-untagged": 30 104 | } 105 | ] 106 | }, 107 | "of:0000000000000205/11" : { 108 | "interfaces" : [ 109 | { 110 | "ips" : [ "10.0.1.254/24", "10.0.7.254/24", "2000::1ff/120", "2000::7ff/120" ], 111 | "vlan-tagged": [110, 170] 112 | } 113 | ] 114 | }, 115 | "of:0000000000000205/12" : { 116 | "interfaces" : [ 117 | { 118 | "ips" : [ "10.0.1.254/24", "2000::1ff/120" ], 119 | "vlan-untagged": 110 120 | } 121 | ] 122 | }, 123 | "of:0000000000000205/13" : { 124 | "interfaces" : [ 125 | { 126 | "ips" : [ "10.0.7.254/24", "2000::7ff/120" ], 127 | "vlan-untagged": 170 128 | } 129 | ] 130 | }, 131 | "of:0000000000000206/6" : { 132 | "interfaces" : [ 133 | { 134 | "ips" : [ "10.0.5.254/24", "10.0.6.254/24", "2000::5ff/120", "2000::6ff/120" ], 135 | "vlan-tagged": [150, 160] 136 | } 137 | ] 138 | }, 139 | "of:0000000000000206/7" : { 140 | "interfaces" : [ 141 | { 142 | "ips" : [ "10.0.5.254/24", "2000::5ff/120" ], 143 | "vlan-untagged": 150 144 | } 145 | ] 146 | }, 147 | "of:0000000000000206/8" : { 148 | "interfaces" : [ 149 | { 150 | "ips" : [ "10.0.6.254/24", "2000::6ff/120" ], 151 | "vlan-untagged": 160 152 | } 153 | ] 154 | } 155 | }, 156 | "devices" : { 157 | "of:0000000000000203" : { 158 | "segmentrouting" : { 159 | "name" : "s203", 160 | "ipv4NodeSid" : 203, 161 | "ipv4Loopback" : "192.168.0.203", 162 | "ipv6NodeSid" : 213, 163 | "ipv6Loopback" : "2000::c0a8:0203", 164 | "routerMac" : "00:00:00:00:02:03", 165 | "isEdgeRouter" : true, 166 | "pairDeviceId" : "of:0000000000000204", 167 | "pairLocalPort" : 5, 168 | "adjacencySids" : [] 169 | }, 170 | "basic" : { 171 | "name": "s203", 172 | "driver" : "ofdpa-ovs" 173 | } 174 | }, 175 | "of:0000000000000204" : { 176 | "segmentrouting" : { 177 | "name" : "s204", 178 | "ipv4NodeSid" : 204, 179 | "ipv4Loopback" : "192.168.0.204", 180 | "ipv6NodeSid" : 214, 181 | "ipv6Loopback" : "2000::c0a8:0204", 182 | "routerMac" : "00:00:00:00:02:03", 183 | "isEdgeRouter" : true, 184 | "pairDeviceId" : "of:0000000000000203", 185 | "pairLocalPort" : 5, 186 | "adjacencySids" : [] 187 | }, 188 | "basic" : { 189 | "name": "s204", 190 | "driver" : "ofdpa-ovs" 191 | } 192 | }, 193 | "of:0000000000000205" : { 194 | "segmentrouting" : { 195 | "name" : "s205", 196 | "ipv4NodeSid" : 205, 197 | "ipv4Loopback" : "192.168.0.205", 198 | "ipv6NodeSid" : 215, 199 | "ipv6Loopback" : "2000::c0a8:0205", 200 | "routerMac" : "00:00:00:00:02:05", 201 | "isEdgeRouter" : true, 202 | "adjacencySids" : [], 203 | "pairDeviceId": "of:0000000000000206", 204 | "pairLocalPort": 5 205 | }, 206 | "basic" : { 207 | "name": "s205", 208 | "driver" : "ofdpa-ovs" 209 | } 210 | }, 211 | "of:0000000000000206" : { 212 | "segmentrouting" : { 213 | "name" : "s206", 214 | "ipv4NodeSid" : 206, 215 | "ipv4Loopback" : "192.168.0.206", 216 | "ipv6NodeSid" : 216, 217 | "ipv6Loopback" : "2000::c0a8:0206", 218 | "routerMac" : "00:00:00:00:02:05", 219 | "isEdgeRouter" : true, 220 | "adjacencySids" : [], 221 | "pairDeviceId": "of:0000000000000205", 222 | "pairLocalPort": 5 223 | }, 224 | "basic" : { 225 | "name": "s206", 226 | "driver" : "ofdpa-ovs" 227 | } 228 | }, 229 | "of:0000000000000226" : { 230 | "segmentrouting" : { 231 | "name" : "s226", 232 | "ipv4NodeSid" : 226, 233 | "ipv4Loopback" : "192.168.0.226", 234 | "ipv6NodeSid" : 236, 235 | "ipv6Loopback" : "2000::c0a8:0226", 236 | "routerMac" : "00:00:00:00:02:26", 237 | "isEdgeRouter" : false, 238 | "adjacencySids" : [] 239 | }, 240 | "basic" : { 241 | "name": "s226", 242 | "driver" : "ofdpa-ovs" 243 | } 244 | }, 245 | "of:0000000000000227" : { 246 | "segmentrouting" : { 247 | "name" : "s227", 248 | "ipv4NodeSid" : 227, 249 | "ipv4Loopback" : "192.168.0.227", 250 | "ipv6NodeSid" : 237, 251 | "ipv6Loopback" : "2000::c0a8:0227", 252 | "routerMac" : "00:00:00:00:02:27", 253 | "isEdgeRouter" : false, 254 | "adjacencySids" : [] 255 | }, 256 | "basic" : { 257 | "name": "s227", 258 | "driver" : "ofdpa-ovs" 259 | } 260 | } 261 | }, 262 | "apps" : { 263 | "org.onosproject.dhcprelay" : { 264 | "default": [ 265 | { 266 | "dhcpServerConnectPoint": "of:0000000000000205/10", 267 | "serverIps": ["10.0.3.253", "2000::3fd"] 268 | } 269 | ] 270 | } 271 | } 272 | } 273 | -------------------------------------------------------------------------------- /trellis/trellis_dualhome.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | import sys 4 | sys.path.append('..') 5 | from mininet.topo import Topo 6 | from mininet.net import Mininet 7 | from mininet.cli import CLI 8 | from mininet.log import setLogLevel 9 | from mininet.node import RemoteController, OVSBridge, Host, OVSSwitch 10 | from mininet.link import TCLink 11 | from ipaddress import ip_network 12 | from routinglib import BgpRouter 13 | from routinglib import RoutedHost, RoutedHost6, UserNAT 14 | from trellislib import DhcpClient, Dhcp6Client, DhcpRelay, DhcpServer, Dhcp6Server 15 | from trellislib import DualHomedDhcpClient 16 | from trellislib import get_mininet, parse_trellis_args, set_up_zebra_config 17 | from functools import partial 18 | 19 | class Trellis( Topo ): 20 | "Trellis basic topology" 21 | 22 | def __init__( self, *args, **kwargs ): 23 | Topo.__init__( self, *args, **kwargs ) 24 | 25 | # Spines 26 | s226 = self.addSwitch('s226', dpid='226') 27 | s227 = self.addSwitch('s227', dpid='227') 28 | 29 | # Leaves 30 | s203 = self.addSwitch('s203', dpid='203') 31 | s204 = self.addSwitch('s204', dpid='204') 32 | s205 = self.addSwitch('s205', dpid='205') 33 | s206 = self.addSwitch('s206', dpid='206') 34 | 35 | # Leaf-Spine Links 36 | self.addLink(s226, s203) 37 | self.addLink(s226, s203) 38 | self.addLink(s226, s204) 39 | self.addLink(s226, s204) 40 | self.addLink(s226, s205) 41 | self.addLink(s226, s205) 42 | self.addLink(s226, s206) 43 | self.addLink(s226, s206) 44 | self.addLink(s227, s203) 45 | self.addLink(s227, s203) 46 | self.addLink(s227, s204) 47 | self.addLink(s227, s204) 48 | self.addLink(s227, s205) 49 | self.addLink(s227, s205) 50 | self.addLink(s227, s206) 51 | self.addLink(s227, s206) 52 | 53 | # Leaf-Leaf Links 54 | self.addLink(s203, s204) 55 | self.addLink(s205, s206) 56 | 57 | # NOTE avoid using 10.0.1.0/24 which is the default subnet of quaggas 58 | # NOTE avoid using 00:00:00:00:00:xx which is the default mac of host behind upstream router 59 | # IPv4 Hosts 60 | h1 = self.addHost('h1', cls=DhcpClient, mac='00:aa:00:00:00:01') 61 | h2 = self.addHost('h2', cls=DhcpClient, mac='00:aa:00:00:00:02') 62 | h3 = self.addHost('h3', cls=DhcpClient, mac='00:aa:00:00:00:03') 63 | h4 = self.addHost('h4', cls=DhcpClient, mac='00:aa:00:00:00:04') 64 | self.addLink(h1, s204) 65 | self.addLink(h2, s204) 66 | self.addLink(h3, s205) 67 | self.addLink(h4, s205) 68 | 69 | # IPv6 Hosts 70 | h1v6 = self.addHost('h1v6', cls=Dhcp6Client, mac='00:bb:00:00:00:01') 71 | h2v6 = self.addHost('h2v6', cls=Dhcp6Client, mac='00:bb:00:00:00:02') 72 | h3v6 = self.addHost('h3v6', cls=Dhcp6Client, mac='00:bb:00:00:00:03') 73 | h4v6 = self.addHost('h4v6', cls=Dhcp6Client, mac='00:bb:00:00:00:04') 74 | self.addLink(h1v6, s204) 75 | self.addLink(h2v6, s204) 76 | self.addLink(h3v6, s205) 77 | self.addLink(h4v6, s205) 78 | 79 | # Dual-homed IPv4 Hosts 80 | dh1 = self.addHost('dh1', cls=DualHomedDhcpClient, mac='00:cc:00:00:00:01') 81 | self.addLink(dh1, s204) 82 | self.addLink(dh1, s203) 83 | 84 | # DHCP server 85 | dhcp = self.addHost('dhcp', cls=DhcpServer, mac='00:99:00:00:00:01', ips=['10.0.3.253/24'], gateway='10.0.3.254') 86 | 87 | # DHCPv6 server 88 | dhcp6 = self.addHost('dhcp6', cls=Dhcp6Server, mac='00:99:66:00:00:01', ips=['2000::3fd/120'], gateway='2000::3ff') 89 | 90 | # Control plane switch (for DHCP servers) 91 | cs1 = self.addSwitch('cs1', cls=OVSBridge, datapath='user') 92 | self.addLink(cs1, s205) 93 | self.addLink(dhcp, cs1) 94 | self.addLink(dhcp6, cs1) 95 | 96 | # Control plane switch (for quagga fpm) 97 | cs0 = self.addSwitch('cs0', cls=OVSBridge, datapath='user') 98 | 99 | # Control plane NAT (for quagga fpm) 100 | nat = self.addHost('nat', cls=UserNAT, 101 | ip='172.16.0.1/24', 102 | subnet=str(ip_network(u'172.16.0.0/24')), inNamespace=False) 103 | self.addLink(cs0, nat) 104 | 105 | # Internal Quagga bgp1 106 | intfs = {'bgp1-eth0': [{'ipAddrs': ['10.0.1.2/24', '2000::102/120'], 'mac': '00:88:00:00:00:03', 'vlan': '110'}, 107 | {'ipAddrs': ['10.0.7.2/24', '2000::702/120'], 'mac': '00:88:00:00:00:03', 'vlan': '170'}], 108 | 'bgp1-eth1': {'ipAddrs': ['172.16.0.3/24']}} 109 | bgp1 = self.addHost('bgp1', cls=BgpRouter, 110 | interfaces=intfs, 111 | quaggaConfFile='./bgpdbgp1.conf', 112 | zebraConfFile='./zebradbgp1.conf') 113 | self.addLink(bgp1, s205) 114 | self.addLink(bgp1, cs0) 115 | 116 | # Internal Quagga bgp2 117 | intfs = {'bgp2-eth0': [{'ipAddrs': ['10.0.5.2/24', '2000::502/120'], 'mac': '00:88:00:00:00:04', 'vlan': '150'}, 118 | {'ipAddrs': ['10.0.6.2/24', '2000::602/120'], 'mac': '00:88:00:00:00:04', 'vlan': '160'}], 119 | 'bgp2-eth1': {'ipAddrs': ['172.16.0.4/24']}} 120 | bgp2 = self.addHost('bgp2', cls=BgpRouter, 121 | interfaces=intfs, 122 | quaggaConfFile='./bgpdbgp2.conf', 123 | zebraConfFile='./zebradbgp2.conf') 124 | self.addLink(bgp2, s206) 125 | self.addLink(bgp2, cs0) 126 | 127 | # External Quagga r1 128 | intfs = {'r1-eth0': {'ipAddrs': ['10.0.1.1/24', '2000::101/120'], 'mac': '00:88:00:00:00:01'}, 129 | 'r1-eth1': {'ipAddrs': ['10.0.5.1/24', '2000::501/120'], 'mac': '00:88:00:00:00:11'}, 130 | 'r1-eth2': {'ipAddrs': ['10.0.99.1/16']}, 131 | 'r1-eth3': {'ipAddrs': ['2000::9901/120']}, 132 | 'r1-eth4': {'ipAddrs': ['2000::7701/120']}} 133 | r1 = self.addHost('r1', cls=BgpRouter, 134 | interfaces=intfs, 135 | quaggaConfFile='./bgpdr1.conf') 136 | self.addLink(r1, s205) 137 | self.addLink(r1, s206) 138 | 139 | # External IPv4 Host behind r1 140 | rh1 = self.addHost('rh1', cls=RoutedHost, ips=['10.0.99.2/24'], gateway='10.0.99.1') 141 | self.addLink(r1, rh1) 142 | 143 | # External IPv6 Host behind r1 144 | rh1v6 = self.addHost('rh1v6', cls=RoutedHost, ips=['2000::9902/120'], gateway='2000::9901') 145 | self.addLink(r1, rh1v6) 146 | 147 | # Another external IPv6 Host behind r1 148 | rh11v6 = self.addHost('rh11v6', cls=RoutedHost, ips=['2000::7702/120'], gateway='2000::7701') 149 | self.addLink(r1, rh11v6) 150 | 151 | # External Quagga r2 152 | intfs = {'r2-eth0': {'ipAddrs': ['10.0.6.1/24', '2000::601/120'], 'mac': '00:88:00:00:00:02'}, 153 | 'r2-eth1': {'ipAddrs': ['10.0.7.1/24', '2000::701/120'], 'mac': '00:88:00:00:00:22'}, 154 | 'r2-eth2': {'ipAddrs': ['10.0.99.1/16']}, 155 | 'r2-eth3': {'ipAddrs': ['2000::9901/120']}, 156 | 'r2-eth4': {'ipAddrs': ['2000::8801/120']}} 157 | r2 = self.addHost('r2', cls=BgpRouter, 158 | interfaces=intfs, 159 | quaggaConfFile='./bgpdr2.conf') 160 | self.addLink(r2, s206) 161 | self.addLink(r2, s205) 162 | 163 | # External IPv4 Host behind r2 164 | rh2 = self.addHost('rh2', cls=RoutedHost, ips=['10.0.99.2/24'], gateway='10.0.99.1') 165 | self.addLink(r2, rh2) 166 | 167 | # External IPv6 Host behind r2 168 | rh2v6 = self.addHost('rh126', cls=RoutedHost, ips=['2000::9902/120'], gateway='2000::9901') 169 | self.addLink(r2, rh2v6) 170 | 171 | # Another external IPv6 Host behind r1 172 | rh22v6 = self.addHost('rh22v6', cls=RoutedHost, ips=['2000::8802/120'], gateway='2000::8801') 173 | self.addLink(r2, rh22v6) 174 | 175 | topos = { 'trellis' : Trellis } 176 | 177 | if __name__ == "__main__": 178 | setLogLevel('debug') 179 | topo = Trellis() 180 | switch = partial(OVSSwitch, protocols='OpenFlow13', datapath='user') 181 | arguments = parse_trellis_args() 182 | set_up_zebra_config(arguments.controllers) 183 | net = get_mininet(arguments, topo, switch) 184 | 185 | net.start() 186 | CLI(net) 187 | net.stop() 188 | -------------------------------------------------------------------------------- /trellis/trellis_dualhome_lacp.json: -------------------------------------------------------------------------------- 1 | { 2 | "ports" : { 3 | "of:0000000000000203/5" : { 4 | "interfaces" : [ 5 | { 6 | "ips" : [ "10.1.2.254/24", "2001::2ff/120" ], 7 | "vlan-tagged": [20, 21] 8 | } 9 | ] 10 | }, 11 | "of:0000000000000203/6" : { 12 | "interfaces" : [ 13 | { 14 | "ips" : [ "10.1.2.254/24", "2001::2ff/120" ], 15 | "vlan-untagged": 21 16 | } 17 | ] 18 | }, 19 | "of:0000000000000204/5" : { 20 | "interfaces" : [ 21 | { 22 | "ips" : [ "10.1.2.254/24", "2001::2ff/120" ], 23 | "vlan-tagged": [20, 21] 24 | } 25 | ] 26 | }, 27 | "of:0000000000000204/6" : { 28 | "interfaces" : [ 29 | { 30 | "ips" : [ "10.0.2.254/24" ], 31 | "vlan-untagged": 20 32 | } 33 | ] 34 | }, 35 | "of:0000000000000204/7" : { 36 | "interfaces" : [ 37 | { 38 | "ips" : [ "10.0.2.254/24" ], 39 | "vlan-untagged": 20 40 | } 41 | ] 42 | }, 43 | "of:0000000000000204/8" : { 44 | "interfaces" : [ 45 | { 46 | "ips" : [ "2000::2ff/120" ], 47 | "vlan-untagged": 40 48 | } 49 | ] 50 | }, 51 | "of:0000000000000204/9" : { 52 | "interfaces" : [ 53 | { 54 | "ips" : [ "2000::2ff/120" ], 55 | "vlan-untagged": 40 56 | } 57 | ] 58 | }, 59 | "of:0000000000000204/10" : { 60 | "interfaces" : [ 61 | { 62 | "ips" : [ "10.1.2.254/24", "2001::2ff/120" ], 63 | "vlan-untagged": 21 64 | } 65 | ] 66 | }, 67 | "of:0000000000000205/6" : { 68 | "interfaces" : [ 69 | { 70 | "ips" : [ "10.0.3.254/24" ], 71 | "vlan-untagged": 30 72 | } 73 | ] 74 | }, 75 | "of:0000000000000205/7" : { 76 | "interfaces" : [ 77 | { 78 | "ips" : [ "10.0.3.254/24" ], 79 | "vlan-untagged": 30 80 | } 81 | ] 82 | }, 83 | "of:0000000000000205/8" : { 84 | "interfaces" : [ 85 | { 86 | "ips" : [ "2000::3ff/120" ], 87 | "vlan-untagged": 50 88 | } 89 | ] 90 | }, 91 | "of:0000000000000205/9" : { 92 | "interfaces" : [ 93 | { 94 | "ips" : [ "2000::3ff/120" ], 95 | "vlan-untagged": 50 96 | } 97 | ] 98 | }, 99 | "of:0000000000000205/10" : { 100 | "interfaces" : [ 101 | { 102 | "ips" : [ "10.0.3.254/24", "2000::3ff/120" ], 103 | "vlan-untagged": 30 104 | } 105 | ] 106 | }, 107 | "of:0000000000000205/11" : { 108 | "interfaces" : [ 109 | { 110 | "ips" : [ "10.0.1.254/24", "10.0.7.254/24", "2000::1ff/120", "2000::7ff/120" ], 111 | "vlan-tagged": [110, 170] 112 | } 113 | ] 114 | }, 115 | "of:0000000000000205/12" : { 116 | "interfaces" : [ 117 | { 118 | "ips" : [ "10.0.1.254/24", "2000::1ff/120" ], 119 | "vlan-untagged": 110 120 | } 121 | ] 122 | }, 123 | "of:0000000000000205/13" : { 124 | "interfaces" : [ 125 | { 126 | "ips" : [ "10.0.7.254/24", "2000::7ff/120" ], 127 | "vlan-untagged": 170 128 | } 129 | ] 130 | }, 131 | "of:0000000000000206/6" : { 132 | "interfaces" : [ 133 | { 134 | "ips" : [ "10.0.5.254/24", "10.0.6.254/24", "2000::5ff/120", "2000::6ff/120" ], 135 | "vlan-tagged": [150, 160] 136 | } 137 | ] 138 | }, 139 | "of:0000000000000206/7" : { 140 | "interfaces" : [ 141 | { 142 | "ips" : [ "10.0.5.254/24", "2000::5ff/120" ], 143 | "vlan-untagged": 150 144 | } 145 | ] 146 | }, 147 | "of:0000000000000206/8" : { 148 | "interfaces" : [ 149 | { 150 | "ips" : [ "10.0.6.254/24", "2000::6ff/120" ], 151 | "vlan-untagged": 160 152 | } 153 | ] 154 | } 155 | }, 156 | "devices" : { 157 | "of:0000000000000203" : { 158 | "segmentrouting" : { 159 | "name" : "s203", 160 | "ipv4NodeSid" : 203, 161 | "ipv4Loopback" : "192.168.0.203", 162 | "ipv6NodeSid" : 213, 163 | "ipv6Loopback" : "2000::c0a8:0203", 164 | "routerMac" : "00:00:00:00:02:03", 165 | "isEdgeRouter" : true, 166 | "pairDeviceId" : "of:0000000000000204", 167 | "pairLocalPort" : 5, 168 | "adjacencySids" : [] 169 | }, 170 | "basic" : { 171 | "name": "s203", 172 | "driver" : "ofdpa-ovs" 173 | } 174 | }, 175 | "of:0000000000000204" : { 176 | "segmentrouting" : { 177 | "name" : "s204", 178 | "ipv4NodeSid" : 204, 179 | "ipv4Loopback" : "192.168.0.204", 180 | "ipv6NodeSid" : 214, 181 | "ipv6Loopback" : "2000::c0a8:0204", 182 | "routerMac" : "00:00:00:00:02:03", 183 | "isEdgeRouter" : true, 184 | "pairDeviceId" : "of:0000000000000203", 185 | "pairLocalPort" : 5, 186 | "adjacencySids" : [] 187 | }, 188 | "basic" : { 189 | "name": "s204", 190 | "driver" : "ofdpa-ovs" 191 | } 192 | }, 193 | "of:0000000000000205" : { 194 | "segmentrouting" : { 195 | "name" : "s205", 196 | "ipv4NodeSid" : 205, 197 | "ipv4Loopback" : "192.168.0.205", 198 | "ipv6NodeSid" : 215, 199 | "ipv6Loopback" : "2000::c0a8:0205", 200 | "routerMac" : "00:00:00:00:02:05", 201 | "isEdgeRouter" : true, 202 | "adjacencySids" : [], 203 | "pairDeviceId": "of:0000000000000206", 204 | "pairLocalPort": 5 205 | }, 206 | "basic" : { 207 | "name": "s205", 208 | "driver" : "ofdpa-ovs" 209 | } 210 | }, 211 | "of:0000000000000206" : { 212 | "segmentrouting" : { 213 | "name" : "s206", 214 | "ipv4NodeSid" : 206, 215 | "ipv4Loopback" : "192.168.0.206", 216 | "ipv6NodeSid" : 216, 217 | "ipv6Loopback" : "2000::c0a8:0206", 218 | "routerMac" : "00:00:00:00:02:05", 219 | "isEdgeRouter" : true, 220 | "adjacencySids" : [], 221 | "pairDeviceId": "of:0000000000000205", 222 | "pairLocalPort": 5 223 | }, 224 | "basic" : { 225 | "name": "s206", 226 | "driver" : "ofdpa-ovs" 227 | } 228 | }, 229 | "of:0000000000000226" : { 230 | "segmentrouting" : { 231 | "name" : "s226", 232 | "ipv4NodeSid" : 226, 233 | "ipv4Loopback" : "192.168.0.226", 234 | "ipv6NodeSid" : 236, 235 | "ipv6Loopback" : "2000::c0a8:0226", 236 | "routerMac" : "00:00:00:00:02:26", 237 | "isEdgeRouter" : false, 238 | "adjacencySids" : [] 239 | }, 240 | "basic" : { 241 | "name": "s226", 242 | "driver" : "ofdpa-ovs" 243 | } 244 | }, 245 | "of:0000000000000227" : { 246 | "segmentrouting" : { 247 | "name" : "s227", 248 | "ipv4NodeSid" : 227, 249 | "ipv4Loopback" : "192.168.0.227", 250 | "ipv6NodeSid" : 237, 251 | "ipv6Loopback" : "2000::c0a8:0227", 252 | "routerMac" : "00:00:00:00:02:27", 253 | "isEdgeRouter" : false, 254 | "adjacencySids" : [] 255 | }, 256 | "basic" : { 257 | "name": "s227", 258 | "driver" : "ofdpa-ovs" 259 | } 260 | } 261 | }, 262 | "apps" : { 263 | "org.onosproject.dhcprelay" : { 264 | "default": [ 265 | { 266 | "dhcpServerConnectPoint": "of:0000000000000205/10", 267 | "serverIps": ["10.0.3.253", "2000::3fd"] 268 | } 269 | ] 270 | } 271 | } 272 | } 273 | -------------------------------------------------------------------------------- /trellis/trellis_dualhome_lacp.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | import sys 4 | sys.path.append('..') 5 | from mininet.topo import Topo 6 | from mininet.net import Mininet 7 | from mininet.cli import CLI 8 | from mininet.log import setLogLevel 9 | from mininet.node import RemoteController, OVSBridge, Host, OVSSwitch 10 | from mininet.link import TCLink 11 | from ipaddress import ip_network 12 | from routinglib import BgpRouter 13 | from routinglib import RoutedHost, RoutedHost6, UserNAT 14 | from trellislib import DhcpClient, Dhcp6Client, DhcpRelay, DhcpServer, Dhcp6Server 15 | from trellislib import DualHomedDhcpClient, DualHomedLacpDhcpClient 16 | from trellislib import get_mininet, parse_trellis_args, set_up_zebra_config 17 | from functools import partial 18 | 19 | class Trellis( Topo ): 20 | "Trellis basic topology" 21 | 22 | def __init__( self, *args, **kwargs ): 23 | Topo.__init__( self, *args, **kwargs ) 24 | 25 | # Spines 26 | s226 = self.addSwitch('s226', dpid='226') 27 | s227 = self.addSwitch('s227', dpid='227') 28 | 29 | # Leaves 30 | s203 = self.addSwitch('s203', dpid='203') 31 | s204 = self.addSwitch('s204', dpid='204') 32 | s205 = self.addSwitch('s205', dpid='205') 33 | s206 = self.addSwitch('s206', dpid='206') 34 | 35 | # Leaf-Spine Links 36 | self.addLink(s226, s203) 37 | self.addLink(s226, s203) 38 | self.addLink(s226, s204) 39 | self.addLink(s226, s204) 40 | self.addLink(s226, s205) 41 | self.addLink(s226, s205) 42 | self.addLink(s226, s206) 43 | self.addLink(s226, s206) 44 | self.addLink(s227, s203) 45 | self.addLink(s227, s203) 46 | self.addLink(s227, s204) 47 | self.addLink(s227, s204) 48 | self.addLink(s227, s205) 49 | self.addLink(s227, s205) 50 | self.addLink(s227, s206) 51 | self.addLink(s227, s206) 52 | 53 | # Leaf-Leaf Links 54 | self.addLink(s203, s204) 55 | self.addLink(s205, s206) 56 | 57 | # NOTE avoid using 10.0.1.0/24 which is the default subnet of quaggas 58 | # NOTE avoid using 00:00:00:00:00:xx which is the default mac of host behind upstream router 59 | # IPv4 Hosts 60 | h1 = self.addHost('h1', cls=DhcpClient, mac='00:aa:00:00:00:01') 61 | h2 = self.addHost('h2', cls=DhcpClient, mac='00:aa:00:00:00:02') 62 | h3 = self.addHost('h3', cls=DhcpClient, mac='00:aa:00:00:00:03') 63 | h4 = self.addHost('h4', cls=DhcpClient, mac='00:aa:00:00:00:04') 64 | self.addLink(h1, s204) 65 | self.addLink(h2, s204) 66 | self.addLink(h3, s205) 67 | self.addLink(h4, s205) 68 | 69 | # IPv6 Hosts 70 | h1v6 = self.addHost('h1v6', cls=Dhcp6Client, mac='00:bb:00:00:00:01') 71 | h2v6 = self.addHost('h2v6', cls=Dhcp6Client, mac='00:bb:00:00:00:02') 72 | h3v6 = self.addHost('h3v6', cls=Dhcp6Client, mac='00:bb:00:00:00:03') 73 | h4v6 = self.addHost('h4v6', cls=Dhcp6Client, mac='00:bb:00:00:00:04') 74 | self.addLink(h1v6, s204) 75 | self.addLink(h2v6, s204) 76 | self.addLink(h3v6, s205) 77 | self.addLink(h4v6, s205) 78 | 79 | # Dual-homed IPv4 Hosts 80 | dh1 = self.addHost('dh1', cls=DualHomedLacpDhcpClient, mac='00:cc:00:00:00:01') 81 | self.addLink(dh1, s204) 82 | self.addLink(dh1, s203) 83 | 84 | # DHCP server 85 | dhcp = self.addHost('dhcp', cls=DhcpServer, mac='00:99:00:00:00:01', ips=['10.0.3.253/24'], gateway='10.0.3.254') 86 | 87 | # DHCPv6 server 88 | dhcp6 = self.addHost('dhcp6', cls=Dhcp6Server, mac='00:99:66:00:00:01', ips=['2000::3fd/120'], gateway='2000::3ff') 89 | 90 | # Control plane switch (for DHCP servers) 91 | cs1 = self.addSwitch('cs1', cls=OVSBridge, datapath='user') 92 | self.addLink(cs1, s205) 93 | self.addLink(dhcp, cs1) 94 | self.addLink(dhcp6, cs1) 95 | 96 | # Control plane switch (for quagga fpm) 97 | cs0 = self.addSwitch('cs0', cls=OVSBridge, datapath='user') 98 | 99 | # Control plane NAT (for quagga fpm) 100 | nat = self.addHost('nat', cls=UserNAT, 101 | ip='172.16.0.1/24', 102 | subnet=str(ip_network(u'172.16.0.0/24')), inNamespace=False) 103 | self.addLink(cs0, nat) 104 | 105 | # Internal Quagga bgp1 106 | intfs = {'bgp1-eth0': [{'ipAddrs': ['10.0.1.2/24', '2000::102/120'], 'mac': '00:88:00:00:00:03', 'vlan': '110'}, 107 | {'ipAddrs': ['10.0.7.2/24', '2000::702/120'], 'mac': '00:88:00:00:00:03', 'vlan': '170'}], 108 | 'bgp1-eth1': {'ipAddrs': ['172.16.0.3/24']}} 109 | bgp1 = self.addHost('bgp1', cls=BgpRouter, 110 | interfaces=intfs, 111 | quaggaConfFile='./bgpdbgp1.conf', 112 | zebraConfFile='./zebradbgp1.conf') 113 | self.addLink(bgp1, s205) 114 | self.addLink(bgp1, cs0) 115 | 116 | # Internal Quagga bgp2 117 | intfs = {'bgp2-eth0': [{'ipAddrs': ['10.0.5.2/24', '2000::502/120'], 'mac': '00:88:00:00:00:04', 'vlan': '150'}, 118 | {'ipAddrs': ['10.0.6.2/24', '2000::602/120'], 'mac': '00:88:00:00:00:04', 'vlan': '160'}], 119 | 'bgp2-eth1': {'ipAddrs': ['172.16.0.4/24']}} 120 | bgp2 = self.addHost('bgp2', cls=BgpRouter, 121 | interfaces=intfs, 122 | quaggaConfFile='./bgpdbgp2.conf', 123 | zebraConfFile='./zebradbgp2.conf') 124 | self.addLink(bgp2, s206) 125 | self.addLink(bgp2, cs0) 126 | 127 | # External Quagga r1 128 | intfs = {'r1-eth0': {'ipAddrs': ['10.0.1.1/24', '2000::101/120'], 'mac': '00:88:00:00:00:01'}, 129 | 'r1-eth1': {'ipAddrs': ['10.0.5.1/24', '2000::501/120'], 'mac': '00:88:00:00:00:11'}, 130 | 'r1-eth2': {'ipAddrs': ['10.0.99.1/16']}, 131 | 'r1-eth3': {'ipAddrs': ['2000::9901/120']}, 132 | 'r1-eth4': {'ipAddrs': ['2000::7701/120']}} 133 | r1 = self.addHost('r1', cls=BgpRouter, 134 | interfaces=intfs, 135 | quaggaConfFile='./bgpdr1.conf') 136 | self.addLink(r1, s205) 137 | self.addLink(r1, s206) 138 | 139 | # External IPv4 Host behind r1 140 | rh1 = self.addHost('rh1', cls=RoutedHost, ips=['10.0.99.2/24'], gateway='10.0.99.1') 141 | self.addLink(r1, rh1) 142 | 143 | # External IPv6 Host behind r1 144 | rh1v6 = self.addHost('rh1v6', cls=RoutedHost, ips=['2000::9902/120'], gateway='2000::9901') 145 | self.addLink(r1, rh1v6) 146 | 147 | # Another external IPv6 Host behind r1 148 | rh11v6 = self.addHost('rh11v6', cls=RoutedHost, ips=['2000::7702/120'], gateway='2000::7701') 149 | self.addLink(r1, rh11v6) 150 | 151 | # External Quagga r2 152 | intfs = {'r2-eth0': {'ipAddrs': ['10.0.6.1/24', '2000::601/120'], 'mac': '00:88:00:00:00:02'}, 153 | 'r2-eth1': {'ipAddrs': ['10.0.7.1/24', '2000::701/120'], 'mac': '00:88:00:00:00:22'}, 154 | 'r2-eth2': {'ipAddrs': ['10.0.99.1/16']}, 155 | 'r2-eth3': {'ipAddrs': ['2000::9901/120']}, 156 | 'r2-eth4': {'ipAddrs': ['2000::8801/120']}} 157 | r2 = self.addHost('r2', cls=BgpRouter, 158 | interfaces=intfs, 159 | quaggaConfFile='./bgpdr2.conf') 160 | self.addLink(r2, s206) 161 | self.addLink(r2, s205) 162 | 163 | # External IPv4 Host behind r2 164 | rh2 = self.addHost('rh2', cls=RoutedHost, ips=['10.0.99.2/24'], gateway='10.0.99.1') 165 | self.addLink(r2, rh2) 166 | 167 | # External IPv6 Host behind r2 168 | rh2v6 = self.addHost('rh126', cls=RoutedHost, ips=['2000::9902/120'], gateway='2000::9901') 169 | self.addLink(r2, rh2v6) 170 | 171 | # Another external IPv6 Host behind r1 172 | rh22v6 = self.addHost('rh22v6', cls=RoutedHost, ips=['2000::8802/120'], gateway='2000::8801') 173 | self.addLink(r2, rh22v6) 174 | 175 | topos = { 'trellis' : Trellis } 176 | 177 | if __name__ == "__main__": 178 | setLogLevel('debug') 179 | topo = Trellis() 180 | switch = partial(OVSSwitch, protocols='OpenFlow13', datapath='user') 181 | arguments = parse_trellis_args() 182 | set_up_zebra_config(arguments.controllers) 183 | net = get_mininet(arguments, topo, switch) 184 | 185 | net.start() 186 | CLI(net) 187 | net.stop() 188 | -------------------------------------------------------------------------------- /trellis/trellis_duallink.json: -------------------------------------------------------------------------------- 1 | { 2 | "ports" : { 3 | "of:0000000000000204/5" : { 4 | "interfaces" : [ 5 | { 6 | "ips" : [ "10.0.2.254/24" ], 7 | "vlan-untagged": 20 8 | } 9 | ] 10 | }, 11 | "of:0000000000000204/6" : { 12 | "interfaces" : [ 13 | { 14 | "ips" : [ "10.0.2.254/24" ], 15 | "vlan-untagged": 20 16 | } 17 | ] 18 | }, 19 | "of:0000000000000204/7" : { 20 | "interfaces" : [ 21 | { 22 | "ips" : [ "2000::2ff/120" ], 23 | "vlan-untagged": 40 24 | } 25 | ] 26 | }, 27 | "of:0000000000000204/8" : { 28 | "interfaces" : [ 29 | { 30 | "ips" : [ "2000::2ff/120" ], 31 | "vlan-untagged": 40 32 | } 33 | ] 34 | }, 35 | "of:0000000000000205/5" : { 36 | "interfaces" : [ 37 | { 38 | "ips" : [ "10.0.3.254/24" ], 39 | "vlan-untagged": 30 40 | } 41 | ] 42 | }, 43 | "of:0000000000000205/6" : { 44 | "interfaces" : [ 45 | { 46 | "ips" : [ "10.0.3.254/24" ], 47 | "vlan-untagged": 30 48 | } 49 | ] 50 | }, 51 | "of:0000000000000205/7" : { 52 | "interfaces" : [ 53 | { 54 | "ips" : [ "2000::3ff/120" ], 55 | "vlan-untagged": 50 56 | } 57 | ] 58 | }, 59 | "of:0000000000000205/8" : { 60 | "interfaces" : [ 61 | { 62 | "ips" : [ "2000::3ff/120" ], 63 | "vlan-untagged": 50 64 | } 65 | ] 66 | }, 67 | "of:0000000000000205/9" : { 68 | "interfaces" : [ 69 | { 70 | "ips" : [ "10.0.3.254/24", "2000::3ff/120" ], 71 | "vlan-untagged": 30 72 | } 73 | ] 74 | }, 75 | "of:0000000000000205/10" : { 76 | "interfaces" : [ 77 | { 78 | "ips" : [ "10.0.1.254/24", "2000::1ff/120" ], 79 | "vlan-untagged": 10 80 | } 81 | ] 82 | }, 83 | "of:0000000000000205/11" : { 84 | "interfaces" : [ 85 | { 86 | "ips" : [ "10.0.1.254/24", "2000::1ff/120" ], 87 | "vlan-untagged": 10 88 | } 89 | ] 90 | } 91 | }, 92 | "devices" : { 93 | "of:0000000000000204" : { 94 | "segmentrouting" : { 95 | "name" : "s204", 96 | "ipv4NodeSid" : 204, 97 | "ipv4Loopback" : "192.168.0.204", 98 | "ipv6NodeSid" : 214, 99 | "ipv6Loopback" : "2000::c0a8:0204", 100 | "routerMac" : "00:00:00:00:02:04", 101 | "isEdgeRouter" : true, 102 | "adjacencySids" : [] 103 | }, 104 | "basic" : { 105 | "name": "s204", 106 | "driver" : "ofdpa-ovs" 107 | } 108 | }, 109 | "of:0000000000000205" : { 110 | "segmentrouting" : { 111 | "name" : "s205", 112 | "ipv4NodeSid" : 205, 113 | "ipv4Loopback" : "192.168.0.205", 114 | "ipv6NodeSid" : 215, 115 | "ipv6Loopback" : "2000::c0a8:0205", 116 | "routerMac" : "00:00:00:00:02:05", 117 | "isEdgeRouter" : true, 118 | "adjacencySids" : [] 119 | }, 120 | "basic" : { 121 | "name": "s205", 122 | "driver" : "ofdpa-ovs" 123 | } 124 | }, 125 | "of:0000000000000226" : { 126 | "segmentrouting" : { 127 | "name" : "s226", 128 | "ipv4NodeSid" : 226, 129 | "ipv4Loopback" : "192.168.0.226", 130 | "ipv6NodeSid" : 236, 131 | "ipv6Loopback" : "2000::c0a8:0226", 132 | "routerMac" : "00:00:00:00:02:26", 133 | "isEdgeRouter" : false, 134 | "adjacencySids" : [] 135 | }, 136 | "basic" : { 137 | "name": "s226", 138 | "driver" : "ofdpa-ovs" 139 | } 140 | }, 141 | "of:0000000000000227" : { 142 | "segmentrouting" : { 143 | "name" : "s227", 144 | "ipv4NodeSid" : 227, 145 | "ipv4Loopback" : "192.168.0.227", 146 | "ipv6NodeSid" : 237, 147 | "ipv6Loopback" : "2000::c0a8:0227", 148 | "routerMac" : "00:00:00:00:02:27", 149 | "isEdgeRouter" : false, 150 | "adjacencySids" : [] 151 | }, 152 | "basic" : { 153 | "name": "s227", 154 | "driver" : "ofdpa-ovs" 155 | } 156 | } 157 | }, 158 | "apps" : { 159 | "org.onosproject.dhcprelay" : { 160 | "default": [ 161 | { 162 | "dhcpServerConnectPoint": "of:0000000000000205/9", 163 | "serverIps": ["10.0.3.253", "2000::3fd"] 164 | } 165 | ] 166 | } 167 | } 168 | } 169 | -------------------------------------------------------------------------------- /trellis/trellis_duallink.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | import sys 4 | sys.path.append('..') 5 | from mininet.topo import Topo 6 | from mininet.net import Mininet 7 | from mininet.cli import CLI 8 | from mininet.log import setLogLevel 9 | from mininet.node import RemoteController, OVSBridge, Host, OVSSwitch 10 | from ipaddress import ip_network 11 | from routinglib import BgpRouter 12 | from routinglib import RoutedHost, RoutedHost6, UserNAT 13 | from trellislib import DhcpClient, Dhcp6Client, DhcpRelay, DhcpServer, Dhcp6Server 14 | from trellislib import get_mininet, parse_trellis_args, set_up_zebra_config 15 | from functools import partial 16 | 17 | class Trellis( Topo ): 18 | "Trellis dual-link topology" 19 | 20 | def __init__( self, *args, **kwargs ): 21 | Topo.__init__( self, *args, **kwargs ) 22 | 23 | # Spines 24 | s226 = self.addSwitch('s226', dpid='226') 25 | s227 = self.addSwitch('s227', dpid='227') 26 | 27 | # Leaves 28 | s204 = self.addSwitch('s204', dpid='204') 29 | s205 = self.addSwitch('s205', dpid='205') 30 | 31 | # Switch Links - dual-link 32 | self.addLink(s226, s204) 33 | self.addLink(s226, s204) 34 | 35 | self.addLink(s226, s205) 36 | self.addLink(s226, s205) 37 | 38 | self.addLink(s227, s204) 39 | self.addLink(s227, s204) 40 | 41 | self.addLink(s227, s205) 42 | self.addLink(s227, s205) 43 | 44 | # NOTE avoid using 10.0.1.0/24 which is the default subnet of quaggas 45 | # NOTE avoid using 00:00:00:00:00:xx which is the default mac of host behind upstream router 46 | # IPv4 Hosts 47 | h1 = self.addHost('h1', cls=DhcpClient, mac='00:aa:00:00:00:01') 48 | h2 = self.addHost('h2', cls=DhcpClient, mac='00:aa:00:00:00:02') 49 | h3 = self.addHost('h3', cls=DhcpClient, mac='00:aa:00:00:00:03') 50 | h4 = self.addHost('h4', cls=DhcpClient, mac='00:aa:00:00:00:04') 51 | self.addLink(h1, s204) 52 | self.addLink(h2, s204) 53 | self.addLink(h3, s205) 54 | self.addLink(h4, s205) 55 | 56 | # IPv6 Hosts 57 | h1v6 = self.addHost('h1v6', cls=Dhcp6Client, mac='00:bb:00:00:00:01') 58 | h2v6 = self.addHost('h2v6', cls=Dhcp6Client, mac='00:bb:00:00:00:02') 59 | h3v6 = self.addHost('h3v6', cls=Dhcp6Client, mac='00:bb:00:00:00:03') 60 | h4v6 = self.addHost('h4v6', cls=Dhcp6Client, mac='00:bb:00:00:00:04') 61 | self.addLink(h1v6, s204) 62 | self.addLink(h2v6, s204) 63 | self.addLink(h3v6, s205) 64 | self.addLink(h4v6, s205) 65 | 66 | # DHCP server 67 | dhcp = self.addHost('dhcp', cls=DhcpServer, mac='00:99:00:00:00:01', ips=['10.0.3.253/24'], gateway='10.0.3.254') 68 | 69 | # DHCPv6 server 70 | dhcp6 = self.addHost('dhcp6', cls=Dhcp6Server, mac='00:99:66:00:00:01', ips=['2000::3fd/120'], gateway='2000::3ff') 71 | 72 | # Data plane switch (for DHCP servers) 73 | cs1 = self.addSwitch('cs1', cls=OVSBridge, datapath='user') 74 | self.addLink(cs1, s205) 75 | self.addLink(dhcp, cs1) 76 | self.addLink(dhcp6, cs1) 77 | 78 | # Control plane switch (for quagga fpm) 79 | cs0 = self.addSwitch('cs0', cls=OVSBridge, datapath='user') 80 | 81 | # Control plane NAT (for quagga fpm) 82 | nat = self.addHost('nat', cls=UserNAT, 83 | ip='172.16.0.1/24', 84 | subnet=str(ip_network(u'172.16.0.0/24')), inNamespace=False) 85 | self.addLink(cs0, nat) 86 | 87 | # Internal Quagga bgp1 88 | intfs = {'bgp1-eth0': {'ipAddrs': ['10.0.1.2/24', '2000::102/120'], 'mac': '00:88:00:00:00:02'}, 89 | 'bgp1-eth1': {'ipAddrs': ['172.16.0.2/24']}} 90 | bgp1 = self.addHost('bgp1', cls=BgpRouter, 91 | interfaces=intfs, 92 | quaggaConfFile='./bgpdbgp1.conf', 93 | zebraConfFile='./zebradbgp1.conf') 94 | self.addLink(bgp1, s205) 95 | self.addLink(bgp1, cs0) 96 | 97 | # External Quagga r1 98 | intfs = {'r1-eth0': {'ipAddrs': ['10.0.1.1/24', '2000::101/120'], 'mac': '00:88:00:00:00:01'}, 99 | 'r1-eth1': {'ipAddrs': ['10.0.99.1/16']}, 100 | 'r1-eth2': {'ipAddrs': ['2000::9901/120']}} 101 | r1 = self.addHost('r1', cls=BgpRouter, 102 | interfaces=intfs, 103 | quaggaConfFile='./bgpdr1.conf') 104 | self.addLink(r1, s205) 105 | 106 | # External IPv4 Host behind r1 107 | rh1 = self.addHost('rh1', cls=RoutedHost, ips=['10.0.99.2/24'], gateway='10.0.99.1') 108 | self.addLink(r1, rh1) 109 | 110 | # External IPv6 Host behind r1 111 | rh1v6 = self.addHost('rh1v6', cls=RoutedHost, ips=['2000::9902/120'], gateway='2000::9901') 112 | self.addLink(r1, rh1v6) 113 | 114 | topos = { 'trellis' : Trellis } 115 | 116 | if __name__ == "__main__": 117 | setLogLevel('debug') 118 | topo = Trellis() 119 | switch = partial(OVSSwitch, protocols='OpenFlow13', datapath='user') 120 | arguments = parse_trellis_args() 121 | set_up_zebra_config(arguments.controllers) 122 | net = get_mininet(arguments, topo, switch) 123 | 124 | net.start() 125 | CLI(net) 126 | net.stop() 127 | -------------------------------------------------------------------------------- /trellis/trellis_hag.json: -------------------------------------------------------------------------------- 1 | { 2 | "ports" : { 3 | "of:0000000000000203/5" : { 4 | "interfaces" : [ 5 | { 6 | "ips" : [ "10.1.2.254/24", "2001::2ff/120" ], 7 | "vlan-tagged": [21] 8 | } 9 | ] 10 | }, 11 | "of:0000000000000203/6" : { 12 | "interfaces" : [ 13 | { 14 | "ips" : [ "10.0.4.254/24" ], 15 | "vlan-untagged": 22 16 | } 17 | ] 18 | }, 19 | "of:0000000000000203/7" : { 20 | "interfaces" : [ 21 | { 22 | "ips" : [ "2000::4ff/120" ], 23 | "vlan-untagged": 23 24 | } 25 | ] 26 | }, 27 | "of:0000000000000203/8" : { 28 | "interfaces" : [ 29 | { 30 | "ips" : [ "10.1.2.254/24", "2001::2ff/120" ], 31 | "vlan-untagged": 21 32 | } 33 | ] 34 | }, 35 | "of:0000000000000204/5" : { 36 | "interfaces" : [ 37 | { 38 | "ips" : [ "10.1.2.254/24", "2001::2ff/120" ], 39 | "vlan-tagged": [21] 40 | } 41 | ] 42 | }, 43 | "of:0000000000000204/6" : { 44 | "interfaces" : [ 45 | { 46 | "ips" : [ "10.0.2.254/24" ], 47 | "vlan-untagged": 20 48 | } 49 | ] 50 | }, 51 | "of:0000000000000204/7" : { 52 | "interfaces" : [ 53 | { 54 | "ips" : [ "10.0.2.254/24" ], 55 | "vlan-untagged": 20 56 | } 57 | ] 58 | }, 59 | "of:0000000000000204/8" : { 60 | "interfaces" : [ 61 | { 62 | "ips" : [ "2000::2ff/120" ], 63 | "vlan-untagged": 40 64 | } 65 | ] 66 | }, 67 | "of:0000000000000204/9" : { 68 | "interfaces" : [ 69 | { 70 | "ips" : [ "2000::2ff/120" ], 71 | "vlan-untagged": 40 72 | } 73 | ] 74 | }, 75 | "of:0000000000000204/10" : { 76 | "interfaces" : [ 77 | { 78 | "ips" : [ "10.1.2.254/24", "2001::2ff/120" ], 79 | "vlan-untagged": 21 80 | } 81 | ] 82 | }, 83 | "of:0000000000000205/6" : { 84 | "interfaces" : [ 85 | { 86 | "ips" : [ "10.0.3.254/24" ], 87 | "vlan-untagged": 30 88 | } 89 | ] 90 | }, 91 | "of:0000000000000205/7" : { 92 | "interfaces" : [ 93 | { 94 | "ips" : [ "10.0.3.254/24" ], 95 | "vlan-untagged": 30 96 | } 97 | ] 98 | }, 99 | "of:0000000000000205/8" : { 100 | "interfaces" : [ 101 | { 102 | "ips" : [ "2000::3ff/120" ], 103 | "vlan-untagged": 50 104 | } 105 | ] 106 | }, 107 | "of:0000000000000205/9" : { 108 | "interfaces" : [ 109 | { 110 | "ips" : [ "2000::3ff/120" ], 111 | "vlan-untagged": 50 112 | } 113 | ] 114 | }, 115 | "of:0000000000000205/10" : { 116 | "interfaces" : [ 117 | { 118 | "ips" : [ "10.0.3.254/24", "2000::3ff/120" ], 119 | "vlan-untagged": 30 120 | } 121 | ] 122 | }, 123 | "of:0000000000000205/11" : { 124 | "interfaces" : [ 125 | { 126 | "ips" : [ "10.0.1.254/24", "2000::1ff/120" ], 127 | "vlan-tagged": [110] 128 | } 129 | ] 130 | }, 131 | "of:0000000000000205/12" : { 132 | "interfaces" : [ 133 | { 134 | "ips" : [ "10.0.1.254/24", "2000::1ff/120" ], 135 | "vlan-untagged": 110 136 | } 137 | ] 138 | }, 139 | "of:0000000000000205/13" : { 140 | "interfaces" : [ 141 | { 142 | "ips" : [ "10.5.6.254/24" ], 143 | "vlan-untagged": 56 144 | } 145 | ] 146 | }, 147 | "of:0000000000000205/5" : { 148 | "interfaces" : [ 149 | { 150 | "ips" : [ "10.5.6.254/24" ], 151 | "vlan-tagged": [56] 152 | } 153 | ] 154 | }, 155 | "of:0000000000000206/5" : { 156 | "interfaces" : [ 157 | { 158 | "ips" : [ "10.5.6.254/24" ], 159 | "vlan-tagged": [56] 160 | } 161 | ] 162 | }, 163 | "of:0000000000000206/6" : { 164 | "interfaces" : [ 165 | { 166 | "ips" : [ "10.0.6.254/24", "2000::6ff/120" ], 167 | "vlan-tagged": [160] 168 | } 169 | ] 170 | }, 171 | "of:0000000000000206/8" : { 172 | "interfaces" : [ 173 | { 174 | "ips" : [ "10.5.6.254/24"], 175 | "vlan-untagged": 56 176 | } 177 | ] 178 | }, 179 | "of:0000000000000206/7" : { 180 | "interfaces" : [ 181 | { 182 | "ips" : [ "10.0.6.254/24", "2000::6ff/120" ], 183 | "vlan-untagged": 160 184 | } 185 | ] 186 | }, 187 | 188 | "of:0000000000000207/3" : { 189 | "interfaces" : [ 190 | { 191 | "ips" : [ "10.11.1.254/24" ], 192 | "vlan-untagged": 1000 193 | } 194 | ] 195 | }, 196 | "of:0000000000000207/4" : { 197 | "interfaces" : [ 198 | { 199 | "ips" : [ "2000::aff/120" ], 200 | "vlan-untagged": 1001 201 | } 202 | ] 203 | }, 204 | "of:0000000000000208/3" : { 205 | "interfaces" : [ 206 | { 207 | "ips" : [ "10.11.2.254/24" ], 208 | "vlan-untagged": 1002 209 | } 210 | ] 211 | }, 212 | "of:0000000000000208/4" : { 213 | "interfaces" : [ 214 | { 215 | "ips" : [ "2000::bff/120" ], 216 | "vlan-untagged": 1003 217 | } 218 | ] 219 | } 220 | 221 | }, 222 | "devices" : { 223 | "of:0000000000000203" : { 224 | "segmentrouting" : { 225 | "name" : "s203", 226 | "ipv4NodeSid" : 203, 227 | "ipv4Loopback" : "192.168.0.203", 228 | "ipv6NodeSid" : 213, 229 | "ipv6Loopback" : "2000::c0a8:0203", 230 | "routerMac" : "00:00:00:00:02:03", 231 | "isEdgeRouter" : true, 232 | "pairDeviceId" : "of:0000000000000204", 233 | "pairLocalPort" : 5, 234 | "adjacencySids" : [] 235 | }, 236 | "basic" : { 237 | "name": "s203", 238 | "driver" : "ofdpa-ovs", 239 | "latitude" : "36.766", 240 | "longitude" : "-111.359" 241 | } 242 | }, 243 | "of:0000000000000204" : { 244 | "segmentrouting" : { 245 | "name" : "s204", 246 | "ipv4NodeSid" : 204, 247 | "ipv4Loopback" : "192.168.0.204", 248 | "ipv6NodeSid" : 214, 249 | "ipv6Loopback" : "2000::c0a8:0204", 250 | "routerMac" : "00:00:00:00:02:03", 251 | "isEdgeRouter" : true, 252 | "pairDeviceId" : "of:0000000000000203", 253 | "pairLocalPort" : 5, 254 | "adjacencySids" : [] 255 | }, 256 | "basic" : { 257 | "name": "s204", 258 | "driver" : "ofdpa-ovs", 259 | "latitude" : "36.766", 260 | "longitude" : "-106.359" 261 | } 262 | }, 263 | "of:0000000000000205" : { 264 | "segmentrouting" : { 265 | "name" : "s205", 266 | "ipv4NodeSid" : 205, 267 | "ipv4Loopback" : "192.168.0.205", 268 | "ipv6NodeSid" : 215, 269 | "ipv6Loopback" : "2000::c0a8:0205", 270 | "routerMac" : "00:00:00:00:02:05", 271 | "isEdgeRouter" : true, 272 | "adjacencySids" : [], 273 | "pairDeviceId": "of:0000000000000206", 274 | "pairLocalPort": 5 275 | }, 276 | "basic" : { 277 | "name": "s205", 278 | "driver" : "ofdpa-ovs", 279 | "latitude" : "36.766", 280 | "longitude" : "-96.89" 281 | 282 | } 283 | }, 284 | "of:0000000000000206" : { 285 | "segmentrouting" : { 286 | "name" : "s206", 287 | "ipv4NodeSid" : 206, 288 | "ipv4Loopback" : "192.168.0.206", 289 | "ipv6NodeSid" : 216, 290 | "ipv6Loopback" : "2000::c0a8:0206", 291 | "routerMac" : "00:00:00:00:02:05", 292 | "isEdgeRouter" : true, 293 | "adjacencySids" : [], 294 | "pairDeviceId": "of:0000000000000205", 295 | "pairLocalPort": 5 296 | }, 297 | "basic" : { 298 | "name": "s206", 299 | "driver" : "ofdpa-ovs", 300 | "latitude" : "36.766", 301 | "longitude" : "-92.029" 302 | } 303 | }, 304 | "of:0000000000000226" : { 305 | "segmentrouting" : { 306 | "name" : "s226", 307 | "ipv4NodeSid" : 226, 308 | "ipv4Loopback" : "192.168.0.226", 309 | "ipv6NodeSid" : 236, 310 | "ipv6Loopback" : "2000::c0a8:0226", 311 | "routerMac" : "00:00:00:00:02:26", 312 | "isEdgeRouter" : false, 313 | "adjacencySids" : [] 314 | }, 315 | "basic" : { 316 | "name": "s226", 317 | "driver" : "ofdpa-ovs", 318 | "latitude" : "44.15", 319 | "longitude" : "-107.679" 320 | } 321 | }, 322 | "of:0000000000000227" : { 323 | "segmentrouting" : { 324 | "name" : "s227", 325 | "ipv4NodeSid" : 227, 326 | "ipv4Loopback" : "192.168.0.227", 327 | "ipv6NodeSid" : 237, 328 | "ipv6Loopback" : "2000::c0a8:0227", 329 | "routerMac" : "00:00:00:00:02:27", 330 | "isEdgeRouter" : false, 331 | "adjacencySids" : [] 332 | }, 333 | "basic" : { 334 | "name": "s227", 335 | "driver" : "ofdpa-ovs", 336 | "latitude" : "44.205", 337 | "longitude" : "-96.359" 338 | 339 | } 340 | }, 341 | 342 | "of:0000000000000207" : { 343 | "segmentrouting" : { 344 | "name" : "s207", 345 | "ipv4NodeSid" : 207, 346 | "ipv4Loopback" : "192.168.0.207", 347 | "ipv6NodeSid" : 217, 348 | "ipv6Loopback" : "2000::c0a8:0207", 349 | "routerMac" : "00:00:00:00:02:07", 350 | "isEdgeRouter" : true, 351 | "adjacencySids" : [] 352 | }, 353 | "basic" : { 354 | "name": "s207", 355 | "driver" : "ofdpa-ovs", 356 | "latitude" : "36.766", 357 | "longitude" : "-122.359" 358 | } 359 | }, 360 | "of:0000000000000208" : { 361 | "segmentrouting" : { 362 | "name" : "s208", 363 | "ipv4NodeSid" : 208, 364 | "ipv4Loopback" : "192.168.0.208", 365 | "ipv6NodeSid" : 218, 366 | "ipv6Loopback" : "2000::c0a8:0208", 367 | "routerMac" : "00:00:00:00:02:08", 368 | "isEdgeRouter" : true, 369 | "adjacencySids" : [] 370 | }, 371 | "basic" : { 372 | "name": "s208", 373 | "driver" : "ofdpa-ovs", 374 | "latitude" : "36.766", 375 | "longitude" : "-116.029" 376 | } 377 | }, 378 | "of:0000000000000246" : { 379 | "segmentrouting" : { 380 | "name" : "s246", 381 | "ipv4NodeSid" : 246, 382 | "ipv4Loopback" : "192.168.0.246", 383 | "ipv6NodeSid" : 256, 384 | "ipv6Loopback" : "2000::c0a8:0246", 385 | "routerMac" : "00:00:00:00:02:46", 386 | "isEdgeRouter" : false, 387 | "adjacencySids" : [] 388 | }, 389 | "basic" : { 390 | "name": "s246", 391 | "driver" : "ofdpa-ovs", 392 | "latitude" : "40.15", 393 | "longitude" : "-121.679" 394 | } 395 | }, 396 | "of:0000000000000247" : { 397 | "segmentrouting" : { 398 | "name" : "s247", 399 | "ipv4NodeSid" : 247, 400 | "ipv4Loopback" : "192.168.0.247", 401 | "ipv6NodeSid" : 257, 402 | "ipv6Loopback" : "2000::c0a8:0247", 403 | "routerMac" : "00:00:00:00:02:47", 404 | "isEdgeRouter" : false, 405 | "adjacencySids" : [] 406 | }, 407 | "basic" : { 408 | "name": "s247", 409 | "driver" : "ofdpa-ovs", 410 | "latitude" : "40.205", 411 | "longitude" : "-117.359" 412 | 413 | } 414 | } 415 | 416 | }, 417 | "apps" : { 418 | "org.onosproject.dhcprelay" : { 419 | "default": [ 420 | { 421 | "dhcpServerConnectPoint": "of:0000000000000205/10", 422 | "serverIps": ["10.0.3.253", "2000::3fd"] 423 | } 424 | ] 425 | } 426 | } 427 | } 428 | -------------------------------------------------------------------------------- /trellis/trellis_hag.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | import sys 4 | sys.path.append('..') 5 | from mininet.topo import Topo 6 | from mininet.cli import CLI 7 | from mininet.log import setLogLevel 8 | from mininet.node import RemoteController, OVSBridge, Host, OVSSwitch 9 | from mininet.link import TCLink 10 | from ipaddress import ip_network 11 | from routinglib import BgpRouter 12 | from routinglib import RoutedHost, RoutedHost6, UserNAT 13 | from trellislib import DhcpClient, Dhcp6Client, Dhcp4and6Client, DhcpRelay, DhcpServer, Dhcp6Server 14 | from trellislib import DualHomedDhcpClient 15 | from trellislib import DualHomedDhcp4and6Client 16 | from trellislib import get_mininet, parse_trellis_args, set_up_zebra_config 17 | from functools import partial 18 | 19 | 20 | class Trellis( Topo ): 21 | """Trellis HAG topology""" 22 | 23 | def __init__( self, *args, **kwargs ): 24 | Topo.__init__( self, *args, **kwargs ) 25 | 26 | # Spines 27 | s226 = self.addSwitch('s226', dpid='226') 28 | s227 = self.addSwitch('s227', dpid='227') 29 | 30 | # Leaves 31 | s203 = self.addSwitch('s203', dpid='203') 32 | s204 = self.addSwitch('s204', dpid='204') 33 | s205 = self.addSwitch('s205', dpid='205') 34 | s206 = self.addSwitch('s206', dpid='206') 35 | 36 | # Leaf-Spine Links 37 | self.addLink(s226, s203) 38 | self.addLink(s226, s203) 39 | self.addLink(s226, s204) 40 | self.addLink(s226, s204) 41 | self.addLink(s226, s205) 42 | self.addLink(s226, s205) 43 | self.addLink(s226, s206) 44 | self.addLink(s226, s206) 45 | self.addLink(s227, s203) 46 | self.addLink(s227, s203) 47 | self.addLink(s227, s204) 48 | self.addLink(s227, s204) 49 | self.addLink(s227, s205) 50 | self.addLink(s227, s205) 51 | self.addLink(s227, s206) 52 | self.addLink(s227, s206) 53 | 54 | # Leaf-Leaf Links 55 | self.addLink(s203, s204) 56 | self.addLink(s205, s206) 57 | 58 | # NOTE avoid using 10.0.1.0/24 which is the default subnet of quaggas 59 | # NOTE avoid using 00:00:00:00:00:xx which is the default mac of host behind upstream router 60 | # IPv4 Hosts 61 | h1 = self.addHost('h1', cls=DhcpClient, mac='00:aa:00:00:00:01') 62 | h2 = self.addHost('h2', cls=DhcpClient, mac='00:aa:00:00:00:02') 63 | h3 = self.addHost('h3', cls=DhcpClient, mac='00:aa:00:00:00:03') 64 | h4 = self.addHost('h4', cls=DhcpClient, mac='00:aa:00:00:00:04') 65 | h5 = self.addHost('h5', cls=DhcpClient, mac='00:aa:00:00:00:05') 66 | self.addLink(h1, s204) 67 | self.addLink(h2, s204) 68 | self.addLink(h3, s205) 69 | self.addLink(h4, s205) 70 | self.addLink(h5, s203) 71 | 72 | # IPv6 Hosts 73 | h1v6 = self.addHost('h1v6', cls=Dhcp6Client, mac='00:bb:00:00:00:01') 74 | h2v6 = self.addHost('h2v6', cls=Dhcp6Client, mac='00:bb:00:00:00:02') 75 | h3v6 = self.addHost('h3v6', cls=Dhcp6Client, mac='00:bb:00:00:00:03') 76 | h4v6 = self.addHost('h4v6', cls=Dhcp6Client, mac='00:bb:00:00:00:04') 77 | h5v6 = self.addHost('h5v6', cls=Dhcp6Client, mac='00:bb:00:00:00:05') 78 | self.addLink(h1v6, s204) 79 | self.addLink(h2v6, s204) 80 | self.addLink(h3v6, s205) 81 | self.addLink(h4v6, s205) 82 | self.addLink(h5v6, s203) 83 | 84 | # Dual-homed IPv4 and IPv6 Host on 203-204 85 | dh1 = self.addHost('dh1', cls=DualHomedDhcp4and6Client, mac='00:cc:00:00:00:01') 86 | self.addLink(dh1, s204) 87 | self.addLink(dh1, s203) 88 | 89 | # DHCP server 90 | dhcp = self.addHost('dhcp', cls=DhcpServer, mac='00:99:00:00:00:01', ips=['10.0.3.253/24'], gateway='10.0.3.254') 91 | 92 | # DHCPv6 server 93 | dhcp6 = self.addHost('dhcp6', cls=Dhcp6Server, mac='00:99:66:00:00:01', ips=['2000::3fd/120'], gateway='2000::3ff') 94 | 95 | # Dataplane L2 plane switch (for DHCP servers) 96 | cs1 = self.addSwitch('cs1', cls=OVSBridge, datapath='user') 97 | self.addLink(cs1, s205) 98 | self.addLink(dhcp, cs1) 99 | self.addLink(dhcp6, cs1) 100 | 101 | # Control plane switch (for quagga fpm) 102 | cs0 = self.addSwitch('cs0', cls=OVSBridge, datapath='user') 103 | 104 | # Control plane NAT (for quagga fpm) 105 | nat = self.addHost('nat', cls=UserNAT, 106 | ip='172.16.0.1/24', 107 | subnet=str(ip_network(u'172.16.0.0/24')), inNamespace=False) 108 | self.addLink(cs0, nat) 109 | 110 | # Internal Quagga bgp1 111 | """ 112 | intfs = {'bgp1-eth0': [{'ipAddrs': ['10.0.1.2/24', '2000::102/120'], 'mac': '00:88:00:00:00:03', 'vlan': '110'}, 113 | {'ipAddrs': ['10.0.7.2/24', '2000::702/120'], 'mac': '00:88:00:00:00:03', 'vlan': '170'}], 114 | 'bgp1-eth1': {'ipAddrs': ['172.16.0.3/24']}} 115 | """ 116 | intfs = {'bgp1-eth0': {'ipAddrs': ['10.0.1.2/24', '2000::102/120'], 'mac': '00:88:00:00:00:03', 'vlan': '110'}, 117 | 'bgp1-eth1': {'ipAddrs': ['172.16.0.3/24']}} 118 | bgp1 = self.addHost('bgp1', cls=BgpRouter, 119 | interfaces=intfs, 120 | quaggaConfFile='./bgpdbgp1.conf', 121 | zebraConfFile='./zebradbgp1.conf') 122 | self.addLink(bgp1, s205) 123 | self.addLink(bgp1, cs0) 124 | 125 | # Internal Quagga bgp2 126 | """ 127 | intfs = {'bgp2-eth0': [{'ipAddrs': ['10.0.5.2/24', '2000::502/120'], 'mac': '00:88:00:00:00:04', 'vlan': '150'}, 128 | {'ipAddrs': ['10.0.6.2/24', '2000::602/120'], 'mac': '00:88:00:00:00:04', 'vlan': '160'}], 129 | 'bgp2-eth1': {'ipAddrs': ['172.16.0.4/24']}} 130 | """ 131 | intfs = {'bgp2-eth0': {'ipAddrs': ['10.0.6.2/24', '2000::602/120'], 'mac': '00:88:00:00:00:04', 'vlan': '160'}, 132 | 'bgp2-eth1': {'ipAddrs': ['172.16.0.4/24']}} 133 | bgp2 = self.addHost('bgp2', cls=BgpRouter, 134 | interfaces=intfs, 135 | quaggaConfFile='./bgpdbgp2.conf', 136 | zebraConfFile='./zebradbgp2.conf') 137 | self.addLink(bgp2, s206) 138 | self.addLink(bgp2, cs0) 139 | 140 | # External Quagga r1 141 | intfs = {'r1-eth0': {'ipAddrs': ['10.0.1.1/24', '2000::101/120'], 'mac': '00:88:00:00:00:01'}, 142 | #'r1-eth1': {'ipAddrs': ['10.0.5.1/24', '2000::501/120'], 'mac': '00:88:00:00:00:11'}, 143 | 'r1-eth1': {'ipAddrs': ['10.0.99.1/16']}, 144 | 'r1-eth2': {'ipAddrs': ['2000::9901/120']}, 145 | 'r1-eth3': {'ipAddrs': ['2000::7701/120']}} 146 | r1 = self.addHost('r1', cls=BgpRouter, 147 | interfaces=intfs, 148 | quaggaConfFile='./bgpdr1.conf') 149 | self.addLink(r1, s205) 150 | #self.addLink(r1, s206) 151 | 152 | # External IPv4 Host behind r1 153 | rh1 = self.addHost('rh1', cls=RoutedHost, ips=['10.0.99.2/24'], gateway='10.0.99.1') 154 | self.addLink(r1, rh1) 155 | 156 | # External IPv6 Host behind r1 157 | rh1v6 = self.addHost('rh1v6', cls=RoutedHost, ips=['2000::9902/120'], gateway='2000::9901') 158 | self.addLink(r1, rh1v6) 159 | 160 | # Another external IPv6 Host behind r1 161 | rh11v6 = self.addHost('rh11v6', cls=RoutedHost, ips=['2000::7702/120'], gateway='2000::7701') 162 | self.addLink(r1, rh11v6) 163 | 164 | # External Quagga r2 165 | intfs = {'r2-eth0': {'ipAddrs': ['10.0.6.1/24', '2000::601/120'], 'mac': '00:88:00:00:00:02'}, 166 | #'r2-eth1': {'ipAddrs': ['10.0.7.1/24', '2000::701/120'], 'mac': '00:88:00:00:00:22'}, 167 | 'r2-eth1': {'ipAddrs': ['10.0.99.1/16']}, 168 | 'r2-eth2': {'ipAddrs': ['2000::9901/120']}, 169 | 'r2-eth3': {'ipAddrs': ['2000::8801/120']}} 170 | r2 = self.addHost('r2', cls=BgpRouter, 171 | interfaces=intfs, 172 | quaggaConfFile='./bgpdr2.conf') 173 | self.addLink(r2, s206) 174 | #self.addLink(r2, s205) 175 | 176 | # External IPv4 Host behind r2 177 | rh2 = self.addHost('rh2', cls=RoutedHost, ips=['10.0.99.2/24'], gateway='10.0.99.1') 178 | self.addLink(r2, rh2) 179 | 180 | # External IPv6 Host behind r2 181 | rh2v6 = self.addHost('rh126', cls=RoutedHost, ips=['2000::9902/120'], gateway='2000::9901') 182 | self.addLink(r2, rh2v6) 183 | 184 | # Another external IPv6 Host behind r1 185 | rh22v6 = self.addHost('rh22v6', cls=RoutedHost, ips=['2000::8802/120'], gateway='2000::8801') 186 | self.addLink(r2, rh22v6) 187 | 188 | # Dual-homed IPv4 Host for 205-206 189 | dh2 = self.addHost('dh2', cls=DualHomedDhcpClient, mac='00:cc:00:00:00:02') 190 | self.addLink(dh2, s205) 191 | self.addLink(dh2, s206) 192 | 193 | # ----- Secondary fabric ----- 194 | 195 | # Spines(HAG) 196 | s246 = self.addSwitch('s246', dpid='246') 197 | s247 = self.addSwitch('s247', dpid='247') 198 | 199 | # Leaves(DAAS) 200 | s207 = self.addSwitch('s207', dpid='207') 201 | s208 = self.addSwitch('s208', dpid='208') 202 | 203 | # HAG-DAAS Links 204 | self.addLink(s246, s207) 205 | self.addLink(s246, s208) 206 | self.addLink(s247, s207) 207 | self.addLink(s247, s208) 208 | 209 | # HAG - Spine Links 210 | self.addLink(s246, s226) 211 | self.addLink(s247, s227) 212 | 213 | # IPv4 Hosts - RPDs 214 | rpd5 = self.addHost('rpd5', cls=DhcpClient, mac='00:dd:00:00:00:01') 215 | rpd6 = self.addHost('rpd6', cls=DhcpClient, mac='00:dd:00:00:00:02') 216 | self.addLink(rpd5, s207) 217 | self.addLink(rpd6, s208) 218 | 219 | # IPv6 Hosts - RPDs 220 | rpd5v6 = self.addHost('rpd5v6', cls=Dhcp6Client, mac='00:ee:00:00:00:01') 221 | rpd6v6 = self.addHost('rpd6v6', cls=Dhcp6Client, mac='00:ee:00:00:00:02') 222 | self.addLink(rpd5v6, s207) 223 | self.addLink(rpd6v6, s208) 224 | 225 | 226 | 227 | 228 | 229 | topos = { 'trellis' : Trellis } 230 | 231 | if __name__ == "__main__": 232 | setLogLevel('debug') 233 | 234 | topo = Trellis() 235 | switch = partial(OVSSwitch, protocols='OpenFlow13', datapath='user') 236 | arguments = parse_trellis_args() 237 | set_up_zebra_config(arguments.controllers) 238 | net = get_mininet(arguments, topo, switch) 239 | 240 | net.start() 241 | CLI(net) 242 | net.stop() 243 | -------------------------------------------------------------------------------- /trellis/trellis_hybrid.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | import sys 4 | sys.path.append('..') 5 | from mininet.topo import Topo 6 | from mininet.cli import CLI 7 | from mininet.log import setLogLevel 8 | from mininet.node import RemoteController, OVSBridge, Host, OVSSwitch 9 | from mininet.link import TCLink 10 | from ipaddress import ip_network 11 | from routinglib import BgpRouter 12 | from routinglib import RoutedHost, RoutedHost6, UserNAT 13 | from trellislib import DhcpClient, Dhcp6Client, Dhcp4and6Client, DhcpRelay, DhcpServer, Dhcp6Server 14 | from trellislib import DualHomedDhcpClient 15 | from trellislib import DualHomedDhcp4and6Client 16 | from trellislib import get_mininet, parse_trellis_args, set_up_zebra_config 17 | from functools import partial 18 | from bmv2 import ONOSBmv2Switch 19 | 20 | PIPECONF_ID = 'org.onosproject.pipelines.fabric' 21 | 22 | class Trellis( Topo ): 23 | """Trellis HAG topology with both OVS and BMV2 switches""" 24 | 25 | def __init__( self, *args, **kwargs ): 26 | Topo.__init__( self, *args, **kwargs ) 27 | 28 | # Spines 29 | s226 = self.addSwitch('s226', cls=ONOSBmv2Switch, pipeconf=PIPECONF_ID, portcfg=True) 30 | s227 = self.addSwitch('s227', dpid='227') 31 | 32 | # Leaves 33 | s203 = self.addSwitch('s203', dpid='203') 34 | s204 = self.addSwitch('s204', cls=ONOSBmv2Switch, pipeconf=PIPECONF_ID, portcfg=True) 35 | s205 = self.addSwitch('s205', dpid='205') 36 | s206 = self.addSwitch('s206', dpid='206') 37 | 38 | # Leaf-Spine Links 39 | self.addLink(s226, s203) 40 | self.addLink(s226, s203) 41 | self.addLink(s226, s204) 42 | self.addLink(s226, s204) 43 | self.addLink(s226, s205) 44 | self.addLink(s226, s205) 45 | self.addLink(s226, s206) 46 | self.addLink(s226, s206) 47 | self.addLink(s227, s203) 48 | self.addLink(s227, s203) 49 | self.addLink(s227, s204) 50 | self.addLink(s227, s204) 51 | self.addLink(s227, s205) 52 | self.addLink(s227, s205) 53 | self.addLink(s227, s206) 54 | self.addLink(s227, s206) 55 | 56 | # Leaf-Leaf Links 57 | self.addLink(s203, s204) 58 | self.addLink(s205, s206) 59 | 60 | # NOTE avoid using 10.0.1.0/24 which is the default subnet of quaggas 61 | # NOTE avoid using 00:00:00:00:00:xx which is the default mac of host behind upstream router 62 | # IPv4 Hosts 63 | h1 = self.addHost('h1', cls=DhcpClient, mac='00:aa:00:00:00:01') 64 | h2 = self.addHost('h2', cls=DhcpClient, mac='00:aa:00:00:00:02') 65 | h3 = self.addHost('h3', cls=DhcpClient, mac='00:aa:00:00:00:03') 66 | h4 = self.addHost('h4', cls=DhcpClient, mac='00:aa:00:00:00:04') 67 | h5 = self.addHost('h5', cls=DhcpClient, mac='00:aa:00:00:00:05') 68 | self.addLink(h1, s204) 69 | self.addLink(h2, s204) 70 | self.addLink(h3, s205) 71 | self.addLink(h4, s205) 72 | self.addLink(h5, s203) 73 | 74 | # IPv6 Hosts 75 | h1v6 = self.addHost('h1v6', cls=Dhcp6Client, mac='00:bb:00:00:00:01') 76 | h2v6 = self.addHost('h2v6', cls=Dhcp6Client, mac='00:bb:00:00:00:02') 77 | h3v6 = self.addHost('h3v6', cls=Dhcp6Client, mac='00:bb:00:00:00:03') 78 | h4v6 = self.addHost('h4v6', cls=Dhcp6Client, mac='00:bb:00:00:00:04') 79 | h5v6 = self.addHost('h5v6', cls=Dhcp6Client, mac='00:bb:00:00:00:05') 80 | self.addLink(h1v6, s204) 81 | self.addLink(h2v6, s204) 82 | self.addLink(h3v6, s205) 83 | self.addLink(h4v6, s205) 84 | self.addLink(h5v6, s203) 85 | 86 | # Dual-homed IPv4 and IPv6 Host on 203-204 87 | dh1 = self.addHost('dh1', cls=DualHomedDhcp4and6Client, mac='00:cc:00:00:00:01') 88 | self.addLink(dh1, s204) 89 | self.addLink(dh1, s203) 90 | 91 | # DHCP server 92 | dhcp = self.addHost('dhcp', cls=DhcpServer, mac='00:99:00:00:00:01', ips=['10.0.3.253/24'], gateway='10.0.3.254') 93 | 94 | # DHCPv6 server 95 | dhcp6 = self.addHost('dhcp6', cls=Dhcp6Server, mac='00:99:66:00:00:01', ips=['2000::3fd/120'], gateway='2000::3ff') 96 | 97 | # Dataplane L2 plane switch (for DHCP servers) 98 | cs1 = self.addSwitch('cs1', cls=OVSBridge, datapath='user') 99 | self.addLink(cs1, s205) 100 | self.addLink(dhcp, cs1) 101 | self.addLink(dhcp6, cs1) 102 | 103 | # Control plane switch (for quagga fpm) 104 | cs0 = self.addSwitch('cs0', cls=OVSBridge, datapath='user') 105 | 106 | # Control plane NAT (for quagga fpm) 107 | nat = self.addHost('nat', cls=UserNAT, 108 | ip='172.16.0.1/24', 109 | subnet=str(ip_network(u'172.16.0.0/24')), inNamespace=False) 110 | self.addLink(cs0, nat) 111 | 112 | # Internal Quagga bgp1 113 | """ 114 | intfs = {'bgp1-eth0': [{'ipAddrs': ['10.0.1.2/24', '2000::102/120'], 'mac': '00:88:00:00:00:03', 'vlan': '110'}, 115 | {'ipAddrs': ['10.0.7.2/24', '2000::702/120'], 'mac': '00:88:00:00:00:03', 'vlan': '170'}], 116 | 'bgp1-eth1': {'ipAddrs': ['172.16.0.3/24']}} 117 | """ 118 | intfs = {'bgp1-eth0': {'ipAddrs': ['10.0.1.2/24', '2000::102/120'], 'mac': '00:88:00:00:00:03', 'vlan': '110'}, 119 | 'bgp1-eth1': {'ipAddrs': ['172.16.0.3/24']}} 120 | bgp1 = self.addHost('bgp1', cls=BgpRouter, 121 | interfaces=intfs, 122 | quaggaConfFile='./bgpdbgp1.conf', 123 | zebraConfFile='./zebradbgp1.conf') 124 | self.addLink(bgp1, s205) 125 | self.addLink(bgp1, cs0) 126 | 127 | # Internal Quagga bgp2 128 | """ 129 | intfs = {'bgp2-eth0': [{'ipAddrs': ['10.0.5.2/24', '2000::502/120'], 'mac': '00:88:00:00:00:04', 'vlan': '150'}, 130 | {'ipAddrs': ['10.0.6.2/24', '2000::602/120'], 'mac': '00:88:00:00:00:04', 'vlan': '160'}], 131 | 'bgp2-eth1': {'ipAddrs': ['172.16.0.4/24']}} 132 | """ 133 | intfs = {'bgp2-eth0': {'ipAddrs': ['10.0.6.2/24', '2000::602/120'], 'mac': '00:88:00:00:00:04', 'vlan': '160'}, 134 | 'bgp2-eth1': {'ipAddrs': ['172.16.0.4/24']}} 135 | bgp2 = self.addHost('bgp2', cls=BgpRouter, 136 | interfaces=intfs, 137 | quaggaConfFile='./bgpdbgp2.conf', 138 | zebraConfFile='./zebradbgp2.conf') 139 | self.addLink(bgp2, s206) 140 | self.addLink(bgp2, cs0) 141 | 142 | # External Quagga r1 143 | intfs = {'r1-eth0': {'ipAddrs': ['10.0.1.1/24', '2000::101/120'], 'mac': '00:88:00:00:00:01'}, 144 | #'r1-eth1': {'ipAddrs': ['10.0.5.1/24', '2000::501/120'], 'mac': '00:88:00:00:00:11'}, 145 | 'r1-eth1': {'ipAddrs': ['10.0.99.1/16']}, 146 | 'r1-eth2': {'ipAddrs': ['2000::9901/120']}, 147 | 'r1-eth3': {'ipAddrs': ['2000::7701/120']}} 148 | r1 = self.addHost('r1', cls=BgpRouter, 149 | interfaces=intfs, 150 | quaggaConfFile='./bgpdr1.conf') 151 | self.addLink(r1, s205) 152 | #self.addLink(r1, s206) 153 | 154 | # External IPv4 Host behind r1 155 | rh1 = self.addHost('rh1', cls=RoutedHost, ips=['10.0.99.2/24'], gateway='10.0.99.1') 156 | self.addLink(r1, rh1) 157 | 158 | # External IPv6 Host behind r1 159 | rh1v6 = self.addHost('rh1v6', cls=RoutedHost, ips=['2000::9902/120'], gateway='2000::9901') 160 | self.addLink(r1, rh1v6) 161 | 162 | # Another external IPv6 Host behind r1 163 | rh11v6 = self.addHost('rh11v6', cls=RoutedHost, ips=['2000::7702/120'], gateway='2000::7701') 164 | self.addLink(r1, rh11v6) 165 | 166 | # External Quagga r2 167 | intfs = {'r2-eth0': {'ipAddrs': ['10.0.6.1/24', '2000::601/120'], 'mac': '00:88:00:00:00:02'}, 168 | #'r2-eth1': {'ipAddrs': ['10.0.7.1/24', '2000::701/120'], 'mac': '00:88:00:00:00:22'}, 169 | 'r2-eth1': {'ipAddrs': ['10.0.99.1/16']}, 170 | 'r2-eth2': {'ipAddrs': ['2000::9901/120']}, 171 | 'r2-eth3': {'ipAddrs': ['2000::8801/120']}} 172 | r2 = self.addHost('r2', cls=BgpRouter, 173 | interfaces=intfs, 174 | quaggaConfFile='./bgpdr2.conf') 175 | self.addLink(r2, s206) 176 | #self.addLink(r2, s205) 177 | 178 | # External IPv4 Host behind r2 179 | rh2 = self.addHost('rh2', cls=RoutedHost, ips=['10.0.99.2/24'], gateway='10.0.99.1') 180 | self.addLink(r2, rh2) 181 | 182 | # External IPv6 Host behind r2 183 | rh2v6 = self.addHost('rh126', cls=RoutedHost, ips=['2000::9902/120'], gateway='2000::9901') 184 | self.addLink(r2, rh2v6) 185 | 186 | # Another external IPv6 Host behind r1 187 | rh22v6 = self.addHost('rh22v6', cls=RoutedHost, ips=['2000::8802/120'], gateway='2000::8801') 188 | self.addLink(r2, rh22v6) 189 | 190 | # Dual-homed IPv4 Host for 205-206 191 | dh2 = self.addHost('dh2', cls=DualHomedDhcpClient, mac='00:cc:00:00:00:02') 192 | self.addLink(dh2, s205) 193 | self.addLink(dh2, s206) 194 | 195 | # ----- Secondary fabric ----- 196 | 197 | # Spines(HAG) 198 | s246 = self.addSwitch('s246', cls=ONOSBmv2Switch, pipeconf=PIPECONF_ID, portcfg=True) 199 | s247 = self.addSwitch('s247', cls=ONOSBmv2Switch, pipeconf=PIPECONF_ID, portcfg=True) 200 | 201 | # Leaves(DAAS) 202 | s207 = self.addSwitch('s207', dpid='207') 203 | s208 = self.addSwitch('s208', cls=ONOSBmv2Switch, pipeconf=PIPECONF_ID, portcfg=True) 204 | 205 | # HAG-DAAS Links 206 | self.addLink(s246, s207) 207 | self.addLink(s246, s208) 208 | self.addLink(s247, s207) 209 | self.addLink(s247, s208) 210 | 211 | # HAG - Spine Links 212 | self.addLink(s246, s226) 213 | self.addLink(s247, s227) 214 | 215 | # IPv4 Hosts - RPDs 216 | rpd5 = self.addHost('rpd5', cls=DhcpClient, mac='00:dd:00:00:00:01') 217 | rpd6 = self.addHost('rpd6', cls=DhcpClient, mac='00:dd:00:00:00:02') 218 | self.addLink(rpd5, s207) 219 | self.addLink(rpd6, s208) 220 | 221 | # IPv6 Hosts - RPDs 222 | rpd5v6 = self.addHost('rpd5v6', cls=Dhcp6Client, mac='00:ee:00:00:00:01') 223 | rpd6v6 = self.addHost('rpd6v6', cls=Dhcp6Client, mac='00:ee:00:00:00:02') 224 | self.addLink(rpd5v6, s207) 225 | self.addLink(rpd6v6, s208) 226 | 227 | 228 | 229 | 230 | 231 | topos = { 'trellis' : Trellis } 232 | 233 | if __name__ == "__main__": 234 | setLogLevel('debug') 235 | 236 | topo = Trellis() 237 | switch = partial(OVSSwitch, protocols='OpenFlow13', datapath='user') 238 | arguments = parse_trellis_args() 239 | set_up_zebra_config(arguments.controllers) 240 | net = get_mininet(arguments, topo, switch) 241 | 242 | net.start() 243 | CLI(net) 244 | net.stop() 245 | -------------------------------------------------------------------------------- /trellis/trellis_hybrid_v4.json: -------------------------------------------------------------------------------- 1 | { 2 | "ports" : { 3 | "of:0000000000000203/5" : { 4 | "interfaces" : [ 5 | { 6 | "ips" : [ "10.1.2.254/24"], 7 | "vlan-tagged": [21] 8 | } 9 | ] 10 | }, 11 | "of:0000000000000203/6" : { 12 | "interfaces" : [ 13 | { 14 | "name": "h3-eth0", 15 | "ips" : [ "10.0.4.254/24" ], 16 | "vlan-untagged": 22 17 | } 18 | ] 19 | }, 20 | "of:0000000000000203/7" : { 21 | "interfaces" : [ 22 | { 23 | "name": "dh1-eth1", 24 | "ips" : [ "10.1.2.254/24"], 25 | "vlan-untagged": 21 26 | } 27 | ] 28 | }, 29 | "device:bmv2-s204/5" : { 30 | "interfaces" : [ 31 | { 32 | "ips" : [ "10.1.2.254/24"], 33 | "vlan-tagged": [21] 34 | } 35 | ] 36 | }, 37 | "device:bmv2-s204/6" : { 38 | "interfaces" : [ 39 | { 40 | "name": "h4-eth0", 41 | "ips" : [ "10.0.2.254/24" ], 42 | "vlan-untagged": 20 43 | } 44 | ] 45 | }, 46 | "device:bmv2-s204/7" : { 47 | "interfaces" : [ 48 | { 49 | "name": "dh1-eth0", 50 | "ips" : [ "10.1.2.254/24"], 51 | "vlan-untagged": 21 52 | } 53 | ] 54 | }, 55 | "of:0000000000000205/5" : { 56 | "interfaces" : [ 57 | { 58 | "ips" : [ "10.5.6.254/24" ], 59 | "vlan-tagged": [56] 60 | } 61 | ] 62 | }, 63 | "of:0000000000000205/6" : { 64 | "interfaces" : [ 65 | { 66 | "name": "h5-eth0", 67 | "ips" : [ "10.0.3.254/24" ], 68 | "vlan-untagged": 30 69 | } 70 | ] 71 | }, 72 | "of:0000000000000205/7" : { 73 | "interfaces" : [ 74 | { 75 | "name": "h6-eth0", 76 | "ips" : [ "10.0.3.254/24" ], 77 | "vlan-untagged": 30 78 | } 79 | ] 80 | }, 81 | "of:0000000000000205/8" : { 82 | "interfaces" : [ 83 | { 84 | "name": "dh2-eth0", 85 | "ips" : [ "10.5.6.254/24" ], 86 | "vlan-untagged": 56 87 | } 88 | ] 89 | }, 90 | "of:0000000000000205/9" : { 91 | "interfaces" : [ 92 | { 93 | "name": "cs1 - dhcp - eth0", 94 | "ips" : [ "10.0.3.254/24" ], 95 | "vlan-untagged": 30 96 | } 97 | ] 98 | }, 99 | "of:0000000000000205/10" : { 100 | "interfaces" : [ 101 | { 102 | "name": "bgp1-eth0", 103 | "ips" : [ "10.0.1.254/24"], 104 | "vlan-tagged": [110] 105 | } 106 | ] 107 | }, 108 | "of:0000000000000205/11" : { 109 | "interfaces" : [ 110 | { 111 | "name": "r1-eth0", 112 | "ips" : [ "10.0.1.254/24"], 113 | "vlan-untagged": 110 114 | } 115 | ] 116 | }, 117 | "of:0000000000000206/5" : { 118 | "interfaces" : [ 119 | { 120 | "ips" : [ "10.5.6.254/24" ], 121 | "vlan-tagged": [56] 122 | } 123 | ] 124 | }, 125 | "of:0000000000000206/6" : { 126 | "interfaces" : [ 127 | { 128 | "name": "dh2-eth1", 129 | "ips" : [ "10.5.6.254/24"], 130 | "vlan-untagged": 56 131 | } 132 | ] 133 | }, 134 | "of:0000000000000206/7" : { 135 | "interfaces" : [ 136 | { 137 | "name": "bgp2-eth0", 138 | "ips" : [ "10.0.6.254/24"], 139 | "vlan-tagged": [160] 140 | } 141 | ] 142 | }, 143 | 144 | "of:0000000000000206/8" : { 145 | "interfaces" : [ 146 | { 147 | "name": "r2-eth0", 148 | "ips" : [ "10.0.6.254/24"], 149 | "vlan-untagged": 160 150 | } 151 | ] 152 | }, 153 | 154 | "of:0000000000000207/3" : { 155 | "interfaces" : [ 156 | { 157 | "name": "h1-eth0", 158 | "ips" : [ "10.11.1.254/24" ], 159 | "vlan-untagged": 1000 160 | } 161 | ] 162 | }, 163 | "device:bmv2-s208/3" : { 164 | "interfaces" : [ 165 | { 166 | "name": "h2-eth0", 167 | "ips" : [ "10.11.2.254/24" ], 168 | "vlan-untagged": 1002 169 | } 170 | ] 171 | } 172 | }, 173 | "devices" : { 174 | "of:0000000000000203" : { 175 | "segmentrouting" : { 176 | "name" : "ovs-s203", 177 | "ipv4NodeSid" : 203, 178 | "ipv4Loopback" : "192.168.0.203", 179 | "routerMac" : "00:00:00:00:02:03", 180 | "isEdgeRouter" : true, 181 | "pairDeviceId" : "device:bmv2-s204", 182 | "pairLocalPort" : 5, 183 | "adjacencySids" : [] 184 | }, 185 | "basic" : { 186 | "driver" : "ofdpa-ovs" 187 | } 188 | }, 189 | "device:bmv2-s204" : { 190 | "segmentrouting" : { 191 | "name" : "bmv2-s204", 192 | "ipv4NodeSid" : 204, 193 | "ipv4Loopback" : "192.168.0.204", 194 | "routerMac" : "00:00:00:00:02:03", 195 | "isEdgeRouter" : true, 196 | "pairDeviceId" : "of:0000000000000203", 197 | "pairLocalPort" : 5, 198 | "adjacencySids" : [] 199 | } 200 | }, 201 | "of:0000000000000205" : { 202 | "segmentrouting" : { 203 | "name" : "ovs-s205", 204 | "ipv4NodeSid" : 205, 205 | "ipv4Loopback" : "192.168.0.205", 206 | "routerMac" : "00:00:00:00:02:05", 207 | "isEdgeRouter" : true, 208 | "adjacencySids" : [], 209 | "pairDeviceId": "of:0000000000000206", 210 | "pairLocalPort": 5 211 | }, 212 | "basic" : { 213 | "driver" : "ofdpa-ovs" 214 | } 215 | }, 216 | "of:0000000000000206" : { 217 | "segmentrouting" : { 218 | "name" : "ovs-s206", 219 | "ipv4NodeSid" : 206, 220 | "ipv4Loopback" : "192.168.0.206", 221 | "routerMac" : "00:00:00:00:02:05", 222 | "isEdgeRouter" : true, 223 | "adjacencySids" : [], 224 | "pairDeviceId": "of:0000000000000205", 225 | "pairLocalPort": 5 226 | }, 227 | "basic" : { 228 | "driver" : "ofdpa-ovs" 229 | } 230 | }, 231 | "device:bmv2-s226" : { 232 | "segmentrouting" : { 233 | "name" : "ovs-s226", 234 | "ipv4NodeSid" : 226, 235 | "ipv4Loopback" : "192.168.0.226", 236 | "routerMac" : "00:00:00:00:02:26", 237 | "isEdgeRouter" : false, 238 | "adjacencySids" : [] 239 | } 240 | }, 241 | "of:0000000000000227" : { 242 | "segmentrouting" : { 243 | "name" : "ovs-s227", 244 | "ipv4NodeSid" : 227, 245 | "ipv4Loopback" : "192.168.0.227", 246 | "routerMac" : "00:00:00:00:02:27", 247 | "isEdgeRouter" : false, 248 | "adjacencySids" : [] 249 | }, 250 | "basic" : { 251 | "driver" : "ofdpa-ovs" 252 | } 253 | }, 254 | 255 | "of:0000000000000207" : { 256 | "segmentrouting" : { 257 | "name" : "ovs-s207", 258 | "ipv4NodeSid" : 207, 259 | "ipv4Loopback" : "192.168.0.207", 260 | "routerMac" : "00:00:00:00:02:07", 261 | "isEdgeRouter" : true, 262 | "adjacencySids" : [] 263 | }, 264 | "basic" : { 265 | "driver" : "ofdpa-ovs" 266 | } 267 | }, 268 | "device:bmv2-s208" : { 269 | "segmentrouting" : { 270 | "name" : "bmv2-s208", 271 | "ipv4NodeSid" : 208, 272 | "ipv4Loopback" : "192.168.0.208", 273 | "routerMac" : "00:00:00:00:02:08", 274 | "isEdgeRouter" : true, 275 | "adjacencySids" : [] 276 | } 277 | }, 278 | "device:bmv2-s246" : { 279 | "segmentrouting" : { 280 | "name" : "bmv2-s246", 281 | "ipv4NodeSid" : 246, 282 | "ipv4Loopback" : "192.168.0.246", 283 | "routerMac" : "00:00:00:00:02:46", 284 | "isEdgeRouter" : false, 285 | "adjacencySids" : [] 286 | } 287 | }, 288 | "device:bmv2-s247" : { 289 | "segmentrouting" : { 290 | "name" : "bmv2-s247", 291 | "ipv4NodeSid" : 247, 292 | "ipv4Loopback" : "192.168.0.247", 293 | "routerMac" : "00:00:00:00:02:47", 294 | "isEdgeRouter" : false, 295 | "adjacencySids" : [] 296 | } 297 | } 298 | }, 299 | "apps" : { 300 | "org.onosproject.dhcprelay" : { 301 | "default": [ 302 | { 303 | "dhcpServerConnectPoint": "of:0000000000000205/9", 304 | "serverIps": ["10.0.3.253"] 305 | } 306 | ] 307 | } 308 | }, 309 | "hosts": { 310 | "00:DD:00:00:00:01/None": { 311 | "basic": { 312 | "name": "Host 1", 313 | "latitude": "49", 314 | "longitude": "-105" 315 | } 316 | }, 317 | "00:DD:00:00:00:02/None": { 318 | "basic": { 319 | "name": "Host 2", 320 | "latitude": "49", 321 | "longitude": "-95" 322 | } 323 | }, 324 | "00:AA:00:00:00:03/None": { 325 | "basic": { 326 | "name": "Host 3", 327 | "latitude": "33", 328 | "longitude": "-110" 329 | } 330 | }, 331 | "00:AA:00:00:00:04/None": { 332 | "basic": { 333 | "name": "Host 4", 334 | "latitude": "33", 335 | "longitude": "-105" 336 | } 337 | }, 338 | "00:AA:00:00:00:05/None": { 339 | "basic": { 340 | "name": "Host 5", 341 | "latitude": "33", 342 | "longitude": "-95" 343 | } 344 | }, 345 | "00:AA:00:00:00:06/None": { 346 | "basic": { 347 | "name": "Host 6", 348 | "latitude": "33", 349 | "longitude": "-92.5" 350 | } 351 | }, 352 | "00:CC:00:00:00:01/None": { 353 | "basic": { 354 | "name": "Dual Homed Host 1", 355 | "latitude": "31", 356 | "longitude": "-107.5" 357 | } 358 | }, 359 | "00:CC:00:00:00:02/None": { 360 | "basic": { 361 | "name": "Dual Homed Host 2", 362 | "latitude": "31", 363 | "longitude": "-92.5" 364 | } 365 | }, 366 | "00:99:00:00:00:01/None": { 367 | "basic": { 368 | "name": "DHCP Server", 369 | "latitude": "33", 370 | "longitude": "-98" 371 | } 372 | }, 373 | "00:88:00:00:00:01/None": { 374 | "basic": { 375 | "name": "Upstream Router 1", 376 | "latitude": "39", 377 | "longitude": "-85", 378 | "uiType": "m_router" 379 | } 380 | }, 381 | "00:88:00:00:00:02/None": { 382 | "basic": { 383 | "name": "Upstream Router 2", 384 | "latitude": "37", 385 | "longitude": "-85", 386 | "uiType": "m_router" 387 | } 388 | }, 389 | 390 | "00:88:00:00:00:03/110": { 391 | "basic": { 392 | "name": "Quagga 1", 393 | "latitude": "35", 394 | "longitude": "-98", 395 | "uiType": "m_bgpSpeaker" 396 | } 397 | }, 398 | "00:88:00:00:00:04/160": { 399 | "basic": { 400 | "name": "Quagga 2", 401 | "latitude": "33", 402 | "longitude": "-90", 403 | "uiType": "m_bgpSpeaker" 404 | } 405 | } 406 | } 407 | } 408 | -------------------------------------------------------------------------------- /trellis/trellis_hybrid_v4.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | import argparse 3 | import sys 4 | import os 5 | import json 6 | import random 7 | import urllib2 8 | sys.path.append('..') 9 | from mininet.topo import Topo 10 | from mininet.cli import CLI 11 | from mininet.log import setLogLevel 12 | from mininet.node import OVSBridge, OVSSwitch 13 | from ipaddress import ip_network 14 | from routinglib import BgpRouter 15 | from routinglib import RoutedHost, UserNAT 16 | from trellislib import DhcpClient, DhcpServer 17 | from trellislib import DualHomedDhcpClient 18 | from trellislib import get_mininet, set_up_zebra_config 19 | from functools import partial 20 | 21 | PIPECONF_ID = 'org.onosproject.pipelines.fabric' 22 | 23 | 24 | class Trellis(Topo): 25 | """Trellis HAG topology with both OVS and BMV2 switches""" 26 | 27 | p4_cls = None 28 | 29 | def get_p4_switch_args(self, name): 30 | assert Trellis.p4_cls is not None 31 | return dict( 32 | name=name, 33 | cls=Trellis.p4_cls, 34 | pipeconf=PIPECONF_ID, 35 | portcfg=True, 36 | onosdevid="device:" + name) 37 | 38 | def __init__(self, *args, **kwargs): 39 | Topo.__init__(self, *args, **kwargs) 40 | 41 | # Spines 42 | s226 = self.addSwitch(latitude="39", longitude="-105", 43 | **self.get_p4_switch_args('bmv2-s226')) 44 | s227 = self.addSwitch('ovs-s227', dpid='227', latitude="39",longitude="-95") 45 | 46 | # Leaves 47 | s203 = self.addSwitch('ovs-s203', dpid='203', latitude="35",longitude="-110") 48 | s204 = self.addSwitch(latitude="35", longitude="-105", 49 | **self.get_p4_switch_args('bmv2-s204')) 50 | s205 = self.addSwitch('ovs-s205', dpid='205', latitude="35",longitude="-95") 51 | s206 = self.addSwitch('ovs-s206', dpid='206', latitude="35",longitude="-90") 52 | 53 | # Leaf-Spine Links 54 | self.addLink(s226, s203) 55 | self.addLink(s226, s203) 56 | self.addLink(s226, s204) 57 | self.addLink(s226, s204) 58 | self.addLink(s226, s205) 59 | self.addLink(s226, s205) 60 | self.addLink(s226, s206) 61 | self.addLink(s226, s206) 62 | self.addLink(s227, s203) 63 | self.addLink(s227, s203) 64 | self.addLink(s227, s204) 65 | self.addLink(s227, s204) 66 | self.addLink(s227, s205) 67 | self.addLink(s227, s205) 68 | self.addLink(s227, s206) 69 | self.addLink(s227, s206) 70 | 71 | # Leaf-Leaf Links 72 | self.addLink(s203, s204) 73 | self.addLink(s205, s206) 74 | 75 | # NOTE avoid using 10.0.1.0/24 which is the default subnet of quaggas 76 | # NOTE avoid using 00:00:00:00:00:xx which is the default mac of host behind upstream router 77 | # IPv4 Hosts 78 | h3 = self.addHost('h3', cls=DhcpClient, mac='00:aa:00:00:00:03') 79 | h4 = self.addHost('h4', cls=DhcpClient, mac='00:aa:00:00:00:04') 80 | h5 = self.addHost('h5', cls=DhcpClient, mac='00:aa:00:00:00:05') 81 | h6 = self.addHost('h6', cls=DhcpClient, mac='00:aa:00:00:00:06') 82 | self.addLink(h3, s203) 83 | self.addLink(h4, s204) 84 | self.addLink(h5, s205) 85 | self.addLink(h6, s205) 86 | 87 | # Dual-homed IPv4 Host on 203-204 88 | dh1 = self.addHost('dh1', cls=DualHomedDhcpClient, mac='00:cc:00:00:00:01') 89 | self.addLink(dh1, s204) 90 | self.addLink(dh1, s203) 91 | 92 | # Dual-homed IPv4 Host for 205-206 93 | dh2 = self.addHost('dh2', cls=DualHomedDhcpClient, mac='00:cc:00:00:00:02') 94 | self.addLink(dh2, s205) 95 | self.addLink(dh2, s206) 96 | 97 | # DHCP server 98 | dhcp = self.addHost('dhcp', cls=DhcpServer, mac='00:99:00:00:00:01', 99 | ips=['10.0.3.253/24'], gateway='10.0.3.254', 100 | configFile='./dhcpd_hybrid_v4.conf') 101 | 102 | # Dataplane L2 plane switch (for DHCP servers) 103 | cs1 = self.addSwitch('cs1', cls=OVSBridge, datapath='user') 104 | self.addLink(cs1, s205) 105 | self.addLink(dhcp, cs1) 106 | 107 | # Control plane switch (for quagga fpm) 108 | cs0 = self.addSwitch('cs0', cls=OVSBridge, datapath='user') 109 | 110 | # Control plane NAT (for quagga fpm) 111 | nat = self.addHost('nat', cls=UserNAT, 112 | ip='172.16.0.1/24', 113 | subnet=str(ip_network(u'172.16.0.0/24')), inNamespace=False) 114 | self.addLink(cs0, nat) 115 | 116 | # Internal Quagga bgp1 117 | """ 118 | intfs = {'bgp1-eth0': [{'ipAddrs': ['10.0.1.2/24', '2000::102/120'], 'mac': '00:88:00:00:00:03', 'vlan': '110'}, 119 | {'ipAddrs': ['10.0.7.2/24', '2000::702/120'], 'mac': '00:88:00:00:00:03', 'vlan': '170'}], 120 | 'bgp1-eth1': {'ipAddrs': ['172.16.0.3/24']}} 121 | """ 122 | intfs = {'bgp1-eth0': {'ipAddrs': ['10.0.1.2/24'], 'mac': '00:88:00:00:00:03', 'vlan': '110'}, 123 | 'bgp1-eth1': {'ipAddrs': ['172.16.0.3/24']}} 124 | bgp1 = self.addHost('bgp1', cls=BgpRouter, 125 | interfaces=intfs, 126 | quaggaConfFile='./bgpdbgp1.conf', 127 | zebraConfFile='./zebradbgp1.conf') 128 | self.addLink(bgp1, s205) 129 | self.addLink(bgp1, cs0) 130 | 131 | # Internal Quagga bgp2 132 | """ 133 | intfs = {'bgp2-eth0': [{'ipAddrs': ['10.0.5.2/24', '2000::502/120'], 'mac': '00:88:00:00:00:04', 'vlan': '150'}, 134 | {'ipAddrs': ['10.0.6.2/24', '2000::602/120'], 'mac': '00:88:00:00:00:04', 'vlan': '160'}], 135 | 'bgp2-eth1': {'ipAddrs': ['172.16.0.4/24']}} 136 | """ 137 | intfs = {'bgp2-eth0': {'ipAddrs': ['10.0.6.2/24'], 'mac': '00:88:00:00:00:04', 'vlan': '160'}, 138 | 'bgp2-eth1': {'ipAddrs': ['172.16.0.4/24']}} 139 | bgp2 = self.addHost('bgp2', cls=BgpRouter, 140 | interfaces=intfs, 141 | quaggaConfFile='./bgpdbgp2.conf', 142 | zebraConfFile='./zebradbgp2.conf') 143 | self.addLink(bgp2, s206) 144 | self.addLink(bgp2, cs0) 145 | 146 | # External Quagga r1 147 | intfs = {'r1-eth0': {'ipAddrs': ['10.0.1.1/24'], 'mac': '00:88:00:00:00:01'}, 148 | 'r1-eth1': {'ipAddrs': ['10.0.99.1/16']}} 149 | r1 = self.addHost('r1', cls=BgpRouter, 150 | interfaces=intfs, 151 | quaggaConfFile='./bgpdr1.conf') 152 | self.addLink(r1, s205) 153 | #self.addLink(r1, s206) 154 | 155 | # External IPv4 Host behind r1 156 | rh1 = self.addHost('rh1', cls=RoutedHost, ips=['10.0.99.2/24'], gateway='10.0.99.1') 157 | self.addLink(r1, rh1) 158 | 159 | # External Quagga r2 160 | intfs = {'r2-eth0': {'ipAddrs': ['10.0.6.1/24'], 'mac': '00:88:00:00:00:02'}, 161 | 'r2-eth1': {'ipAddrs': ['10.0.99.1/16']}} 162 | r2 = self.addHost('r2', cls=BgpRouter, 163 | interfaces=intfs, 164 | quaggaConfFile='./bgpdr2.conf') 165 | self.addLink(r2, s206) 166 | #self.addLink(r2, s205) 167 | 168 | # External IPv4 Host behind r2 169 | rh2 = self.addHost('rh2', cls=RoutedHost, ips=['10.0.99.2/24'], gateway='10.0.99.1') 170 | self.addLink(r2, rh2) 171 | 172 | # ----- Secondary fabric ----- 173 | 174 | # Spines(HAG) 175 | s246 = self.addSwitch(latitude="44", longitude="-105", 176 | **self.get_p4_switch_args('bmv2-s246')) 177 | s247 = self.addSwitch(latitude="44", longitude="-95", 178 | **self.get_p4_switch_args('bmv2-s247')) 179 | 180 | # Leaves(DAAS) 181 | s207 = self.addSwitch('ovs-s207', dpid='207', latitude="47", longitude="-105") 182 | s208 = self.addSwitch(latitude="47", longitude="-95", 183 | **self.get_p4_switch_args('bmv2-s208')) 184 | 185 | # HAG-DAAS Links 186 | self.addLink(s246, s207) 187 | self.addLink(s246, s208) 188 | self.addLink(s247, s207) 189 | self.addLink(s247, s208) 190 | 191 | # HAG - Spine Links 192 | self.addLink(s246, s226) 193 | self.addLink(s247, s227) 194 | 195 | # IPv4 Hosts - RPDs 196 | h1 = self.addHost('h1', cls=DhcpClient, mac='00:dd:00:00:00:01') 197 | h2 = self.addHost('h2', cls=DhcpClient, mac='00:dd:00:00:00:02') 198 | self.addLink(h1, s207) 199 | self.addLink(h2, s208) 200 | 201 | 202 | topos = { 'trellis' : Trellis } 203 | 204 | class ONOSOVSSwitch( OVSSwitch ): 205 | """OVSSwitch that generates and pushes config to ONOS""" 206 | 207 | def __init__(self, name, netcfg=True, **kwargs): 208 | OVSSwitch.__init__(self, name, **kwargs) 209 | self.netcfg = netcfg in (True, '1', 'true', 'True') 210 | self.netcfgfile = '/tmp/ovs-%s-netcfg.json' % self.name 211 | self.onosDeviceId = 'of:%s' % self.dpid 212 | self.longitude = kwargs['longitude'] if 'longitude' in kwargs else None 213 | self.latitude = kwargs['latitude'] if 'latitude' in kwargs else None 214 | 215 | @staticmethod 216 | def controllerIp(controllers): 217 | try: 218 | clist = controllers[0].nodes() 219 | except AttributeError: 220 | clist = controllers 221 | assert len(clist) > 0 222 | return random.choice(clist).IP() 223 | 224 | def start(self, controllers): 225 | """ 226 | Starts the switch, then notifies ONOS about the new device via Netcfg. 227 | """ 228 | OVSSwitch.start(self, controllers) 229 | 230 | if not self.netcfg: 231 | # Do not push config to ONOS. 232 | return 233 | 234 | controllerIP = self.controllerIp(controllers) 235 | 236 | basicCfg = { 237 | "name": self.name, 238 | "driver": "ofdpa-ovs" 239 | } 240 | 241 | if self.longitude and self.latitude: 242 | basicCfg["longitude"] = self.longitude 243 | basicCfg["latitude"] = self.latitude 244 | 245 | cfgData = { 246 | "devices": { 247 | self.onosDeviceId: { "basic": basicCfg } 248 | } 249 | } 250 | with open(self.netcfgfile, 'w') as fp: 251 | json.dump(cfgData, fp, indent=4) 252 | 253 | # Build netcfg URL 254 | url = 'http://%s:8181/onos/v1/network/configuration/' % controllerIP 255 | # Instantiate password manager for HTTP auth 256 | pm = urllib2.HTTPPasswordMgrWithDefaultRealm() 257 | user = os.environ['ONOS_WEB_USER'] if 'ONOS_WEB_USER' in os.environ else 'onos' 258 | password = os.environ['ONOS_WEB_PASS'] if 'ONOS_WEB_PASS' in os.environ else 'rocks' 259 | pm.add_password(None, url, user, password) 260 | urllib2.install_opener(urllib2.build_opener(urllib2.HTTPBasicAuthHandler(pm))) 261 | try: 262 | # Push config data to controller 263 | req = urllib2.Request(url, json.dumps(cfgData), 264 | {'Content-Type': 'application/json'}) 265 | f = urllib2.urlopen(req) 266 | print f.read() 267 | f.close() 268 | except urllib2.URLError as e: 269 | warn("*** WARN: unable to push config to ONOS (%s)\n" % e.reason) 270 | 271 | if __name__ == "__main__": 272 | setLogLevel('info') 273 | 274 | parser = argparse.ArgumentParser(description="Trellis Arguments") 275 | parser.add_argument("-c", "--controllers", help = "Comma Separated List of ONOS controllers", 276 | required = True, default = "") 277 | parser.add_argument("-a", "--p4runtime-agent", help = "P4Runtime agent to use on Bmv2 devices (pi or stratum)", 278 | required = False, default = "pi") 279 | arguments = parser.parse_args() 280 | agent = arguments.p4runtime_agent 281 | 282 | if agent == "stratum": 283 | from stratum import ONOSStratumBmv2Switch 284 | Trellis.p4_cls = ONOSStratumBmv2Switch 285 | else: 286 | from bmv2 import ONOSBmv2Switch 287 | Trellis.p4_cls = ONOSBmv2Switch 288 | 289 | set_up_zebra_config(arguments.controllers) 290 | 291 | topo = Trellis() 292 | switch = partial(ONOSOVSSwitch, protocols='OpenFlow13', datapath='user') 293 | net = get_mininet(arguments, topo, switch) 294 | 295 | net.start() 296 | CLI(net) 297 | net.stop() 298 | -------------------------------------------------------------------------------- /trellis/trellis_mcast.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | import sys 4 | sys.path.append('..') 5 | from mininet.topo import Topo 6 | from mininet.cli import CLI 7 | from mininet.log import setLogLevel 8 | from mininet.node import RemoteController, OVSBridge, Host, OVSSwitch 9 | from mininet.link import TCLink 10 | from mininet.nodelib import NAT 11 | from ipaddress import ip_network 12 | from routinglib import BgpRouter 13 | from routinglib import RoutedHost, RoutedHost6 14 | from trellislib import DhcpClient, Dhcp6Client, Dhcp4and6Client, DhcpRelay, DhcpServer, Dhcp6Server 15 | from trellislib import DualHomedDhcpClient 16 | from trellislib import DualHomedDhcp4and6Client 17 | from trellislib import get_mininet, parse_trellis_args, set_up_zebra_config, get_mac_from_int 18 | from functools import partial 19 | 20 | MAX_AGGREGATION = 4 21 | MAX_ACCESS = 48 22 | 23 | class Trellis( Topo ): 24 | """Trellis HAG topology""" 25 | 26 | def __init__( self, *args, **kwargs ): 27 | Topo.__init__( self, *args, **kwargs ) 28 | 29 | # Spines 30 | s226 = self.addSwitch('s226', dpid='226') 31 | s227 = self.addSwitch('s227', dpid='227') 32 | 33 | # Leaves 34 | s203 = self.addSwitch('s203', dpid='203') 35 | s204 = self.addSwitch('s204', dpid='204') 36 | s205 = self.addSwitch('s205', dpid='205') 37 | s206 = self.addSwitch('s206', dpid='206') 38 | 39 | # Leaf-Spine Links 40 | self.addLink(s226, s203) 41 | self.addLink(s226, s203) 42 | self.addLink(s226, s204) 43 | self.addLink(s226, s204) 44 | self.addLink(s226, s205) 45 | self.addLink(s226, s205) 46 | self.addLink(s226, s206) 47 | self.addLink(s226, s206) 48 | self.addLink(s227, s203) 49 | self.addLink(s227, s203) 50 | self.addLink(s227, s204) 51 | self.addLink(s227, s204) 52 | self.addLink(s227, s205) 53 | self.addLink(s227, s205) 54 | self.addLink(s227, s206) 55 | self.addLink(s227, s206) 56 | 57 | # Leaf-Leaf Links 58 | self.addLink(s203, s204) 59 | self.addLink(s205, s206) 60 | 61 | # NOTE avoid using 10.0.1.0/24 which is the default subnet of quaggas 62 | # NOTE avoid using 00:00:00:00:00:xx which is the default mac of host behind upstream router 63 | # IPv4 Hosts 64 | h1 = self.addHost('h1', cls=DhcpClient, mac='00:aa:00:00:00:01') 65 | h2 = self.addHost('h2', cls=DhcpClient, mac='00:aa:00:00:00:02') 66 | h3 = self.addHost('h3', cls=DhcpClient, mac='00:aa:00:00:00:03') 67 | h4 = self.addHost('h4', cls=DhcpClient, mac='00:aa:00:00:00:04') 68 | h5 = self.addHost('h5', cls=DhcpClient, mac='00:aa:00:00:00:05') 69 | self.addLink(h1, s204) 70 | self.addLink(h2, s204) 71 | self.addLink(h3, s205) 72 | self.addLink(h4, s205) 73 | self.addLink(h5, s203) 74 | 75 | # IPv6 Hosts 76 | h1v6 = self.addHost('h1v6', cls=Dhcp6Client, mac='00:bb:00:00:00:01', sleep=0.250) 77 | h2v6 = self.addHost('h2v6', cls=Dhcp6Client, mac='00:bb:00:00:00:02', sleep=0.250) 78 | h3v6 = self.addHost('h3v6', cls=Dhcp6Client, mac='00:bb:00:00:00:03', sleep=0.250) 79 | h4v6 = self.addHost('h4v6', cls=Dhcp6Client, mac='00:bb:00:00:00:04', sleep=0.250) 80 | h5v6 = self.addHost('h5v6', cls=Dhcp6Client, mac='00:bb:00:00:00:05', sleep=0.250) 81 | self.addLink(h1v6, s204) 82 | self.addLink(h2v6, s204) 83 | self.addLink(h3v6, s205) 84 | self.addLink(h4v6, s205) 85 | self.addLink(h5v6, s203) 86 | 87 | # Dual-homed IPv4 and IPv6 Host on 203-204 88 | dh1 = self.addHost('dh1', cls=DualHomedDhcp4and6Client, mac='00:cc:00:00:00:01', sleep=0.250) 89 | self.addLink(dh1, s204) 90 | self.addLink(dh1, s203) 91 | 92 | # DHCP server 93 | dhcp = self.addHost('dhcp', cls=DhcpServer, mac='00:99:00:00:00:01', ips=['10.0.3.253/24'], gateway='10.0.3.254') 94 | 95 | # DHCPv6 server 96 | dhcp6 = self.addHost('dhcp6', cls=Dhcp6Server, mac='00:99:66:00:00:01', ips=['2000::3fd/120'], gateway='2000::3ff') 97 | 98 | # Dataplane L2 plane switch (for DHCP servers) 99 | cs1 = self.addSwitch('cs1', cls=OVSBridge) 100 | self.addLink(cs1, s205) 101 | self.addLink(dhcp, cs1) 102 | self.addLink(dhcp6, cs1) 103 | 104 | # Control plane switch (for quagga fpm) 105 | cs0 = self.addSwitch('cs0', cls=OVSBridge) 106 | 107 | # Control plane NAT (for quagga fpm) 108 | nat = self.addHost('nat', cls=NAT, 109 | ip='172.16.0.1/12', 110 | subnet=str(ip_network(u'172.16.0.0/12')), inNamespace=False) 111 | self.addLink(cs0, nat) 112 | 113 | # Internal Quagga bgp1 114 | """ 115 | intfs = {'bgp1-eth0': [{'ipAddrs': ['10.0.1.2/24', '2000::102/120'], 'mac': '00:88:00:00:00:03', 'vlan': '110'}, 116 | {'ipAddrs': ['10.0.7.2/24', '2000::702/120'], 'mac': '00:88:00:00:00:03', 'vlan': '170'}], 117 | 'bgp1-eth1': {'ipAddrs': ['172.16.0.3/12']}} 118 | """ 119 | intfs = {'bgp1-eth0': {'ipAddrs': ['10.0.1.2/24', '2000::102/120'], 'mac': '00:88:00:00:00:03', 'vlan': '110'}, 120 | 'bgp1-eth1': {'ipAddrs': ['172.16.0.3/12']}} 121 | bgp1 = self.addHost('bgp1', cls=BgpRouter, 122 | interfaces=intfs, 123 | quaggaConfFile='./bgpdbgp1.conf', 124 | zebraConfFile='./zebradbgp1.conf') 125 | self.addLink(bgp1, s205) 126 | self.addLink(bgp1, cs0) 127 | 128 | # Internal Quagga bgp2 129 | """ 130 | intfs = {'bgp2-eth0': [{'ipAddrs': ['10.0.5.2/24', '2000::502/120'], 'mac': '00:88:00:00:00:04', 'vlan': '150'}, 131 | {'ipAddrs': ['10.0.6.2/24', '2000::602/120'], 'mac': '00:88:00:00:00:04', 'vlan': '160'}], 132 | 'bgp2-eth1': {'ipAddrs': ['172.16.0.4/12']}} 133 | """ 134 | intfs = {'bgp2-eth0': {'ipAddrs': ['10.0.6.2/24', '2000::602/120'], 'mac': '00:88:00:00:00:04', 'vlan': '160'}, 135 | 'bgp2-eth1': {'ipAddrs': ['172.16.0.4/12']}} 136 | bgp2 = self.addHost('bgp2', cls=BgpRouter, 137 | interfaces=intfs, 138 | quaggaConfFile='./bgpdbgp2.conf', 139 | zebraConfFile='./zebradbgp2.conf') 140 | self.addLink(bgp2, s206) 141 | self.addLink(bgp2, cs0) 142 | 143 | # External Quagga r1 144 | intfs = {'r1-eth0': {'ipAddrs': ['10.0.1.1/24', '2000::101/120'], 'mac': '00:88:00:00:00:01'}, 145 | #'r1-eth1': {'ipAddrs': ['10.0.5.1/24', '2000::501/120'], 'mac': '00:88:00:00:00:11'}, 146 | 'r1-eth1': {'ipAddrs': ['10.0.99.1/16']}, 147 | 'r1-eth2': {'ipAddrs': ['2000::9901/120']}, 148 | 'r1-eth3': {'ipAddrs': ['2000::7701/120']}} 149 | r1 = self.addHost('r1', cls=BgpRouter, 150 | interfaces=intfs, 151 | quaggaConfFile='./bgpdr1.conf') 152 | self.addLink(r1, s205) 153 | 154 | # External IPv4 Host behind r1 155 | rh1 = self.addHost('rh1', cls=RoutedHost, ips=['10.0.99.2/24'], gateway='10.0.99.1') 156 | self.addLink(r1, rh1) 157 | 158 | # External IPv6 Host behind r1 159 | rh1v6 = self.addHost('rh1v6', cls=RoutedHost, ips=['2000::9902/120'], gateway='2000::9901') 160 | self.addLink(r1, rh1v6) 161 | 162 | # Another external IPv6 Host behind r1 163 | rh11v6 = self.addHost('rh11v6', cls=RoutedHost, ips=['2000::7702/120'], gateway='2000::7701') 164 | self.addLink(r1, rh11v6) 165 | 166 | # External Quagga r2 167 | intfs = {'r2-eth0': {'ipAddrs': ['10.0.6.1/24', '2000::601/120'], 'mac': '00:88:00:00:00:02'}, 168 | #'r2-eth1': {'ipAddrs': ['10.0.7.1/24', '2000::701/120'], 'mac': '00:88:00:00:00:22'}, 169 | 'r2-eth1': {'ipAddrs': ['10.0.99.1/16']}, 170 | 'r2-eth2': {'ipAddrs': ['2000::9901/120']}, 171 | 'r2-eth3': {'ipAddrs': ['2000::8801/120']}} 172 | r2 = self.addHost('r2', cls=BgpRouter, 173 | interfaces=intfs, 174 | quaggaConfFile='./bgpdr2.conf') 175 | self.addLink(r2, s206) 176 | 177 | # External IPv4 Host behind r2 178 | rh2 = self.addHost('rh2', cls=RoutedHost, ips=['10.0.99.2/24'], gateway='10.0.99.1') 179 | self.addLink(r2, rh2) 180 | 181 | # External IPv6 Host behind r2 182 | rh2v6 = self.addHost('rh126', cls=RoutedHost, ips=['2000::9902/120'], gateway='2000::9901') 183 | self.addLink(r2, rh2v6) 184 | 185 | # Another external IPv6 Host behind r1 186 | rh22v6 = self.addHost('rh22v6', cls=RoutedHost, ips=['2000::8802/120'], gateway='2000::8801') 187 | self.addLink(r2, rh22v6) 188 | 189 | # Dual-homed IPv4 Host for 205-206 190 | dh2 = self.addHost('dh2', cls=DualHomedDhcpClient, mac='00:cc:00:00:00:02') 191 | self.addLink(dh2, s205) 192 | self.addLink(dh2, s206) 193 | 194 | # ----- Secondary fabric ----- 195 | 196 | # Spines(HAG) 197 | s246 = self.addSwitch('s246', dpid='246') 198 | s247 = self.addSwitch('s247', dpid='247') 199 | 200 | # HAG - Spine Links 201 | self.addLink(s246, s226) 202 | self.addLink(s247, s227) 203 | 204 | # Access network - aggregation switches and access devices 205 | aggregation = int(args[0]) 206 | aggregation = min(max(0, aggregation), MAX_AGGREGATION) 207 | for i in range(0, aggregation): 208 | # Adding the aggregation switch 209 | aggregation_dev = self.addSwitch('s%d' % (i + 1) , dpid='%s' % (i + 1)) 210 | # Adding MAX_ACCESS access devices 211 | for j in range (1, MAX_ACCESS + 1): 212 | mac_int = j + (MAX_ACCESS * i) 213 | mac = get_mac_from_int(mac_int) 214 | # Half are IPv6 and half are IPv4 215 | if j % 2 == 0: 216 | access_dev = self.addHost('acc%d' % mac_int, cls=Dhcp6Client, mac=mac, sleep=0.250) 217 | else: 218 | access_dev = self.addHost('acc%d' % mac_int, cls=DhcpClient, mac=mac) 219 | self.addLink(aggregation_dev, access_dev) 220 | # HAG - Aggregation Links 221 | self.addLink(s246, aggregation_dev) 222 | self.addLink(s247, aggregation_dev) 223 | 224 | topos = { 'trellis' : Trellis } 225 | 226 | if __name__ == "__main__": 227 | setLogLevel('info') 228 | arguments = parse_trellis_args() 229 | 230 | topo = Trellis(arguments.aggregation) 231 | switch = partial(OVSSwitch, protocols='OpenFlow13') 232 | set_up_zebra_config(arguments.controllers) 233 | net = get_mininet(arguments, topo, switch) 234 | 235 | net.start() 236 | CLI(net) 237 | net.stop() 238 | -------------------------------------------------------------------------------- /trellis/trellis_mcast_netcfg_gen.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/python 2 | 3 | import json 4 | 5 | # It contains the fixed parts of the netcfg. 6 | # In this case, they are the ports of the leafs 7 | # hosts attached to the leafs. These are parts 8 | # that at the moment we don't need to scale 9 | netcfg = {} 10 | 11 | # Base latitude and longitude for access devices 12 | groups_cord = { 13 | "0" : [36, -106], 14 | "1" : [36, -110], 15 | "2" : [36, -114], 16 | "3" : [36, -118] 17 | } 18 | 19 | # Groups, host per groups and networks for each access device 20 | groups = 4 21 | hosts_per_group = 48 22 | networks = (("10.100.1.254/24", "2002::1ff/120", 100, 200), \ 23 | ("10.100.2.254/24", "2002::2ff/120", 101, 201), \ 24 | ("10.100.3.254/24", "2002::3ff/120", 102, 202), \ 25 | ("10.100.4.254/24", "2002::4ff/120", 103, 203), ) 26 | 27 | def generateDpid(device): 28 | dpid = hex( int( device ) )[ 2: ] 29 | return '0' * ( 16 - len( dpid ) ) + dpid 30 | 31 | # Generate ports config 32 | def generate_port_cfg(host, device, networks): 33 | device_index = device + 1 34 | port_index = host + 1 35 | dpid = generateDpid(device_index) 36 | dpid_port = 'of:%s/%s' %(dpid, port_index) 37 | netcfg['ports'][dpid_port] = {} 38 | interfaces = [] 39 | interface = {} 40 | ips = [] 41 | network = "" 42 | vlan = "" 43 | if port_index % 2 == 0: 44 | network = networks[1] 45 | vlan = networks[3] 46 | else: 47 | network = networks[0] 48 | vlan = networks[2] 49 | ips.append(network) 50 | interface['ips'] = ips 51 | interface['vlan-untagged'] = vlan 52 | interfaces.append(interface) 53 | netcfg['ports'][dpid_port]["interfaces"] = interfaces 54 | 55 | # Generate hosts coordinate 56 | def generate_host_cfg(mac, index, layer, group, counter): 57 | lat = groups_cord[str(group)][0] - layer 58 | lon = index + groups_cord[str(group)][1] 59 | name = "%s%d" %("acc", counter + 1) 60 | data = { 61 | "basic" : {} 62 | } 63 | data["basic"]["name"] = name 64 | data["basic"]["latitude"] = float(lat) 65 | data["basic"]["longitude"] = float(lon) 66 | netcfg["hosts"]["%s/-1" % mac] = data 67 | 68 | # Read initial netcfg from file 69 | with open('trellis_mcast_netcfg_gen.json') as json_file: 70 | netcfg = json.load(json_file) 71 | 72 | # Main function 73 | counter = 0 74 | for g in range(0, groups): 75 | index = 0 76 | layer = 0 77 | for h in range(0, hosts_per_group): 78 | mac = hex(counter + 1)[2:] 79 | mac = '0' * ( 12 - len( mac ) ) + mac 80 | mac = ':'.join(s.encode('hex') for s in mac.decode('hex')) 81 | index = counter % 3 82 | if index == 0 : 83 | layer = layer + 1 84 | generate_port_cfg(h, g, networks[g]) 85 | generate_host_cfg(mac, index, layer, g, counter) 86 | counter = counter + 1 87 | 88 | # Dump the netcfg on file 89 | with open('data.txt', 'w') as outfile: 90 | json.dump(netcfg, outfile) 91 | 92 | -------------------------------------------------------------------------------- /trellis/trellis_remote_dhcp.json: -------------------------------------------------------------------------------- 1 | { 2 | "ports" : { 3 | "of:0000000000000204/3" : { 4 | "interfaces" : [ 5 | { 6 | "ips" : [ "10.0.2.254/24" ], 7 | "vlan-untagged": 20 8 | } 9 | ] 10 | }, 11 | "of:0000000000000204/4" : { 12 | "interfaces" : [ 13 | { 14 | "ips" : [ "10.0.2.254/24" ], 15 | "vlan-untagged": 20 16 | } 17 | ] 18 | }, 19 | "of:0000000000000204/5" : { 20 | "interfaces" : [ 21 | { 22 | "ips" : [ "2000::2ff/120" ], 23 | "vlan-untagged": 40 24 | } 25 | ] 26 | }, 27 | "of:0000000000000204/6" : { 28 | "interfaces" : [ 29 | { 30 | "ips" : [ "2000::2ff/120" ], 31 | "vlan-untagged": 40 32 | } 33 | ] 34 | }, 35 | "of:0000000000000205/3" : { 36 | "interfaces" : [ 37 | { 38 | "ips" : [ "10.0.3.254/24" ], 39 | "vlan-untagged": 30 40 | } 41 | ] 42 | }, 43 | "of:0000000000000205/4" : { 44 | "interfaces" : [ 45 | { 46 | "ips" : [ "10.0.3.254/24" ], 47 | "vlan-untagged": 30 48 | } 49 | ] 50 | }, 51 | "of:0000000000000205/5" : { 52 | "interfaces" : [ 53 | { 54 | "ips" : [ "2000::3ff/120" ], 55 | "vlan-untagged": 50 56 | } 57 | ] 58 | }, 59 | "of:0000000000000205/6" : { 60 | "interfaces" : [ 61 | { 62 | "ips" : [ "2000::3ff/120" ], 63 | "vlan-untagged": 50 64 | } 65 | ] 66 | }, 67 | "of:0000000000000205/7" : { 68 | "interfaces" : [ 69 | { 70 | "ips" : [ "10.0.1.254/24", "2000::1ff/120" ], 71 | "vlan-untagged": 10 72 | } 73 | ] 74 | }, 75 | "of:0000000000000205/8" : { 76 | "interfaces" : [ 77 | { 78 | "ips" : [ "10.0.1.254/24", "2000::1ff/120" ], 79 | "vlan-untagged": 10 80 | } 81 | ] 82 | } 83 | }, 84 | "devices" : { 85 | "of:0000000000000204" : { 86 | "segmentrouting" : { 87 | "name" : "s204", 88 | "ipv4NodeSid" : 204, 89 | "ipv4Loopback" : "192.168.0.204", 90 | "ipv6NodeSid" : 214, 91 | "ipv6Loopback" : "2000::c0a8:0204", 92 | "routerMac" : "00:00:00:00:02:04", 93 | "isEdgeRouter" : true, 94 | "adjacencySids" : [] 95 | }, 96 | "basic" : { 97 | "name": "s204", 98 | "driver" : "ofdpa-ovs" 99 | } 100 | }, 101 | "of:0000000000000205" : { 102 | "segmentrouting" : { 103 | "name" : "s205", 104 | "ipv4NodeSid" : 205, 105 | "ipv4Loopback" : "192.168.0.205", 106 | "ipv6NodeSid" : 215, 107 | "ipv6Loopback" : "2000::c0a8:0205", 108 | "routerMac" : "00:00:00:00:02:05", 109 | "isEdgeRouter" : true, 110 | "adjacencySids" : [] 111 | }, 112 | "basic" : { 113 | "name": "s205", 114 | "driver" : "ofdpa-ovs" 115 | } 116 | }, 117 | "of:0000000000000226" : { 118 | "segmentrouting" : { 119 | "name" : "s226", 120 | "ipv4NodeSid" : 226, 121 | "ipv4Loopback" : "192.168.0.226", 122 | "ipv6NodeSid" : 236, 123 | "ipv6Loopback" : "2000::c0a8:0226", 124 | "routerMac" : "00:00:00:00:02:26", 125 | "isEdgeRouter" : false, 126 | "adjacencySids" : [] 127 | }, 128 | "basic" : { 129 | "name": "s226", 130 | "driver" : "ofdpa-ovs" 131 | } 132 | }, 133 | "of:0000000000000227" : { 134 | "segmentrouting" : { 135 | "name" : "s227", 136 | "ipv4NodeSid" : 227, 137 | "ipv4Loopback" : "192.168.0.227", 138 | "ipv6NodeSid" : 237, 139 | "ipv6Loopback" : "2000::c0a8:0227", 140 | "routerMac" : "00:00:00:00:02:27", 141 | "isEdgeRouter" : false, 142 | "adjacencySids" : [] 143 | }, 144 | "basic" : { 145 | "name": "s227", 146 | "driver" : "ofdpa-ovs" 147 | } 148 | } 149 | }, 150 | "hosts": { 151 | "00:bb:00:00:00:01/None": { 152 | "basic": { 153 | "ips": ["2000::201"], 154 | "locations": ["of:0000000000000204/5"] 155 | } 156 | }, 157 | "00:bb:00:00:00:02/None": { 158 | "basic": { 159 | "ips": ["2000::202"], 160 | "locations": ["of:0000000000000204/6"] 161 | } 162 | }, 163 | "00:bb:00:00:00:03/None": { 164 | "basic": { 165 | "ips": ["2000::301"], 166 | "locations": ["of:0000000000000205/5"] 167 | } 168 | }, 169 | "00:bb:00:00:00:04/None": { 170 | "basic": { 171 | "ips": ["2000::302"], 172 | "locations": ["of:0000000000000205/6"] 173 | } 174 | } 175 | }, 176 | "apps" : { 177 | "org.onosproject.dhcprelay" : { 178 | "default" : [ 179 | { 180 | "dhcpServerConnectPoint": "of:0000000000000205/8", 181 | "serverIps": ["10.0.99.3"], 182 | "gatewayIps": ["10.0.1.1"] 183 | } 184 | ], 185 | "indirect" : [ 186 | { 187 | "dhcpServerConnectPoint": "of:0000000000000205/8", 188 | "serverIps": ["10.0.99.3"], 189 | "gatewayIps": ["10.0.1.1"], 190 | "relayAgentIps": { 191 | "of:0000000000000204": { 192 | "ipv4": "10.0.4.254" 193 | } 194 | } 195 | } 196 | ] 197 | } 198 | } 199 | } 200 | -------------------------------------------------------------------------------- /trellis/trellis_remote_dhcp.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | import sys 4 | sys.path.append('..') 5 | from mininet.topo import Topo 6 | from mininet.net import Mininet 7 | from mininet.cli import CLI 8 | from mininet.log import setLogLevel 9 | from mininet.node import RemoteController, OVSBridge, Host, OVSSwitch 10 | from ipaddress import ip_network 11 | from routinglib import BgpRouter 12 | from routinglib import RoutedHost, UserNAT 13 | from trellislib import DhcpClient, DhcpServer, DhcpRelay 14 | from trellislib import get_mininet, parse_trellis_args, set_up_zebra_config 15 | from functools import partial 16 | 17 | class Trellis( Topo ): 18 | "Trellis basic topology" 19 | 20 | def __init__( self, *args, **kwargs ): 21 | Topo.__init__( self, *args, **kwargs ) 22 | 23 | # Spines 24 | s226 = self.addSwitch('s226', dpid='226') 25 | s227 = self.addSwitch('s227', dpid='227') 26 | 27 | # Leaves 28 | s204 = self.addSwitch('s204', dpid='204') 29 | s205 = self.addSwitch('s205', dpid='205') 30 | 31 | # Switch Links 32 | self.addLink(s226, s204) 33 | self.addLink(s226, s205) 34 | self.addLink(s227, s204) 35 | self.addLink(s227, s205) 36 | 37 | intfs = { 38 | 'relay-eth0': { 39 | 'ipAddrs': ['10.0.4.254/24'] 40 | }, 41 | 'relay-eth1': { 42 | 'ipAddrs': ['10.0.2.100/24'] 43 | } 44 | } 45 | dhcpRelay = self.addHost('relay', cls=DhcpRelay, serverIp='10.0.99.3', 46 | gateway='10.0.2.254', interfaces=intfs) 47 | 48 | # NOTE avoid using 10.0.1.0/24 which is the default subnet of quaggas 49 | # NOTE avoid using 00:00:00:00:00:xx which is the default mac of host behind upstream router 50 | # IPv4 Hosts 51 | h1 = self.addHost('h1', cls=DhcpClient, mac='00:ee:00:00:00:01') 52 | h2 = self.addHost('h2', cls=DhcpClient, mac='00:aa:00:00:00:02') 53 | h3 = self.addHost('h3', cls=DhcpClient, mac='00:aa:00:00:00:03') 54 | h4 = self.addHost('h4', cls=DhcpClient, mac='00:aa:00:00:00:04') 55 | self.addLink(h1, dhcpRelay) 56 | self.addLink(dhcpRelay, s204) 57 | self.addLink(h2, s204) 58 | self.addLink(h3, s205) 59 | self.addLink(h4, s205) 60 | 61 | # IPv6 Hosts 62 | h1v6 = self.addHost('h1v6', cls=RoutedHost, mac='00:bb:00:00:00:01', ips=['2000::201/120'], gateway='2000::2ff') 63 | h2v6 = self.addHost('h2v6', cls=RoutedHost, mac='00:bb:00:00:00:02', ips=['2000::202/120'], gateway='2000::2ff') 64 | h3v6 = self.addHost('h3v6', cls=RoutedHost, mac='00:bb:00:00:00:03', ips=['2000::301/120'], gateway='2000::3ff') 65 | h4v6 = self.addHost('h4v6', cls=RoutedHost, mac='00:bb:00:00:00:04', ips=['2000::302/120'], gateway='2000::3ff') 66 | self.addLink(h1v6, s204) 67 | self.addLink(h2v6, s204) 68 | self.addLink(h3v6, s205) 69 | self.addLink(h4v6, s205) 70 | 71 | # Control plane switch (for quagga fpm) 72 | cs0 = self.addSwitch('cs0', cls=OVSBridge, datapath='user') 73 | 74 | # Control plane NAT (for quagga fpm) 75 | nat = self.addHost('nat', cls=UserNAT, 76 | ip='172.16.0.1/24', 77 | subnet=str(ip_network(u'172.16.0.0/24')), inNamespace=False) 78 | self.addLink(cs0, nat) 79 | 80 | # Internal Quagga bgp1 81 | intfs = {'bgp1-eth0': {'ipAddrs': ['10.0.1.2/24', '2000::102/120'], 'mac': '00:88:00:00:00:02'}, 82 | 'bgp1-eth1': {'ipAddrs': ['172.16.0.2/24']}} 83 | bgp1 = self.addHost('bgp1', cls=BgpRouter, 84 | interfaces=intfs, 85 | quaggaConfFile='./bgpdbgp1.conf', 86 | zebraConfFile='./zebradbgp1.conf') 87 | self.addLink(bgp1, s205) 88 | self.addLink(bgp1, cs0) 89 | 90 | # External Quagga r1 91 | intfs = {'r1-eth0': {'ipAddrs': ['10.0.1.1/24', '2000::101/120'], 'mac': '00:88:00:00:00:01'}, 92 | 'r1-eth1': {'ipAddrs': ['10.0.99.1/16']}, 93 | 'r1-eth2': {'ipAddrs': ['2000::9901/120']}} 94 | r1 = self.addHost('r1', cls=BgpRouter, 95 | interfaces=intfs, 96 | quaggaConfFile='./bgpdr1.conf') 97 | self.addLink(r1, s205) 98 | 99 | # External switch behind r1 100 | rs0 = self.addSwitch('rs0', cls=OVSBridge, datapath='user') 101 | self.addLink(r1, rs0) 102 | 103 | # External IPv4 Host behind r1 104 | rh1 = self.addHost('rh1', cls=RoutedHost, ips=['10.0.99.2/24'], gateway='10.0.99.1') 105 | self.addLink(rs0, rh1) 106 | 107 | # External DHCP server behind r1 108 | dhcp = self.addHost('dhcp', cls=DhcpServer, mac='00:99:00:00:00:01', ips=['10.0.99.3/24'], gateway='10.0.99.1') 109 | self.addLink(rs0, dhcp) 110 | 111 | # External IPv6 Host behind r1 112 | rh1v6 = self.addHost('rh1v6', cls=RoutedHost, ips=['2000::9902/120'], gateway='2000::9901') 113 | self.addLink(r1, rh1v6) 114 | 115 | topos = { 'trellis' : Trellis } 116 | 117 | if __name__ == "__main__": 118 | setLogLevel('debug') 119 | topo = Trellis() 120 | switch = partial(OVSSwitch, protocols='OpenFlow13', datapath='user') 121 | arguments = parse_trellis_args() 122 | set_up_zebra_config(arguments.controllers) 123 | net = get_mininet(arguments, topo, switch) 124 | 125 | net.start() 126 | CLI(net) 127 | net.stop() 128 | -------------------------------------------------------------------------------- /trellis/trellis_vlan.json: -------------------------------------------------------------------------------- 1 | { 2 | "ports" : { 3 | "of:0000000000000204/3" : { 4 | "interfaces" : [ 5 | { 6 | "ips" : [ "10.0.2.254/24" ], 7 | "vlan-untagged": 20 8 | } 9 | ] 10 | }, 11 | "of:0000000000000204/4" : { 12 | "interfaces" : [ 13 | { 14 | "ips" : [ "10.0.2.254/24" ], 15 | "vlan-tagged": [20] 16 | } 17 | ] 18 | }, 19 | "of:0000000000000204/5" : { 20 | "interfaces" : [ 21 | { 22 | "ips" : [ "2000::2ff/120" ], 23 | "vlan-untagged": 40 24 | } 25 | ] 26 | }, 27 | "of:0000000000000204/6" : { 28 | "interfaces" : [ 29 | { 30 | "ips" : [ "2000::2ff/120" ], 31 | "vlan-untagged": 40 32 | } 33 | ] 34 | }, 35 | "of:0000000000000205/3" : { 36 | "interfaces" : [ 37 | { 38 | "ips" : [ "10.0.3.254/24" ], 39 | "vlan-untagged": 30 40 | } 41 | ] 42 | }, 43 | "of:0000000000000205/4" : { 44 | "interfaces" : [ 45 | { 46 | "ips" : [ "10.0.3.254/24", "10.0.1.254/24", "2000::1ff/120" ], 47 | "vlan-tagged": [10], 48 | "vlan-native": 30 49 | } 50 | ] 51 | }, 52 | "of:0000000000000205/5" : { 53 | "interfaces" : [ 54 | { 55 | "ips" : [ "2000::3ff/120" ], 56 | "vlan-untagged": 50 57 | } 58 | ] 59 | }, 60 | "of:0000000000000205/6" : { 61 | "interfaces" : [ 62 | { 63 | "ips" : [ "2000::3ff/120" ], 64 | "vlan-untagged": 50 65 | } 66 | ] 67 | }, 68 | "of:0000000000000205/7" : { 69 | "interfaces" : [ 70 | { 71 | "ips" : [ "10.0.3.254/24" ], 72 | "vlan-tagged": [30] 73 | } 74 | ] 75 | }, 76 | "of:0000000000000205/8" : { 77 | "interfaces" : [ 78 | { 79 | "ips" : [ "10.0.1.254/24", "2000::1ff/120" ], 80 | "vlan-untagged": 10 81 | } 82 | ] 83 | } 84 | }, 85 | "devices" : { 86 | "of:0000000000000204" : { 87 | "segmentrouting" : { 88 | "name" : "s204", 89 | "ipv4NodeSid" : 204, 90 | "ipv4Loopback" : "192.168.0.204", 91 | "ipv6NodeSid" : 214, 92 | "ipv6Loopback" : "2000::c0a8:0204", 93 | "routerMac" : "00:00:00:00:02:04", 94 | "isEdgeRouter" : true, 95 | "adjacencySids" : [] 96 | }, 97 | "basic" : { 98 | "name": "s204", 99 | "driver" : "ofdpa-ovs" 100 | } 101 | }, 102 | "of:0000000000000205" : { 103 | "segmentrouting" : { 104 | "name" : "s205", 105 | "ipv4NodeSid" : 205, 106 | "ipv4Loopback" : "192.168.0.205", 107 | "ipv6NodeSid" : 215, 108 | "ipv6Loopback" : "2000::c0a8:0205", 109 | "routerMac" : "00:00:00:00:02:05", 110 | "isEdgeRouter" : true, 111 | "adjacencySids" : [] 112 | }, 113 | "basic" : { 114 | "name": "s205", 115 | "driver" : "ofdpa-ovs" 116 | } 117 | }, 118 | "of:0000000000000226" : { 119 | "segmentrouting" : { 120 | "name" : "s226", 121 | "ipv4NodeSid" : 226, 122 | "ipv4Loopback" : "192.168.0.226", 123 | "ipv6NodeSid" : 236, 124 | "ipv6Loopback" : "2000::c0a8:0226", 125 | "routerMac" : "00:00:00:00:02:26", 126 | "isEdgeRouter" : false, 127 | "adjacencySids" : [] 128 | }, 129 | "basic" : { 130 | "name": "s226", 131 | "driver" : "ofdpa-ovs" 132 | } 133 | }, 134 | "of:0000000000000227" : { 135 | "segmentrouting" : { 136 | "name" : "s227", 137 | "ipv4NodeSid" : 227, 138 | "ipv4Loopback" : "192.168.0.227", 139 | "ipv6NodeSid" : 237, 140 | "ipv6Loopback" : "2000::c0a8:0227", 141 | "routerMac" : "00:00:00:00:02:27", 142 | "isEdgeRouter" : false, 143 | "adjacencySids" : [] 144 | }, 145 | "basic" : { 146 | "name": "s227", 147 | "driver" : "ofdpa-ovs" 148 | } 149 | } 150 | }, 151 | "hosts": { 152 | "00:bb:00:00:00:01/None": { 153 | "basic": { 154 | "ips": ["2000::201"], 155 | "locations": ["of:0000000000000204/5"] 156 | } 157 | }, 158 | "00:bb:00:00:00:02/None": { 159 | "basic": { 160 | "ips": ["2000::202"], 161 | "locations": ["of:0000000000000204/6"] 162 | } 163 | }, 164 | "00:bb:00:00:00:03/None": { 165 | "basic": { 166 | "ips": ["2000::301"], 167 | "locations": ["of:0000000000000205/5"] 168 | } 169 | }, 170 | "00:bb:00:00:00:04/None": { 171 | "basic": { 172 | "ips": ["2000::302"], 173 | "locations": ["of:0000000000000205/6"] 174 | } 175 | } 176 | }, 177 | "apps" : { 178 | "org.onosproject.dhcprelay" : { 179 | "default": [ 180 | { 181 | "dhcpServerConnectPoint": "of:0000000000000205/7", 182 | "serverIps": ["10.0.3.253"] 183 | } 184 | ] 185 | } 186 | } 187 | } 188 | -------------------------------------------------------------------------------- /trellis/trellis_vlan.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | import sys 4 | sys.path.append('..') 5 | from mininet.topo import Topo 6 | from mininet.net import Mininet 7 | from mininet.cli import CLI 8 | from mininet.log import setLogLevel 9 | from mininet.node import RemoteController, OVSBridge, Host, OVSSwitch 10 | from ipaddress import ip_network 11 | from routinglib import BgpRouter 12 | from routinglib import RoutedHost, UserNAT 13 | from trellislib import DhcpClient, DhcpServer 14 | from trellislib import TaggedDhcpClient, TaggedDhcpServer 15 | from trellislib import get_mininet, parse_trellis_args, set_up_zebra_config 16 | from functools import partial 17 | 18 | class Trellis( Topo ): 19 | "Trellis basic topology" 20 | 21 | def __init__( self, *args, **kwargs ): 22 | Topo.__init__( self, *args, **kwargs ) 23 | 24 | # Spines 25 | s226 = self.addSwitch('s226', dpid='226') 26 | s227 = self.addSwitch('s227', dpid='227') 27 | 28 | # Leaves 29 | s204 = self.addSwitch('s204', dpid='204') 30 | s205 = self.addSwitch('s205', dpid='205') 31 | 32 | # Switch Links 33 | self.addLink(s226, s204) 34 | self.addLink(s226, s205) 35 | self.addLink(s227, s204) 36 | self.addLink(s227, s205) 37 | 38 | # NOTE avoid using 10.0.1.0/24 which is the default subnet of quaggas 39 | # NOTE avoid using 00:00:00:00:00:xx which is the default mac of host behind upstream router 40 | # IPv4 Hosts 41 | h1 = self.addHost('h1', cls=DhcpClient, mac='00:aa:00:00:00:01') 42 | h2 = self.addHost('h2', cls=TaggedDhcpClient, mac='00:aa:00:00:00:02', vlan=20) 43 | h3 = self.addHost('h3', cls=DhcpClient, mac='00:aa:00:00:00:03') 44 | h4 = self.addHost('h4', cls=DhcpClient, mac='00:aa:00:00:00:04') 45 | # In order to emulate tagged Quagga VM in h4 46 | h4ovs = self.addSwitch('h4ovs', cls=OVSBridge, datapath='user') 47 | self.addLink(h1, s204) 48 | self.addLink(h2, s204) 49 | self.addLink(h3, s205) 50 | self.addLink(h4ovs, s205) 51 | self.addLink(h4ovs, h4) 52 | 53 | # IPv6 Hosts 54 | h1v6 = self.addHost('h1v6', cls=RoutedHost, mac='00:bb:00:00:00:01', ips=['2000::201/120'], gateway='2000::2ff') 55 | h2v6 = self.addHost('h2v6', cls=RoutedHost, mac='00:bb:00:00:00:02', ips=['2000::202/120'], gateway='2000::2ff') 56 | h3v6 = self.addHost('h3v6', cls=RoutedHost, mac='00:bb:00:00:00:03', ips=['2000::301/120'], gateway='2000::3ff') 57 | h4v6 = self.addHost('h4v6', cls=RoutedHost, mac='00:bb:00:00:00:04', ips=['2000::302/120'], gateway='2000::3ff') 58 | self.addLink(h1v6, s204) 59 | self.addLink(h2v6, s204) 60 | self.addLink(h3v6, s205) 61 | self.addLink(h4v6, s205) 62 | 63 | # DHCP server 64 | dhcp = self.addHost('dhcp', cls=TaggedDhcpServer, mac='00:99:00:00:00:01', ips=['10.0.3.253/24'], gateway='10.0.3.254', vlan=30) 65 | self.addLink(dhcp, s205) 66 | 67 | # Control plane switch (for quagga fpm) 68 | cs0 = self.addSwitch('cs0', cls=OVSBridge, datapath='user') 69 | 70 | # Control plane NAT (for quagga fpm) 71 | nat = self.addHost('nat', cls=UserNAT, 72 | ip='172.16.0.1/24', 73 | subnet=str(ip_network(u'172.16.0.0/24')), inNamespace=False) 74 | self.addLink(cs0, nat) 75 | 76 | # Internal Quagga bgp1 77 | intfs = {'bgp1-eth0': {'ipAddrs': ['10.0.1.2/24', '2000::102/120'], 'mac': '00:88:00:00:00:02', 'vlan': '10'}, 78 | 'bgp1-eth1': {'ipAddrs': ['172.16.0.2/24']}} 79 | bgp1 = self.addHost('bgp1', cls=BgpRouter, 80 | interfaces=intfs, 81 | quaggaConfFile='./bgpdbgp1.conf', 82 | zebraConfFile='./zebradbgp1.conf') 83 | self.addLink(bgp1, h4ovs) 84 | self.addLink(bgp1, cs0) 85 | 86 | # External Quagga r1 87 | intfs = {'r1-eth0': {'ipAddrs': ['10.0.1.1/24', '2000::101/120'], 'mac': '00:88:00:00:00:01'}, 88 | 'r1-eth1': {'ipAddrs': ['10.0.99.1/16']}, 89 | 'r1-eth2': {'ipAddrs': ['2000::9901/120']}} 90 | r1 = self.addHost('r1', cls=BgpRouter, 91 | interfaces=intfs, 92 | quaggaConfFile='./bgpdr1.conf') 93 | self.addLink(r1, s205) 94 | 95 | # External IPv4 Host behind r1 96 | rh1 = self.addHost('rh1', cls=RoutedHost, ips=['10.0.99.2/24'], gateway='10.0.99.1') 97 | self.addLink(r1, rh1) 98 | 99 | # External IPv6 Host behind r1 100 | rh1v6 = self.addHost('rh1v6', cls=RoutedHost, ips=['2000::9902/120'], gateway='2000::9901') 101 | self.addLink(r1, rh1v6) 102 | 103 | topos = { 'trellis' : Trellis } 104 | 105 | if __name__ == "__main__": 106 | setLogLevel('debug') 107 | topo = Trellis() 108 | switch = partial(OVSSwitch, protocols='OpenFlow13', datapath='user') 109 | arguments = parse_trellis_args() 110 | set_up_zebra_config(arguments.controllers) 111 | net = get_mininet(arguments, topo, switch) 112 | 113 | net.start() 114 | CLI(net) 115 | net.stop() 116 | -------------------------------------------------------------------------------- /trellis/trellisp4.json: -------------------------------------------------------------------------------- 1 | { 2 | "ports": { 3 | "device:s204/3": { 4 | "interfaces": [ 5 | { 6 | "name": "h1", 7 | "ips": [ 8 | "10.0.2.254/24" 9 | ], 10 | "vlan-untagged": 10 11 | } 12 | ] 13 | }, 14 | "device:s204/4": { 15 | "interfaces": [ 16 | { 17 | "name": "h2", 18 | "ips": [ 19 | "10.0.2.254/24" 20 | ], 21 | "vlan-tagged": [ 22 | 10 23 | ] 24 | } 25 | ] 26 | }, 27 | "device:s205/3": { 28 | "interfaces": [ 29 | { 30 | "name": "h3", 31 | "ips": [ 32 | "10.0.3.254/24" 33 | ], 34 | "vlan-untagged": 20 35 | } 36 | ] 37 | }, 38 | "device:s205/4": { 39 | "interfaces": [ 40 | { 41 | "name": "h4", 42 | "ips": [ 43 | "10.0.3.254/24" 44 | ], 45 | "vlan-tagged": [ 46 | 20 47 | ] 48 | } 49 | ] 50 | } 51 | }, 52 | "devices": { 53 | "device:s204": { 54 | "segmentrouting": { 55 | "name": "s204", 56 | "ipv4NodeSid": 204, 57 | "ipv4Loopback": "192.168.0.204", 58 | "ipv6NodeSid": 214, 59 | "ipv6Loopback": "2000::c0a8:0204", 60 | "routerMac": "00:00:00:00:02:04", 61 | "isEdgeRouter": true, 62 | "adjacencySids": [] 63 | } 64 | }, 65 | "device:s205": { 66 | "segmentrouting": { 67 | "name": "s205", 68 | "ipv4NodeSid": 205, 69 | "ipv4Loopback": "192.168.0.205", 70 | "ipv6NodeSid": 215, 71 | "ipv6Loopback": "2000::c0a8:0205", 72 | "routerMac": "00:00:00:00:02:05", 73 | "isEdgeRouter": true, 74 | "adjacencySids": [] 75 | } 76 | }, 77 | "device:s226": { 78 | "segmentrouting": { 79 | "name": "s226", 80 | "ipv4NodeSid": 226, 81 | "ipv4Loopback": "192.168.0.226", 82 | "ipv6NodeSid": 236, 83 | "ipv6Loopback": "2000::c0a8:0226", 84 | "routerMac": "00:00:00:00:02:26", 85 | "isEdgeRouter": false, 86 | "adjacencySids": [] 87 | } 88 | }, 89 | "device:s227": { 90 | "segmentrouting": { 91 | "name": "s227", 92 | "ipv4NodeSid": 227, 93 | "ipv4Loopback": "192.168.0.227", 94 | "ipv6NodeSid": 237, 95 | "ipv6Loopback": "2000::c0a8:0227", 96 | "routerMac": "00:00:00:00:02:27", 97 | "isEdgeRouter": false, 98 | "adjacencySids": [] 99 | } 100 | } 101 | }, 102 | "apps": { 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /trellis/trellisp4.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | import argparse 4 | import os 5 | import sys 6 | 7 | sys.path.append('..') 8 | 9 | from mininet.topo import Topo 10 | from mininet.net import Mininet 11 | from mininet.cli import CLI 12 | from mininet.log import setLogLevel 13 | from mininet.node import RemoteController 14 | from routinglib import RoutedHost 15 | from trellislib import TaggedRoutedHost 16 | 17 | try: 18 | from bmv2 import ONOSBmv2Switch, ONOSStratumSwitch 19 | except ImportError as e: 20 | if os.getenv("ONOS_ROOT"): 21 | sys.path.append("%s/tools/dev/mininet" % os.getenv("ONOS_ROOT")) 22 | from bmv2 import ONOSBmv2Switch, ONOSStratumSwitch 23 | else: 24 | raise e 25 | 26 | PIPECONF_ID = 'org.onosproject.pipelines.fabric' 27 | 28 | 29 | class Trellis(Topo): 30 | "Trellis basic topology" 31 | 32 | def __init__(self, *args, **kwargs): 33 | Topo.__init__(self, *args, **kwargs) 34 | 35 | # Spines 36 | s226 = self.addP4Switch('s226') 37 | s227 = self.addP4Switch('s227') 38 | 39 | # Leaves 40 | s204 = self.addP4Switch('s204') 41 | s205 = self.addP4Switch('s205') 42 | 43 | # Switch Links 44 | self.addLink(s226, s204) 45 | self.addLink(s226, s205) 46 | self.addLink(s227, s204) 47 | self.addLink(s227, s205) 48 | 49 | # NOTE avoid using 10.0.1.0/24 which is the default subnet of quaggas 50 | # NOTE avoid using 00:00:00:00:00:xx which is the default mac of host behind upstream router 51 | # IPv4 Hosts 52 | h1 = self.addHost('h1', cls=RoutedHost, mac='00:aa:00:00:00:01', 53 | ips=['10.0.2.1/24'], gateway='10.0.2.254') 54 | h2 = self.addHost('h2', cls=TaggedRoutedHost, mac='00:aa:00:00:00:02', 55 | ips=['10.0.2.2/24'], gateway='10.0.2.254', vlan=10) 56 | h3 = self.addHost('h3', cls=RoutedHost, mac='00:aa:00:00:00:03', 57 | ips=['10.0.3.1/24'], gateway='10.0.3.254') 58 | h4 = self.addHost('h4', cls=TaggedRoutedHost, mac='00:aa:00:00:00:04', 59 | ips=['10.0.3.2/24'], gateway='10.0.3.254', vlan=20) 60 | self.addLink(h1, s204) 61 | self.addLink(h2, s204) 62 | self.addLink(h3, s205) 63 | self.addLink(h4, s205) 64 | 65 | def addP4Switch(self, name): 66 | return self.addSwitch(name=name, 67 | pipeconf=PIPECONF_ID, 68 | portcfg=True, 69 | onosdevid="device:" + name) 70 | 71 | 72 | topos = {'trellis': Trellis} 73 | 74 | 75 | def main(args): 76 | topo = Trellis() 77 | controller = RemoteController('c0', ip=args.onos_ip) 78 | 79 | if args.agent == "stratum": 80 | switch = ONOSStratumSwitch 81 | else: 82 | switch = ONOSBmv2Switch 83 | 84 | net = Mininet(topo=topo, switch=switch, controller=None) 85 | net.addController(controller) 86 | 87 | net.start() 88 | CLI(net) 89 | net.stop() 90 | 91 | 92 | if __name__ == "__main__": 93 | parser = argparse.ArgumentParser( 94 | description='BMv2 mininet demo script (2 by 2 fabric)') 95 | parser.add_argument('--onos-ip', help='ONOS-BMv2 controller IP address', 96 | type=str, action="store", required=True) 97 | parser.add_argument("-a", "--agent", 98 | help="Agent to use on Bmv2 (pi or stratum)", 99 | required=False, default="pi") 100 | args = parser.parse_args() 101 | setLogLevel('info') 102 | main(args) 103 | -------------------------------------------------------------------------------- /vrouter.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | from mininet.topo import Topo 4 | from mininet.net import Mininet 5 | from mininet.cli import CLI 6 | from mininet.log import setLogLevel 7 | from mininet.node import RemoteController, OVSBridge, UserSwitch 8 | from routinglib import BasicAutonomousSystem 9 | from routinglib import SdnAutonomousSystem, AutonomousSystem 10 | from routinglib import generateRoutes 11 | 12 | 13 | class VrouterTopo( Topo ): 14 | "Single switch topology for testing the vRouter" 15 | 16 | def __init__( self, *args, **kwargs ): 17 | Topo.__init__( self, *args, **kwargs ) 18 | # Router switch 19 | s1 = self.addSwitch('s1', dpid='000000000b1') 20 | 21 | # SDN AS 22 | onosIps = ['192.168.56.11'] 23 | sdnAs = SdnAutonomousSystem(onosIps, numBgpSpeakers=1, asNum=65000, withFpm=True) 24 | 25 | numRoutesPerAs = 1 26 | 27 | # Normal ASes 28 | as1 = BasicAutonomousSystem(1, 29 | generateRoutes(u'10.1.0.0/16', numRoutesPerAs)) 30 | AutonomousSystem.addPeering(as1, sdnAs, useVlans=True) 31 | as1.addLink(s1) 32 | as1.build(self) 33 | 34 | as2 = BasicAutonomousSystem(2, 35 | generateRoutes(u'10.2.0.0/16', numRoutesPerAs)) 36 | AutonomousSystem.addPeering(as2, sdnAs, useVlans=True) 37 | as2.addLink(s1) 38 | as2.build(self) 39 | 40 | as3 = BasicAutonomousSystem(3, 41 | generateRoutes(u'10.3.0.0/16', numRoutesPerAs)) 42 | AutonomousSystem.addPeering(as3, sdnAs, useVlans=True) 43 | as3.addLink(s1) 44 | as3.build(self) 45 | 46 | as4 = BasicAutonomousSystem(4, 47 | generateRoutes(u'10.4.0.0/16', numRoutesPerAs)) 48 | AutonomousSystem.addPeering(as4, sdnAs, useVlans=False) 49 | as4.addLink(s1) 50 | as4.build(self) 51 | 52 | # SDN AS (internal BGP speaker) connects to control plane switch 53 | cs0 = self.addSwitch('cs0', cls=OVSBridge) 54 | sdnAs.build(self, s1, cs0) 55 | 56 | topos = { 'vrouter' : VrouterTopo } 57 | 58 | if __name__ == "__main__": 59 | setLogLevel('debug') 60 | topo = VrouterTopo() 61 | 62 | net = Mininet(topo=topo, controller=None) 63 | net.addController(RemoteController('c0', ip='192.168.56.11')) 64 | net.addController(RemoteController('c1', ip='192.168.56.12')) 65 | net.addController(RemoteController('c2', ip='192.168.56.13')) 66 | 67 | net.start() 68 | 69 | CLI(net) 70 | 71 | net.stop() 72 | 73 | --------------------------------------------------------------------------------