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