1#!/usr/bin/env python
2# Copyright (c) PLUMgrid, Inc.
3# Licensed under the Apache License, Version 2.0 (the "License")
4
5from bcc import BPF
6from pyroute2 import IPRoute, NetNS, IPDB, NSPopen
7from simulation import Simulation
8import sys
9from time import sleep
10from builtins import input
11
12ipr = IPRoute()
13ipdb = IPDB(nl=ipr)
14b = BPF(src_file="tc_neighbor_sharing.c", debug=0)
15
16wan_fn = b.load_func("classify_wan", BPF.SCHED_CLS)
17pass_fn = b.load_func("pass", BPF.SCHED_CLS)
18neighbor_fn = b.load_func("classify_neighbor", BPF.SCHED_CLS)
19
20num_neighbors = 3
21num_locals = 2
22
23# class to build the simulation network
24class SharedNetSimulation(Simulation):
25
26    def __init__(self, ipdb):
27        super(SharedNetSimulation, self).__init__(ipdb)
28
29        # Create the wan namespace, and attach an ingress filter for throttling
30        # inbound (download) traffic
31        wan_if = self._create_ns("wan0", ipaddr="172.16.1.5/24")[1]
32        ipr.tc("add", "ingress", wan_if["index"], "ffff:")
33        ipr.tc("add-filter", "bpf", wan_if["index"], ":1", fd=wan_fn.fd,
34               prio=1, name=wan_fn.name, parent="ffff:", action="drop",
35               classid=1, rate="128kbit", burst=1024 * 32, mtu=16 * 1024)
36        ipr.tc("add-filter", "bpf", wan_if["index"], ":2", fd=pass_fn.fd,
37               prio=2, name=pass_fn.name, parent="ffff:", action="drop",
38               classid=2, rate="1024kbit", burst=1024 * 32, mtu=16 * 1024)
39        self.wan_if = wan_if
40
41    # start the namespaces that compose the network, interconnect them with the
42    # bridge, and attach the tc filters
43    def start(self):
44        neighbor_list = []
45        local_list = []
46        cmd = ["netserver", "-D"]
47        for i in range(0, num_neighbors):
48            ipaddr = "172.16.1.%d/24" % (i + 100)
49            ret = self._create_ns("neighbor%d" % i, ipaddr=ipaddr,
50                                  fn=neighbor_fn, cmd=cmd)
51            neighbor_list.append(ret)
52        for i in range(0, num_locals):
53            ipaddr = "172.16.1.%d/24" % (i + 150)
54            ret = self._create_ns("local%d" % i, ipaddr=ipaddr,
55                                  fn=pass_fn, cmd=cmd)
56            local_list.append(ret)
57
58        with ipdb.create(ifname="br100", kind="bridge") as br100:
59            for x in neighbor_list:
60                br100.add_port(x[1])
61            for x in local_list:
62                br100.add_port(x[1])
63            br100.add_port(self.wan_if)
64            br100.up()
65
66try:
67    sim = SharedNetSimulation(ipdb)
68    sim.start()
69    print("Network ready. Create a shell in the wan0 namespace and test with netperf")
70    print("   (Neighbors are 172.16.1.100-%d, and LAN clients are 172.16.1.150-%d)"
71            % (100 + num_neighbors - 1, 150 + num_locals - 1))
72    print(" e.g.: ip netns exec wan0 netperf -H 172.16.1.100 -l 2")
73    input("Press enter when finished: ")
74finally:
75    if "sim" in locals(): sim.release()
76    if "br100" in ipdb.interfaces: ipdb.interfaces.br100.remove().commit()
77    ipdb.release()
78
79
80