1 #!/usr/bin/env python 2 # Copyright (c) PLUMgrid, Inc. 3 # Licensed under the Apache License, Version 2.0 (the "License") 4 5 from sys import argv 6 from bcc import BPF 7 from builtins import input 8 from ctypes import c_int, c_uint 9 from http.server import HTTPServer, SimpleHTTPRequestHandler 10 import json 11 from netaddr import EUI, IPAddress 12 from pyroute2 import IPRoute, NetNS, IPDB, NSPopen 13 from socket import htons, AF_INET 14 from threading import Thread 15 from subprocess import call 16 17 host_id = int(argv[1]) 18 19 b = BPF(src_file="tunnel.c") 20 ingress_fn = b.load_func("handle_ingress", BPF.SCHED_CLS) 21 egress_fn = b.load_func("handle_egress", BPF.SCHED_CLS) 22 mac2host = b.get_table("mac2host") 23 vni2if = b.get_table("vni2if") 24 conf = b.get_table("conf") 25 26 ipr = IPRoute() 27 ipdb = IPDB(nl=ipr) 28 29 ifc = ipdb.interfaces.eth0 30 mcast = IPAddress("239.1.1.1") 31 32 # ifcs to cleanup at the end 33 ifc_gc = [] 34 35 def run(): 36 ipdb.routes.add({"dst": "224.0.0.0/4", "oif": ifc.index}).commit() 37 with ipdb.create(ifname="vxlan0", kind="vxlan", vxlan_id=0, 38 vxlan_link=ifc, vxlan_port=4789, 39 vxlan_group=str(mcast), vxlan_flowbased=True, 40 vxlan_collect_metadata=True, 41 vxlan_learning=False) as vx: 42 vx.up() 43 ifc_gc.append(vx.ifname) 44 45 conf[c_int(1)] = c_int(vx.index) 46 47 ipr.tc("add", "ingress", vx.index, "ffff:") 48 ipr.tc("add-filter", "bpf", vx.index, ":1", fd=ingress_fn.fd, 49 name=ingress_fn.name, parent="ffff:", action="drop", classid=1) 50 51 for i in range(0, 2): 52 vni = 10000 + i 53 with ipdb.create(ifname="br%d" % i, kind="bridge") as br: 54 v = ipdb.create(ifname="dummy%d" % i, kind="dummy").up().commit() 55 mcast_key = mac2host.Key(0xFFFFFFFFFFFF, v.index, 0) 56 mcast_leaf = mac2host.Leaf(vni, mcast.value, 0, 0) 57 mac2host[mcast_key] = mcast_leaf 58 59 ipr.tc("add", "sfq", v.index, "1:") 60 ipr.tc("add-filter", "bpf", v.index, ":1", fd=egress_fn.fd, 61 name=egress_fn.name, parent="1:", action="drop", classid=1) 62 br.add_port(v) 63 br.up() 64 ifc_gc.append(v.ifname) 65 ifc_gc.append(br.ifname) 66 vni2if[c_uint(vni)] = c_int(v.index) 67 ipaddr = "99.1.%d.%d/24" % (i, host_id + 1) 68 br.add_ip(ipaddr) 69 70 try: 71 run() 72 ipdb.release() 73 input("") 74 print("---") 75 for k, v in mac2host.items(): 76 print(EUI(k.mac), k.ifindex, IPAddress(v.remote_ipv4), 77 v.tunnel_id, v.rx_pkts, v.tx_pkts) 78 finally: 79 for v in ifc_gc: call(["ip", "link", "del", v]) 80