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>
This commit is contained in:
Amery Hung
2025-05-02 13:16:23 -07:00
committed by Martin KaFai Lau
parent 64d6e3b9df
commit 6cda0e2c47
4 changed files with 72 additions and 0 deletions

View File

@@ -7,6 +7,7 @@
#include "network_helpers.h"
#include "bpf_qdisc_fifo.skel.h"
#include "bpf_qdisc_fq.skel.h"
#include "bpf_qdisc_fail__incompl_ops.skel.h"
#define LO_IFINDEX 1
@@ -159,6 +160,22 @@ static void test_qdisc_attach_to_non_root(void)
bpf_qdisc_fifo__destroy(fifo_skel);
}
static void test_incompl_ops(void)
{
struct bpf_qdisc_fail__incompl_ops *skel;
struct bpf_link *link;
skel = bpf_qdisc_fail__incompl_ops__open_and_load();
if (!ASSERT_OK_PTR(skel, "bpf_qdisc_fifo__open_and_load"))
return;
link = bpf_map__attach_struct_ops(skel->maps.test);
if (!ASSERT_ERR_PTR(link, "bpf_map__attach_struct_ops"))
bpf_link__destroy(link);
bpf_qdisc_fail__incompl_ops__destroy(skel);
}
static int get_default_qdisc(char *qdisc_name)
{
FILE *f;
@@ -230,6 +247,8 @@ void test_bpf_qdisc(void)
test_qdisc_attach_to_mq();
if (test__start_subtest("attach to non root"))
test_qdisc_attach_to_non_root();
if (test__start_subtest("incompl_ops"))
test_incompl_ops();
netns_free(netns);
}

View File

@@ -0,0 +1,41 @@
// SPDX-License-Identifier: GPL-2.0
#include <vmlinux.h>
#include "bpf_experimental.h"
#include "bpf_qdisc_common.h"
char _license[] SEC("license") = "GPL";
SEC("struct_ops")
int BPF_PROG(bpf_qdisc_test_enqueue, struct sk_buff *skb, struct Qdisc *sch,
struct bpf_sk_buff_ptr *to_free)
{
bpf_qdisc_skb_drop(skb, to_free);
return NET_XMIT_DROP;
}
SEC("struct_ops")
struct sk_buff *BPF_PROG(bpf_qdisc_test_dequeue, struct Qdisc *sch)
{
return NULL;
}
SEC("struct_ops")
void BPF_PROG(bpf_qdisc_test_reset, struct Qdisc *sch)
{
}
SEC("struct_ops")
void BPF_PROG(bpf_qdisc_test_destroy, struct Qdisc *sch)
{
}
SEC(".struct_ops")
struct Qdisc_ops test = {
.enqueue = (void *)bpf_qdisc_test_enqueue,
.dequeue = (void *)bpf_qdisc_test_dequeue,
.reset = (void *)bpf_qdisc_test_reset,
.destroy = (void *)bpf_qdisc_test_destroy,
.id = "bpf_qdisc_test",
};

View File

@@ -109,12 +109,18 @@ void BPF_PROG(bpf_fifo_reset, struct Qdisc *sch)
sch->q.qlen = 0;
}
SEC("struct_ops")
void BPF_PROG(bpf_fifo_destroy, struct Qdisc *sch)
{
}
SEC(".struct_ops")
struct Qdisc_ops fifo = {
.enqueue = (void *)bpf_fifo_enqueue,
.dequeue = (void *)bpf_fifo_dequeue,
.init = (void *)bpf_fifo_init,
.reset = (void *)bpf_fifo_reset,
.destroy = (void *)bpf_fifo_destroy,
.id = "bpf_fifo",
};

View File

@@ -740,11 +740,17 @@ int BPF_PROG(bpf_fq_init, struct Qdisc *sch, struct nlattr *opt,
return 0;
}
SEC("struct_ops")
void BPF_PROG(bpf_fq_destroy, struct Qdisc *sch)
{
}
SEC(".struct_ops")
struct Qdisc_ops fq = {
.enqueue = (void *)bpf_fq_enqueue,
.dequeue = (void *)bpf_fq_dequeue,
.reset = (void *)bpf_fq_reset,
.init = (void *)bpf_fq_init,
.destroy = (void *)bpf_fq_destroy,
.id = "bpf_fq",
};