xref: /linux/tools/testing/selftests/bpf/prog_tests/bpf_qdisc.c (revision fe259a1bb26ec78842c975d992331705b0c2c2e8)
1 // SPDX-License-Identifier: GPL-2.0
2 
3 #include <linux/pkt_sched.h>
4 #include <linux/rtnetlink.h>
5 #include <test_progs.h>
6 
7 #include "network_helpers.h"
8 #include "bpf_qdisc_fifo.skel.h"
9 #include "bpf_qdisc_fq.skel.h"
10 
11 #define LO_IFINDEX 1
12 
13 static const unsigned int total_bytes = 10 * 1024 * 1024;
14 
15 static void do_test(char *qdisc)
16 {
17 	DECLARE_LIBBPF_OPTS(bpf_tc_hook, hook, .ifindex = LO_IFINDEX,
18 			    .attach_point = BPF_TC_QDISC,
19 			    .parent = TC_H_ROOT,
20 			    .handle = 0x8000000,
21 			    .qdisc = qdisc);
22 	int srv_fd = -1, cli_fd = -1;
23 	int err;
24 
25 	err = bpf_tc_hook_create(&hook);
26 	if (!ASSERT_OK(err, "attach qdisc"))
27 		return;
28 
29 	srv_fd = start_server(AF_INET6, SOCK_STREAM, NULL, 0, 0);
30 	if (!ASSERT_OK_FD(srv_fd, "start server"))
31 		goto done;
32 
33 	cli_fd = connect_to_fd(srv_fd, 0);
34 	if (!ASSERT_OK_FD(cli_fd, "connect to client"))
35 		goto done;
36 
37 	err = send_recv_data(srv_fd, cli_fd, total_bytes);
38 	ASSERT_OK(err, "send_recv_data");
39 
40 done:
41 	if (srv_fd != -1)
42 		close(srv_fd);
43 	if (cli_fd != -1)
44 		close(cli_fd);
45 
46 	bpf_tc_hook_destroy(&hook);
47 }
48 
49 static void test_fifo(void)
50 {
51 	struct bpf_qdisc_fifo *fifo_skel;
52 	struct bpf_link *link;
53 
54 	fifo_skel = bpf_qdisc_fifo__open_and_load();
55 	if (!ASSERT_OK_PTR(fifo_skel, "bpf_qdisc_fifo__open_and_load"))
56 		return;
57 
58 	link = bpf_map__attach_struct_ops(fifo_skel->maps.fifo);
59 	if (!ASSERT_OK_PTR(link, "bpf_map__attach_struct_ops")) {
60 		bpf_qdisc_fifo__destroy(fifo_skel);
61 		return;
62 	}
63 
64 	do_test("bpf_fifo");
65 
66 	bpf_link__destroy(link);
67 	bpf_qdisc_fifo__destroy(fifo_skel);
68 }
69 
70 static void test_fq(void)
71 {
72 	struct bpf_qdisc_fq *fq_skel;
73 	struct bpf_link *link;
74 
75 	fq_skel = bpf_qdisc_fq__open_and_load();
76 	if (!ASSERT_OK_PTR(fq_skel, "bpf_qdisc_fq__open_and_load"))
77 		return;
78 
79 	link = bpf_map__attach_struct_ops(fq_skel->maps.fq);
80 	if (!ASSERT_OK_PTR(link, "bpf_map__attach_struct_ops")) {
81 		bpf_qdisc_fq__destroy(fq_skel);
82 		return;
83 	}
84 
85 	do_test("bpf_fq");
86 
87 	bpf_link__destroy(link);
88 	bpf_qdisc_fq__destroy(fq_skel);
89 }
90 
91 static void test_qdisc_attach_to_mq(void)
92 {
93 	DECLARE_LIBBPF_OPTS(bpf_tc_hook, hook,
94 			    .attach_point = BPF_TC_QDISC,
95 			    .parent = TC_H_MAKE(1 << 16, 1),
96 			    .handle = 0x11 << 16,
97 			    .qdisc = "bpf_fifo");
98 	struct bpf_qdisc_fifo *fifo_skel;
99 	struct bpf_link *link;
100 	int err;
101 
102 	fifo_skel = bpf_qdisc_fifo__open_and_load();
103 	if (!ASSERT_OK_PTR(fifo_skel, "bpf_qdisc_fifo__open_and_load"))
104 		return;
105 
106 	link = bpf_map__attach_struct_ops(fifo_skel->maps.fifo);
107 	if (!ASSERT_OK_PTR(link, "bpf_map__attach_struct_ops")) {
108 		bpf_qdisc_fifo__destroy(fifo_skel);
109 		return;
110 	}
111 
112 	SYS(out, "ip link add veth0 type veth peer veth1");
113 	hook.ifindex = if_nametoindex("veth0");
114 	SYS(out, "tc qdisc add dev veth0 root handle 1: mq");
115 
116 	err = bpf_tc_hook_create(&hook);
117 	ASSERT_OK(err, "attach qdisc");
118 
119 	bpf_tc_hook_destroy(&hook);
120 
121 	SYS(out, "tc qdisc delete dev veth0 root mq");
122 out:
123 	bpf_link__destroy(link);
124 	bpf_qdisc_fifo__destroy(fifo_skel);
125 }
126 
127 static void test_qdisc_attach_to_non_root(void)
128 {
129 	DECLARE_LIBBPF_OPTS(bpf_tc_hook, hook, .ifindex = LO_IFINDEX,
130 			    .attach_point = BPF_TC_QDISC,
131 			    .parent = TC_H_MAKE(1 << 16, 1),
132 			    .handle = 0x11 << 16,
133 			    .qdisc = "bpf_fifo");
134 	struct bpf_qdisc_fifo *fifo_skel;
135 	struct bpf_link *link;
136 	int err;
137 
138 	fifo_skel = bpf_qdisc_fifo__open_and_load();
139 	if (!ASSERT_OK_PTR(fifo_skel, "bpf_qdisc_fifo__open_and_load"))
140 		return;
141 
142 	link = bpf_map__attach_struct_ops(fifo_skel->maps.fifo);
143 	if (!ASSERT_OK_PTR(link, "bpf_map__attach_struct_ops")) {
144 		bpf_qdisc_fifo__destroy(fifo_skel);
145 		return;
146 	}
147 
148 	SYS(out, "tc qdisc add dev lo root handle 1: htb");
149 	SYS(out_del_htb, "tc class add dev lo parent 1: classid 1:1 htb rate 75Kbit");
150 
151 	err = bpf_tc_hook_create(&hook);
152 	if (!ASSERT_ERR(err, "attach qdisc"))
153 		bpf_tc_hook_destroy(&hook);
154 
155 out_del_htb:
156 	SYS(out, "tc qdisc delete dev lo root htb");
157 out:
158 	bpf_link__destroy(link);
159 	bpf_qdisc_fifo__destroy(fifo_skel);
160 }
161 
162 void test_bpf_qdisc(void)
163 {
164 	struct netns_obj *netns;
165 
166 	netns = netns_new("bpf_qdisc_ns", true);
167 	if (!ASSERT_OK_PTR(netns, "netns_new"))
168 		return;
169 
170 	if (test__start_subtest("fifo"))
171 		test_fifo();
172 	if (test__start_subtest("fq"))
173 		test_fq();
174 	if (test__start_subtest("attach to mq"))
175 		test_qdisc_attach_to_mq();
176 	if (test__start_subtest("attach to non root"))
177 		test_qdisc_attach_to_non_root();
178 
179 	netns_free(netns);
180 }
181