xref: /aosp_15_r20/external/bcc/tests/python/test_brb.py (revision 387f9dfdfa2baef462e92476d413c7bc2470293e)
1*387f9dfdSAndroid Build Coastguard Worker#!/usr/bin/env python3
2*387f9dfdSAndroid Build Coastguard Worker# Copyright (c) PLUMgrid, Inc.
3*387f9dfdSAndroid Build Coastguard Worker# Licensed under the Apache License, Version 2.0 (the "License")
4*387f9dfdSAndroid Build Coastguard Worker
5*387f9dfdSAndroid Build Coastguard Worker# This program implements a topology likes below:
6*387f9dfdSAndroid Build Coastguard Worker#   pem: physical endpoint manager, implemented as a bpf program
7*387f9dfdSAndroid Build Coastguard Worker#
8*387f9dfdSAndroid Build Coastguard Worker#     vm1 <--------+  +----> bridge1 <----+
9*387f9dfdSAndroid Build Coastguard Worker#                  V  V                   V
10*387f9dfdSAndroid Build Coastguard Worker#                  pem                  router
11*387f9dfdSAndroid Build Coastguard Worker#                  ^  ^                   ^
12*387f9dfdSAndroid Build Coastguard Worker#     vm2 <--------+  +----> bridge2 <----+
13*387f9dfdSAndroid Build Coastguard Worker#
14*387f9dfdSAndroid Build Coastguard Worker# The vm1, vm2 and router are implemented as namespaces.
15*387f9dfdSAndroid Build Coastguard Worker# The bridge is implemented with limited functionality in bpf program.
16*387f9dfdSAndroid Build Coastguard Worker#
17*387f9dfdSAndroid Build Coastguard Worker# vm1 and vm2 are in different subnet. For vm1 to communicate to vm2,
18*387f9dfdSAndroid Build Coastguard Worker# the packet will have to travel from vm1 to pem, bridge1, router, bridge2, pem, and
19*387f9dfdSAndroid Build Coastguard Worker# then come to vm2.
20*387f9dfdSAndroid Build Coastguard Worker#
21*387f9dfdSAndroid Build Coastguard Worker# When this test is run with verbose mode (ctest -R <test_name> -V),
22*387f9dfdSAndroid Build Coastguard Worker# the following printout is observed on my local box:
23*387f9dfdSAndroid Build Coastguard Worker#
24*387f9dfdSAndroid Build Coastguard Worker# ......
25*387f9dfdSAndroid Build Coastguard Worker# 8: ARPING 100.1.1.254 from 100.1.1.1 eth0
26*387f9dfdSAndroid Build Coastguard Worker# 8: Unicast reply from 100.1.1.254 [76:62:B5:5C:8C:6F]  0.533ms
27*387f9dfdSAndroid Build Coastguard Worker# 8: Sent 1 probes (1 broadcast(s))
28*387f9dfdSAndroid Build Coastguard Worker# 8: Received 1 response(s)
29*387f9dfdSAndroid Build Coastguard Worker# 8: ARPING 200.1.1.254 from 200.1.1.1 eth0
30*387f9dfdSAndroid Build Coastguard Worker# 8: Unicast reply from 200.1.1.254 [F2:F0:B4:ED:7B:1B]  0.524ms
31*387f9dfdSAndroid Build Coastguard Worker# 8: Sent 1 probes (1 broadcast(s))
32*387f9dfdSAndroid Build Coastguard Worker# 8: Received 1 response(s)
33*387f9dfdSAndroid Build Coastguard Worker# 8: PING 200.1.1.1 (200.1.1.1) 56(84) bytes of data.
34*387f9dfdSAndroid Build Coastguard Worker# 8: 64 bytes from 200.1.1.1: icmp_req=1 ttl=63 time=0.074 ms
35*387f9dfdSAndroid Build Coastguard Worker# 8: 64 bytes from 200.1.1.1: icmp_req=2 ttl=63 time=0.061 ms
36*387f9dfdSAndroid Build Coastguard Worker# 8:
37*387f9dfdSAndroid Build Coastguard Worker# 8: --- 200.1.1.1 ping statistics ---
38*387f9dfdSAndroid Build Coastguard Worker# 8: 2 packets transmitted, 2 received, 0% packet loss, time 999ms
39*387f9dfdSAndroid Build Coastguard Worker# 8: rtt min/avg/max/mdev = 0.061/0.067/0.074/0.010 ms
40*387f9dfdSAndroid Build Coastguard Worker# 8: [ ID] Interval       Transfer     Bandwidth
41*387f9dfdSAndroid Build Coastguard Worker# 8: [  5]  0.0- 1.0 sec  4.00 GBytes  34.3 Gbits/sec
42*387f9dfdSAndroid Build Coastguard Worker# 8: Starting netserver with host 'IN(6)ADDR_ANY' port '12865' and family AF_UNSPEC
43*387f9dfdSAndroid Build Coastguard Worker# 8: MIGRATED TCP STREAM TEST from 0.0.0.0 (0.0.0.0) port 0 AF_INET to 200.1.1.1 (200.1.1.1) port 0 AF_INET : demo
44*387f9dfdSAndroid Build Coastguard Worker# 8: Recv   Send    Send
45*387f9dfdSAndroid Build Coastguard Worker# 8: Socket Socket  Message  Elapsed
46*387f9dfdSAndroid Build Coastguard Worker# 8: Size   Size    Size     Time     Throughput
47*387f9dfdSAndroid Build Coastguard Worker# 8: bytes  bytes   bytes    secs.    10^6bits/sec
48*387f9dfdSAndroid Build Coastguard Worker# 8:
49*387f9dfdSAndroid Build Coastguard Worker# 8:  87380  16384  65160    1.00     41991.68
50*387f9dfdSAndroid Build Coastguard Worker# 8: MIGRATED TCP REQUEST/RESPONSE TEST from 0.0.0.0 (0.0.0.0) port 0 AF_INET to 200.1.1.1 (200.1.1.1) port 0 AF_INET : demo : first burst 0
51*387f9dfdSAndroid Build Coastguard Worker# 8: Local /Remote
52*387f9dfdSAndroid Build Coastguard Worker# 8: Socket Size   Request  Resp.   Elapsed  Trans.
53*387f9dfdSAndroid Build Coastguard Worker# 8: Send   Recv   Size     Size    Time     Rate
54*387f9dfdSAndroid Build Coastguard Worker# 8: bytes  Bytes  bytes    bytes   secs.    per sec
55*387f9dfdSAndroid Build Coastguard Worker# 8:
56*387f9dfdSAndroid Build Coastguard Worker# 8: 16384  87380  1        1       1.00     48645.53
57*387f9dfdSAndroid Build Coastguard Worker# 8: 16384  87380
58*387f9dfdSAndroid Build Coastguard Worker# 8: .
59*387f9dfdSAndroid Build Coastguard Worker# 8: ----------------------------------------------------------------------
60*387f9dfdSAndroid Build Coastguard Worker# 8: Ran 1 test in 11.296s
61*387f9dfdSAndroid Build Coastguard Worker# 8:
62*387f9dfdSAndroid Build Coastguard Worker# 8: OK
63*387f9dfdSAndroid Build Coastguard Worker
64*387f9dfdSAndroid Build Coastguard Workerfrom ctypes import c_uint
65*387f9dfdSAndroid Build Coastguard Workerfrom netaddr import IPAddress, EUI
66*387f9dfdSAndroid Build Coastguard Workerfrom bcc import BPF
67*387f9dfdSAndroid Build Coastguard Workerfrom pyroute2 import IPRoute, NetNS, IPDB, NSPopen
68*387f9dfdSAndroid Build Coastguard Workerfrom utils import NSPopenWithCheck, skipUnlessHasBinaries
69*387f9dfdSAndroid Build Coastguard Workerimport sys
70*387f9dfdSAndroid Build Coastguard Workerfrom time import sleep
71*387f9dfdSAndroid Build Coastguard Workerfrom unittest import main, TestCase
72*387f9dfdSAndroid Build Coastguard Workerfrom simulation import Simulation
73*387f9dfdSAndroid Build Coastguard Worker
74*387f9dfdSAndroid Build Coastguard Workerarg1 = sys.argv.pop(1)
75*387f9dfdSAndroid Build Coastguard Workeripr = IPRoute()
76*387f9dfdSAndroid Build Coastguard Workeripdb = IPDB(nl=ipr)
77*387f9dfdSAndroid Build Coastguard Workersim = Simulation(ipdb)
78*387f9dfdSAndroid Build Coastguard Worker
79*387f9dfdSAndroid Build Coastguard Workerclass TestBPFSocket(TestCase):
80*387f9dfdSAndroid Build Coastguard Worker    def set_default_const(self):
81*387f9dfdSAndroid Build Coastguard Worker        self.ns1            = "ns1"
82*387f9dfdSAndroid Build Coastguard Worker        self.ns2            = "ns2"
83*387f9dfdSAndroid Build Coastguard Worker        self.ns_router      = "ns_router"
84*387f9dfdSAndroid Build Coastguard Worker        self.vm1_ip         = "100.1.1.1"
85*387f9dfdSAndroid Build Coastguard Worker        self.vm2_ip         = "200.1.1.1"
86*387f9dfdSAndroid Build Coastguard Worker        self.vm1_rtr_ip     = "100.1.1.254"
87*387f9dfdSAndroid Build Coastguard Worker        self.vm2_rtr_ip     = "200.1.1.254"
88*387f9dfdSAndroid Build Coastguard Worker        self.vm1_rtr_mask   = "100.1.1.0/24"
89*387f9dfdSAndroid Build Coastguard Worker        self.vm2_rtr_mask   = "200.1.1.0/24"
90*387f9dfdSAndroid Build Coastguard Worker
91*387f9dfdSAndroid Build Coastguard Worker    def get_table(self, b):
92*387f9dfdSAndroid Build Coastguard Worker        self.jump = b.get_table(b"jump")
93*387f9dfdSAndroid Build Coastguard Worker
94*387f9dfdSAndroid Build Coastguard Worker        self.pem_dest = b.get_table(b"pem_dest")
95*387f9dfdSAndroid Build Coastguard Worker        self.pem_port = b.get_table(b"pem_port")
96*387f9dfdSAndroid Build Coastguard Worker        self.pem_ifindex = b.get_table(b"pem_ifindex")
97*387f9dfdSAndroid Build Coastguard Worker        self.pem_stats = b.get_table(b"pem_stats")
98*387f9dfdSAndroid Build Coastguard Worker
99*387f9dfdSAndroid Build Coastguard Worker        self.br1_dest = b.get_table(b"br1_dest")
100*387f9dfdSAndroid Build Coastguard Worker        self.br1_mac = b.get_table(b"br1_mac")
101*387f9dfdSAndroid Build Coastguard Worker        self.br1_rtr = b.get_table(b"br1_rtr")
102*387f9dfdSAndroid Build Coastguard Worker
103*387f9dfdSAndroid Build Coastguard Worker        self.br2_dest = b.get_table(b"br2_dest")
104*387f9dfdSAndroid Build Coastguard Worker        self.br2_mac = b.get_table(b"br2_mac")
105*387f9dfdSAndroid Build Coastguard Worker        self.br2_rtr = b.get_table(b"br2_rtr")
106*387f9dfdSAndroid Build Coastguard Worker
107*387f9dfdSAndroid Build Coastguard Worker    def connect_ports(self, prog_id_pem, prog_id_br, curr_pem_pid, curr_br_pid,
108*387f9dfdSAndroid Build Coastguard Worker                      br_dest_map, br_mac_map, ifindex, vm_mac, vm_ip):
109*387f9dfdSAndroid Build Coastguard Worker        self.pem_dest[c_uint(curr_pem_pid)] = self.pem_dest.Leaf(prog_id_br, curr_br_pid)
110*387f9dfdSAndroid Build Coastguard Worker        br_dest_map[c_uint(curr_br_pid)] = br_dest_map.Leaf(prog_id_pem, curr_pem_pid)
111*387f9dfdSAndroid Build Coastguard Worker        self.pem_port[c_uint(curr_pem_pid)] = c_uint(ifindex)
112*387f9dfdSAndroid Build Coastguard Worker        self.pem_ifindex[c_uint(ifindex)] = c_uint(curr_pem_pid)
113*387f9dfdSAndroid Build Coastguard Worker        mac_addr = br_mac_map.Key(int(EUI(vm_mac)))
114*387f9dfdSAndroid Build Coastguard Worker        br_mac_map[mac_addr] = c_uint(curr_br_pid)
115*387f9dfdSAndroid Build Coastguard Worker
116*387f9dfdSAndroid Build Coastguard Worker    def config_maps(self):
117*387f9dfdSAndroid Build Coastguard Worker        # program id
118*387f9dfdSAndroid Build Coastguard Worker        prog_id_pem = 1
119*387f9dfdSAndroid Build Coastguard Worker        prog_id_br1 = 2
120*387f9dfdSAndroid Build Coastguard Worker        prog_id_br2 = 3
121*387f9dfdSAndroid Build Coastguard Worker
122*387f9dfdSAndroid Build Coastguard Worker        # initial port id and table pointers
123*387f9dfdSAndroid Build Coastguard Worker        curr_pem_pid = 0
124*387f9dfdSAndroid Build Coastguard Worker        curr_br1_pid = 0
125*387f9dfdSAndroid Build Coastguard Worker        curr_br2_pid = 0
126*387f9dfdSAndroid Build Coastguard Worker
127*387f9dfdSAndroid Build Coastguard Worker        # configure jump table
128*387f9dfdSAndroid Build Coastguard Worker        self.jump[c_uint(prog_id_pem)] = c_uint(self.pem_fn.fd)
129*387f9dfdSAndroid Build Coastguard Worker        self.jump[c_uint(prog_id_br1)] = c_uint(self.br1_fn.fd)
130*387f9dfdSAndroid Build Coastguard Worker        self.jump[c_uint(prog_id_br2)] = c_uint(self.br2_fn.fd)
131*387f9dfdSAndroid Build Coastguard Worker
132*387f9dfdSAndroid Build Coastguard Worker        # connect pem and br1
133*387f9dfdSAndroid Build Coastguard Worker        curr_pem_pid = curr_pem_pid + 1
134*387f9dfdSAndroid Build Coastguard Worker        curr_br1_pid = curr_br1_pid + 1
135*387f9dfdSAndroid Build Coastguard Worker        self.connect_ports(prog_id_pem, prog_id_br1, curr_pem_pid, curr_br1_pid,
136*387f9dfdSAndroid Build Coastguard Worker                      self.br1_dest, self.br1_mac,
137*387f9dfdSAndroid Build Coastguard Worker                      self.ns1_eth_out.index, self.vm1_mac, self.vm1_ip)
138*387f9dfdSAndroid Build Coastguard Worker
139*387f9dfdSAndroid Build Coastguard Worker        # connect pem and br2
140*387f9dfdSAndroid Build Coastguard Worker        curr_pem_pid = curr_pem_pid + 1
141*387f9dfdSAndroid Build Coastguard Worker        curr_br2_pid = curr_br2_pid + 1
142*387f9dfdSAndroid Build Coastguard Worker        self.connect_ports(prog_id_pem, prog_id_br2, curr_pem_pid, curr_br2_pid,
143*387f9dfdSAndroid Build Coastguard Worker                      self.br2_dest, self.br2_mac,
144*387f9dfdSAndroid Build Coastguard Worker                      self.ns2_eth_out.index, self.vm2_mac, self.vm2_ip)
145*387f9dfdSAndroid Build Coastguard Worker
146*387f9dfdSAndroid Build Coastguard Worker        # connect <br1, rtr> and <br2, rtr>
147*387f9dfdSAndroid Build Coastguard Worker        self.br1_rtr[c_uint(0)] = c_uint(self.nsrtr_eth0_out.index)
148*387f9dfdSAndroid Build Coastguard Worker        self.br2_rtr[c_uint(0)] = c_uint(self.nsrtr_eth1_out.index)
149*387f9dfdSAndroid Build Coastguard Worker
150*387f9dfdSAndroid Build Coastguard Worker    @skipUnlessHasBinaries(
151*387f9dfdSAndroid Build Coastguard Worker        ["arping", "iperf", "netperf", "netserver", "ping"],
152*387f9dfdSAndroid Build Coastguard Worker        "iperf and netperf packages must be installed.")
153*387f9dfdSAndroid Build Coastguard Worker    def test_brb(self):
154*387f9dfdSAndroid Build Coastguard Worker        try:
155*387f9dfdSAndroid Build Coastguard Worker            b = BPF(src_file=arg1.encode(), debug=0)
156*387f9dfdSAndroid Build Coastguard Worker            self.pem_fn = b.load_func(b"pem", BPF.SCHED_CLS)
157*387f9dfdSAndroid Build Coastguard Worker            self.br1_fn = b.load_func(b"br1", BPF.SCHED_CLS)
158*387f9dfdSAndroid Build Coastguard Worker            self.br2_fn = b.load_func(b"br2", BPF.SCHED_CLS)
159*387f9dfdSAndroid Build Coastguard Worker            self.get_table(b)
160*387f9dfdSAndroid Build Coastguard Worker
161*387f9dfdSAndroid Build Coastguard Worker            # set up the topology
162*387f9dfdSAndroid Build Coastguard Worker            self.set_default_const()
163*387f9dfdSAndroid Build Coastguard Worker            (ns1_ipdb, self.ns1_eth_out, _) = sim._create_ns(self.ns1, ipaddr=self.vm1_ip+'/24',
164*387f9dfdSAndroid Build Coastguard Worker                                                             fn=self.pem_fn, action='drop',
165*387f9dfdSAndroid Build Coastguard Worker                                                             disable_ipv6=True)
166*387f9dfdSAndroid Build Coastguard Worker            (ns2_ipdb, self.ns2_eth_out, _) = sim._create_ns(self.ns2, ipaddr=self.vm2_ip+'/24',
167*387f9dfdSAndroid Build Coastguard Worker                                                             fn=self.pem_fn, action='drop',
168*387f9dfdSAndroid Build Coastguard Worker                                                             disable_ipv6=True)
169*387f9dfdSAndroid Build Coastguard Worker            ns1_ipdb.routes.add({'dst': self.vm2_rtr_mask, 'gateway': self.vm1_rtr_ip}).commit()
170*387f9dfdSAndroid Build Coastguard Worker            ns2_ipdb.routes.add({'dst': self.vm1_rtr_mask, 'gateway': self.vm2_rtr_ip}).commit()
171*387f9dfdSAndroid Build Coastguard Worker            self.vm1_mac = ns1_ipdb.interfaces['eth0'].address
172*387f9dfdSAndroid Build Coastguard Worker            self.vm2_mac = ns2_ipdb.interfaces['eth0'].address
173*387f9dfdSAndroid Build Coastguard Worker
174*387f9dfdSAndroid Build Coastguard Worker            (_, self.nsrtr_eth0_out, _) = sim._create_ns(self.ns_router, ipaddr=self.vm1_rtr_ip+'/24',
175*387f9dfdSAndroid Build Coastguard Worker                                                         fn=self.br1_fn, action='drop',
176*387f9dfdSAndroid Build Coastguard Worker                                                         disable_ipv6=True)
177*387f9dfdSAndroid Build Coastguard Worker            (rt_ipdb, self.nsrtr_eth1_out, _) = sim._ns_add_ifc(self.ns_router, "eth1", "ns_router2",
178*387f9dfdSAndroid Build Coastguard Worker                                                                ipaddr=self.vm2_rtr_ip+'/24',
179*387f9dfdSAndroid Build Coastguard Worker                                                                fn=self.br2_fn, action='drop',
180*387f9dfdSAndroid Build Coastguard Worker                                                                disable_ipv6=True)
181*387f9dfdSAndroid Build Coastguard Worker            nsp = NSPopen(rt_ipdb.nl.netns, ["sysctl", "-w", "net.ipv4.ip_forward=1"])
182*387f9dfdSAndroid Build Coastguard Worker            nsp.wait(); nsp.release()
183*387f9dfdSAndroid Build Coastguard Worker
184*387f9dfdSAndroid Build Coastguard Worker            # configure maps
185*387f9dfdSAndroid Build Coastguard Worker            self.config_maps()
186*387f9dfdSAndroid Build Coastguard Worker
187*387f9dfdSAndroid Build Coastguard Worker            # our bridge is not smart enough, so send arping for router learning to prevent router
188*387f9dfdSAndroid Build Coastguard Worker            # from sending out arp request
189*387f9dfdSAndroid Build Coastguard Worker            nsp = NSPopen(ns1_ipdb.nl.netns,
190*387f9dfdSAndroid Build Coastguard Worker                          ["arping", "-w", "1", "-c", "1", "-I", "eth0", self.vm1_rtr_ip])
191*387f9dfdSAndroid Build Coastguard Worker            nsp.wait(); nsp.release()
192*387f9dfdSAndroid Build Coastguard Worker            nsp = NSPopen(ns2_ipdb.nl.netns,
193*387f9dfdSAndroid Build Coastguard Worker                          ["arping", "-w", "1", "-c", "1", "-I", "eth0", self.vm2_rtr_ip])
194*387f9dfdSAndroid Build Coastguard Worker            nsp.wait(); nsp.release()
195*387f9dfdSAndroid Build Coastguard Worker
196*387f9dfdSAndroid Build Coastguard Worker            # ping
197*387f9dfdSAndroid Build Coastguard Worker            nsp = NSPopen(ns1_ipdb.nl.netns, ["ping", self.vm2_ip, "-c", "2"])
198*387f9dfdSAndroid Build Coastguard Worker            nsp.wait(); nsp.release()
199*387f9dfdSAndroid Build Coastguard Worker            # pem_stats only counts pem->bridge traffic, each VM has 4: arping/arp request/2 icmp request
200*387f9dfdSAndroid Build Coastguard Worker            # total 8 packets should be counted
201*387f9dfdSAndroid Build Coastguard Worker            self.assertEqual(self.pem_stats[c_uint(0)].value, 8)
202*387f9dfdSAndroid Build Coastguard Worker
203*387f9dfdSAndroid Build Coastguard Worker            nsp_server = NSPopenWithCheck(ns2_ipdb.nl.netns, ["iperf", "-s", "-xSC"])
204*387f9dfdSAndroid Build Coastguard Worker            sleep(1)
205*387f9dfdSAndroid Build Coastguard Worker            nsp = NSPopen(ns1_ipdb.nl.netns, ["iperf", "-c", self.vm2_ip, "-t", "1", "-xSC"])
206*387f9dfdSAndroid Build Coastguard Worker            nsp.wait(); nsp.release()
207*387f9dfdSAndroid Build Coastguard Worker            nsp_server.kill(); nsp_server.wait(); nsp_server.release()
208*387f9dfdSAndroid Build Coastguard Worker
209*387f9dfdSAndroid Build Coastguard Worker            nsp_server = NSPopenWithCheck(ns2_ipdb.nl.netns, ["netserver", "-D"])
210*387f9dfdSAndroid Build Coastguard Worker            sleep(1)
211*387f9dfdSAndroid Build Coastguard Worker            nsp = NSPopenWithCheck(ns1_ipdb.nl.netns, ["netperf", "-l", "1", "-H", self.vm2_ip, "--", "-m", "65160"])
212*387f9dfdSAndroid Build Coastguard Worker            nsp.wait(); nsp.release()
213*387f9dfdSAndroid Build Coastguard Worker            nsp = NSPopen(ns1_ipdb.nl.netns, ["netperf", "-l", "1", "-H", self.vm2_ip, "-t", "TCP_RR"])
214*387f9dfdSAndroid Build Coastguard Worker            nsp.wait(); nsp.release()
215*387f9dfdSAndroid Build Coastguard Worker            nsp_server.kill(); nsp_server.wait(); nsp_server.release()
216*387f9dfdSAndroid Build Coastguard Worker
217*387f9dfdSAndroid Build Coastguard Worker        finally:
218*387f9dfdSAndroid Build Coastguard Worker            sim.release()
219*387f9dfdSAndroid Build Coastguard Worker            ipdb.release()
220*387f9dfdSAndroid Build Coastguard Worker
221*387f9dfdSAndroid Build Coastguard Worker
222*387f9dfdSAndroid Build Coastguard Workerif __name__ == "__main__":
223*387f9dfdSAndroid Build Coastguard Worker    main()
224