Import scripts from old repository
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..d81967c
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,5 @@
+*~
+\#*\#
+*.pyc
+*.project
+*.pydevproject
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..7b918e7
--- /dev/null
+++ b/README.md
@@ -0,0 +1,15 @@
+Routing libraries and topologies for Mininet
+========================================================
+
+This repository contains a set of libraries and scripts that build on
+top of Mininet to construct topologies that include L3 routing elements.
+Quagga is used to construct routes that support a variety of routing
+protocols.
+
+### Dependencies
+
+- Mininet: `sudo apt-get install mininet`
+- Quagga: `sudo apt-get install quagga`
+- ipaddress: `sudo pip install ipaddress` (if that doesn't work use `sudo apt-get install python-pip`)
+
+
diff --git a/__init__.py b/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/__init__.py
diff --git a/bgprouter_deploy.py b/bgprouter_deploy.py
new file mode 100755
index 0000000..97f2228
--- /dev/null
+++ b/bgprouter_deploy.py
@@ -0,0 +1,60 @@
+#!/usr/bin/python
+
+from mininet.topo import Topo
+from mininet.net import Mininet
+from mininet.cli import CLI
+from mininet.log import setLogLevel, info
+from mininet.node import RemoteController, OVSSwitch
+from routinglib import BgpRouter
+
+class BgpRouterDeployTopo( Topo ):
+ "Sets up control plane components for BgpRouter deployment"
+
+ def __init__( self, *args, **kwargs ):
+ Topo.__init__( self, *args, **kwargs )
+ s1 = self.addSwitch('s1', dpid='0000000000000001')
+
+ sdnAs = 65000
+
+ # Set up BGP speakers
+ bgp1eth0 = { 'ipAddrs' : ['1.1.1.11/24'] }
+
+ bgp1eth1 = [
+ { 'vlan': 1,
+ 'mac':'00:00:00:00:00:01',
+ 'ipAddrs' : ['192.168.10.101/24'] },
+ { 'vlan': 2,
+ 'mac':'00:00:00:00:00:02',
+ 'ipAddrs' : ['192.168.20.101/24'] }
+ ]
+
+ bgp1Intfs = { 'bgp1-eth0' : bgp1eth0,
+ 'bgp1-eth1' : bgp1eth1 }
+
+ neighbors = [{'address':'192.168.10.1', 'as':65001},
+ {'address':'192.168.20.1', 'as':65001},
+ {'address':'192.168.30.1', 'as':65002},
+ {'address':'192.168.40.1', 'as':65003},
+ {'address':'1.1.1.1', 'as':sdnAs, 'port': 2000}]
+
+ bgp1 = self.addHost( "bgp1", interfaces=bgp1Intfs, asNum=sdnAs,
+ neighbors=neighbors, routes=[], cls=BgpRouter)
+
+ root = self.addHost('root', ip='1.1.1.1/24', inNamespace=False)
+
+ self.addLink( bgp1, root )
+ self.addLink( bgp1, s1 )
+
+if __name__ == "__main__":
+ setLogLevel('debug')
+ topo = BgpRouterDeployTopo()
+
+ net = Mininet(topo=topo, controller=RemoteController, switch=OVSSwitch)
+
+ net.start()
+
+ CLI(net)
+
+ net.stop()
+
+ info("done\n")
diff --git a/bgprouter_dev.py b/bgprouter_dev.py
new file mode 100755
index 0000000..9af70d9
--- /dev/null
+++ b/bgprouter_dev.py
@@ -0,0 +1,72 @@
+#!/usr/bin/python
+
+from mininet.topo import Topo
+from mininet.net import Mininet
+from mininet.cli import CLI
+from mininet.log import setLogLevel, info
+from mininet.node import RemoteController, OVSBridge
+from routinglib import BasicAutonomousSystem
+from routinglib import SdnAutonomousSystem, AutonomousSystem
+from routinglib import generateRoutes
+
+
+class BgpRouterTopo( Topo ):
+ "Single switch topology for testing the BgpRouter"
+
+ def __init__( self, *args, **kwargs ):
+ Topo.__init__( self, *args, **kwargs )
+ # Router switch
+ s1 = self.addSwitch('s1', dpid='00000000000000a1')
+
+ # Control plane switch for BGP daemon
+ s7 = self.addSwitch('s7', dpid='00000000000000a7')
+
+ # SDN AS
+ onosIps = ['192.168.56.11']
+ sdnAs = SdnAutonomousSystem(onosIps, numBgpSpeakers=1, asNum=65000)
+
+ numRoutesPerAs = 1
+
+ # Normal ASes
+ as1 = BasicAutonomousSystem(1,
+ generateRoutes(u'10.1.0.0/16', numRoutesPerAs))
+ AutonomousSystem.addPeering(as1, sdnAs, useVlans=True)
+ as1.addLink(s1)
+ as1.build(self)
+
+ as2 = BasicAutonomousSystem(2,
+ generateRoutes(u'10.2.0.0/16', numRoutesPerAs))
+ AutonomousSystem.addPeering(as2, sdnAs, useVlans=True)
+ as2.addLink(s1)
+ as2.build(self)
+
+ as3 = BasicAutonomousSystem(3,
+ generateRoutes(u'10.3.0.0/16', numRoutesPerAs))
+ AutonomousSystem.addPeering(as3, sdnAs, useVlans=True)
+ as3.addLink(s1)
+ as3.build(self)
+
+ as4 = BasicAutonomousSystem(4,
+ generateRoutes(u'10.4.0.0/16', numRoutesPerAs))
+ AutonomousSystem.addPeering(as4, sdnAs, useVlans=False)
+ as4.addLink(s1)
+ as4.build(self)
+
+ # SDN AS (internal BGP speaker) connects to control plane switch
+ cs0 = self.addSwitch('cs0', cls=OVSBridge)
+ sdnAs.build(self, s7, cs0)
+
+if __name__ == "__main__":
+ setLogLevel('debug')
+ topo = BgpRouterTopo()
+
+ net = Mininet(topo=topo, controller=None)
+ net.addController(RemoteController('c0', ip='192.168.56.11'))
+
+ net.start()
+
+ CLI(net)
+
+ net.stop()
+
+ info("done\n")
diff --git a/dec14demo.py b/dec14demo.py
new file mode 100755
index 0000000..f5fe71d
--- /dev/null
+++ b/dec14demo.py
@@ -0,0 +1,119 @@
+#!/usr/bin/python
+
+from mininet.topo import Topo
+from mininet.node import RemoteController, OVSSwitch, OVSBridge
+from mininet.log import setLogLevel, info
+from mininet.net import Mininet
+from routinglib import RoutingCli as CLI
+from routinglib import AutonomousSystem, BasicAutonomousSystem, SdnAutonomousSystem
+from routinglib import generateRoutes
+
+onoses = [ '192.168.56.11', '192.168.56.12', '192.168.56.13' ]
+
+class Dec14DemoTopo( Topo ):
+
+ "Topology from the Dec 14 SDN-IP demo"
+
+ def __init__( self, **kwargs ):
+ Topo.__init__( self, **kwargs )
+ coreMesh = []
+
+ for i in range( 1, 5 ):
+ coreMesh.append( self.addSwitch( 's%s' %i ) )
+
+ # create full mesh between middle 4 switches
+ remaining = list( coreMesh )
+ while True:
+ first = remaining[ 0 ]
+ for switch in tuple( remaining ):
+ if switch is not first:
+ self.addLink( switch, first )
+ remaining.remove( first )
+ if not remaining:
+ break
+
+
+ s5 = self.addSwitch( 's5', dpid='00:00:00:00:00:00:00:05' )
+ s6 = self.addSwitch( 's6', dpid='00:00:00:00:00:00:00:06' )
+ s7 = self.addSwitch( 's7', dpid='00:00:00:00:00:00:00:07' )
+ self.addLink( s5, s6 )
+ self.addLink( s6, s7 )
+
+ s8 = self.addSwitch( 's8', dpid='00:00:00:00:00:00:00:08' )
+ s9 = self.addSwitch( 's9', dpid='00:00:00:00:00:00:00:09' )
+ s10 = self.addSwitch( 's10', dpid='00:00:00:00:00:00:00:10' )
+ self.addLink( s8, s9 )
+ self.addLink( s9, s10 )
+
+ self.addLink( s5, s8 )
+
+ # add links between core mesh and satellite switches
+ self.addLink( coreMesh[ 0 ], s5 )
+ self.addLink( coreMesh[ 0 ], s6 )
+ self.addLink( coreMesh[ 0 ], s7 )
+ self.addLink( coreMesh[ 1 ], s8 )
+ self.addLink( coreMesh[ 1 ], s9 )
+ self.addLink( coreMesh[ 1 ], s10 )
+ self.addLink( coreMesh[ 2 ], s7 )
+ self.addLink( coreMesh[ 3 ], s10 )
+
+ # SDN AS
+ sdnAs = SdnAutonomousSystem(onoses, numBgpSpeakers=3, asNum=65000, externalOnos=True)
+ cs0 = self.addSwitch('cs0', cls=OVSBridge)
+
+ numRoutesPerAs = 32
+
+ # Add external ASes
+ as1 = BasicAutonomousSystem(1, generateRoutes(u'192.168.1.0/24', numRoutesPerAs))
+ AutonomousSystem.addPeering(as1, sdnAs)
+ AutonomousSystem.addPeering(as1, sdnAs, router2=3, intf1=2)
+ as1.addLink(s5)
+ as1.addLink(s6)
+ as1.build(self)
+
+ as2 = BasicAutonomousSystem(2, generateRoutes(u'192.168.2.0/24', numRoutesPerAs))
+ AutonomousSystem.addPeering(as2, sdnAs)
+ AutonomousSystem.addPeering(as2, sdnAs, router2=2)
+ as2.addLink(s7)
+ as2.build(self)
+
+ as3 = BasicAutonomousSystem(3, generateRoutes(u'192.168.3.0/24', numRoutesPerAs))
+ AutonomousSystem.addPeering(as3, sdnAs, router2=2)
+ AutonomousSystem.addPeering(as3, sdnAs, router2=3)
+ as3.addLink(s8)
+ as3.build(self)
+
+ as4 = BasicAutonomousSystem(4, generateRoutes(u'192.168.4.0/24', numRoutesPerAs), numRouters=2)
+ AutonomousSystem.addPeering(as4, sdnAs)
+ AutonomousSystem.addPeering(as4, sdnAs, router1=2, router2=3)
+ as4.addLink(s9)
+ as4.addLink(s10, router=2)
+ as4.build(self)
+
+ # add links between nets
+ #self.addLink( BGP1, coreMesh[ 0 ], port2=10 )
+ #self.addLink( BGP2, coreMesh[ 1 ], port2=10 )
+ #self.addLink( BGP3, coreMesh[ 2 ], port2=10 )
+
+ sdnAs.build(self, coreMesh[0], cs0)
+ # TODO multihome the BGP speakers to different switches
+
+def run():
+ topo = Dec14DemoTopo( )
+ net = Mininet( topo=topo, switch=OVSSwitch, controller=None )
+
+ for i in range(len(onoses)):
+ net.addController( RemoteController( 'c%s' % (i+1), ip=onoses[i], checkListening=False ) )
+
+ net.start()
+
+ CLI( net )
+
+ net.stop()
+ info( 'done\n' )
+
+if __name__ == '__main__':
+ setLogLevel( 'debug' )
+ run()
+
+
diff --git a/onoslib.py b/onoslib.py
new file mode 100644
index 0000000..138b071
--- /dev/null
+++ b/onoslib.py
@@ -0,0 +1,70 @@
+"""
+Libraries for using ONOS from within Mininet.
+"""
+
+from mininet.node import OVSBridge
+from mininet.util import netParse, ipStr
+import os, sys, imp
+
+# Import the ONOS classes from onos.py in the ONOS repository
+if not 'ONOS_ROOT' in os.environ:
+ print 'ONOS_ROOT is not set.'
+ print 'Try running the script with \'sudo -E\' to pass your environment in.'
+ sys.exit(1)
+
+onos_path = os.path.join(os.path.abspath(os.environ['ONOS_ROOT']), 'tools/test/topos/onos.py')
+onos = imp.load_source('onos', onos_path)
+from onos import ONOS
+
+class ONOSHostCluster(object):
+ def __init__(self, controlSubnet='192.168.1.0/24', numInstances=1, basename='ONOS',
+ features=[]):
+ self.controlSubnet = controlSubnet
+ self.numInstances = numInstances
+ self.basename = basename
+ self.instances = []
+ self.features = features
+
+ def create(self, topology):
+ cs0 = topology.addSwitch('cs0', cls=OVSBridge)
+
+ ctrlIp, ctrlPrefixLen = netParse(self.controlSubnet)
+
+ for i in range(1, self.numInstances + 1):
+ strCtrlIp = '%s/%i' % (ipStr(ctrlIp + i), ctrlPrefixLen)
+
+ c = topology.addHost('%s%s' % (self.basename, i), cls=ONOS, inNamespace=True,
+ ip=strCtrlIp,
+ features=['onos-app-config', 'onos-app-proxyarp',
+ 'onos-core'] + self.features,
+ reactive=False)
+
+ topology.addLink(c, cs0, params1={ 'ip' : strCtrlIp })
+
+ self.instances.append(c)
+
+ # Connect switch to root namespace so that data network
+ # switches will be able to talk to us
+ highestIp = '%s/%i' % (ipStr(ctrlIp + (2 ** (32 - ctrlPrefixLen)) - 2), ctrlPrefixLen)
+ root = topology.addHost('root', inNamespace=False, ip=highestIp)
+ topology.addLink(root, cs0)
+
+class ONOSHostSdnipCluster(ONOSHostCluster):
+
+ def __init__(self, dataSubnet='10.0.0.0/24', features=['onos-app-sdnip'], **kwargs):
+ super(ONOSHostSdnipCluster, self).__init__(features=features, **kwargs)
+
+ self.dataSubnet = dataSubnet
+
+ def create(self, topology):
+ super(ONOSHostSdnipCluster, self).create(topology)
+
+ cs1 = topology.addSwitch('cs1', cls=OVSBridge)
+
+ dataIp, dataPrefixLen = netParse(self.dataSubnet)
+ for i in range(1, len(self.instances) + 1):
+ c = self.instances[i-1]
+ strDataIp = '%s/%i' % (ipStr(dataIp + i), dataPrefixLen)
+ topology.addLink(c, cs1, params1={ 'ip' : strDataIp })
+
+ return cs1
\ No newline at end of file
diff --git a/onsdemo.py b/onsdemo.py
new file mode 100755
index 0000000..c0dda25
--- /dev/null
+++ b/onsdemo.py
@@ -0,0 +1,172 @@
+#!/usr/bin/python
+
+from mininet.topo import Topo
+from mininet.net import Mininet
+from mininet.node import RemoteController
+from mininet.cli import CLI
+from mininet.log import setLogLevel, info
+from mininet.node import OVSBridge
+from routinglib import BgpRouter, RoutedHost
+from onoslib import ONOSHostSdnipCluster
+
+onoses = [ '192.168.56.11', '192.168.56.12' ]
+
+class BgpRouterDeployTopo( Topo ):
+ "Our familiar ONS demo topology"
+
+ def __init__( self, *args, **kwargs ):
+ Topo.__init__( self, *args, **kwargs )
+ sw1 = self.addSwitch('sw1', dpid='00000000000000a1')
+ sw2 = self.addSwitch('sw2', dpid='00000000000000a2')
+ sw3 = self.addSwitch('sw3', dpid='00000000000000a3')
+ sw4 = self.addSwitch('sw4', dpid='00000000000000a4')
+ sw5 = self.addSwitch('sw5', dpid='00000000000000a5')
+ sw6 = self.addSwitch('sw6', dpid='00000000000000a6')
+
+ #Note this switch isn't part of the SDN topology
+ as6sw = self.addSwitch('as6sw', dpid='00000000000000a7', cls=OVSBridge)
+
+ #AS2 host
+ host3eth0 = { 'mac':'00:00:00:00:02:01', 'ipAddrs' : [ '192.168.10.1/24' ] }
+ host3eth1 = { 'mac':'00:00:00:00:02:02', 'ipAddrs' : [ '192.168.20.1/24' ] }
+ host3eth2 = { 'ipAddrs' : [ '172.16.20.254/24' ] }
+ host3Intfs = {'host3-eth0' : host3eth0,
+ 'host3-eth1' : host3eth1,
+ 'host3-eth2' : host3eth2 }
+ host3neigh = [{'address':'192.168.10.101', 'as':64513},
+ {'address':'192.168.20.101', 'as':64513}]
+ host3routes = ['127.16.10.0/24']
+
+ host3 = self.addHost( 'host3', interfaces=host3Intfs, asNum=65001,
+ neighbors=host3neigh, routes=host3routes,
+ cls=BgpRouter)
+
+ as2host = self.addHost( 'as2host', cls=RoutedHost, ip='172.16.20.1/24',
+ route='172.16.20.254' )
+
+
+ #AS3 host
+ host4eth0 = { 'mac':'00:00:00:00:03:01', 'ipAddrs' : [ '192.168.30.1/24' ] }
+ host4eth1 = { 'ipAddrs' : [ '172.16.30.254/24' ] }
+ host4Intfs = {'host4-eth0' : host4eth0,
+ 'host4-eth1' : host4eth1 }
+ host4neigh = [{'address':'192.168.30.101', 'as':64513}]
+ host4routes = ['172.16.30.0/24']
+ host4 = self.addHost( 'host4', interfaces=host4Intfs, asNum=65002,
+ neighbors=host4neigh, routes=host4routes,
+ cls=BgpRouter)
+
+ as3host = self.addHost( 'as3host', cls=RoutedHost, ip='172.16.30.1/24',
+ route='172.16.30.254' )
+
+
+ #AS4 host
+ host5eth0 = { 'mac':'00:00:00:00:04:01', 'ipAddrs' : [ '192.168.40.1/24' ] }
+ host5eth1 = { 'ipAddrs' : [ '172.16.40.254/24' ] }
+ host5Intfs = {'host5-eth0' : host5eth0,
+ 'host5-eth1' : host5eth1 }
+ host5neigh = [{'address':'192.168.40.101', 'as':64513}]
+ host5routes = ['172.16.40.0/24']
+ host5 = self.addHost( 'host5', interfaces=host5Intfs, asNum=65003,
+ neighbors=host5neigh, routes=host5routes,
+ cls=BgpRouter)
+
+ as4host = self.addHost( 'as4host', cls=RoutedHost, ip='172.16.40.1/24',
+ route='172.16.40.254' )
+
+ #AS6 host
+ #as6rs = self.addHost( 'as6rs' )
+ #as6rs2 = self.addHost( 'as6rs2' )
+ #as6router = self.addHost( 'as6router' )
+ #as6host = self.addHost( 'as6host' )
+
+ # Create a control network
+ onosCluster = ONOSHostSdnipCluster(controlSubnet='192.168.50.0/24',
+ dataSubnet='1.1.1.0/24', numInstances=2)
+ cs1 = onosCluster.create(self)
+ #cs0 = self.createControlNet((u'192.168.50.0/24'), (u'1.1.1.0/24'), numOnos=2)
+
+ # Set up BGP speakers
+ bgp1eth0 = { 'ipAddrs' : ['1.1.1.11/24'] }
+ bgp1eth1 = { 'mac':'00:00:00:00:00:01',
+ 'ipAddrs' : ['192.168.10.101/24',
+ '192.168.20.101/24',
+ '192.168.30.101/24',
+ '192.168.40.101/24',] }
+ bgp1Intfs = { 'BGP1-eth0' : bgp1eth0,
+ 'BGP1-eth1' : bgp1eth1 }
+ bgp1neigh = [{'address':'192.168.10.1', 'as':65001},
+ {'address':'192.168.20.1', 'as':65001},
+ {'address':'192.168.30.1', 'as':65002},
+ {'address':'192.168.40.1', 'as':65003},
+ {'address':'1.1.1.1', 'as':64513},
+ {'address':'1.1.1.2', 'as':64513},
+ {'address':'1.1.1.12', 'as':64513}]
+
+ bgp1 = self.addHost( "BGP1", interfaces=bgp1Intfs, asNum=64513,
+ neighbors=bgp1neigh, routes=[], cls=BgpRouter)
+
+ self.addLink( bgp1, cs1 )
+ self.addLink( bgp1, sw1 )
+
+ #bgp2eth0 = { 'ipAddrs' : ['1.1.1.12/24'] }
+ #bgp2eth1 = { 'mac':'00:00:00:00:00:02',
+ # 'ipAddrs' : ['192.168.10.102/24',
+ # '192.168.20.102/24',
+ # '192.168.30.102/24',
+ # '192.168.40.102/24',] }
+ #bgp2Intfs = { 'BGP2-eth0' : bgp2eth0,
+ # 'BGP2-eth1' : bgp2eth1 }
+
+ #bgp2 = self.addHost( "BGP2", cls=BgpRouter,
+ # quaggaConfFile = '../onsdemo/quagga-sdn2.conf',
+ # zebraConfFile = zebraConf,
+ # interfaces=bgp2Intfs )
+
+ #self.addLink( bgp2, cs0 )
+ #self.addLink( bgp2, sw4 )
+
+ #Links to the multihomed AS
+ self.addLink( host3, sw3 )
+ self.addLink( host3, sw5 )
+ self.addLink( as2host, host3 )
+ #Single links to the remaining two ASes
+ self.addLink( host4, sw2 )
+ self.addLink( as3host, host4 )
+ self.addLink( host5, sw6 )
+ self.addLink( as4host, host5 )
+ #AS3-AS4 link
+ #self.addLink( host4, host5)
+ #Add new AS6 to its bridge
+ #self.addLink( as6rs, as6sw )
+ #self.addLink( as6rs2, as6sw )
+ #self.addLink( as6router, as6sw )
+ #self.addLink( as6host, as6router )
+ #for i in range(1, 10):
+ # host = self.addHost('as6host%d' % i)
+ # self.addLink(host, as6router)
+
+ self.addLink( sw1, sw2 )
+ self.addLink( sw1, sw3 )
+ self.addLink( sw2, sw4 )
+ self.addLink( sw3, sw4 )
+ self.addLink( sw3, sw5 )
+ self.addLink( sw4, sw6 )
+ self.addLink( sw5, sw6 )
+ self.addLink( as6sw, sw4 )
+
+if __name__ == "__main__":
+ setLogLevel('debug')
+ topo = BgpRouterDeployTopo()
+
+ net = Mininet(topo=topo, controller=None)
+ for i in range(len(onoses)):
+ net.addController( RemoteController( 'c%s' % (i+1), ip=onoses[i], checkListening=False ) )
+
+ net.start()
+
+ CLI(net)
+
+ net.stop()
+
+ info("done\n")
diff --git a/routinglib.py b/routinglib.py
new file mode 100644
index 0000000..b2e8245
--- /dev/null
+++ b/routinglib.py
@@ -0,0 +1,638 @@
+#!/usr/bin/python
+
+"""
+Libraries for creating L3 topologies with routing protocols.
+"""
+
+from mininet.node import Host, OVSBridge
+from mininet.nodelib import NAT
+from mininet.log import info, debug, error
+from mininet.cli import CLI
+from ipaddress import ip_network, ip_address, ip_interface
+
+class RoutedHost(Host):
+ """Host that can be configured with multiple IP addresses."""
+ def __init__(self, name, ips, gateway, *args, **kwargs):
+ super(RoutedHost, self).__init__(name, *args, **kwargs)
+
+ self.ips = ips
+ self.gateway = gateway
+
+ def config(self, **kwargs):
+ Host.config(self, **kwargs)
+
+ self.cmd('ip addr flush dev %s' % self.defaultIntf())
+ for ip in self.ips:
+ self.cmd('ip addr add %s dev %s' % (ip, self.defaultIntf()))
+
+ self.cmd('ip route add default via %s' % self.gateway)
+
+class Router(Host):
+
+ """An L3 router.
+ Configures the Linux kernel for L3 forwarding and supports rich interface
+ configuration of IP addresses, MAC addresses and VLANs."""
+
+ def __init__(self, name, interfaces, *args, **kwargs):
+ super(Router, self).__init__(name, **kwargs)
+
+ self.interfaces = interfaces
+
+ def config(self, **kwargs):
+ super(Host, self).config(**kwargs)
+
+ self.cmd('sysctl net.ipv4.ip_forward=1')
+ self.cmd('sysctl net.ipv4.conf.all.rp_filter=0')
+
+ for intf, configs in self.interfaces.items():
+ self.cmd('ip addr flush dev %s' % intf)
+ self.cmd( 'sysctl net.ipv4.conf.%s.rp_filter=0' % intf )
+
+ if not isinstance(configs, list):
+ configs = [configs]
+
+ for attrs in configs:
+ # Configure the vlan if there is one
+ if 'vlan' in attrs:
+ vlanName = '%s.%s' % (intf, attrs['vlan'])
+ self.cmd('ip link add link %s name %s type vlan id %s' %
+ (intf, vlanName, attrs['vlan']))
+ self.cmd('ip link set %s up' % vlanName)
+ addrIntf = vlanName
+ else:
+ addrIntf = intf
+
+ # Now configure the addresses on the vlan/native interface
+ if 'mac' in attrs:
+ self.cmd('ip link set %s down' % addrIntf)
+ self.cmd('ip link set %s address %s' % (addrIntf, attrs['mac']))
+ self.cmd('ip link set %s up' % addrIntf)
+ for addr in attrs['ipAddrs']:
+ self.cmd('ip addr add %s dev %s' % (addr, addrIntf))
+
+class QuaggaRouter(Router):
+
+ """Runs Quagga to create a router that can speak routing protocols."""
+
+ binDir = '/usr/lib/quagga'
+
+ def __init__(self, name, interfaces,
+ defaultRoute=None,
+ zebraConfFile=None,
+ protocols=[],
+ fpm=None,
+ runDir='/var/run/quagga', *args, **kwargs):
+ super(QuaggaRouter, self).__init__(name, interfaces, **kwargs)
+
+ self.protocols = protocols
+ self.fpm = fpm
+
+ for p in self.protocols:
+ p.setQuaggaRouter(self)
+
+ self.runDir = runDir
+ self.defaultRoute = defaultRoute
+
+ self.zebraConfFile = zebraConfFile
+ if (self.zebraConfFile is None):
+ self.zebraConfFile = '%s/zebrad%s.conf' % (self.runDir, self.name)
+ self.generateZebra()
+
+ self.socket = '%s/zebra%s.api' % (self.runDir, self.name)
+
+ self.zebraPidFile = '%s/zebra%s.pid' % (self.runDir, self.name)
+
+ def generateZebra(self):
+ configFile = open(self.zebraConfFile, 'w+')
+ configFile.write('hostname zebra-%s\n' % self.name)
+ configFile.write('password %s\n' % 'hello')
+ if (self.fpm is not None):
+ configFile.write('fpm connection ip %s port 2620' % self.fpm)
+ configFile.close()
+
+ def config(self, **kwargs):
+ super(QuaggaRouter, self).config(**kwargs)
+
+ self.cmd('%s/zebra -d -f %s -z %s -i %s'
+ % (QuaggaRouter.binDir, self.zebraConfFile, self.socket, self.zebraPidFile))
+
+ for p in self.protocols:
+ p.config(**kwargs)
+
+ if self.defaultRoute:
+ self.cmd('ip route add default via %s' % self.defaultRoute)
+
+ def terminate(self, **kwargs):
+ self.cmd("ps ax | grep '%s' | awk '{print $1}' | xargs kill"
+ % (self.socket))
+
+ for p in self.protocols:
+ p.terminate(**kwargs)
+
+ super(QuaggaRouter, self).terminate()
+
+class Protocol(object):
+
+ """Base abstraction of a protocol that the QuaggaRouter can run."""
+
+ def setQuaggaRouter(self, qr):
+ self.qr = qr
+
+ def config(self, **kwargs):
+ pass
+
+ def terminate(self, **kwargs):
+ pass
+
+class BgpProtocol(Protocol):
+
+ """Configures and runs the BGP protocol in Quagga."""
+
+ def __init__(self, configFile=None, asNum=None, neighbors=[], routes=[], *args, **kwargs):
+ self.configFile = configFile
+
+ self.asNum = asNum
+ self.neighbors = neighbors
+ self.routes = routes
+
+ def config(self, **kwargs):
+ if self.configFile is None:
+ self.configFile = '%s/bgpd%s.conf' % (self.qr.runDir, self.qr.name)
+ self.generateConfig()
+
+ bgpdPidFile = '%s/bgpd%s.pid' % (self.qr.runDir, self.qr.name)
+
+ self.qr.cmd('%s/bgpd -d -f %s -z %s -i %s'
+ % (QuaggaRouter.binDir, self.configFile, self.qr.socket, bgpdPidFile))
+
+ def generateConfig(self):
+ conf = ConfigurationWriter(self.configFile)
+
+ def getRouterId(interfaces):
+ intfAttributes = interfaces.itervalues().next()
+ print intfAttributes
+ if isinstance(intfAttributes, list):
+ # Try use the first set of attributes, but if using vlans they might not have addresses
+ intfAttributes = intfAttributes[1] if not intfAttributes[0]['ipAddrs'] else intfAttributes[0]
+ return intfAttributes['ipAddrs'][0].split('/')[0]
+
+ conf.writeLine('hostname bgp-%s' % self.qr.name);
+ conf.writeLine('password %s' % 'sdnip')
+ conf.writeLine('!')
+ conf.writeLine('router bgp %s' % self.asNum)
+
+ conf.indent()
+
+ conf.writeLine('bgp router-id %s' % getRouterId(self.qr.interfaces))
+ conf.writeLine('timers bgp %s' % '3 9')
+ conf.writeLine('!')
+
+ for neighbor in self.neighbors:
+ conf.writeLine('neighbor %s remote-as %s' % (neighbor['address'], neighbor['as']))
+ conf.writeLine('neighbor %s ebgp-multihop' % neighbor['address'])
+ conf.writeLine('neighbor %s timers connect %s' % (neighbor['address'], '5'))
+ conf.writeLine('neighbor %s advertisement-interval %s' % (neighbor['address'], '5'))
+ if 'port' in neighbor:
+ conf.writeLine('neighbor %s port %s' % (neighbor['address'], neighbor['port']))
+ conf.writeLine('!')
+
+ for route in self.routes:
+ conf.writeLine('network %s' % route)
+
+ conf.close()
+
+class OspfProtocol(Protocol):
+
+ """Configures and runs the OSPF protocol in Quagga."""
+
+ def __init__(self, configFile=None, *args, **kwargs):
+ self.configFile = configFile
+
+ def config(self, **kwargs):
+ if self.configFile is None:
+ self.configFile = '%s/ospfd%s.conf' % (self.qr.runDir, self.qr.name)
+ self.generateConfig()
+
+ ospfPidFile = '%s/ospf%s.pid' % (self.qr.runDir, self.qr.name)
+
+ self.qr.cmd('%s/ospfd -d -f %s -z %s -i %s'
+ % (QuaggaRouter.binDir, self.configFile, self.qr.socket, ospfPidFile))
+
+ def generateConfig(self):
+ conf = ConfigurationWriter(self.configFile)
+
+ def getRouterId(interfaces):
+ intfAttributes = interfaces.itervalues().next()
+ print intfAttributes
+ if isinstance(intfAttributes, list):
+ # Try use the first set of attributes, but if using vlans they might not have addresses
+ intfAttributes = intfAttributes[1] if not intfAttributes[0]['ipAddrs'] else intfAttributes[0]
+ return intfAttributes['ipAddrs'][0].split('/')[0]
+
+ conf.writeLine('hostname ospf-%s' % self.qr.name);
+ conf.writeLine('password %s' % 'hello')
+ conf.writeLine('!')
+ conf.writeLine('router ospf')
+
+ conf.indent()
+
+ conf.writeLine('ospf router-id %s' % getRouterId(self.qr.interfaces))
+ conf.writeLine('!')
+
+ for name, intf in self.qr.interfaces.items():
+ for ip in intf['ipAddrs']:
+ conf.writeLine('network %s area 0' % ip)
+ #if intf['ipAddrs'][0].startswith('192.168'):
+ # writeLine(1, 'passive-interface %s' % name)
+
+ conf.close()
+
+class PimProtocol(Protocol):
+
+ """Configures and runs the PIM protcol in Quagga."""
+
+ def __init__(self, configFile=None, *args, **kwargs):
+ self.configFile = configFile
+
+ def config(self, **kwargs):
+ pimPidFile = '%s/pim%s.pid' % (self.qr.runDir, self.qr.name)
+
+ self.qr.cmd('%s/pimd -d -f %s -z %s -i %s'
+ % (QuaggaRouter.binDir, self.configFile, self.qr.socket, pimPidFile))
+
+class ConfigurationWriter(object):
+
+ """Utility class for writing a configuration file."""
+
+ def __init__(self, filename):
+ self.filename = filename
+ self.indentValue = 0;
+
+ self.configFile = open(self.filename, 'w+')
+
+ def indent(self):
+ self.indentValue += 1
+
+ def unindent(self):
+ if (self.indentValue > 0):
+ self.indentValue -= 1
+
+ def write(self, string):
+ self.configFile.write(string)
+
+ def writeLine(self, string):
+ intentStr = ''
+ for _ in range(0, self.indentValue):
+ intentStr += ' '
+ self.write('%s%s\n' % (intentStr, string))
+
+ def close(self):
+ self.configFile.close()
+
+#Backward compatibility for BGP-only use case
+class BgpRouter(QuaggaRouter):
+
+ """Quagga router running the BGP protocol."""
+
+ def __init__(self, name, interfaces,
+ asNum, neighbors, routes=[],
+ defaultRoute=None,
+ quaggaConfFile=None,
+ zebraConfFile=None,
+ *args, **kwargs):
+ bgp = BgpProtocol(configFile=quaggaConfFile, asNum=asNum, neighbors=neighbors, routes=routes)
+
+ super(BgpRouter, self).__init__(name, interfaces,
+ zebraConfFile=zebraConfFile,
+ defaultRoute=defaultRoute,
+ protocols=[bgp],
+ *args, **kwargs)
+
+class RouterData(object):
+
+ """Internal data structure storing information about a router."""
+
+ def __init__(self, index):
+ self.index = index;
+ self.neighbors = []
+ self.interfaces = {}
+ self.switches = []
+
+ def addNeighbor(self, theirAddress, theirAsNum):
+ self.neighbors.append({'address':theirAddress.ip, 'as':theirAsNum})
+
+ def addInterface(self, intf, vlan, address):
+ if not intf in self.interfaces:
+ self.interfaces[intf] = InterfaceData(intf)
+
+ self.interfaces[intf].addAddress(vlan, address)
+
+ def setSwitch(self, switch):
+ self.switches.append(switch)
+
+class InterfaceData(object):
+
+ """Internal data structure storing information about an interface."""
+
+ def __init__(self, number):
+ self.number = number
+ self.addressesByVlan = {}
+
+ def addAddress(self, vlan, address):
+ if not vlan in self.addressesByVlan:
+ self.addressesByVlan[vlan] = []
+
+ self.addressesByVlan[vlan].append(address.with_prefixlen)
+
+class RoutedNetwork(object):
+
+ """Creates a host behind a router. This is common boilerplate topology
+ segment in routed networks."""
+
+ @staticmethod
+ def build(topology, router, hostName, networks):
+ # There's a convention that the router's addresses are already set up,
+ # and it has the last address in the network.
+
+ def getFirstAddress(network):
+ return '%s/%s' % (network[1], network.prefixlen)
+
+ defaultRoute = AutonomousSystem.getLastAddress(networks[0]).ip
+
+ host = topology.addHost(hostName, cls=RoutedHost,
+ ips=[getFirstAddress(network) for network in networks],
+ gateway=defaultRoute)
+
+ topology.addLink(router, host)
+
+class AutonomousSystem(object):
+
+ """Base abstraction of an autonomous system, which implies some internal
+ topology and connections to other topology elements (switches/other ASes)."""
+
+ psIdx = 1
+
+ def __init__(self, asNum, numRouters):
+ self.asNum = asNum
+ self.numRouters = numRouters
+ self.routers = {}
+ for i in range(1, numRouters + 1):
+ self.routers[i] = RouterData(i)
+
+ self.routerNodes={}
+
+ self.neighbors=[]
+ self.vlanAddresses={}
+
+ def peerWith(self, myRouter, myAddress, theirAddress, theirAsNum, intf=1, vlan=None):
+ router = self.routers[myRouter]
+
+ router.addInterface(intf, vlan, myAddress)
+ router.addNeighbor(theirAddress, theirAsNum)
+
+ def getRouter(self, i):
+ return self.routerNodes[i]
+
+ @staticmethod
+ def generatePeeringAddresses():
+ network = ip_network(u'10.0.%s.0/24' % AutonomousSystem.psIdx)
+ AutonomousSystem.psIdx += 1
+
+ return ip_interface('%s/%s' % (network[1], network.prefixlen)), \
+ ip_interface('%s/%s' % (network[2], network.prefixlen))
+
+ @staticmethod
+ def addPeering(as1, as2, router1=1, router2=1, intf1=1, intf2=1, address1=None, address2=None, useVlans=False):
+ vlan = AutonomousSystem.psIdx if useVlans else None
+
+ if address1 is None or address2 is None:
+ (address1, address2) = AutonomousSystem.generatePeeringAddresses()
+
+ as1.peerWith(router1, address1, address2, as2.asNum, intf=intf1, vlan=vlan)
+ as2.peerWith(router2, address2, address1, as1.asNum, intf=intf2, vlan=vlan)
+
+ @staticmethod
+ def getLastAddress(network):
+ return ip_interface(network.network_address + network.num_addresses - 2)
+
+ @staticmethod
+ def getIthAddress(network, i):
+ return ip_interface('%s/%s' % (network[i], network.prefixlen))
+
+class BasicAutonomousSystem(AutonomousSystem):
+
+ """Basic autonomous system containing one host and one or more routers
+ which peer with other ASes."""
+
+ def __init__(self, num, routes, numRouters=1):
+ super(BasicAutonomousSystem, self).__init__(65000+num, numRouters)
+ self.num = num
+ self.routes = routes
+
+ def addLink(self, switch, router=1):
+ self.routers[router].setSwitch(switch)
+
+ def build(self, topology):
+ self.addRouterAndHost(topology)
+
+ def addRouterAndHost(self, topology):
+
+ # TODO implementation is messy and needs to be cleaned up
+
+ intfs = {}
+
+ router = self.routers[1]
+ for i, router in self.routers.items():
+
+ #routerName = 'r%i%i' % (self.num, i)
+ routerName = 'r%i' % self.num
+ if not i==1:
+ routerName += ('%i' % i)
+
+ hostName = 'h%i' % self.num
+
+ for j, interface in router.interfaces.items():
+ nativeAddresses = interface.addressesByVlan.pop(None, [])
+ peeringIntf = [{'mac' : '00:00:%02x:00:%02x:%02x' % (self.num, i, j),
+ 'ipAddrs' : nativeAddresses}]
+
+ for vlan, addresses in interface.addressesByVlan.items():
+ peeringIntf.append({'vlan':vlan,
+ 'mac':'00:00:%02x:%02x:%02x:%02x' % (self.num, vlan, i, j),
+ 'ipAddrs':addresses})
+
+ intfs.update({'%s-eth%s' % (routerName, j-1) : peeringIntf})
+
+ # Only add the host to the first router for now
+ if i==1:
+ internalAddresses=[]
+ for route in self.routes:
+ internalAddresses.append('%s/%s' % (AutonomousSystem.getLastAddress(route).ip, route.prefixlen))
+
+ internalIntf = {'ipAddrs' : internalAddresses}
+
+ # This is the configuration of the next interface after all the peering interfaces
+ intfs.update({'%s-eth%s' % (routerName, len(router.interfaces.keys())) : internalIntf})
+
+ routerNode = topology.addHost(routerName,
+ asNum=self.asNum, neighbors=router.neighbors,
+ routes=self.routes,
+ cls=BgpRouter, interfaces=intfs)
+
+ self.routerNodes[i] = routerNode
+
+ for switch in router.switches:
+ topology.addLink(switch, routerNode)
+
+ # Only add the host to the first router for now
+ if i==1:
+ defaultRoute = internalAddresses[0].split('/')[0]
+
+ host = topology.addHost(hostName, cls=RoutedHost,
+ ips=[self.getFirstAddress(route) for route in self.routes],
+ gateway=defaultRoute)
+
+ topology.addLink(routerNode, host)
+
+ #def getLastAddress(self, network):
+ # return ip_address(network.network_address + network.num_addresses - 2)
+
+ def getFirstAddress(self, network):
+ return '%s/%s' % (network[1], network.prefixlen)
+
+# TODO fix this AS - doesn't currently work
+class RouteServerAutonomousSystem(BasicAutonomousSystem):
+
+ def __init__(self, routerAddress, *args, **kwargs):
+ BasicAutonomousSystem.__init__(self, *args, **kwargs)
+
+ self.routerAddress = routerAddress
+
+ def build(self, topology, connectAtSwitch):
+
+ switch = topology.addSwitch('as%isw' % self.num, cls=OVSBridge)
+
+ self.addRouterAndHost(topology, self.routerAddress, switch)
+
+ rsName = 'rs%i' % self.num
+ routeServer = topology.addHost(rsName,
+ self.asnum, self.neighbors,
+ cls=BgpRouter,
+ interfaces={'%s-eth0' % rsName : {'ipAddrs':[self.peeringAddress]}})
+
+ topology.addLink(routeServer, switch)
+ topology.addLink(switch, connectAtSwitch)
+
+class SdnAutonomousSystem(AutonomousSystem):
+
+ """Runs the internal BGP speakers needed for ONOS routing apps like
+ SDN-IP."""
+
+ def __init__(self, onosIps, numBgpSpeakers=1, asNum=65000, externalOnos=True, peerIntfConfig=None):
+ super(SdnAutonomousSystem, self).__init__(asNum, numBgpSpeakers)
+ self.onosIps = onosIps
+ self.numBgpSpeakers = numBgpSpeakers
+ self.peerIntfConfig = peerIntfConfig
+ self.externalOnos= externalOnos
+ self.internalPeeringSubnet = ip_network(u'1.1.1.0/24')
+
+ for router in self.routers.values():
+ # Add iBGP sessions to ONOS nodes
+ for onosIp in onosIps:
+ router.neighbors.append({'address':onosIp, 'as':asNum, 'port':2000})
+
+ # Add iBGP sessions to other BGP speakers
+ for i, router2 in self.routers.items():
+ if router == router2:
+ continue
+ ip = AutonomousSystem.getIthAddress(self.internalPeeringSubnet, 10+i)
+ router.neighbors.append({'address':ip.ip, 'as':asNum})
+
+ def build(self, topology, connectAtSwitch, controlSwitch):
+
+ natIp = AutonomousSystem.getLastAddress(self.internalPeeringSubnet)
+
+ for i, router in self.routers.items():
+ name = 'bgp%s' % i
+
+ ip = AutonomousSystem.getIthAddress(self.internalPeeringSubnet, 10+i)
+ eth0 = { 'ipAddrs' : [ str(ip) ] }
+ if self.peerIntfConfig is not None:
+ eth1 = self.peerIntfConfig
+ else:
+ nativeAddresses = router.interfaces[1].addressesByVlan.pop(None, [])
+ eth1 = [{ 'mac':'00:00:00:00:00:%02x' % i,
+ 'ipAddrs' : nativeAddresses }]
+
+ for vlan, addresses in router.interfaces[1].addressesByVlan.items():
+ eth1.append({'vlan':vlan,
+ 'mac':'00:00:00:%02x:%02x:00' % (i, vlan),
+ 'ipAddrs':addresses})
+
+
+ intfs = { '%s-eth0' % name : eth0,
+ '%s-eth1' % name : eth1 }
+
+ bgp = topology.addHost( name, cls=BgpRouter, asNum=self.asNum,
+ neighbors=router.neighbors,
+ interfaces=intfs,
+ defaultRoute=str(natIp.ip),
+ fpm=self.onosIps[0] )
+
+ topology.addLink( bgp, controlSwitch )
+ topology.addLink( bgp, connectAtSwitch )
+
+
+ if self.externalOnos:
+ nat = topology.addHost('nat', cls=NAT,
+ ip='%s/%s' % (natIp.ip, self.internalPeeringSubnet.prefixlen),
+ subnet=str(self.internalPeeringSubnet), inNamespace=False);
+ topology.addLink(controlSwitch, nat)
+
+
+def generateRoutes(baseRange, numRoutes, subnetSize=None):
+ baseNetwork = ip_network(baseRange)
+
+ # We need to get at least 2 addresses out of each subnet, so the biggest
+ # prefix length we can have is /30
+ maxPrefixLength = baseNetwork.max_prefixlen - 2
+
+ if subnetSize is not None:
+ return list(baseNetwork.subnets(new_prefix=subnetSize))
+
+ trySubnetSize = baseNetwork.prefixlen + 1
+ while trySubnetSize <= maxPrefixLength and \
+ len(list(baseNetwork.subnets(new_prefix=trySubnetSize))) < numRoutes:
+ trySubnetSize += 1
+
+ if trySubnetSize > maxPrefixLength:
+ raise Exception("Can't get enough routes from input parameters")
+
+ return list(baseNetwork.subnets(new_prefix=trySubnetSize))[:numRoutes]
+
+class RoutingCli( CLI ):
+
+ """CLI command that can bring a host up or down. Useful for simulating router failure."""
+
+ def do_host( self, line ):
+ args = line.split()
+ if len(args) != 2:
+ error( 'invalid number of args: host <host name> {up, down}\n' )
+ return
+
+ host = args[ 0 ]
+ command = args[ 1 ]
+ if host not in self.mn or self.mn.get( host ) not in self.mn.hosts:
+ error( 'invalid host: %s\n' % args[ 1 ] )
+ else:
+ if command == 'up':
+ op = 'up'
+ elif command == 'down':
+ op = 'down'
+ else:
+ error( 'invalid command: host <host name> {up, down}\n' )
+ return
+
+ for intf in self.mn.get( host ).intfList( ):
+ intf.link.intf1.ifconfig( op )
+ intf.link.intf2.ifconfig( op )
diff --git a/simple.py b/simple.py
new file mode 100755
index 0000000..e2cd797
--- /dev/null
+++ b/simple.py
@@ -0,0 +1,79 @@
+#!/usr/bin/python
+
+from mininet.topo import Topo
+from mininet.net import Mininet
+from mininet.node import RemoteController, OVSBridge
+from mininet.cli import CLI
+from mininet.log import setLogLevel, info
+from routinglib import BasicAutonomousSystem, RouteServerAutonomousSystem
+from routinglib import SdnAutonomousSystem, AutonomousSystem
+from ipaddress import ip_network
+
+onoses = [ '192.168.56.11' ]
+
+class SdnTopo( Topo ):
+ "Topology built using higher-level abstractions (ASes)"
+
+ def __init__( self, *args, **kwargs ):
+ Topo.__init__( self, *args, **kwargs )
+ sw1 = self.addSwitch('sw1', dpid='00000000000000a1')
+ sw2 = self.addSwitch('sw2', dpid='00000000000000a2')
+ sw3 = self.addSwitch('sw3', dpid='00000000000000a3')
+ sw4 = self.addSwitch('sw4', dpid='00000000000000a4')
+ sw5 = self.addSwitch('sw5', dpid='00000000000000a5')
+ sw6 = self.addSwitch('sw6', dpid='00000000000000a6')
+
+ # SDN AS
+ sdnAs = SdnAutonomousSystem(onoses, numBgpSpeakers=1, asNum=65000)
+
+ # Normal ASes
+ as1 = BasicAutonomousSystem(1, [ip_network(u'172.16.10.0/24')])
+
+ AutonomousSystem.addPeering(as1, sdnAs)
+ as1.addLink(sw3)
+ as1.build(self)
+
+ as2 = BasicAutonomousSystem(2, [ip_network(u'172.16.20.0/24')])
+
+ AutonomousSystem.addPeering(as2, sdnAs)
+ as2.addLink(sw2)
+ as2.build(self)
+
+ as3 = BasicAutonomousSystem(3, [ip_network(u'172.16.30.0/24')])
+
+ AutonomousSystem.addPeering(as3, sdnAs)
+ as3.addLink(sw6)
+ as3.build(self)
+
+ # AS containing a route server
+ #as4 = RouteServerAutonomousSystem('192.168.60.2/24', 4, '192.168.60.1/24',
+ # [ip_network(u'172.16.60.0/24')])
+ #as4.build(self, sw4);
+
+ cs0 = self.addSwitch('cs0', cls=OVSBridge)
+
+ sdnAs.build(self, sw1, cs0)
+
+ self.addLink( sw1, sw2 )
+ self.addLink( sw1, sw3 )
+ self.addLink( sw2, sw4 )
+ self.addLink( sw3, sw4 )
+ self.addLink( sw3, sw5 )
+ self.addLink( sw4, sw6 )
+ self.addLink( sw5, sw6 )
+
+if __name__ == "__main__":
+ setLogLevel('debug')
+ topo = SdnTopo()
+
+ net = Mininet(topo=topo, controller=None)
+ for i in range(len(onoses)):
+ net.addController( RemoteController( 'c%s' % (i+1), ip=onoses[i], checkListening=False ) )
+
+ net.start()
+
+ CLI(net)
+
+ net.stop()
+
+ info("done\n")
diff --git a/vrouter.py b/vrouter.py
new file mode 100755
index 0000000..8c6b7f7
--- /dev/null
+++ b/vrouter.py
@@ -0,0 +1,70 @@
+#!/usr/bin/python
+
+from mininet.topo import Topo
+from mininet.net import Mininet
+from mininet.cli import CLI
+from mininet.log import setLogLevel
+from mininet.node import RemoteController, OVSBridge
+from routinglib import BasicAutonomousSystem
+from routinglib import SdnAutonomousSystem, AutonomousSystem
+from routinglib import generateRoutes
+
+
+class VrouterTopo( Topo ):
+ "Single switch topology for testing the vRouter"
+
+ def __init__( self, *args, **kwargs ):
+ Topo.__init__( self, *args, **kwargs )
+ # Router switch
+ s1 = self.addSwitch('s1', dpid='00000000000000b1')
+
+ # SDN AS
+ onosIps = ['192.168.56.11']
+ sdnAs = SdnAutonomousSystem(onosIps, numBgpSpeakers=1, asNum=65000)
+
+ numRoutesPerAs = 1
+
+ # Normal ASes
+ as1 = BasicAutonomousSystem(1,
+ generateRoutes(u'10.1.0.0/16', numRoutesPerAs))
+ AutonomousSystem.addPeering(as1, sdnAs, useVlans=True)
+ as1.addLink(s1)
+ as1.build(self)
+
+ as2 = BasicAutonomousSystem(2,
+ generateRoutes(u'10.2.0.0/16', numRoutesPerAs))
+ AutonomousSystem.addPeering(as2, sdnAs, useVlans=True)
+ as2.addLink(s1)
+ as2.build(self)
+
+ as3 = BasicAutonomousSystem(3,
+ generateRoutes(u'10.3.0.0/16', numRoutesPerAs))
+ AutonomousSystem.addPeering(as3, sdnAs, useVlans=True)
+ as3.addLink(s1)
+ as3.build(self)
+
+ as4 = BasicAutonomousSystem(4,
+ generateRoutes(u'10.4.0.0/16', numRoutesPerAs))
+ AutonomousSystem.addPeering(as4, sdnAs, useVlans=False)
+ as4.addLink(s1)
+ as4.build(self)
+
+ # SDN AS (internal BGP speaker) connects to control plane switch
+ cs0 = self.addSwitch('cs0', cls=OVSBridge)
+ sdnAs.build(self, s1, cs0)
+
+topos = { 'vrouter' : VrouterTopo }
+
+if __name__ == "__main__":
+ setLogLevel('debug')
+ topo = VrouterTopo()
+
+ net = Mininet(topo=topo, controller=None)
+ net.addController(RemoteController('c0', ip='192.168.56.11'))
+
+ net.start()
+
+ CLI(net)
+
+ net.stop()
+