[ONOS-7357] Test TrellisHost class

Change-Id: I1eddd2d84a6d012411d7ea1a9a8226bf9d2bddd9
diff --git a/TestON/tests/USECASE/SegmentRouting/dependencies/trellis_fabric.py b/TestON/tests/USECASE/SegmentRouting/dependencies/trellis_fabric.py
index a39ed13..b0b26a1 100644
--- a/TestON/tests/USECASE/SegmentRouting/dependencies/trellis_fabric.py
+++ b/TestON/tests/USECASE/SegmentRouting/dependencies/trellis_fabric.py
@@ -12,8 +12,8 @@
 from mininet.nodelib import NAT
 from mininet.cli import CLI
 
-from routinglib import BgpRouter, RoutedHost
-from trellislib import DhcpServer, TaggedRoutedHost, DualHomedRoutedHost, DualHomedTaggedRoutedHost
+from routinglib import BgpRouter
+from trellislib import TrellisHost
 
 # Parse command line options and dump results
 def parseOptions():
@@ -124,19 +124,21 @@
                 if vlan_id[ dual_ls * fanout + f] != 0:
                     host = self.addHost(
                         name='h%s' % ( dual_ls * fanout + f + 1),
-                        cls=DualHomedTaggedRoutedHost,
+                        cls=TrellisHost,
                         ips=['10.0.%d.%d/%d' % ( dual_ls + 2, f + 1, IP4_SUBNET_CLASS)],
                         gateway='10.0.%d.254' % ( dual_ls + 2),
                         mac='00:aa:00:00:00:%02x' % (dual_ls * fanout + f + 1),
-                        vlan=vlan_id[ dual_ls*fanout + f ]
+                        vlan=vlan_id[ dual_ls*fanout + f ],
+                        dualHomed=True
                     )
                 else:
                     host = self.addHost(
                         name='h%s' % (dual_ls * fanout + f + 1),
-                        cls= DualHomedRoutedHost,
+                        cls=TrellisHost,
                         ips=['10.0.%d.%d/%d' % (dual_ls+2, f+1, IP4_SUBNET_CLASS)],
                         gateway='10.0.%d.254' % (dual_ls+2),
-                        mac='00:aa:00:00:00:%02x' % (dual_ls * fanout + f + 1)
+                        mac='00:aa:00:00:00:%02x' % (dual_ls * fanout + f + 1),
+                        dualHomed=True
                     )
                 self.addLink(host, leafs[ls], **linkopts)
                 self.addLink(host, leafs[ls-1], **linkopts)
@@ -145,8 +147,8 @@
         last_paired_ls = leafs[leaf-1]
         # Create common components
         # 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')
+        dhcp = self.addHost('dhcp', cls=TrellisHost, mac='00:99:00:00:00:01', ips=['10.0.3.253/24'],
+                            gateway='10.0.3.254', dhcpServer=True)
 
         # Control plane switch (for DHCP servers)
         cs1 = self.addSwitch('cs1', cls=OVSBridge)
@@ -194,7 +196,7 @@
         self.addLink(r1, last_paired_ls)
 
         # External IPv4 Host behind r1
-        rh1 = self.addHost('rh1', cls=RoutedHost, ips=['10.0.99.2/24'], gateway='10.0.99.1')
+        rh1 = self.addHost('rh1', cls=TrellisHost, ips=['10.0.99.2/24'], gateway='10.0.99.1')
         self.addLink(r1, rh1)
 
         # External Quagga r2
@@ -208,7 +210,7 @@
         self.addLink(r2, last_paired_ls)
 
         # External IPv4 Host behind r2
-        rh2 = self.addHost('rh2', cls=RoutedHost, ips=['10.0.99.2/24'], gateway='10.0.99.1')
+        rh2 = self.addHost('rh2', cls=TrellisHost, ips=['10.0.99.2/24'], gateway='10.0.99.1')
         self.addLink(r2, rh2)
 
 class LeafSpineFabric (Topo) :
@@ -241,7 +243,7 @@
                 if vlan_id[ls * fanout + f] != 0:
                     host = self.addHost(
                         name='h%s' % (ls * fanout + f + 1),
-                        cls=TaggedRoutedHost,
+                        cls=TrellisHost,
                         ips=['10.0.%d.%d/%d' % (ls+2, f+1, IP4_SUBNET_CLASS)],
                         gateway='10.0.%d.254' % (ls+2),
                         mac='00:aa:00:00:00:%02x' % (ls * fanout + f + 1),
@@ -250,7 +252,7 @@
                 else:
                     host = self.addHost(
                         name='h%s' % (ls * fanout + f + 1),
-                        cls= RoutedHost,
+                        cls=TrellisHost,
                         ips=['10.0.%d.%d/%d' % (ls+2, f+1, IP4_SUBNET_CLASS)],
                         gateway='10.0.%d.254' % (ls+2),
                         mac='00:aa:00:00:00:%02x' % (ls * fanout + f + 1)
@@ -260,8 +262,8 @@
         last_ls = leafs[leaf-1]
         # Create common components
         # 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')
+        dhcp = self.addHost('dhcp', cls=TrellisHost, mac='00:99:00:00:00:01', ips=['10.0.3.253/24'],
+                            gateway='10.0.3.254', dhcpServer=True)
 
         # Control plane switch (for DHCP servers)
         cs1 = self.addSwitch('cs1', cls=OVSBridge)
@@ -297,7 +299,7 @@
         self.addLink(r1, last_ls)
 
         # External IPv4 Host behind r1
-        rh1 = self.addHost('rh1', cls=RoutedHost, ips=['10.0.99.2/24'], gateway='10.0.99.1')
+        rh1 = self.addHost('rh1', cls=TrellisHost, ips=['10.0.99.2/24'], gateway='10.0.99.1')
         self.addLink(r1, rh1)
 
 def config( opts ):
diff --git a/TestON/tests/USECASE/SegmentRouting/dependencies/trellislib.py b/TestON/tests/USECASE/SegmentRouting/dependencies/trellislib.py
index 08dcf2f..4c827f0 100644
--- a/TestON/tests/USECASE/SegmentRouting/dependencies/trellislib.py
+++ b/TestON/tests/USECASE/SegmentRouting/dependencies/trellislib.py
@@ -252,6 +252,93 @@
         self.cmd('rm -rf %s' % self.pidFile)
         super(DualHomedDhcpClient, self).terminate()
 
+class TrellisHost(Host):
+    def __init__(self, name, ips=[], gateway="", dualHomed=False, vlan=None, dhcpClient=False, dhcpServer=False, ipv6=False, *args, **kwargs):
+        super(TrellisHost, self).__init__(name, *args, **kwargs)
+        self.dualHomed = dualHomed
+        self.bond0 = None
+        self.vlan = vlan
+        self.vlanIntf = None
+        self.dhcpClient = dhcpClient
+        self.dhcpServer = dhcpServer
+        if dhcpClient:
+            self.pidFile = '/run/dhclient-%s.pid' % self.name
+            self.leaseFile = '/var/lib/dhcp/dhcpclient%s-%s.lease' % ("6" if ipv6 else "", self.name)
+        else:
+            self.ips = ips
+            self.gateway = gateway
+            if dhcpServer:
+                self.binFile = '/usr/sbin/dhcpd'
+                self.pidFile = '/run/dhcp-server-dhcpd%s.pid' % ("6" if ipv6 else "")
+                self.configFile = './dhcpd%s.conf' % ("6" if ipv6 else "")
+                self.leasesFile = '/var/lib/dhcp/dhcpd%s.leases' % ("6" if ipv6 else "")
+        self.ipv6 = ipv6
+
+    def config(self, **kwargs):
+        super(TrellisHost, self).config(**kwargs)
+
+        if self.dualHomed:
+            # Setup bond0 interface
+            intf0 = self.intfs[0].name
+            intf1 = self.intfs[1].name
+            self.bond0 = "%s-bond0" % self.name
+            self.cmd('modprobe bonding')
+            self.cmd('ip link add %s type bond' % self.bond0)
+            self.cmd('ip link set %s down' % intf0)
+            self.cmd('ip link set %s down' % intf1)
+            self.cmd('ip link set %s master %s' % (intf0, self.bond0))
+            self.cmd('ip link set %s master %s' % (intf1, self.bond0))
+            self.cmd('ip addr flush dev %s' % intf0)
+            self.cmd('ip addr flush dev %s' % intf1)
+            self.cmd('ip link set %s up' % self.bond0)
+            defaultIntf = self.defaultIntf()
+            defaultIntf.name = self.bond0
+            self.nameToIntf[self.bond0] = defaultIntf
+
+        self.cmd('ip %s addr flush dev %s' % ("-4" if self.ipv6 else "", self.defaultIntf()))
+
+        if self.vlan:
+            # Setup vlan interface
+            defaultIntf = self.defaultIntf()
+            self.vlanIntf = "%s.%s" % (defaultIntf, self.vlan)
+            self.cmd('ip link add link %s name %s type vlan id %s' % (defaultIntf, self.vlanIntf, self.vlan))
+            self.cmd('ip link set up %s' % self.vlanIntf)
+            defaultIntf.name = self.vlanIntf
+            self.nameToIntf[self.vlanIntf] = defaultIntf
+
+        if self.dhcpClient:
+            if self.vlan or self.dualHomed:
+                # Why leaseFile is not required here?
+                self.cmd('dhclient -q -%s -nw -pf %s %s' % (6 if self.ipv6 else 4, self.pidFile, self.defaultIntf()))
+            else:
+                self.cmd('dhclient -q -%s -nw -pf %s -lf %s %s' % (6 if self.ipv6 else 4, self.pidFile, self.leaseFile, self.defaultIntf()))
+        else:
+            # Setup IP addresses
+            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)
+
+            if self.dhcpServer:
+                if self.ipv6:
+                    linkLocalAddr = mac_to_ipv6_linklocal(kwargs['mac'])
+                    self.cmd('ip -6 addr add dev %s scope link %s' % (self.defaultIntf(), linkLocalAddr))
+                self.cmd('touch %s' % self.leasesFile)
+                self.cmd('%s -q -%s -pf %s -cf %s %s' % (self.binFile, 6 if self.ipv6 else 4, self.pidFile, self.configFile, self.defaultIntf()))
+
+    def terminate(self, **kwargs):
+        if self.vlan:
+            self.cmd('ip link remove link %s' % self.vlanIntf)
+        if self.dualHomed:
+            self.cmd('ip link set %s down' % self.bond0)
+            self.cmd('ip link delete %s' % self.bond0)
+        if self.dhcpClient:
+            self.cmd('kill -9 `cat %s`' % self.pidFile)
+            self.cmd('rm -rf %s' % self.pidFile)
+        if self.dhcpServer:
+            self.cmd('kill -9 `cat %s`' % self.pidFile)
+            self.cmd('rm -rf %s' % self.pidFile)
+        super(TrellisHost, self).terminate()
+
 # Utility for IPv6
 def mac_to_ipv6_linklocal(mac):
     '''