Add Trellis hybrid topology with only v4 hosts

Change-Id: I5d075fc2f82c1da6c7c8f3bf2eb7e4b9eb14c7e1
diff --git a/trellis/trellis_hybrid_v4.py b/trellis/trellis_hybrid_v4.py
new file mode 100644
index 0000000..0b0b3bb
--- /dev/null
+++ b/trellis/trellis_hybrid_v4.py
@@ -0,0 +1,239 @@
+#!/usr/bin/python
+
+import sys
+sys.path.append('..')
+from mininet.topo import Topo
+from mininet.cli import CLI
+from mininet.log import setLogLevel
+from mininet.node import RemoteController, OVSBridge, Host, OVSSwitch
+from mininet.link import TCLink
+from mininet.nodelib import NAT
+from ipaddress import ip_network
+from routinglib import BgpRouter
+from routinglib import RoutedHost, RoutedHost6
+from trellislib import DhcpClient, Dhcp6Client, Dhcp4and6Client, DhcpRelay, DhcpServer, Dhcp6Server
+from trellislib import DualHomedDhcpClient
+from trellislib import DualHomedDhcp4and6Client
+from trellislib import get_mininet, parse_trellis_args, set_up_zebra_config
+from functools import partial
+from bmv2 import ONOSBmv2Switch
+
+PIPECONF_ID = 'org.onosproject.pipelines.fabric'
+
+class Trellis( Topo ):
+    """Trellis HAG topology with both OVS and BMV2 switches"""
+
+    def __init__( self, *args, **kwargs ):
+        Topo.__init__( self, *args, **kwargs )
+
+        # Spines
+        s226 = self.addSwitch('s226', cls=ONOSBmv2Switch, pipeconf=PIPECONF_ID, portcfg=True)
+        s227 = self.addSwitch('s227', dpid='227')
+
+        # Leaves
+        s203 = self.addSwitch('s203', dpid='203')
+        s204 = self.addSwitch('s204', cls=ONOSBmv2Switch, pipeconf=PIPECONF_ID, portcfg=True)
+        s205 = self.addSwitch('s205', dpid='205')
+        s206 = self.addSwitch('s206', dpid='206')
+
+        # Leaf-Spine Links
+        self.addLink(s226, s203)
+        self.addLink(s226, s203)
+        self.addLink(s226, s204)
+        self.addLink(s226, s204)
+        self.addLink(s226, s205)
+        self.addLink(s226, s205)
+        self.addLink(s226, s206)
+        self.addLink(s226, s206)
+        self.addLink(s227, s203)
+        self.addLink(s227, s203)
+        self.addLink(s227, s204)
+        self.addLink(s227, s204)
+        self.addLink(s227, s205)
+        self.addLink(s227, s205)
+        self.addLink(s227, s206)
+        self.addLink(s227, s206)
+
+        # Leaf-Leaf Links
+        self.addLink(s203, s204)
+        self.addLink(s205, s206)
+
+        # NOTE avoid using 10.0.1.0/24 which is the default subnet of quaggas
+        # NOTE avoid using 00:00:00:00:00:xx which is the default mac of host behind upstream router
+        # IPv4 Hosts
+        h1 = self.addHost('h1', cls=DhcpClient, mac='00:aa:00:00:00:01')
+        h2 = self.addHost('h2', cls=DhcpClient, mac='00:aa:00:00:00:02')
+        h3 = self.addHost('h3', cls=DhcpClient, mac='00:aa:00:00:00:03')
+        h4 = self.addHost('h4', cls=DhcpClient, mac='00:aa:00:00:00:04')
+        h5 = self.addHost('h5', cls=DhcpClient, mac='00:aa:00:00:00:05')
+        self.addLink(h1, s204)
+        self.addLink(h2, s204)
+        self.addLink(h3, s205)
+        self.addLink(h4, s205)
+        self.addLink(h5, s203)
+
+        # IPv6 Hosts
+        #h1v6 = self.addHost('h1v6', cls=Dhcp6Client, mac='00:bb:00:00:00:01')
+        #h2v6 = self.addHost('h2v6', cls=Dhcp6Client, mac='00:bb:00:00:00:02')
+        #h3v6 = self.addHost('h3v6', cls=Dhcp6Client, mac='00:bb:00:00:00:03')
+        #h4v6 = self.addHost('h4v6', cls=Dhcp6Client, mac='00:bb:00:00:00:04')
+        #h5v6 = self.addHost('h5v6', cls=Dhcp6Client, mac='00:bb:00:00:00:05')
+        #self.addLink(h1v6, s204)
+        #self.addLink(h2v6, s204)
+        #self.addLink(h3v6, s205)
+        #self.addLink(h4v6, s205)
+        #self.addLink(h5v6, s203)
+
+        # Dual-homed IPv4 and IPv6 Host on 203-204
+        dh1 = self.addHost('dh1', cls=DualHomedDhcp4and6Client, mac='00:cc:00:00:00:01')
+        self.addLink(dh1, s204)
+        self.addLink(dh1, s203)
+
+        # DHCP server
+        dhcp = self.addHost('dhcp', cls=DhcpServer, mac='00:99:00:00:00:01', ips=['10.0.3.253/24'], gateway='10.0.3.254')
+
+        # DHCPv6 server
+        #dhcp6 = self.addHost('dhcp6', cls=Dhcp6Server, mac='00:99:66:00:00:01', ips=['2000::3fd/120'], gateway='2000::3ff')
+
+        # Dataplane L2 plane switch (for DHCP servers)
+        cs1 = self.addSwitch('cs1', cls=OVSBridge)
+        self.addLink(cs1, s205)
+        self.addLink(dhcp, cs1)
+        #self.addLink(dhcp6, cs1)
+
+        # Control plane switch (for quagga fpm)
+        cs0 = self.addSwitch('cs0', cls=OVSBridge)
+
+        # Control plane NAT (for quagga fpm)
+        nat = self.addHost('nat', cls=NAT,
+                           ip='172.16.0.1/24',
+                           subnet=str(ip_network(u'172.16.0.0/24')), inNamespace=False)
+        self.addLink(cs0, nat)
+
+        # Internal Quagga bgp1
+        """
+        intfs = {'bgp1-eth0': [{'ipAddrs': ['10.0.1.2/24', '2000::102/120'], 'mac': '00:88:00:00:00:03', 'vlan': '110'},
+                               {'ipAddrs': ['10.0.7.2/24', '2000::702/120'], 'mac': '00:88:00:00:00:03', 'vlan': '170'}],
+                 'bgp1-eth1': {'ipAddrs': ['172.16.0.3/24']}}
+        """
+        intfs = {'bgp1-eth0': {'ipAddrs': ['10.0.1.2/24'], 'mac': '00:88:00:00:00:03', 'vlan': '110'},
+                 'bgp1-eth1': {'ipAddrs': ['172.16.0.3/24']}}
+        bgp1 = self.addHost('bgp1', cls=BgpRouter,
+                            interfaces=intfs,
+                            quaggaConfFile='./bgpdbgp1.conf',
+                            zebraConfFile='./zebradbgp1.conf')
+        self.addLink(bgp1, s205)
+        self.addLink(bgp1, cs0)
+
+        # Internal Quagga bgp2
+        """
+        intfs = {'bgp2-eth0': [{'ipAddrs': ['10.0.5.2/24', '2000::502/120'], 'mac': '00:88:00:00:00:04', 'vlan': '150'},
+                               {'ipAddrs': ['10.0.6.2/24', '2000::602/120'], 'mac': '00:88:00:00:00:04', 'vlan': '160'}],
+                 'bgp2-eth1': {'ipAddrs': ['172.16.0.4/24']}}
+        """
+        intfs = {'bgp2-eth0': {'ipAddrs': ['10.0.6.2/24'], 'mac': '00:88:00:00:00:04', 'vlan': '160'},
+                 'bgp2-eth1': {'ipAddrs': ['172.16.0.4/24']}}
+        bgp2 = self.addHost('bgp2', cls=BgpRouter,
+                            interfaces=intfs,
+                            quaggaConfFile='./bgpdbgp2.conf',
+                            zebraConfFile='./zebradbgp2.conf')
+        self.addLink(bgp2, s206)
+        self.addLink(bgp2, cs0)
+
+        # External Quagga r1
+        intfs = {'r1-eth0': {'ipAddrs': ['10.0.1.1/24'], 'mac': '00:88:00:00:00:01'},
+                 'r1-eth1': {'ipAddrs': ['10.0.99.1/16']}}
+        r1 = self.addHost('r1', cls=BgpRouter,
+                            interfaces=intfs,
+                            quaggaConfFile='./bgpdr1.conf')
+        self.addLink(r1, s205)
+        #self.addLink(r1, s206)
+
+        # External IPv4 Host behind r1
+        rh1 = self.addHost('rh1', cls=RoutedHost, ips=['10.0.99.2/24'], gateway='10.0.99.1')
+        self.addLink(r1, rh1)
+
+        # External IPv6 Host behind r1
+        #rh1v6 = self.addHost('rh1v6', cls=RoutedHost, ips=['2000::9902/120'], gateway='2000::9901')
+        #self.addLink(r1, rh1v6)
+
+        # Another external IPv6 Host behind r1
+        #rh11v6 = self.addHost('rh11v6', cls=RoutedHost, ips=['2000::7702/120'], gateway='2000::7701')
+        #self.addLink(r1, rh11v6)
+
+        # External Quagga r2
+        intfs = {'r2-eth0': {'ipAddrs': ['10.0.6.1/24'], 'mac': '00:88:00:00:00:02'},
+                 'r2-eth1': {'ipAddrs': ['10.0.99.1/16']}}
+        r2 = self.addHost('r2', cls=BgpRouter,
+                            interfaces=intfs,
+                            quaggaConfFile='./bgpdr2.conf')
+        self.addLink(r2, s206)
+        #self.addLink(r2, s205)
+
+        # External IPv4 Host behind r2
+        rh2 = self.addHost('rh2', cls=RoutedHost, ips=['10.0.99.2/24'], gateway='10.0.99.1')
+        self.addLink(r2, rh2)
+
+        # External IPv6 Host behind r2
+        #rh2v6 = self.addHost('rh126', cls=RoutedHost, ips=['2000::9902/120'], gateway='2000::9901')
+        #self.addLink(r2, rh2v6)
+
+        # Another external IPv6 Host behind r1
+        #rh22v6 = self.addHost('rh22v6', cls=RoutedHost, ips=['2000::8802/120'], gateway='2000::8801')
+        #self.addLink(r2, rh22v6)
+
+        # Dual-homed IPv4 Host for 205-206
+        dh2 = self.addHost('dh2', cls=DualHomedDhcpClient, mac='00:cc:00:00:00:02')
+        self.addLink(dh2, s205)
+        self.addLink(dh2, s206)
+
+        # ----- Secondary fabric -----
+
+        # Spines(HAG)
+        s246 = self.addSwitch('s246', cls=ONOSBmv2Switch, pipeconf=PIPECONF_ID, portcfg=True)
+        s247 = self.addSwitch('s247', cls=ONOSBmv2Switch, pipeconf=PIPECONF_ID, portcfg=True)
+
+        # Leaves(DAAS)
+        s207 = self.addSwitch('s207', dpid='207')
+        s208 = self.addSwitch('s208', cls=ONOSBmv2Switch, pipeconf=PIPECONF_ID, portcfg=True)
+
+        # HAG-DAAS Links
+        self.addLink(s246, s207)
+        self.addLink(s246, s208)
+        self.addLink(s247, s207)
+        self.addLink(s247, s208)
+
+        # HAG - Spine Links
+        self.addLink(s246, s226)
+        self.addLink(s247, s227)
+
+        # IPv4 Hosts - RPDs
+        rpd5 = self.addHost('rpd5', cls=DhcpClient, mac='00:dd:00:00:00:01')
+        rpd6 = self.addHost('rpd6', cls=DhcpClient, mac='00:dd:00:00:00:02')
+        self.addLink(rpd5, s207)
+        self.addLink(rpd6, s208)
+
+        # IPv6 Hosts - RPDs
+        #rpd5v6 = self.addHost('rpd5v6', cls=Dhcp6Client, mac='00:ee:00:00:00:01')
+        #rpd6v6 = self.addHost('rpd6v6', cls=Dhcp6Client, mac='00:ee:00:00:00:02')
+        #self.addLink(rpd5v6, s207)
+        #self.addLink(rpd6v6, s208)
+
+
+
+
+
+topos = { 'trellis' : Trellis }
+
+if __name__ == "__main__":
+    setLogLevel('debug')
+
+    topo = Trellis()
+    switch = partial(OVSSwitch, protocols='OpenFlow13')
+    arguments = parse_trellis_args()
+    set_up_zebra_config(arguments.controllers)
+    net = get_mininet(arguments, topo, switch)
+
+    net.start()
+    CLI(net)
+    net.stop()