Add DHCPv6 to trellis script

Change-Id: Idbebc1597c41eb942894d0c3b9a260e9dfa14bfc
diff --git a/routinglib.py b/routinglib.py
index eab92c2..970ce77 100644
--- a/routinglib.py
+++ b/routinglib.py
@@ -28,6 +28,23 @@
 
         self.cmd('ip route add default via %s' % self.gateway)
 
+class RoutedHost6(Host):
+    """Host that can be configured with multiple IP addresses."""
+    def __init__(self, name, ips, gateway, *args, **kwargs):
+        super(RoutedHost6, self).__init__(name, *args, **kwargs)
+
+        self.ips = ips
+        self.gateway = gateway
+
+    def config(self, **kwargs):
+        Host.config(self, **kwargs)
+
+        self.cmd('ip -6 addr flush dev %s' % self.defaultIntf())
+        for ip in self.ips:
+            self.cmd('ip -6 addr add %s dev %s' % (ip, self.defaultIntf()))
+
+        self.cmd('ip -6 route add default via %s' % self.gateway)
+
 class Router(Host):
 
     """An L3 router.
diff --git a/trellis/dhcpd.conf b/trellis/dhcpd.conf
index c16dc33..aa559d2 100644
--- a/trellis/dhcpd.conf
+++ b/trellis/dhcpd.conf
@@ -31,7 +31,7 @@
 
 host h1 {
   hardware ethernet 00:aa:00:00:00:01;
-  fixed-address 10.0.4.1;
+  fixed-address 10.0.2.1;
 }
 
 host h2 {
diff --git a/trellis/dhcpd6.conf b/trellis/dhcpd6.conf
index a8d20ff..526de85 100644
--- a/trellis/dhcpd6.conf
+++ b/trellis/dhcpd6.conf
@@ -4,7 +4,7 @@
 option dhcp6.next-hop code 242 = ip6-address;
 
 subnet6 2000::200/120 {
-  range6 2000::260 2000::02fe;
+  range6 2000::260 2000::2fe;
   option dhcp6.next-hop 2000::02ff;
 }
 
diff --git a/trellis/trellis.json b/trellis/trellis.json
index 1b4a5cd..e0aa174 100644
--- a/trellis/trellis.json
+++ b/trellis/trellis.json
@@ -67,7 +67,7 @@
         "of:0000000000000205/7" : {
             "interfaces" : [
                 {
-                    "ips" : [ "10.0.3.254/24" ],
+                    "ips" : [ "10.0.3.254/24", "2000::3ff/120" ],
                     "vlan-untagged": 30
                 }
             ]
@@ -155,38 +155,12 @@
             }
         }
     },
-    "hosts": {
-        "00:bb:00:00:00:01/None": {
-            "basic": {
-                "ips": ["2000::201"],
-                "locations": ["of:0000000000000204/5"]
-            }
-        },
-        "00:bb:00:00:00:02/None": {
-            "basic": {
-                "ips": ["2000::202"],
-                "locations": ["of:0000000000000204/6"]
-            }
-        },
-        "00:bb:00:00:00:03/None": {
-            "basic": {
-                "ips": ["2000::301"],
-                "locations": ["of:0000000000000205/5"]
-            }
-        },
-        "00:bb:00:00:00:04/None": {
-            "basic": {
-                "ips": ["2000::302"],
-                "locations": ["of:0000000000000205/6"]
-            }
-        }
-    },
     "apps" : {
         "org.onosproject.dhcprelay" : {
             "default": [
                 {
                     "dhcpServerConnectPoint": "of:0000000000000205/7",
-                    "serverIps": ["10.0.3.253"]
+                    "serverIps": ["10.0.3.253", "2000::3fd"]
                 }
             ]
         }
diff --git a/trellis/trellis.py b/trellis/trellis.py
index 2fab97b..dd57eb4 100755
--- a/trellis/trellis.py
+++ b/trellis/trellis.py
@@ -10,8 +10,8 @@
 from mininet.nodelib import NAT
 from ipaddress import ip_network
 from routinglib import BgpRouter
-from routinglib import RoutedHost
-from trellislib import DhcpClient, DhcpServer
+from routinglib import RoutedHost, RoutedHost6
+from trellislib import DhcpClient, Dhcp6Client, DhcpRelay, DhcpServer, Dhcp6Server
 
 class Trellis( Topo ):
     "Trellis basic topology"
@@ -46,10 +46,10 @@
         self.addLink(h4, s205)
 
         # IPv6 Hosts
-        h1v6 = self.addHost('h1v6', cls=RoutedHost, mac='00:bb:00:00:00:01', ips=['2000::201/120'], gateway='2000::2ff')
-        h2v6 = self.addHost('h2v6', cls=RoutedHost, mac='00:bb:00:00:00:02', ips=['2000::202/120'], gateway='2000::2ff')
-        h3v6 = self.addHost('h3v6', cls=RoutedHost, mac='00:bb:00:00:00:03', ips=['2000::301/120'], gateway='2000::3ff')
-        h4v6 = self.addHost('h4v6', cls=RoutedHost, mac='00:bb:00:00:00:04', ips=['2000::302/120'], gateway='2000::3ff')
+        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')
         self.addLink(h1v6, s204)
         self.addLink(h2v6, s204)
         self.addLink(h3v6, s205)
@@ -57,7 +57,15 @@
 
         # 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')
-        self.addLink(dhcp, s205)
+
+        # DHCPv6 server
+        dhcp6 = self.addHost('dhcp6', cls=Dhcp6Server, mac='00:99:66:00:00:01', ips=['2000::3fd/120'], gateway='2000::3ff')
+
+        # Control 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)
diff --git a/trellis/trellis_dualhome.json b/trellis/trellis_dualhome.json
index e9f1dfd..7fd6d6b 100644
--- a/trellis/trellis_dualhome.json
+++ b/trellis/trellis_dualhome.json
@@ -259,38 +259,12 @@
             }
         }
     },
-    "hosts": {
-        "00:bb:00:00:00:01/None": {
-            "basic": {
-                "ips": ["2000::201"],
-                "locations": ["of:0000000000000204/8"]
-            }
-        },
-        "00:bb:00:00:00:02/None": {
-            "basic": {
-                "ips": ["2000::202"],
-                "locations": ["of:0000000000000204/9"]
-            }
-        },
-        "00:bb:00:00:00:03/None": {
-            "basic": {
-                "ips": ["2000::301"],
-                "locations": ["of:0000000000000205/8"]
-            }
-        },
-        "00:bb:00:00:00:04/None": {
-            "basic": {
-                "ips": ["2000::302"],
-                "locations": ["of:0000000000000205/9"]
-            }
-        }
-    },
     "apps" : {
         "org.onosproject.dhcprelay" : {
             "default": [
                 {
                     "dhcpServerConnectPoint": "of:0000000000000205/10",
-                    "serverIps": ["10.0.3.253"]
+                    "serverIps": ["10.0.3.253", "2000::3fd"]
                 }
             ]
         }
diff --git a/trellis/trellis_dualhome.py b/trellis/trellis_dualhome.py
index 62269ed..534a26d 100755
--- a/trellis/trellis_dualhome.py
+++ b/trellis/trellis_dualhome.py
@@ -11,8 +11,8 @@
 from mininet.nodelib import NAT
 from ipaddress import ip_network
 from routinglib import BgpRouter
-from routinglib import RoutedHost
-from trellislib import DhcpClient, DhcpServer
+from routinglib import RoutedHost, RoutedHost6
+from trellislib import DhcpClient, Dhcp6Client, DhcpRelay, DhcpServer, Dhcp6Server
 from trellislib import DualHomedDhcpClient
 
 class Trellis( Topo ):
@@ -66,10 +66,10 @@
         self.addLink(h4, s205)
 
         # IPv6 Hosts
-        h1v6 = self.addHost('h1v6', cls=RoutedHost, mac='00:bb:00:00:00:01', ips=['2000::201/120'], gateway='2000::2ff')
-        h2v6 = self.addHost('h2v6', cls=RoutedHost, mac='00:bb:00:00:00:02', ips=['2000::202/120'], gateway='2000::2ff')
-        h3v6 = self.addHost('h3v6', cls=RoutedHost, mac='00:bb:00:00:00:03', ips=['2000::301/120'], gateway='2000::3ff')
-        h4v6 = self.addHost('h4v6', cls=RoutedHost, mac='00:bb:00:00:00:04', ips=['2000::302/120'], gateway='2000::3ff')
+        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')
         self.addLink(h1v6, s204)
         self.addLink(h2v6, s204)
         self.addLink(h3v6, s205)
@@ -82,7 +82,15 @@
 
         # 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')
-        self.addLink(dhcp, s205)
+
+        # DHCPv6 server
+        dhcp6 = self.addHost('dhcp6', cls=Dhcp6Server, mac='00:99:66:00:00:01', ips=['2000::3fd/120'], gateway='2000::3ff')
+
+        # Control 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)
diff --git a/trellis/trellislib.py b/trellis/trellislib.py
index 7242908..1a9d626 100644
--- a/trellis/trellislib.py
+++ b/trellis/trellislib.py
@@ -7,7 +7,7 @@
 import sys
 sys.path.append('..')
 from mininet.node import Host
-from routinglib import RoutedHost, Router
+from routinglib import RoutedHost, RoutedHost6, Router
 
 class TaggedRoutedHost(RoutedHost):
     """Host that can be configured with multiple IP addresses."""
@@ -38,11 +38,12 @@
     def __init__(self, name, *args, **kwargs):
         super(DhcpClient, self).__init__(name, **kwargs)
         self.pidFile = '/run/dhclient-%s.pid' % self.name
+        self.leaseFile = '/var/lib/dhcp/dhcpclient-%s.lease' % (self.name, )
 
     def config(self, **kwargs):
         super(DhcpClient, self).config(**kwargs)
         self.cmd('ip addr flush dev %s' % self.defaultIntf())
-        self.cmd('dhclient -q -4 -nw -pf %s %s' % (self.pidFile, self.defaultIntf()))
+        self.cmd('dhclient -q -4 -nw -pf %s -lf %s %s' % (self.pidFile, self.leaseFile, self.defaultIntf()))
 
     def terminate(self, **kwargs):
         self.cmd('kill -9 `cat %s`' % self.pidFile)
@@ -53,13 +54,14 @@
     def __init__(self, name, *args, **kwargs):
         super(Dhcp6Client, self).__init__(name, **kwargs)
         self.pidFile = '/run/dhclient-%s.pid' % self.name
+        self.leaseFile = '/var/lib/dhcp/dhcpclient6-%s.lease' % (self.name, )
 
     def config(self, **kwargs):
         super(Dhcp6Client, self).config(**kwargs)
         self.cmd('ip addr flush dev %s' % self.defaultIntf())
         linkLocalAddr = mac_to_ipv6_linklocal(kwargs['mac'])
         self.cmd('ip -6 addr add dev %s scope link %s' % (self.defaultIntf(), linkLocalAddr))
-        self.cmd('dhclient -q -6 -nw -pf %s %s' % (self.pidFile, self.defaultIntf()))
+        self.cmd('dhclient -q -6 -nw -pf %s -lf %s %s' % (self.pidFile, self.leaseFile, self.defaultIntf()))
 
     def terminate(self, **kwargs):
         self.cmd('kill -9 `cat %s`' % self.pidFile)
@@ -68,11 +70,13 @@
 
 class DhcpServer(RoutedHost):
     binFile = '/usr/sbin/dhcpd'
-    pidFile = '/run/dhcp-server/dhcpd.pid'
+    pidFile = '/run/dhcp-server-dhcpd.pid'
     configFile = './dhcpd.conf'
+    leasesFile = '/var/lib/dhcp/dhcpd.leases'
 
     def config(self, **kwargs):
         super(DhcpServer, self).config(**kwargs)
+        self.cmd('touch %s' % self.leasesFile)
         self.cmd('%s -q -4 -pf %s -cf %s %s' % (self.binFile, self.pidFile, self.configFile, self.defaultIntf()))
 
     def terminate(self, **kwargs):
@@ -80,9 +84,9 @@
         self.cmd('rm -rf %s' % self.pidFile)
         super(DhcpServer, self).terminate()
 
-class Dhcp6Server(RoutedHost):
+class Dhcp6Server(RoutedHost6):
     binFile = '/usr/sbin/dhcpd'
-    pidFile = '/run/dhcp-server/dhcpd6.pid'
+    pidFile = '/run/dhcp-server-dhcpd6.pid'
     configFile = './dhcpd6.conf'
     leasesFile = '/var/lib/dhcp/dhcpd6.leases'