Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

selftests/bpf: Test attaching a bpf qdisc with incomplete operators

Implement .destroy in bpf_fq and bpf_fifo as it is now mandatory.

Test attaching a bpf qdisc with a missing operator .init. This is not
allowed as bpf qdisc qdisc_watchdog_cancel() could have been called with
an uninitialized timer.

Signed-off-by: Amery Hung <ameryhung@gmail.com>
Signed-off-by: Martin KaFai Lau <martin.lau@kernel.org>

authored by

Amery Hung and committed by
Martin KaFai Lau
6cda0e2c 64d6e3b9

+72
+19
tools/testing/selftests/bpf/prog_tests/bpf_qdisc.c
··· 7 7 #include "network_helpers.h" 8 8 #include "bpf_qdisc_fifo.skel.h" 9 9 #include "bpf_qdisc_fq.skel.h" 10 + #include "bpf_qdisc_fail__incompl_ops.skel.h" 10 11 11 12 #define LO_IFINDEX 1 12 13 ··· 160 159 bpf_qdisc_fifo__destroy(fifo_skel); 161 160 } 162 161 162 + static void test_incompl_ops(void) 163 + { 164 + struct bpf_qdisc_fail__incompl_ops *skel; 165 + struct bpf_link *link; 166 + 167 + skel = bpf_qdisc_fail__incompl_ops__open_and_load(); 168 + if (!ASSERT_OK_PTR(skel, "bpf_qdisc_fifo__open_and_load")) 169 + return; 170 + 171 + link = bpf_map__attach_struct_ops(skel->maps.test); 172 + if (!ASSERT_ERR_PTR(link, "bpf_map__attach_struct_ops")) 173 + bpf_link__destroy(link); 174 + 175 + bpf_qdisc_fail__incompl_ops__destroy(skel); 176 + } 177 + 163 178 static int get_default_qdisc(char *qdisc_name) 164 179 { 165 180 FILE *f; ··· 247 230 test_qdisc_attach_to_mq(); 248 231 if (test__start_subtest("attach to non root")) 249 232 test_qdisc_attach_to_non_root(); 233 + if (test__start_subtest("incompl_ops")) 234 + test_incompl_ops(); 250 235 251 236 netns_free(netns); 252 237 }
+41
tools/testing/selftests/bpf/progs/bpf_qdisc_fail__incompl_ops.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + 3 + #include <vmlinux.h> 4 + #include "bpf_experimental.h" 5 + #include "bpf_qdisc_common.h" 6 + 7 + char _license[] SEC("license") = "GPL"; 8 + 9 + SEC("struct_ops") 10 + int BPF_PROG(bpf_qdisc_test_enqueue, struct sk_buff *skb, struct Qdisc *sch, 11 + struct bpf_sk_buff_ptr *to_free) 12 + { 13 + bpf_qdisc_skb_drop(skb, to_free); 14 + return NET_XMIT_DROP; 15 + } 16 + 17 + SEC("struct_ops") 18 + struct sk_buff *BPF_PROG(bpf_qdisc_test_dequeue, struct Qdisc *sch) 19 + { 20 + return NULL; 21 + } 22 + 23 + SEC("struct_ops") 24 + void BPF_PROG(bpf_qdisc_test_reset, struct Qdisc *sch) 25 + { 26 + } 27 + 28 + SEC("struct_ops") 29 + void BPF_PROG(bpf_qdisc_test_destroy, struct Qdisc *sch) 30 + { 31 + } 32 + 33 + SEC(".struct_ops") 34 + struct Qdisc_ops test = { 35 + .enqueue = (void *)bpf_qdisc_test_enqueue, 36 + .dequeue = (void *)bpf_qdisc_test_dequeue, 37 + .reset = (void *)bpf_qdisc_test_reset, 38 + .destroy = (void *)bpf_qdisc_test_destroy, 39 + .id = "bpf_qdisc_test", 40 + }; 41 +
+6
tools/testing/selftests/bpf/progs/bpf_qdisc_fifo.c
··· 109 109 sch->q.qlen = 0; 110 110 } 111 111 112 + SEC("struct_ops") 113 + void BPF_PROG(bpf_fifo_destroy, struct Qdisc *sch) 114 + { 115 + } 116 + 112 117 SEC(".struct_ops") 113 118 struct Qdisc_ops fifo = { 114 119 .enqueue = (void *)bpf_fifo_enqueue, 115 120 .dequeue = (void *)bpf_fifo_dequeue, 116 121 .init = (void *)bpf_fifo_init, 117 122 .reset = (void *)bpf_fifo_reset, 123 + .destroy = (void *)bpf_fifo_destroy, 118 124 .id = "bpf_fifo", 119 125 }; 120 126
+6
tools/testing/selftests/bpf/progs/bpf_qdisc_fq.c
··· 740 740 return 0; 741 741 } 742 742 743 + SEC("struct_ops") 744 + void BPF_PROG(bpf_fq_destroy, struct Qdisc *sch) 745 + { 746 + } 747 + 743 748 SEC(".struct_ops") 744 749 struct Qdisc_ops fq = { 745 750 .enqueue = (void *)bpf_fq_enqueue, 746 751 .dequeue = (void *)bpf_fq_dequeue, 747 752 .reset = (void *)bpf_fq_reset, 748 753 .init = (void *)bpf_fq_init, 754 + .destroy = (void *)bpf_fq_destroy, 749 755 .id = "bpf_fq", 750 756 };