add dhcp support for tunnel-mesh
authorYonghong Song <yhs@plumgrid.com>
Thu, 13 Aug 2015 10:04:40 +0000 (03:04 -0700)
committerYonghong Song <yhs@plumgrid.com>
Thu, 13 Aug 2015 22:27:01 +0000 (15:27 -0700)
Signed-off-by: Yonghong Song <yhs@plumgrid.com>
examples/distributed_bridge/main.py
examples/distributed_bridge/tunnel_mesh.py

index 272ec98..37db487 100755 (executable)
@@ -7,11 +7,14 @@ from builtins import input
 from pyroute2 import IPRoute, NetNS, IPDB, NSPopen
 from simulation import Simulation
 from subprocess import PIPE, call, Popen
+import re
 
+dhcp = 0
+multicast = 1
 if len(argv) > 1 and argv[1] == "mesh":
-  multicast = 0
-else:
-  multicast = 1
+    multicast = 0
+    if len(argv) > 2 and argv[2] == "dhcp":
+       dhcp = 1
 
 ipr = IPRoute()
 ipdb = IPDB(nl=ipr)
@@ -34,12 +37,33 @@ class TunnelSimulation(Simulation):
             if multicast:
               cmd = ["python", "tunnel.py", str(i)]
             else:
-              cmd = ["python", "tunnel_mesh.py", str(num_hosts), str(i)]
+              cmd = ["python", "tunnel_mesh.py", str(num_hosts), str(i), str(dhcp)]
             p = NSPopen(host_info[i][0].nl.netns, cmd, stdin=PIPE)
             self.processes.append(p)
         with self.ipdb.create(ifname="br-fabric", kind="bridge") as br:
             for host in host_info: br.add_port(host[1])
             br.up()
+
+        # get host0 bridge ip's
+        host0_br_ips = []
+        if dhcp == 1:
+            print("Waiting for host0 br1/br2 ip addresses available")
+            for j in range(0, 2):
+                retry = -1
+                ip_out = None
+                while retry < 0:
+                    check = Popen(["ip", "netns", "exec", "host0",
+                                   "ip", "addr", "show", "br%d" % j], stdout=PIPE, stderr=PIPE)
+                    ip_out = check.stdout.read()
+                    checkip = "99.1.%d" % j
+                    retry = ip_out.find(checkip)
+                p = re.compile(("99.1.%d." % j) + "\d+")
+                host0_br_ips.append(p.findall(ip_out)[0])
+        else:
+            host0_br_ips.append("99.1.0.1")
+            host0_br_ips.append("99.1.1.1")
+
+        # traffic test
         print("Validating connectivity")
         for i in range(1, num_hosts):
             for j in range(0, 2):
@@ -48,11 +72,11 @@ class TunnelSimulation(Simulation):
                     check = Popen(["ip", "netns", "exec", "host%d" % i,
                                    "ip", "addr", "show", "br%d" % j], stdout=PIPE, stderr=PIPE)
                     out = check.stdout.read()
-                    checkip = "99.1.%d.%d" % (j, i+1)
+                    checkip = "99.1.%d" % j
                     retry = out.find(checkip)
                 print("VNI%d between host0 and host%d" % (10000 + j, i))
                 call(["ip", "netns", "exec", "host%d" % i,
-                      "ping", "99.1.%d.1" % j, "-c", "3", "-i", "0.2", "-q"])
+                      "ping", host0_br_ips[j], "-c", "3", "-i", "0.2", "-q"])
 
 try:
     sim = TunnelSimulation(ipdb)
index 9a6efa9..05d3a5e 100644 (file)
@@ -12,10 +12,11 @@ from netaddr import EUI, IPAddress
 from pyroute2 import IPRoute, NetNS, IPDB, NSPopen
 from socket import htons, AF_INET
 from threading import Thread
-from subprocess import call
+from subprocess import call, Popen, PIPE
 
 num_hosts = int(argv[1])
 host_id = int(argv[2])
+dhcp = int(argv[3])
 
 b = BPF(src_file="tunnel_mesh.c")
 ingress_fn = b.load_func("handle_ingress", BPF.SCHED_CLS)
@@ -32,6 +33,10 @@ ifc = ipdb.interfaces.eth0
 # ifcs to cleanup at the end
 ifc_gc = []
 
+# dhcp server and client processes
+d_serv = []
+d_client = []
+
 def run():
     with ipdb.create(ifname="vxlan0", kind="vxlan", vxlan_id=0,
                      vxlan_link=ifc, vxlan_port=htons(4789),
@@ -68,13 +73,58 @@ def run():
                     br.add_port(v)
                     br.up()
                     ifc_gc.append(v.ifname)
-            ipaddr = "99.1.%d.%d/24" % (j, host_id + 1)
-            br.add_ip(ipaddr)
+            if dhcp == 0:
+                ipaddr = "99.1.%d.%d/24" % (j, host_id + 1)
+                br.add_ip(ipaddr)
             ifc_gc.append(br.ifname)
 
+    # dhcp server only runs on host 0
+    if dhcp == 1 and host_id == 0:
+        for j in range(0, 2):
+            v1 = "dhcp%d_v1" % j
+            v2 = "dhcp%d_v2" % j
+            br = ipdb.interfaces["br%d" % j]
+            with ipdb.create(ifname=v1, kind="veth", peer=v2) as v:
+                    v.up()
+            br.add_port(ipdb.interfaces[v1]).commit()
+            dhcp_v2 = ipdb.interfaces[v2]
+            dhcp_v2.add_ip("99.1.%d.1/24" % j).up().commit()
+
+            call(["/bin/rm", "-f", "/tmp/dnsmasq.%d.leases" % j])
+            cmd = ["dnsmasq", "-d", "--bind-interfaces", "--strict-order",
+                   "--conf-file=",
+                   "--dhcp-range", "99.1.%d.2,99.1.%d.254,255.255.255.0,12h" % (j, j),
+                   "--dhcp-no-override", "--except-interface=lo",
+                   "--interface=dhcp%d_v2" % j,
+                   "--dhcp-authoritative",
+                   "--dhcp-leasefile=/tmp/dnsmasq.%d.leases" % j]
+            d_serv.append(Popen(cmd, stdout=PIPE, stderr=PIPE))
+
+    # dhcp client to assign ip address for each bridge
+    if dhcp == 1:
+        for j in range(0, 2):
+            call(["/bin/rm", "-rf", "/tmp/dhcp_%d_%d" % (host_id, j)])
+            call(["mkdir", "/tmp/dhcp_%d_%d" % (host_id, j)])
+            call(["touch", "/tmp/dhcp_%d_%d/dhclient.conf" % (host_id, j)])
+            call(["touch", "/tmp/dhcp_%d_%d/dhclient.lease" % (host_id, j)])
+            cmd = ["dhclient", "-d", "br%d" % j,
+                   "-cf", "/tmp/dhcp_%d_%d/dhclient.conf" % (host_id, j),
+                   "-lf", "/tmp/dhcp_%d_%d/dhclient.lease" % (host_id, j)]
+            d_client.append(Popen(cmd, stdout=PIPE, stderr=PIPE))
+
+            # make sure we get address for eth0
+            retry = -1
+            while retry < 0:
+                check = Popen(["ip", "addr", "show", "br%d" % j], stdout=PIPE, stderr=PIPE)
+                out = check.stdout.read()
+                checkip = "99.1.%d" % j
+                retry = out.find(checkip)
+
 try:
     run()
-    ipdb.release()
     input("")
 finally:
     for v in ifc_gc: call(["ip", "link", "del", v])
+    ipdb.release()
+    for p in d_client: p.kill()
+    for p in d_serv: p.kill()