bpf-for-netdev
-----BEGIN PGP SIGNATURE----- iHUEABYIAB0WIQTFp0I1jqZrAX+hPRXbK58LschIgwUCZSXLzwAKCRDbK58LschI g1wuAQDTT1mrUmRqrpPob/U3HCcTg64hgdRwyF+6IU39/+neGwEAoP0FKZoy3DDf C8FOdVChBjapPsp9zTeYPv0nlZMITAE= =1Shl -----END PGP SIGNATURE----- Merge tag 'for-netdev' of https://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf Daniel Borkmann says: ==================== pull-request: bpf 2023-10-11 We've added 14 non-merge commits during the last 5 day(s) which contain a total of 12 files changed, 398 insertions(+), 104 deletions(-). The main changes are: 1) Fix s390 JIT backchain issues in the trampoline code generation which previously clobbered the caller's backchain, from Ilya Leoshkevich. 2) Fix zero-size allocation warning in xsk sockets when the configured ring size was close to SIZE_MAX, from Andrew Kanner. 3) Fixes for bpf_mprog API that were found when implementing support in the ebpf-go library along with selftests, from Daniel Borkmann and Lorenz Bauer. 4) Fix riscv JIT to properly sign-extend the return register in programs. This fixes various test_progs selftests on riscv, from Björn Töpel. 5) Fix verifier log for async callback return values where the allowed range was displayed incorrectly, from David Vernet. * tag 'for-netdev' of https://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf: s390/bpf: Fix unwinding past the trampoline s390/bpf: Fix clobbering the caller's backchain in the trampoline selftests/bpf: Add testcase for async callback return value failure bpf: Fix verifier log for async callback return values xdp: Fix zero-size allocation warning in xskq_create() riscv, bpf: Track both a0 (RISC-V ABI) and a5 (BPF) return values riscv, bpf: Sign-extend return values selftests/bpf: Make seen_tc* variable tests more robust selftests/bpf: Test query on empty mprog and pass revision into attach selftests/bpf: Adapt assert_mprog_count to always expect 0 count selftests/bpf: Test bpf_mprog query API via libbpf and raw syscall bpf: Refuse unused attributes in bpf_prog_{attach,detach} bpf: Handle bpf_mprog_query with NULL entry bpf: Fix BPF_PROG_QUERY last field check ==================== Link: https://lore.kernel.org/r/20231010223610.3984-1-daniel@iogearbox.net Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
commit
ad98426a88
|
@ -245,7 +245,7 @@ static void __build_epilogue(bool is_tail_call, struct rv_jit_context *ctx)
|
|||
emit_addi(RV_REG_SP, RV_REG_SP, stack_adjust, ctx);
|
||||
/* Set return value. */
|
||||
if (!is_tail_call)
|
||||
emit_mv(RV_REG_A0, RV_REG_A5, ctx);
|
||||
emit_addiw(RV_REG_A0, RV_REG_A5, 0, ctx);
|
||||
emit_jalr(RV_REG_ZERO, is_tail_call ? RV_REG_T3 : RV_REG_RA,
|
||||
is_tail_call ? (RV_FENTRY_NINSNS + 1) * 4 : 0, /* skip reserved nops and TCC init */
|
||||
ctx);
|
||||
|
@ -759,8 +759,10 @@ static int invoke_bpf_prog(struct bpf_tramp_link *l, int args_off, int retval_of
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (save_ret)
|
||||
emit_sd(RV_REG_FP, -retval_off, regmap[BPF_REG_0], ctx);
|
||||
if (save_ret) {
|
||||
emit_sd(RV_REG_FP, -retval_off, RV_REG_A0, ctx);
|
||||
emit_sd(RV_REG_FP, -(retval_off - 8), regmap[BPF_REG_0], ctx);
|
||||
}
|
||||
|
||||
/* update branch with beqz */
|
||||
if (ctx->insns) {
|
||||
|
@ -853,7 +855,7 @@ static int __arch_prepare_bpf_trampoline(struct bpf_tramp_image *im,
|
|||
|
||||
save_ret = flags & (BPF_TRAMP_F_CALL_ORIG | BPF_TRAMP_F_RET_FENTRY_RET);
|
||||
if (save_ret) {
|
||||
stack_size += 8;
|
||||
stack_size += 16; /* Save both A5 (BPF R0) and A0 */
|
||||
retval_off = stack_size;
|
||||
}
|
||||
|
||||
|
@ -957,6 +959,7 @@ static int __arch_prepare_bpf_trampoline(struct bpf_tramp_image *im,
|
|||
if (ret)
|
||||
goto out;
|
||||
emit_sd(RV_REG_FP, -retval_off, RV_REG_A0, ctx);
|
||||
emit_sd(RV_REG_FP, -(retval_off - 8), regmap[BPF_REG_0], ctx);
|
||||
im->ip_after_call = ctx->insns + ctx->ninsns;
|
||||
/* 2 nops reserved for auipc+jalr pair */
|
||||
emit(rv_nop(), ctx);
|
||||
|
@ -988,8 +991,10 @@ static int __arch_prepare_bpf_trampoline(struct bpf_tramp_image *im,
|
|||
if (flags & BPF_TRAMP_F_RESTORE_REGS)
|
||||
restore_args(nregs, args_off, ctx);
|
||||
|
||||
if (save_ret)
|
||||
if (save_ret) {
|
||||
emit_ld(RV_REG_A0, -retval_off, RV_REG_FP, ctx);
|
||||
emit_ld(regmap[BPF_REG_0], -(retval_off - 8), RV_REG_FP, ctx);
|
||||
}
|
||||
|
||||
emit_ld(RV_REG_S1, -sreg_off, RV_REG_FP, ctx);
|
||||
|
||||
|
@ -1515,7 +1520,8 @@ out_be:
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
emit_mv(bpf_to_rv_reg(BPF_REG_0, ctx), RV_REG_A0, ctx);
|
||||
if (insn->src_reg != BPF_PSEUDO_CALL)
|
||||
emit_mv(bpf_to_rv_reg(BPF_REG_0, ctx), RV_REG_A0, ctx);
|
||||
break;
|
||||
}
|
||||
/* tail call */
|
||||
|
|
|
@ -2066,6 +2066,7 @@ struct bpf_tramp_jit {
|
|||
* func_addr's original caller
|
||||
*/
|
||||
int stack_size; /* Trampoline stack size */
|
||||
int backchain_off; /* Offset of backchain */
|
||||
int stack_args_off; /* Offset of stack arguments for calling
|
||||
* func_addr, has to be at the top
|
||||
*/
|
||||
|
@ -2086,9 +2087,10 @@ struct bpf_tramp_jit {
|
|||
* for __bpf_prog_enter() return value and
|
||||
* func_addr respectively
|
||||
*/
|
||||
int r14_off; /* Offset of saved %r14 */
|
||||
int run_ctx_off; /* Offset of struct bpf_tramp_run_ctx */
|
||||
int tccnt_off; /* Offset of saved tailcall counter */
|
||||
int r14_off; /* Offset of saved %r14, has to be at the
|
||||
* bottom */
|
||||
int do_fexit; /* do_fexit: label */
|
||||
};
|
||||
|
||||
|
@ -2247,8 +2249,12 @@ static int __arch_prepare_bpf_trampoline(struct bpf_tramp_image *im,
|
|||
* Calculate the stack layout.
|
||||
*/
|
||||
|
||||
/* Reserve STACK_FRAME_OVERHEAD bytes for the callees. */
|
||||
/*
|
||||
* Allocate STACK_FRAME_OVERHEAD bytes for the callees. As the s390x
|
||||
* ABI requires, put our backchain at the end of the allocated memory.
|
||||
*/
|
||||
tjit->stack_size = STACK_FRAME_OVERHEAD;
|
||||
tjit->backchain_off = tjit->stack_size - sizeof(u64);
|
||||
tjit->stack_args_off = alloc_stack(tjit, nr_stack_args * sizeof(u64));
|
||||
tjit->reg_args_off = alloc_stack(tjit, nr_reg_args * sizeof(u64));
|
||||
tjit->ip_off = alloc_stack(tjit, sizeof(u64));
|
||||
|
@ -2256,16 +2262,25 @@ static int __arch_prepare_bpf_trampoline(struct bpf_tramp_image *im,
|
|||
tjit->bpf_args_off = alloc_stack(tjit, nr_bpf_args * sizeof(u64));
|
||||
tjit->retval_off = alloc_stack(tjit, sizeof(u64));
|
||||
tjit->r7_r8_off = alloc_stack(tjit, 2 * sizeof(u64));
|
||||
tjit->r14_off = alloc_stack(tjit, sizeof(u64));
|
||||
tjit->run_ctx_off = alloc_stack(tjit,
|
||||
sizeof(struct bpf_tramp_run_ctx));
|
||||
tjit->tccnt_off = alloc_stack(tjit, sizeof(u64));
|
||||
/* The caller has already reserved STACK_FRAME_OVERHEAD bytes. */
|
||||
tjit->stack_size -= STACK_FRAME_OVERHEAD;
|
||||
tjit->r14_off = alloc_stack(tjit, sizeof(u64) * 2);
|
||||
/*
|
||||
* In accordance with the s390x ABI, the caller has allocated
|
||||
* STACK_FRAME_OVERHEAD bytes for us. 8 of them contain the caller's
|
||||
* backchain, and the rest we can use.
|
||||
*/
|
||||
tjit->stack_size -= STACK_FRAME_OVERHEAD - sizeof(u64);
|
||||
tjit->orig_stack_args_off = tjit->stack_size + STACK_FRAME_OVERHEAD;
|
||||
|
||||
/* lgr %r1,%r15 */
|
||||
EMIT4(0xb9040000, REG_1, REG_15);
|
||||
/* aghi %r15,-stack_size */
|
||||
EMIT4_IMM(0xa70b0000, REG_15, -tjit->stack_size);
|
||||
/* stg %r1,backchain_off(%r15) */
|
||||
EMIT6_DISP_LH(0xe3000000, 0x0024, REG_1, REG_0, REG_15,
|
||||
tjit->backchain_off);
|
||||
/* mvc tccnt_off(4,%r15),stack_size+STK_OFF_TCCNT(%r15) */
|
||||
_EMIT6(0xd203f000 | tjit->tccnt_off,
|
||||
0xf000 | (tjit->stack_size + STK_OFF_TCCNT));
|
||||
|
|
|
@ -401,14 +401,16 @@ int bpf_mprog_query(const union bpf_attr *attr, union bpf_attr __user *uattr,
|
|||
struct bpf_mprog_cp *cp;
|
||||
struct bpf_prog *prog;
|
||||
const u32 flags = 0;
|
||||
u32 id, count = 0;
|
||||
u64 revision = 1;
|
||||
int i, ret = 0;
|
||||
u32 id, count;
|
||||
u64 revision;
|
||||
|
||||
if (attr->query.query_flags || attr->query.attach_flags)
|
||||
return -EINVAL;
|
||||
revision = bpf_mprog_revision(entry);
|
||||
count = bpf_mprog_total(entry);
|
||||
if (entry) {
|
||||
revision = bpf_mprog_revision(entry);
|
||||
count = bpf_mprog_total(entry);
|
||||
}
|
||||
if (copy_to_user(&uattr->query.attach_flags, &flags, sizeof(flags)))
|
||||
return -EFAULT;
|
||||
if (copy_to_user(&uattr->query.revision, &revision, sizeof(revision)))
|
||||
|
|
|
@ -3796,7 +3796,6 @@ static int bpf_prog_attach(const union bpf_attr *attr)
|
|||
{
|
||||
enum bpf_prog_type ptype;
|
||||
struct bpf_prog *prog;
|
||||
u32 mask;
|
||||
int ret;
|
||||
|
||||
if (CHECK_ATTR(BPF_PROG_ATTACH))
|
||||
|
@ -3805,10 +3804,16 @@ static int bpf_prog_attach(const union bpf_attr *attr)
|
|||
ptype = attach_type_to_prog_type(attr->attach_type);
|
||||
if (ptype == BPF_PROG_TYPE_UNSPEC)
|
||||
return -EINVAL;
|
||||
mask = bpf_mprog_supported(ptype) ?
|
||||
BPF_F_ATTACH_MASK_MPROG : BPF_F_ATTACH_MASK_BASE;
|
||||
if (attr->attach_flags & ~mask)
|
||||
return -EINVAL;
|
||||
if (bpf_mprog_supported(ptype)) {
|
||||
if (attr->attach_flags & ~BPF_F_ATTACH_MASK_MPROG)
|
||||
return -EINVAL;
|
||||
} else {
|
||||
if (attr->attach_flags & ~BPF_F_ATTACH_MASK_BASE)
|
||||
return -EINVAL;
|
||||
if (attr->relative_fd ||
|
||||
attr->expected_revision)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
prog = bpf_prog_get_type(attr->attach_bpf_fd, ptype);
|
||||
if (IS_ERR(prog))
|
||||
|
@ -3878,6 +3883,10 @@ static int bpf_prog_detach(const union bpf_attr *attr)
|
|||
if (IS_ERR(prog))
|
||||
return PTR_ERR(prog);
|
||||
}
|
||||
} else if (attr->attach_flags ||
|
||||
attr->relative_fd ||
|
||||
attr->expected_revision) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
switch (ptype) {
|
||||
|
@ -3913,7 +3922,7 @@ static int bpf_prog_detach(const union bpf_attr *attr)
|
|||
return ret;
|
||||
}
|
||||
|
||||
#define BPF_PROG_QUERY_LAST_FIELD query.link_attach_flags
|
||||
#define BPF_PROG_QUERY_LAST_FIELD query.revision
|
||||
|
||||
static int bpf_prog_query(const union bpf_attr *attr,
|
||||
union bpf_attr __user *uattr)
|
||||
|
|
|
@ -123,7 +123,6 @@ int tcx_prog_query(const union bpf_attr *attr, union bpf_attr __user *uattr)
|
|||
{
|
||||
bool ingress = attr->query.attach_type == BPF_TCX_INGRESS;
|
||||
struct net *net = current->nsproxy->net_ns;
|
||||
struct bpf_mprog_entry *entry;
|
||||
struct net_device *dev;
|
||||
int ret;
|
||||
|
||||
|
@ -133,12 +132,7 @@ int tcx_prog_query(const union bpf_attr *attr, union bpf_attr __user *uattr)
|
|||
ret = -ENODEV;
|
||||
goto out;
|
||||
}
|
||||
entry = tcx_entry_fetch(dev, ingress);
|
||||
if (!entry) {
|
||||
ret = -ENOENT;
|
||||
goto out;
|
||||
}
|
||||
ret = bpf_mprog_query(attr, uattr, entry);
|
||||
ret = bpf_mprog_query(attr, uattr, tcx_entry_fetch(dev, ingress));
|
||||
out:
|
||||
rtnl_unlock();
|
||||
return ret;
|
||||
|
|
|
@ -14479,7 +14479,7 @@ static int check_return_code(struct bpf_verifier_env *env)
|
|||
struct tnum enforce_attach_type_range = tnum_unknown;
|
||||
const struct bpf_prog *prog = env->prog;
|
||||
struct bpf_reg_state *reg;
|
||||
struct tnum range = tnum_range(0, 1);
|
||||
struct tnum range = tnum_range(0, 1), const_0 = tnum_const(0);
|
||||
enum bpf_prog_type prog_type = resolve_prog_type(env->prog);
|
||||
int err;
|
||||
struct bpf_func_state *frame = env->cur_state->frame[0];
|
||||
|
@ -14527,8 +14527,8 @@ static int check_return_code(struct bpf_verifier_env *env)
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!tnum_in(tnum_const(0), reg->var_off)) {
|
||||
verbose_invalid_scalar(env, reg, &range, "async callback", "R0");
|
||||
if (!tnum_in(const_0, reg->var_off)) {
|
||||
verbose_invalid_scalar(env, reg, &const_0, "async callback", "R0");
|
||||
return -EINVAL;
|
||||
}
|
||||
return 0;
|
||||
|
|
|
@ -34,6 +34,16 @@ struct xsk_queue *xskq_create(u32 nentries, bool umem_queue)
|
|||
q->ring_mask = nentries - 1;
|
||||
|
||||
size = xskq_get_ring_size(q, umem_queue);
|
||||
|
||||
/* size which is overflowing or close to SIZE_MAX will become 0 in
|
||||
* PAGE_ALIGN(), checking SIZE_MAX is enough due to the previous
|
||||
* is_power_of_2(), the rest will be handled by vmalloc_user()
|
||||
*/
|
||||
if (unlikely(size == SIZE_MAX)) {
|
||||
kfree(q);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
size = PAGE_ALIGN(size);
|
||||
|
||||
q->ring = vmalloc_user(size);
|
||||
|
|
|
@ -45,7 +45,7 @@ static inline __u32 ifindex_from_link_fd(int fd)
|
|||
return link_info.tcx.ifindex;
|
||||
}
|
||||
|
||||
static inline void __assert_mprog_count(int target, int expected, bool miniq, int ifindex)
|
||||
static inline void __assert_mprog_count(int target, int expected, int ifindex)
|
||||
{
|
||||
__u32 count = 0, attach_flags = 0;
|
||||
int err;
|
||||
|
@ -53,20 +53,22 @@ static inline void __assert_mprog_count(int target, int expected, bool miniq, in
|
|||
err = bpf_prog_query(ifindex, target, 0, &attach_flags,
|
||||
NULL, &count);
|
||||
ASSERT_EQ(count, expected, "count");
|
||||
if (!expected && !miniq)
|
||||
ASSERT_EQ(err, -ENOENT, "prog_query");
|
||||
else
|
||||
ASSERT_EQ(err, 0, "prog_query");
|
||||
ASSERT_EQ(err, 0, "prog_query");
|
||||
}
|
||||
|
||||
static inline void assert_mprog_count(int target, int expected)
|
||||
{
|
||||
__assert_mprog_count(target, expected, false, loopback);
|
||||
__assert_mprog_count(target, expected, loopback);
|
||||
}
|
||||
|
||||
static inline void assert_mprog_count_ifindex(int ifindex, int target, int expected)
|
||||
{
|
||||
__assert_mprog_count(target, expected, false, ifindex);
|
||||
__assert_mprog_count(target, expected, ifindex);
|
||||
}
|
||||
|
||||
static inline void tc_skel_reset_all_seen(struct test_tc_link *skel)
|
||||
{
|
||||
memset(skel->bss, 0, sizeof(*skel->bss));
|
||||
}
|
||||
|
||||
#endif /* TC_HELPERS */
|
||||
|
|
|
@ -65,6 +65,7 @@ void serial_test_tc_links_basic(void)
|
|||
ASSERT_EQ(optq.prog_ids[1], 0, "prog_ids[1]");
|
||||
ASSERT_EQ(optq.link_ids[1], 0, "link_ids[1]");
|
||||
|
||||
tc_skel_reset_all_seen(skel);
|
||||
ASSERT_OK(system(ping_cmd), ping_cmd);
|
||||
|
||||
ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");
|
||||
|
@ -97,6 +98,7 @@ void serial_test_tc_links_basic(void)
|
|||
ASSERT_EQ(optq.prog_ids[1], 0, "prog_ids[1]");
|
||||
ASSERT_EQ(optq.link_ids[1], 0, "link_ids[1]");
|
||||
|
||||
tc_skel_reset_all_seen(skel);
|
||||
ASSERT_OK(system(ping_cmd), ping_cmd);
|
||||
|
||||
ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");
|
||||
|
@ -187,6 +189,7 @@ static void test_tc_links_before_target(int target)
|
|||
ASSERT_EQ(optq.prog_ids[2], 0, "prog_ids[2]");
|
||||
ASSERT_EQ(optq.link_ids[2], 0, "link_ids[2]");
|
||||
|
||||
tc_skel_reset_all_seen(skel);
|
||||
ASSERT_OK(system(ping_cmd), ping_cmd);
|
||||
|
||||
ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");
|
||||
|
@ -194,9 +197,6 @@ static void test_tc_links_before_target(int target)
|
|||
ASSERT_EQ(skel->bss->seen_tc3, false, "seen_tc3");
|
||||
ASSERT_EQ(skel->bss->seen_tc4, false, "seen_tc4");
|
||||
|
||||
skel->bss->seen_tc1 = false;
|
||||
skel->bss->seen_tc2 = false;
|
||||
|
||||
LIBBPF_OPTS_RESET(optl,
|
||||
.flags = BPF_F_BEFORE,
|
||||
.relative_fd = bpf_program__fd(skel->progs.tc2),
|
||||
|
@ -246,6 +246,7 @@ static void test_tc_links_before_target(int target)
|
|||
ASSERT_EQ(optq.prog_ids[4], 0, "prog_ids[4]");
|
||||
ASSERT_EQ(optq.link_ids[4], 0, "link_ids[4]");
|
||||
|
||||
tc_skel_reset_all_seen(skel);
|
||||
ASSERT_OK(system(ping_cmd), ping_cmd);
|
||||
|
||||
ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");
|
||||
|
@ -342,6 +343,7 @@ static void test_tc_links_after_target(int target)
|
|||
ASSERT_EQ(optq.prog_ids[2], 0, "prog_ids[2]");
|
||||
ASSERT_EQ(optq.link_ids[2], 0, "link_ids[2]");
|
||||
|
||||
tc_skel_reset_all_seen(skel);
|
||||
ASSERT_OK(system(ping_cmd), ping_cmd);
|
||||
|
||||
ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");
|
||||
|
@ -349,9 +351,6 @@ static void test_tc_links_after_target(int target)
|
|||
ASSERT_EQ(skel->bss->seen_tc3, false, "seen_tc3");
|
||||
ASSERT_EQ(skel->bss->seen_tc4, false, "seen_tc4");
|
||||
|
||||
skel->bss->seen_tc1 = false;
|
||||
skel->bss->seen_tc2 = false;
|
||||
|
||||
LIBBPF_OPTS_RESET(optl,
|
||||
.flags = BPF_F_AFTER,
|
||||
.relative_fd = bpf_program__fd(skel->progs.tc1),
|
||||
|
@ -401,6 +400,7 @@ static void test_tc_links_after_target(int target)
|
|||
ASSERT_EQ(optq.prog_ids[4], 0, "prog_ids[4]");
|
||||
ASSERT_EQ(optq.link_ids[4], 0, "link_ids[4]");
|
||||
|
||||
tc_skel_reset_all_seen(skel);
|
||||
ASSERT_OK(system(ping_cmd), ping_cmd);
|
||||
|
||||
ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");
|
||||
|
@ -502,6 +502,7 @@ static void test_tc_links_revision_target(int target)
|
|||
ASSERT_EQ(optq.prog_ids[2], 0, "prog_ids[2]");
|
||||
ASSERT_EQ(optq.link_ids[2], 0, "prog_ids[2]");
|
||||
|
||||
tc_skel_reset_all_seen(skel);
|
||||
ASSERT_OK(system(ping_cmd), ping_cmd);
|
||||
|
||||
ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");
|
||||
|
@ -581,22 +582,20 @@ static void test_tc_chain_classic(int target, bool chain_tc_old)
|
|||
|
||||
assert_mprog_count(target, 2);
|
||||
|
||||
tc_skel_reset_all_seen(skel);
|
||||
ASSERT_OK(system(ping_cmd), ping_cmd);
|
||||
|
||||
ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");
|
||||
ASSERT_EQ(skel->bss->seen_tc2, true, "seen_tc2");
|
||||
ASSERT_EQ(skel->bss->seen_tc3, chain_tc_old, "seen_tc3");
|
||||
|
||||
skel->bss->seen_tc1 = false;
|
||||
skel->bss->seen_tc2 = false;
|
||||
skel->bss->seen_tc3 = false;
|
||||
|
||||
err = bpf_link__detach(skel->links.tc2);
|
||||
if (!ASSERT_OK(err, "prog_detach"))
|
||||
goto cleanup;
|
||||
|
||||
assert_mprog_count(target, 1);
|
||||
|
||||
tc_skel_reset_all_seen(skel);
|
||||
ASSERT_OK(system(ping_cmd), ping_cmd);
|
||||
|
||||
ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");
|
||||
|
@ -707,16 +706,13 @@ static void test_tc_links_replace_target(int target)
|
|||
ASSERT_EQ(optq.prog_ids[2], 0, "prog_ids[2]");
|
||||
ASSERT_EQ(optq.link_ids[2], 0, "link_ids[2]");
|
||||
|
||||
tc_skel_reset_all_seen(skel);
|
||||
ASSERT_OK(system(ping_cmd), ping_cmd);
|
||||
|
||||
ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");
|
||||
ASSERT_EQ(skel->bss->seen_tc2, true, "seen_tc2");
|
||||
ASSERT_EQ(skel->bss->seen_tc3, false, "seen_tc3");
|
||||
|
||||
skel->bss->seen_tc1 = false;
|
||||
skel->bss->seen_tc2 = false;
|
||||
skel->bss->seen_tc3 = false;
|
||||
|
||||
LIBBPF_OPTS_RESET(optl,
|
||||
.flags = BPF_F_REPLACE,
|
||||
.relative_fd = bpf_program__fd(skel->progs.tc2),
|
||||
|
@ -781,16 +777,13 @@ static void test_tc_links_replace_target(int target)
|
|||
ASSERT_EQ(optq.prog_ids[2], 0, "prog_ids[2]");
|
||||
ASSERT_EQ(optq.link_ids[2], 0, "link_ids[2]");
|
||||
|
||||
tc_skel_reset_all_seen(skel);
|
||||
ASSERT_OK(system(ping_cmd), ping_cmd);
|
||||
|
||||
ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");
|
||||
ASSERT_EQ(skel->bss->seen_tc2, false, "seen_tc2");
|
||||
ASSERT_EQ(skel->bss->seen_tc3, true, "seen_tc3");
|
||||
|
||||
skel->bss->seen_tc1 = false;
|
||||
skel->bss->seen_tc2 = false;
|
||||
skel->bss->seen_tc3 = false;
|
||||
|
||||
err = bpf_link__detach(skel->links.tc2);
|
||||
if (!ASSERT_OK(err, "link_detach"))
|
||||
goto cleanup;
|
||||
|
@ -812,16 +805,13 @@ static void test_tc_links_replace_target(int target)
|
|||
ASSERT_EQ(optq.prog_ids[1], 0, "prog_ids[1]");
|
||||
ASSERT_EQ(optq.link_ids[1], 0, "link_ids[1]");
|
||||
|
||||
tc_skel_reset_all_seen(skel);
|
||||
ASSERT_OK(system(ping_cmd), ping_cmd);
|
||||
|
||||
ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");
|
||||
ASSERT_EQ(skel->bss->seen_tc2, false, "seen_tc2");
|
||||
ASSERT_EQ(skel->bss->seen_tc3, false, "seen_tc3");
|
||||
|
||||
skel->bss->seen_tc1 = false;
|
||||
skel->bss->seen_tc2 = false;
|
||||
skel->bss->seen_tc3 = false;
|
||||
|
||||
err = bpf_link__update_program(skel->links.tc1, skel->progs.tc1);
|
||||
if (!ASSERT_OK(err, "link_update_self"))
|
||||
goto cleanup;
|
||||
|
@ -843,6 +833,7 @@ static void test_tc_links_replace_target(int target)
|
|||
ASSERT_EQ(optq.prog_ids[1], 0, "prog_ids[1]");
|
||||
ASSERT_EQ(optq.link_ids[1], 0, "link_ids[1]");
|
||||
|
||||
tc_skel_reset_all_seen(skel);
|
||||
ASSERT_OK(system(ping_cmd), ping_cmd);
|
||||
|
||||
ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");
|
||||
|
@ -1254,6 +1245,7 @@ static void test_tc_links_prepend_target(int target)
|
|||
ASSERT_EQ(optq.prog_ids[2], 0, "prog_ids[2]");
|
||||
ASSERT_EQ(optq.link_ids[2], 0, "link_ids[2]");
|
||||
|
||||
tc_skel_reset_all_seen(skel);
|
||||
ASSERT_OK(system(ping_cmd), ping_cmd);
|
||||
|
||||
ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");
|
||||
|
@ -1261,9 +1253,6 @@ static void test_tc_links_prepend_target(int target)
|
|||
ASSERT_EQ(skel->bss->seen_tc3, false, "seen_tc3");
|
||||
ASSERT_EQ(skel->bss->seen_tc4, false, "seen_tc4");
|
||||
|
||||
skel->bss->seen_tc1 = false;
|
||||
skel->bss->seen_tc2 = false;
|
||||
|
||||
LIBBPF_OPTS_RESET(optl,
|
||||
.flags = BPF_F_BEFORE,
|
||||
);
|
||||
|
@ -1311,6 +1300,7 @@ static void test_tc_links_prepend_target(int target)
|
|||
ASSERT_EQ(optq.prog_ids[4], 0, "prog_ids[4]");
|
||||
ASSERT_EQ(optq.link_ids[4], 0, "link_ids[4]");
|
||||
|
||||
tc_skel_reset_all_seen(skel);
|
||||
ASSERT_OK(system(ping_cmd), ping_cmd);
|
||||
|
||||
ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");
|
||||
|
@ -1411,6 +1401,7 @@ static void test_tc_links_append_target(int target)
|
|||
ASSERT_EQ(optq.prog_ids[2], 0, "prog_ids[2]");
|
||||
ASSERT_EQ(optq.link_ids[2], 0, "link_ids[2]");
|
||||
|
||||
tc_skel_reset_all_seen(skel);
|
||||
ASSERT_OK(system(ping_cmd), ping_cmd);
|
||||
|
||||
ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");
|
||||
|
@ -1418,9 +1409,6 @@ static void test_tc_links_append_target(int target)
|
|||
ASSERT_EQ(skel->bss->seen_tc3, false, "seen_tc3");
|
||||
ASSERT_EQ(skel->bss->seen_tc4, false, "seen_tc4");
|
||||
|
||||
skel->bss->seen_tc1 = false;
|
||||
skel->bss->seen_tc2 = false;
|
||||
|
||||
LIBBPF_OPTS_RESET(optl,
|
||||
.flags = BPF_F_AFTER,
|
||||
);
|
||||
|
@ -1468,6 +1456,7 @@ static void test_tc_links_append_target(int target)
|
|||
ASSERT_EQ(optq.prog_ids[4], 0, "prog_ids[4]");
|
||||
ASSERT_EQ(optq.link_ids[4], 0, "link_ids[4]");
|
||||
|
||||
tc_skel_reset_all_seen(skel);
|
||||
ASSERT_OK(system(ping_cmd), ping_cmd);
|
||||
|
||||
ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");
|
||||
|
@ -1637,38 +1626,33 @@ static void test_tc_chain_mixed(int target)
|
|||
|
||||
assert_mprog_count(target, 1);
|
||||
|
||||
tc_skel_reset_all_seen(skel);
|
||||
ASSERT_OK(system(ping_cmd), ping_cmd);
|
||||
|
||||
ASSERT_EQ(skel->bss->seen_tc4, false, "seen_tc4");
|
||||
ASSERT_EQ(skel->bss->seen_tc5, false, "seen_tc5");
|
||||
ASSERT_EQ(skel->bss->seen_tc6, true, "seen_tc6");
|
||||
|
||||
skel->bss->seen_tc4 = false;
|
||||
skel->bss->seen_tc5 = false;
|
||||
skel->bss->seen_tc6 = false;
|
||||
|
||||
err = bpf_link__update_program(skel->links.tc6, skel->progs.tc4);
|
||||
if (!ASSERT_OK(err, "link_update"))
|
||||
goto cleanup;
|
||||
|
||||
assert_mprog_count(target, 1);
|
||||
|
||||
tc_skel_reset_all_seen(skel);
|
||||
ASSERT_OK(system(ping_cmd), ping_cmd);
|
||||
|
||||
ASSERT_EQ(skel->bss->seen_tc4, true, "seen_tc4");
|
||||
ASSERT_EQ(skel->bss->seen_tc5, true, "seen_tc5");
|
||||
ASSERT_EQ(skel->bss->seen_tc6, false, "seen_tc6");
|
||||
|
||||
skel->bss->seen_tc4 = false;
|
||||
skel->bss->seen_tc5 = false;
|
||||
skel->bss->seen_tc6 = false;
|
||||
|
||||
err = bpf_link__detach(skel->links.tc6);
|
||||
if (!ASSERT_OK(err, "prog_detach"))
|
||||
goto cleanup;
|
||||
|
||||
__assert_mprog_count(target, 0, true, loopback);
|
||||
assert_mprog_count(target, 0);
|
||||
|
||||
tc_skel_reset_all_seen(skel);
|
||||
ASSERT_OK(system(ping_cmd), ping_cmd);
|
||||
|
||||
ASSERT_EQ(skel->bss->seen_tc4, false, "seen_tc4");
|
||||
|
@ -1758,22 +1742,20 @@ static void test_tc_links_ingress(int target, bool chain_tc_old,
|
|||
|
||||
assert_mprog_count(target, 2);
|
||||
|
||||
tc_skel_reset_all_seen(skel);
|
||||
ASSERT_OK(system(ping_cmd), ping_cmd);
|
||||
|
||||
ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");
|
||||
ASSERT_EQ(skel->bss->seen_tc2, true, "seen_tc2");
|
||||
ASSERT_EQ(skel->bss->seen_tc3, chain_tc_old, "seen_tc3");
|
||||
|
||||
skel->bss->seen_tc1 = false;
|
||||
skel->bss->seen_tc2 = false;
|
||||
skel->bss->seen_tc3 = false;
|
||||
|
||||
err = bpf_link__detach(skel->links.tc2);
|
||||
if (!ASSERT_OK(err, "prog_detach"))
|
||||
goto cleanup;
|
||||
|
||||
assert_mprog_count(target, 1);
|
||||
|
||||
tc_skel_reset_all_seen(skel);
|
||||
ASSERT_OK(system(ping_cmd), ping_cmd);
|
||||
|
||||
ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");
|
||||
|
|
|
@ -59,6 +59,7 @@ void serial_test_tc_opts_basic(void)
|
|||
ASSERT_EQ(optq.prog_ids[0], id1, "prog_ids[0]");
|
||||
ASSERT_EQ(optq.prog_ids[1], 0, "prog_ids[1]");
|
||||
|
||||
tc_skel_reset_all_seen(skel);
|
||||
ASSERT_OK(system(ping_cmd), ping_cmd);
|
||||
|
||||
ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");
|
||||
|
@ -83,6 +84,7 @@ void serial_test_tc_opts_basic(void)
|
|||
ASSERT_EQ(optq.prog_ids[0], id2, "prog_ids[0]");
|
||||
ASSERT_EQ(optq.prog_ids[1], 0, "prog_ids[1]");
|
||||
|
||||
tc_skel_reset_all_seen(skel);
|
||||
ASSERT_OK(system(ping_cmd), ping_cmd);
|
||||
|
||||
ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");
|
||||
|
@ -163,6 +165,7 @@ static void test_tc_opts_before_target(int target)
|
|||
ASSERT_EQ(optq.prog_ids[1], id2, "prog_ids[1]");
|
||||
ASSERT_EQ(optq.prog_ids[2], 0, "prog_ids[2]");
|
||||
|
||||
tc_skel_reset_all_seen(skel);
|
||||
ASSERT_OK(system(ping_cmd), ping_cmd);
|
||||
|
||||
ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");
|
||||
|
@ -219,6 +222,7 @@ static void test_tc_opts_before_target(int target)
|
|||
ASSERT_EQ(optq.prog_ids[3], id2, "prog_ids[3]");
|
||||
ASSERT_EQ(optq.prog_ids[4], 0, "prog_ids[4]");
|
||||
|
||||
tc_skel_reset_all_seen(skel);
|
||||
ASSERT_OK(system(ping_cmd), ping_cmd);
|
||||
|
||||
ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");
|
||||
|
@ -313,6 +317,7 @@ static void test_tc_opts_after_target(int target)
|
|||
ASSERT_EQ(optq.prog_ids[1], id2, "prog_ids[1]");
|
||||
ASSERT_EQ(optq.prog_ids[2], 0, "prog_ids[2]");
|
||||
|
||||
tc_skel_reset_all_seen(skel);
|
||||
ASSERT_OK(system(ping_cmd), ping_cmd);
|
||||
|
||||
ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");
|
||||
|
@ -369,6 +374,7 @@ static void test_tc_opts_after_target(int target)
|
|||
ASSERT_EQ(optq.prog_ids[3], id4, "prog_ids[3]");
|
||||
ASSERT_EQ(optq.prog_ids[4], 0, "prog_ids[4]");
|
||||
|
||||
tc_skel_reset_all_seen(skel);
|
||||
ASSERT_OK(system(ping_cmd), ping_cmd);
|
||||
|
||||
ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");
|
||||
|
@ -514,6 +520,7 @@ static void test_tc_opts_revision_target(int target)
|
|||
ASSERT_EQ(optq.prog_ids[1], id2, "prog_ids[1]");
|
||||
ASSERT_EQ(optq.prog_ids[2], 0, "prog_ids[2]");
|
||||
|
||||
tc_skel_reset_all_seen(skel);
|
||||
ASSERT_OK(system(ping_cmd), ping_cmd);
|
||||
|
||||
ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");
|
||||
|
@ -608,22 +615,20 @@ static void test_tc_chain_classic(int target, bool chain_tc_old)
|
|||
|
||||
assert_mprog_count(target, 2);
|
||||
|
||||
tc_skel_reset_all_seen(skel);
|
||||
ASSERT_OK(system(ping_cmd), ping_cmd);
|
||||
|
||||
ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");
|
||||
ASSERT_EQ(skel->bss->seen_tc2, true, "seen_tc2");
|
||||
ASSERT_EQ(skel->bss->seen_tc3, chain_tc_old, "seen_tc3");
|
||||
|
||||
skel->bss->seen_tc1 = false;
|
||||
skel->bss->seen_tc2 = false;
|
||||
skel->bss->seen_tc3 = false;
|
||||
|
||||
err = bpf_prog_detach_opts(fd2, loopback, target, &optd);
|
||||
if (!ASSERT_OK(err, "prog_detach"))
|
||||
goto cleanup_detach;
|
||||
|
||||
assert_mprog_count(target, 1);
|
||||
|
||||
tc_skel_reset_all_seen(skel);
|
||||
ASSERT_OK(system(ping_cmd), ping_cmd);
|
||||
|
||||
ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");
|
||||
|
@ -635,7 +640,7 @@ cleanup_detach:
|
|||
if (!ASSERT_OK(err, "prog_detach"))
|
||||
goto cleanup;
|
||||
|
||||
__assert_mprog_count(target, 0, chain_tc_old, loopback);
|
||||
assert_mprog_count(target, 0);
|
||||
cleanup:
|
||||
if (tc_attached) {
|
||||
tc_opts.flags = tc_opts.prog_fd = tc_opts.prog_id = 0;
|
||||
|
@ -730,16 +735,13 @@ static void test_tc_opts_replace_target(int target)
|
|||
ASSERT_EQ(optq.prog_attach_flags[1], 0, "prog_flags[1]");
|
||||
ASSERT_EQ(optq.prog_attach_flags[2], 0, "prog_flags[2]");
|
||||
|
||||
tc_skel_reset_all_seen(skel);
|
||||
ASSERT_OK(system(ping_cmd), ping_cmd);
|
||||
|
||||
ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");
|
||||
ASSERT_EQ(skel->bss->seen_tc2, true, "seen_tc2");
|
||||
ASSERT_EQ(skel->bss->seen_tc3, false, "seen_tc3");
|
||||
|
||||
skel->bss->seen_tc1 = false;
|
||||
skel->bss->seen_tc2 = false;
|
||||
skel->bss->seen_tc3 = false;
|
||||
|
||||
LIBBPF_OPTS_RESET(opta,
|
||||
.flags = BPF_F_REPLACE,
|
||||
.replace_prog_fd = fd2,
|
||||
|
@ -767,16 +769,13 @@ static void test_tc_opts_replace_target(int target)
|
|||
ASSERT_EQ(optq.prog_ids[1], id1, "prog_ids[1]");
|
||||
ASSERT_EQ(optq.prog_ids[2], 0, "prog_ids[2]");
|
||||
|
||||
tc_skel_reset_all_seen(skel);
|
||||
ASSERT_OK(system(ping_cmd), ping_cmd);
|
||||
|
||||
ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");
|
||||
ASSERT_EQ(skel->bss->seen_tc2, false, "seen_tc2");
|
||||
ASSERT_EQ(skel->bss->seen_tc3, true, "seen_tc3");
|
||||
|
||||
skel->bss->seen_tc1 = false;
|
||||
skel->bss->seen_tc2 = false;
|
||||
skel->bss->seen_tc3 = false;
|
||||
|
||||
LIBBPF_OPTS_RESET(opta,
|
||||
.flags = BPF_F_REPLACE | BPF_F_BEFORE,
|
||||
.replace_prog_fd = fd3,
|
||||
|
@ -805,6 +804,7 @@ static void test_tc_opts_replace_target(int target)
|
|||
ASSERT_EQ(optq.prog_ids[1], id1, "prog_ids[1]");
|
||||
ASSERT_EQ(optq.prog_ids[2], 0, "prog_ids[2]");
|
||||
|
||||
tc_skel_reset_all_seen(skel);
|
||||
ASSERT_OK(system(ping_cmd), ping_cmd);
|
||||
|
||||
ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");
|
||||
|
@ -1084,6 +1084,7 @@ static void test_tc_opts_prepend_target(int target)
|
|||
ASSERT_EQ(optq.prog_ids[1], id1, "prog_ids[1]");
|
||||
ASSERT_EQ(optq.prog_ids[2], 0, "prog_ids[2]");
|
||||
|
||||
tc_skel_reset_all_seen(skel);
|
||||
ASSERT_OK(system(ping_cmd), ping_cmd);
|
||||
|
||||
ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");
|
||||
|
@ -1124,6 +1125,7 @@ static void test_tc_opts_prepend_target(int target)
|
|||
ASSERT_EQ(optq.prog_ids[3], id1, "prog_ids[3]");
|
||||
ASSERT_EQ(optq.prog_ids[4], 0, "prog_ids[4]");
|
||||
|
||||
tc_skel_reset_all_seen(skel);
|
||||
ASSERT_OK(system(ping_cmd), ping_cmd);
|
||||
|
||||
ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");
|
||||
|
@ -1222,6 +1224,7 @@ static void test_tc_opts_append_target(int target)
|
|||
ASSERT_EQ(optq.prog_ids[1], id2, "prog_ids[1]");
|
||||
ASSERT_EQ(optq.prog_ids[2], 0, "prog_ids[2]");
|
||||
|
||||
tc_skel_reset_all_seen(skel);
|
||||
ASSERT_OK(system(ping_cmd), ping_cmd);
|
||||
|
||||
ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");
|
||||
|
@ -1262,6 +1265,7 @@ static void test_tc_opts_append_target(int target)
|
|||
ASSERT_EQ(optq.prog_ids[3], id4, "prog_ids[3]");
|
||||
ASSERT_EQ(optq.prog_ids[4], 0, "prog_ids[4]");
|
||||
|
||||
tc_skel_reset_all_seen(skel);
|
||||
ASSERT_OK(system(ping_cmd), ping_cmd);
|
||||
|
||||
ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");
|
||||
|
@ -2250,7 +2254,7 @@ static void test_tc_opts_delete_empty(int target, bool chain_tc_old)
|
|||
BPF_TC_INGRESS : BPF_TC_EGRESS;
|
||||
err = bpf_tc_hook_create(&tc_hook);
|
||||
ASSERT_OK(err, "bpf_tc_hook_create");
|
||||
__assert_mprog_count(target, 0, true, loopback);
|
||||
assert_mprog_count(target, 0);
|
||||
}
|
||||
err = bpf_prog_detach_opts(0, loopback, target, &optd);
|
||||
ASSERT_EQ(err, -ENOENT, "prog_detach");
|
||||
|
@ -2316,16 +2320,13 @@ static void test_tc_chain_mixed(int target)
|
|||
|
||||
assert_mprog_count(target, 1);
|
||||
|
||||
tc_skel_reset_all_seen(skel);
|
||||
ASSERT_OK(system(ping_cmd), ping_cmd);
|
||||
|
||||
ASSERT_EQ(skel->bss->seen_tc4, false, "seen_tc4");
|
||||
ASSERT_EQ(skel->bss->seen_tc5, false, "seen_tc5");
|
||||
ASSERT_EQ(skel->bss->seen_tc6, true, "seen_tc6");
|
||||
|
||||
skel->bss->seen_tc4 = false;
|
||||
skel->bss->seen_tc5 = false;
|
||||
skel->bss->seen_tc6 = false;
|
||||
|
||||
LIBBPF_OPTS_RESET(opta,
|
||||
.flags = BPF_F_REPLACE,
|
||||
.replace_prog_fd = fd3,
|
||||
|
@ -2339,21 +2340,19 @@ static void test_tc_chain_mixed(int target)
|
|||
|
||||
assert_mprog_count(target, 1);
|
||||
|
||||
tc_skel_reset_all_seen(skel);
|
||||
ASSERT_OK(system(ping_cmd), ping_cmd);
|
||||
|
||||
ASSERT_EQ(skel->bss->seen_tc4, true, "seen_tc4");
|
||||
ASSERT_EQ(skel->bss->seen_tc5, true, "seen_tc5");
|
||||
ASSERT_EQ(skel->bss->seen_tc6, false, "seen_tc6");
|
||||
|
||||
skel->bss->seen_tc4 = false;
|
||||
skel->bss->seen_tc5 = false;
|
||||
skel->bss->seen_tc6 = false;
|
||||
|
||||
cleanup_opts:
|
||||
err = bpf_prog_detach_opts(detach_fd, loopback, target, &optd);
|
||||
ASSERT_OK(err, "prog_detach");
|
||||
__assert_mprog_count(target, 0, true, loopback);
|
||||
assert_mprog_count(target, 0);
|
||||
|
||||
tc_skel_reset_all_seen(skel);
|
||||
ASSERT_OK(system(ping_cmd), ping_cmd);
|
||||
|
||||
ASSERT_EQ(skel->bss->seen_tc4, false, "seen_tc4");
|
||||
|
@ -2462,3 +2461,229 @@ void serial_test_tc_opts_max(void)
|
|||
test_tc_opts_max_target(BPF_TCX_INGRESS, BPF_F_AFTER, true);
|
||||
test_tc_opts_max_target(BPF_TCX_EGRESS, BPF_F_AFTER, false);
|
||||
}
|
||||
|
||||
static void test_tc_opts_query_target(int target)
|
||||
{
|
||||
const size_t attr_size = offsetofend(union bpf_attr, query);
|
||||
LIBBPF_OPTS(bpf_prog_attach_opts, opta);
|
||||
LIBBPF_OPTS(bpf_prog_detach_opts, optd);
|
||||
LIBBPF_OPTS(bpf_prog_query_opts, optq);
|
||||
__u32 fd1, fd2, fd3, fd4, id1, id2, id3, id4;
|
||||
struct test_tc_link *skel;
|
||||
union bpf_attr attr;
|
||||
__u32 prog_ids[5];
|
||||
int err;
|
||||
|
||||
skel = test_tc_link__open_and_load();
|
||||
if (!ASSERT_OK_PTR(skel, "skel_load"))
|
||||
goto cleanup;
|
||||
|
||||
fd1 = bpf_program__fd(skel->progs.tc1);
|
||||
fd2 = bpf_program__fd(skel->progs.tc2);
|
||||
fd3 = bpf_program__fd(skel->progs.tc3);
|
||||
fd4 = bpf_program__fd(skel->progs.tc4);
|
||||
|
||||
id1 = id_from_prog_fd(fd1);
|
||||
id2 = id_from_prog_fd(fd2);
|
||||
id3 = id_from_prog_fd(fd3);
|
||||
id4 = id_from_prog_fd(fd4);
|
||||
|
||||
assert_mprog_count(target, 0);
|
||||
|
||||
LIBBPF_OPTS_RESET(opta,
|
||||
.expected_revision = 1,
|
||||
);
|
||||
|
||||
err = bpf_prog_attach_opts(fd1, loopback, target, &opta);
|
||||
if (!ASSERT_EQ(err, 0, "prog_attach"))
|
||||
goto cleanup;
|
||||
|
||||
assert_mprog_count(target, 1);
|
||||
|
||||
LIBBPF_OPTS_RESET(opta,
|
||||
.expected_revision = 2,
|
||||
);
|
||||
|
||||
err = bpf_prog_attach_opts(fd2, loopback, target, &opta);
|
||||
if (!ASSERT_EQ(err, 0, "prog_attach"))
|
||||
goto cleanup1;
|
||||
|
||||
assert_mprog_count(target, 2);
|
||||
|
||||
LIBBPF_OPTS_RESET(opta,
|
||||
.expected_revision = 3,
|
||||
);
|
||||
|
||||
err = bpf_prog_attach_opts(fd3, loopback, target, &opta);
|
||||
if (!ASSERT_EQ(err, 0, "prog_attach"))
|
||||
goto cleanup2;
|
||||
|
||||
assert_mprog_count(target, 3);
|
||||
|
||||
LIBBPF_OPTS_RESET(opta,
|
||||
.expected_revision = 4,
|
||||
);
|
||||
|
||||
err = bpf_prog_attach_opts(fd4, loopback, target, &opta);
|
||||
if (!ASSERT_EQ(err, 0, "prog_attach"))
|
||||
goto cleanup3;
|
||||
|
||||
assert_mprog_count(target, 4);
|
||||
|
||||
/* Test 1: Double query via libbpf API */
|
||||
err = bpf_prog_query_opts(loopback, target, &optq);
|
||||
if (!ASSERT_OK(err, "prog_query"))
|
||||
goto cleanup4;
|
||||
|
||||
ASSERT_EQ(optq.count, 4, "count");
|
||||
ASSERT_EQ(optq.revision, 5, "revision");
|
||||
ASSERT_EQ(optq.prog_ids, NULL, "prog_ids");
|
||||
ASSERT_EQ(optq.link_ids, NULL, "link_ids");
|
||||
|
||||
memset(prog_ids, 0, sizeof(prog_ids));
|
||||
optq.prog_ids = prog_ids;
|
||||
|
||||
err = bpf_prog_query_opts(loopback, target, &optq);
|
||||
if (!ASSERT_OK(err, "prog_query"))
|
||||
goto cleanup4;
|
||||
|
||||
ASSERT_EQ(optq.count, 4, "count");
|
||||
ASSERT_EQ(optq.revision, 5, "revision");
|
||||
ASSERT_EQ(optq.prog_ids[0], id1, "prog_ids[0]");
|
||||
ASSERT_EQ(optq.prog_ids[1], id2, "prog_ids[1]");
|
||||
ASSERT_EQ(optq.prog_ids[2], id3, "prog_ids[2]");
|
||||
ASSERT_EQ(optq.prog_ids[3], id4, "prog_ids[3]");
|
||||
ASSERT_EQ(optq.prog_ids[4], 0, "prog_ids[4]");
|
||||
ASSERT_EQ(optq.link_ids, NULL, "link_ids");
|
||||
|
||||
/* Test 2: Double query via bpf_attr & bpf(2) directly */
|
||||
memset(&attr, 0, attr_size);
|
||||
attr.query.target_ifindex = loopback;
|
||||
attr.query.attach_type = target;
|
||||
|
||||
err = syscall(__NR_bpf, BPF_PROG_QUERY, &attr, attr_size);
|
||||
if (!ASSERT_OK(err, "prog_query"))
|
||||
goto cleanup4;
|
||||
|
||||
ASSERT_EQ(attr.query.count, 4, "count");
|
||||
ASSERT_EQ(attr.query.revision, 5, "revision");
|
||||
ASSERT_EQ(attr.query.query_flags, 0, "query_flags");
|
||||
ASSERT_EQ(attr.query.attach_flags, 0, "attach_flags");
|
||||
ASSERT_EQ(attr.query.target_ifindex, loopback, "target_ifindex");
|
||||
ASSERT_EQ(attr.query.attach_type, target, "attach_type");
|
||||
ASSERT_EQ(attr.query.prog_ids, 0, "prog_ids");
|
||||
ASSERT_EQ(attr.query.prog_attach_flags, 0, "prog_attach_flags");
|
||||
ASSERT_EQ(attr.query.link_ids, 0, "link_ids");
|
||||
ASSERT_EQ(attr.query.link_attach_flags, 0, "link_attach_flags");
|
||||
|
||||
memset(prog_ids, 0, sizeof(prog_ids));
|
||||
attr.query.prog_ids = ptr_to_u64(prog_ids);
|
||||
|
||||
err = syscall(__NR_bpf, BPF_PROG_QUERY, &attr, attr_size);
|
||||
if (!ASSERT_OK(err, "prog_query"))
|
||||
goto cleanup4;
|
||||
|
||||
ASSERT_EQ(attr.query.count, 4, "count");
|
||||
ASSERT_EQ(attr.query.revision, 5, "revision");
|
||||
ASSERT_EQ(attr.query.query_flags, 0, "query_flags");
|
||||
ASSERT_EQ(attr.query.attach_flags, 0, "attach_flags");
|
||||
ASSERT_EQ(attr.query.target_ifindex, loopback, "target_ifindex");
|
||||
ASSERT_EQ(attr.query.attach_type, target, "attach_type");
|
||||
ASSERT_EQ(attr.query.prog_ids, ptr_to_u64(prog_ids), "prog_ids");
|
||||
ASSERT_EQ(prog_ids[0], id1, "prog_ids[0]");
|
||||
ASSERT_EQ(prog_ids[1], id2, "prog_ids[1]");
|
||||
ASSERT_EQ(prog_ids[2], id3, "prog_ids[2]");
|
||||
ASSERT_EQ(prog_ids[3], id4, "prog_ids[3]");
|
||||
ASSERT_EQ(prog_ids[4], 0, "prog_ids[4]");
|
||||
ASSERT_EQ(attr.query.prog_attach_flags, 0, "prog_attach_flags");
|
||||
ASSERT_EQ(attr.query.link_ids, 0, "link_ids");
|
||||
ASSERT_EQ(attr.query.link_attach_flags, 0, "link_attach_flags");
|
||||
|
||||
cleanup4:
|
||||
err = bpf_prog_detach_opts(fd4, loopback, target, &optd);
|
||||
ASSERT_OK(err, "prog_detach");
|
||||
assert_mprog_count(target, 3);
|
||||
|
||||
cleanup3:
|
||||
err = bpf_prog_detach_opts(fd3, loopback, target, &optd);
|
||||
ASSERT_OK(err, "prog_detach");
|
||||
assert_mprog_count(target, 2);
|
||||
|
||||
cleanup2:
|
||||
err = bpf_prog_detach_opts(fd2, loopback, target, &optd);
|
||||
ASSERT_OK(err, "prog_detach");
|
||||
assert_mprog_count(target, 1);
|
||||
|
||||
cleanup1:
|
||||
err = bpf_prog_detach_opts(fd1, loopback, target, &optd);
|
||||
ASSERT_OK(err, "prog_detach");
|
||||
assert_mprog_count(target, 0);
|
||||
|
||||
cleanup:
|
||||
test_tc_link__destroy(skel);
|
||||
}
|
||||
|
||||
void serial_test_tc_opts_query(void)
|
||||
{
|
||||
test_tc_opts_query_target(BPF_TCX_INGRESS);
|
||||
test_tc_opts_query_target(BPF_TCX_EGRESS);
|
||||
}
|
||||
|
||||
static void test_tc_opts_query_attach_target(int target)
|
||||
{
|
||||
LIBBPF_OPTS(bpf_prog_attach_opts, opta);
|
||||
LIBBPF_OPTS(bpf_prog_detach_opts, optd);
|
||||
LIBBPF_OPTS(bpf_prog_query_opts, optq);
|
||||
struct test_tc_link *skel;
|
||||
__u32 prog_ids[2];
|
||||
__u32 fd1, id1;
|
||||
int err;
|
||||
|
||||
skel = test_tc_link__open_and_load();
|
||||
if (!ASSERT_OK_PTR(skel, "skel_load"))
|
||||
goto cleanup;
|
||||
|
||||
fd1 = bpf_program__fd(skel->progs.tc1);
|
||||
id1 = id_from_prog_fd(fd1);
|
||||
|
||||
err = bpf_prog_query_opts(loopback, target, &optq);
|
||||
if (!ASSERT_OK(err, "prog_query"))
|
||||
goto cleanup;
|
||||
|
||||
ASSERT_EQ(optq.count, 0, "count");
|
||||
ASSERT_EQ(optq.revision, 1, "revision");
|
||||
|
||||
LIBBPF_OPTS_RESET(opta,
|
||||
.expected_revision = optq.revision,
|
||||
);
|
||||
|
||||
err = bpf_prog_attach_opts(fd1, loopback, target, &opta);
|
||||
if (!ASSERT_EQ(err, 0, "prog_attach"))
|
||||
goto cleanup;
|
||||
|
||||
memset(prog_ids, 0, sizeof(prog_ids));
|
||||
optq.prog_ids = prog_ids;
|
||||
optq.count = ARRAY_SIZE(prog_ids);
|
||||
|
||||
err = bpf_prog_query_opts(loopback, target, &optq);
|
||||
if (!ASSERT_OK(err, "prog_query"))
|
||||
goto cleanup1;
|
||||
|
||||
ASSERT_EQ(optq.count, 1, "count");
|
||||
ASSERT_EQ(optq.revision, 2, "revision");
|
||||
ASSERT_EQ(optq.prog_ids[0], id1, "prog_ids[0]");
|
||||
ASSERT_EQ(optq.prog_ids[1], 0, "prog_ids[1]");
|
||||
|
||||
cleanup1:
|
||||
err = bpf_prog_detach_opts(fd1, loopback, target, &optd);
|
||||
ASSERT_OK(err, "prog_detach");
|
||||
assert_mprog_count(target, 0);
|
||||
cleanup:
|
||||
test_tc_link__destroy(skel);
|
||||
}
|
||||
|
||||
void serial_test_tc_opts_query_attach(void)
|
||||
{
|
||||
test_tc_opts_query_attach_target(BPF_TCX_INGRESS);
|
||||
test_tc_opts_query_attach_target(BPF_TCX_EGRESS);
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
/* Copyright (c) 2021 Facebook */
|
||||
#include <test_progs.h>
|
||||
#include "timer.skel.h"
|
||||
#include "timer_failure.skel.h"
|
||||
|
||||
static int timer(struct timer *timer_skel)
|
||||
{
|
||||
|
@ -49,10 +50,11 @@ void serial_test_timer(void)
|
|||
|
||||
timer_skel = timer__open_and_load();
|
||||
if (!ASSERT_OK_PTR(timer_skel, "timer_skel_load"))
|
||||
goto cleanup;
|
||||
return;
|
||||
|
||||
err = timer(timer_skel);
|
||||
ASSERT_OK(err, "timer");
|
||||
cleanup:
|
||||
timer__destroy(timer_skel);
|
||||
|
||||
RUN_TESTS(timer_failure);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,47 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/* Copyright (c) 2023 Meta Platforms, Inc. and affiliates. */
|
||||
|
||||
#include <linux/bpf.h>
|
||||
#include <time.h>
|
||||
#include <errno.h>
|
||||
#include <bpf/bpf_helpers.h>
|
||||
#include "bpf_misc.h"
|
||||
#include "bpf_tcp_helpers.h"
|
||||
|
||||
char _license[] SEC("license") = "GPL";
|
||||
|
||||
struct elem {
|
||||
struct bpf_timer t;
|
||||
};
|
||||
|
||||
struct {
|
||||
__uint(type, BPF_MAP_TYPE_ARRAY);
|
||||
__uint(max_entries, 1);
|
||||
__type(key, int);
|
||||
__type(value, struct elem);
|
||||
} timer_map SEC(".maps");
|
||||
|
||||
static int timer_cb_ret1(void *map, int *key, struct bpf_timer *timer)
|
||||
{
|
||||
if (bpf_get_smp_processor_id() % 2)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
SEC("fentry/bpf_fentry_test1")
|
||||
__failure __msg("should have been in (0x0; 0x0)")
|
||||
int BPF_PROG2(test_ret_1, int, a)
|
||||
{
|
||||
int key = 0;
|
||||
struct bpf_timer *timer;
|
||||
|
||||
timer = bpf_map_lookup_elem(&timer_map, &key);
|
||||
if (timer) {
|
||||
bpf_timer_init(timer, &timer_map, CLOCK_BOOTTIME);
|
||||
bpf_timer_set_callback(timer, timer_cb_ret1);
|
||||
bpf_timer_start(timer, 1000, 0);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
Loading…
Reference in New Issue