blob: f111ac9a06ab15eb5410cace647c5d7e74c5de28 [file] [log] [blame]
#!/usr/bin/env python
# Copyright (c) PLUMgrid, Inc.
# Licensed under the Apache License, Version 2.0 (the "License")
from sys import argv
from bcc import BPF
from builtins import input
from ctypes import c_int, c_uint
from http.server import HTTPServer, SimpleHTTPRequestHandler
import json
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, Popen, PIPE
num_hosts = int(argv[1])
host_id = int(argv[2])
dhcp = int(argv[3])
gretap = int(argv[4])
b = BPF(src_file="tunnel_mesh.c")
ingress_fn = b.load_func("handle_ingress", BPF.SCHED_CLS)
egress_fn = b.load_func("handle_egress", BPF.SCHED_CLS)
tunkey2if = b.get_table("tunkey2if")
if2tunkey = b.get_table("if2tunkey")
conf = b.get_table("conf")
ipr = IPRoute()
ipdb = IPDB(nl=ipr)
ifc = ipdb.interfaces.eth0
# ifcs to cleanup at the end
ifc_gc = []
# dhcp server and client processes
d_serv = []
d_client = []
def run():
if gretap:
with ipdb.create(ifname="gretap1", kind="gretap", gre_ikey=0, gre_okey=0,
gre_local='172.16.1.%d' % (100 + host_id),
gre_ttl=16, gre_collect_metadata=1) as vx:
vx.up()
ifc_gc.append(vx.ifname)
else:
with ipdb.create(ifname="vxlan0", kind="vxlan", vxlan_id=0,
vxlan_link=ifc, vxlan_port=4789,
vxlan_collect_metadata=True,
vxlan_learning=False) as vx:
vx.up()
ifc_gc.append(vx.ifname)
conf[c_int(1)] = c_int(vx.index)
ipr.tc("add", "ingress", vx.index, "ffff:")
ipr.tc("add-filter", "bpf", vx.index, ":1", fd=ingress_fn.fd,
name=ingress_fn.name, parent="ffff:", action="drop", classid=1)
for j in range(0, 2):
vni = 10000 + j
with ipdb.create(ifname="br%d" % j, kind="bridge") as br:
for i in range(0, num_hosts):
if i != host_id:
v = ipdb.create(ifname="dummy%d%d" % (j , i), kind="dummy").up().commit()
ipaddr = "172.16.1.%d" % (100 + i)
tunkey2if_key = tunkey2if.Key(vni)
tunkey2if_key.remote_ipv4 = IPAddress(ipaddr)
tunkey2if_leaf = tunkey2if.Leaf(v.index)
tunkey2if[tunkey2if_key] = tunkey2if_leaf
if2tunkey_key = if2tunkey.Key(v.index)
if2tunkey_leaf = if2tunkey.Leaf(vni)
if2tunkey_leaf.remote_ipv4 = IPAddress(ipaddr)
if2tunkey[if2tunkey_key] = if2tunkey_leaf
ipr.tc("add", "sfq", v.index, "1:")
ipr.tc("add-filter", "bpf", v.index, ":1", fd=egress_fn.fd,
name=egress_fn.name, parent="1:", action="drop", classid=1)
br.add_port(v)
br.up()
ifc_gc.append(v.ifname)
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 = b"99.1.%d" % j
retry = out.find(checkip)
try:
run()
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()