Linux kernel mirror (for testing)
git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel
os
linux
1// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
2
3/*
4 * BPF-based flow shaping
5 *
6 * The test brings up two veth in two isolated namespaces, attach some flow
7 * shaping program onto it, and ensures that a manual speedtest maximum
8 * value matches the rate set in the BPF shapers.
9 */
10
11#include <asm-generic/socket.h>
12#include <stdio.h>
13#include <unistd.h>
14#include <fcntl.h>
15#include <math.h>
16#include <sys/time.h>
17#include <sys/socket.h>
18#include <bpf/libbpf.h>
19#include <pthread.h>
20#include "test_progs.h"
21#include "network_helpers.h"
22#include "test_tc_edt.skel.h"
23
24#define SERVER_NS "tc-edt-server-ns"
25#define CLIENT_NS "tc-edt-client-ns"
26#define IP4_ADDR_VETH1 "192.168.1.1"
27#define IP4_ADDR_VETH2 "192.168.1.2"
28#define IP4_ADDR_VETH2_HEX 0xC0A80102
29
30#define TIMEOUT_MS 2000
31#define TEST_PORT 9000
32#define TARGET_RATE_MBPS 5.0
33#define TX_BYTES_COUNT (1 * 1000 * 1000)
34#define RATE_ERROR_PERCENT 2.0
35
36struct connection {
37 int server_listen_fd;
38 int server_conn_fd;
39 int client_conn_fd;
40};
41
42static int setup(struct test_tc_edt *skel)
43{
44 struct nstoken *nstoken_client, *nstoken_server;
45 int ret;
46
47 if (!ASSERT_OK(make_netns(CLIENT_NS), "create client ns"))
48 goto fail;
49 if (!ASSERT_OK(make_netns(SERVER_NS), "create server ns"))
50 goto fail_delete_client_ns;
51
52 nstoken_client = open_netns(CLIENT_NS);
53 if (!ASSERT_OK_PTR(nstoken_client, "open client ns"))
54 goto fail_delete_server_ns;
55 SYS(fail_close_client_ns, "ip link add veth1 type veth peer name %s",
56 "veth2 netns " SERVER_NS);
57 SYS(fail_close_client_ns, "ip -4 addr add " IP4_ADDR_VETH1 "/24 dev veth1");
58 SYS(fail_close_client_ns, "ip link set veth1 up");
59
60 nstoken_server = open_netns(SERVER_NS);
61 if (!ASSERT_OK_PTR(nstoken_server, "enter server ns"))
62 goto fail_close_client_ns;
63 SYS(fail_close_server_ns, "ip -4 addr add " IP4_ADDR_VETH2 "/24 dev veth2");
64 SYS(fail_close_server_ns, "ip link set veth2 up");
65 SYS(fail_close_server_ns, "tc qdisc add dev veth2 root fq");
66 ret = tc_prog_attach("veth2", -1, bpf_program__fd(skel->progs.tc_prog));
67 if (!ASSERT_OK(ret, "attach bpf prog"))
68 goto fail_close_server_ns;
69 skel->bss->target_rate = TARGET_RATE_MBPS * 1000 * 1000;
70 close_netns(nstoken_server);
71 close_netns(nstoken_client);
72
73 return 0;
74
75fail_close_server_ns:
76 close_netns(nstoken_server);
77fail_close_client_ns:
78 close_netns(nstoken_client);
79fail_delete_server_ns:
80 remove_netns(SERVER_NS);
81fail_delete_client_ns:
82 remove_netns(CLIENT_NS);
83fail:
84 return -1;
85}
86
87static void cleanup(void)
88{
89 remove_netns(CLIENT_NS);
90 remove_netns(SERVER_NS);
91}
92
93static void run_test(void)
94{
95 int server_fd, client_fd, err;
96 double rate_mbps, rate_error;
97 struct nstoken *nstoken;
98 __u64 ts_start, ts_end;
99
100 nstoken = open_netns(SERVER_NS);
101 if (!ASSERT_OK_PTR(nstoken, "open server ns"))
102 return;
103 server_fd = start_server(AF_INET, SOCK_STREAM, IP4_ADDR_VETH2,
104 TEST_PORT, TIMEOUT_MS);
105 if (!ASSERT_OK_FD(server_fd, "start server"))
106 return;
107
108 close_netns(nstoken);
109 nstoken = open_netns(CLIENT_NS);
110 if (!ASSERT_OK_PTR(nstoken, "open client ns"))
111 return;
112 client_fd = connect_to_fd(server_fd, 0);
113 if (!ASSERT_OK_FD(client_fd, "connect client"))
114 return;
115
116 ts_start = get_time_ns();
117 err = send_recv_data(server_fd, client_fd, TX_BYTES_COUNT);
118 ts_end = get_time_ns();
119 close_netns(nstoken);
120 ASSERT_OK(err, "send_recv_data");
121
122 rate_mbps = TX_BYTES_COUNT / ((ts_end - ts_start) / 1000.0);
123 rate_error =
124 fabs((rate_mbps - TARGET_RATE_MBPS) * 100.0 / TARGET_RATE_MBPS);
125
126 ASSERT_LE(rate_error, RATE_ERROR_PERCENT,
127 "rate error is lower than threshold");
128}
129
130void test_tc_edt(void)
131{
132 struct test_tc_edt *skel;
133
134 skel = test_tc_edt__open_and_load();
135 if (!ASSERT_OK_PTR(skel, "skel open and load"))
136 return;
137
138 if (!ASSERT_OK(setup(skel), "global setup"))
139 return;
140
141 run_test();
142
143 cleanup();
144 test_tc_edt__destroy(skel);
145}