1#!/usr/bin/env python 2# Copyright (c) PLUMgrid, Inc. 3# Licensed under the Apache License, Version 2.0 (the "License") 4 5from sys import argv 6from bcc import BPF 7from builtins import input 8from ctypes import c_int, c_uint 9from http.server import HTTPServer, SimpleHTTPRequestHandler 10import json 11from netaddr import EUI, IPAddress 12from pyroute2 import IPRoute, NetNS, IPDB, NSPopen 13from socket import htons, AF_INET 14from threading import Thread 15from subprocess import call 16 17host_id = int(argv[1]) 18 19b = BPF(src_file="tunnel.c") 20ingress_fn = b.load_func("handle_ingress", BPF.SCHED_CLS) 21egress_fn = b.load_func("handle_egress", BPF.SCHED_CLS) 22mac2host = b.get_table("mac2host") 23vni2if = b.get_table("vni2if") 24conf = b.get_table("conf") 25 26ipr = IPRoute() 27ipdb = IPDB(nl=ipr) 28 29ifc = ipdb.interfaces.eth0 30mcast = IPAddress("239.1.1.1") 31 32# ifcs to cleanup at the end 33ifc_gc = [] 34 35def 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 70try: 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) 78finally: 79 for v in ifc_gc: call(["ip", "link", "del", v]) 80