Brenden Blanco | af95673 | 2015-06-09 13:58:42 -0700 | [diff] [blame] | 1 | #!/usr/bin/env python |
| 2 | # Copyright (c) PLUMgrid, Inc. |
| 3 | # Licensed under the Apache License, Version 2.0 (the "License") |
| 4 | |
Brenden Blanco | c35989d | 2015-09-02 18:04:07 -0700 | [diff] [blame] | 5 | from bcc import BPF |
Brenden Blanco | 6bf723d | 2015-06-18 17:53:31 -0700 | [diff] [blame] | 6 | from builtins import input |
Brenden Blanco | af95673 | 2015-06-09 13:58:42 -0700 | [diff] [blame] | 7 | from pyroute2 import IPRoute, NetNS, IPDB, NSPopen |
| 8 | from random import shuffle |
| 9 | from time import sleep |
Brenden Blanco | 085379b | 2015-06-18 00:28:47 -0700 | [diff] [blame] | 10 | from simulation import Simulation |
Brenden Blanco | af95673 | 2015-06-09 13:58:42 -0700 | [diff] [blame] | 11 | import sys |
| 12 | |
| 13 | ipr = IPRoute() |
Brenden Blanco | af95673 | 2015-06-09 13:58:42 -0700 | [diff] [blame] | 14 | ipdb = IPDB(nl=ipr) |
| 15 | |
Brenden Blanco | 6bf723d | 2015-06-18 17:53:31 -0700 | [diff] [blame] | 16 | num_clients = 3 |
Brenden Blanco | af95673 | 2015-06-09 13:58:42 -0700 | [diff] [blame] | 17 | num_vlans = 16 |
| 18 | |
Brenden Blanco | af95673 | 2015-06-09 13:58:42 -0700 | [diff] [blame] | 19 | # load the bpf program |
Brenden Blanco | 085379b | 2015-06-18 00:28:47 -0700 | [diff] [blame] | 20 | b = BPF(src_file="vlan_learning.c", debug=0) |
Brenden Blanco | af95673 | 2015-06-09 13:58:42 -0700 | [diff] [blame] | 21 | phys_fn = b.load_func("handle_phys2virt", BPF.SCHED_CLS) |
| 22 | virt_fn = b.load_func("handle_virt2phys", BPF.SCHED_CLS) |
| 23 | |
Brenden Blanco | c546271 | 2015-06-12 14:07:04 -0700 | [diff] [blame] | 24 | ingress = b.get_table("ingress") |
| 25 | egress = b.get_table("egress") |
Brenden Blanco | af95673 | 2015-06-09 13:58:42 -0700 | [diff] [blame] | 26 | |
Brenden Blanco | 085379b | 2015-06-18 00:28:47 -0700 | [diff] [blame] | 27 | class VlanSimulation(Simulation): |
| 28 | def __init__(self, ipdb): |
| 29 | super(VlanSimulation, self).__init__(ipdb) |
Brenden Blanco | af95673 | 2015-06-09 13:58:42 -0700 | [diff] [blame] | 30 | |
Brenden Blanco | 085379b | 2015-06-18 00:28:47 -0700 | [diff] [blame] | 31 | def start(self): |
| 32 | # start identical workers each in a namespace |
Brenden Blanco | 6bf723d | 2015-06-18 17:53:31 -0700 | [diff] [blame] | 33 | for i in range(0, num_clients): |
Brenden Blanco | 085379b | 2015-06-18 00:28:47 -0700 | [diff] [blame] | 34 | httpmod = ("SimpleHTTPServer" if sys.version_info[0] < 3 |
| 35 | else "http.server") |
| 36 | cmd = ["python", "-m", httpmod, "80"] |
| 37 | self._create_ns("worker%d" % i, cmd=cmd, fn=virt_fn, action="drop", |
| 38 | ipaddr="172.16.1.5/24") |
Brenden Blanco | af95673 | 2015-06-09 13:58:42 -0700 | [diff] [blame] | 39 | |
Brenden Blanco | 085379b | 2015-06-18 00:28:47 -0700 | [diff] [blame] | 40 | # simulate a physical eth vlan trunk |
| 41 | with self.ipdb.create(ifname="eth0a", kind="veth", peer="eth0b") as v: |
| 42 | v.up() |
| 43 | self.ipdb.interfaces.eth0b.up().commit() |
Brenden Blanco | af95673 | 2015-06-09 13:58:42 -0700 | [diff] [blame] | 44 | |
Yonghong Song | 540d45a | 2015-07-22 10:17:39 -0700 | [diff] [blame] | 45 | # eth0a will be hooked to clients with vlan interfaces |
| 46 | # add the bpf program to eth0b for demuxing phys2virt packets |
| 47 | v = self.ipdb.interfaces["eth0b"] |
| 48 | ipr.tc("add", "ingress", v["index"], "ffff:") |
| 49 | ipr.tc("add-filter", "bpf", v["index"], ":1", fd=phys_fn.fd, |
| 50 | name=phys_fn.name, parent="ffff:", action="drop", classid=1) |
Brenden Blanco | af95673 | 2015-06-09 13:58:42 -0700 | [diff] [blame] | 51 | |
Brenden Blanco | 085379b | 2015-06-18 00:28:47 -0700 | [diff] [blame] | 52 | # allocate vlans randomly |
| 53 | available_vlans = [i for i in range(2, 2 + num_vlans)] |
| 54 | shuffle(available_vlans) |
Brenden Blanco | 6bf723d | 2015-06-18 17:53:31 -0700 | [diff] [blame] | 55 | available_ips = [[i for i in range(100, 105)] for i in range(0, num_clients)] |
Brenden Blanco | af95673 | 2015-06-09 13:58:42 -0700 | [diff] [blame] | 56 | |
Brenden Blanco | 085379b | 2015-06-18 00:28:47 -0700 | [diff] [blame] | 57 | # these are simulations of physical clients |
| 58 | for i in range(0, num_clients): |
Brenden Blanco | 085379b | 2015-06-18 00:28:47 -0700 | [diff] [blame] | 59 | macaddr = ("02:00:00:%.2x:%.2x:%.2x" % |
| 60 | ((i >> 16) & 0xff, (i >> 8) & 0xff, i & 0xff)) |
Brenden Blanco | af95673 | 2015-06-09 13:58:42 -0700 | [diff] [blame] | 61 | |
Brenden Blanco | 085379b | 2015-06-18 00:28:47 -0700 | [diff] [blame] | 62 | # assign this client to the given worker |
Brenden Blanco | 6bf723d | 2015-06-18 17:53:31 -0700 | [diff] [blame] | 63 | idx = self.ipdb.interfaces["worker%da" % i]["index"] |
Brenden Blanco | 085379b | 2015-06-18 00:28:47 -0700 | [diff] [blame] | 64 | mac = int(macaddr.replace(":", ""), 16) |
Yonghong Song | 540d45a | 2015-07-22 10:17:39 -0700 | [diff] [blame] | 65 | ingress[ingress.Key(mac)] = ingress.Leaf(idx, 0, 0, 0, 0) |
Brenden Blanco | af95673 | 2015-06-09 13:58:42 -0700 | [diff] [blame] | 66 | |
Brenden Blanco | 085379b | 2015-06-18 00:28:47 -0700 | [diff] [blame] | 67 | # test traffic with curl loop |
| 68 | cmd = ["bash", "-c", |
| 69 | "for i in {1..8}; do curl 172.16.1.5 -o /dev/null; sleep 1; done"] |
Yonghong Song | 540d45a | 2015-07-22 10:17:39 -0700 | [diff] [blame] | 70 | client_ifc = self.ipdb.create(ifname="eth0a.%d" % i, kind="vlan", |
| 71 | link=self.ipdb.interfaces["eth0a"], |
| 72 | vlan_id=available_vlans.pop(0)).commit() |
| 73 | (out_ifc, in_ifc) = self._create_ns("client%d" % i, in_ifc=client_ifc, |
Brenden Blanco | 6bf723d | 2015-06-18 17:53:31 -0700 | [diff] [blame] | 74 | ipaddr="172.16.1.100/24", |
| 75 | macaddr=macaddr, cmd=cmd)[1:3] |
Brenden Blanco | af95673 | 2015-06-09 13:58:42 -0700 | [diff] [blame] | 76 | |
Brenden Blanco | 085379b | 2015-06-18 00:28:47 -0700 | [diff] [blame] | 77 | try: |
| 78 | sim = VlanSimulation(ipdb) |
| 79 | sim.start() |
| 80 | sleep(10) |
| 81 | input("Press enter to exit: ") |
Brenden Blanco | af95673 | 2015-06-09 13:58:42 -0700 | [diff] [blame] | 82 | |
Brenden Blanco | 085379b | 2015-06-18 00:28:47 -0700 | [diff] [blame] | 83 | stats_collect = {} |
| 84 | for key, leaf in ingress.items(): |
| 85 | stats_collect[key.value] = [leaf.tx_pkts, leaf.tx_bytes, 0, 0] |
| 86 | for key, leaf in egress.items(): |
| 87 | x = stats_collect.get(key.value, [0, 0, 0, 0]) |
| 88 | x[2] = leaf.tx_pkts |
| 89 | x[3] = leaf.tx_bytes |
| 90 | for k, v in stats_collect.items(): |
| 91 | print("mac %.12x rx pkts = %u, rx bytes = %u" % (k, v[0], v[1])) |
| 92 | print(" tx pkts = %u, tx bytes = %u" % (v[2], v[3])) |
| 93 | finally: |
| 94 | if "eth0a" in ipdb.interfaces: ipdb.interfaces.eth0a.remove().commit() |
Brenden Blanco | 085379b | 2015-06-18 00:28:47 -0700 | [diff] [blame] | 95 | if "sim" in locals(): sim.release() |
| 96 | ipdb.release() |