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

selftests/bpf: Add multi_st_ops that supports multiple instances

Current struct_ops in bpf_testmod only support attaching single instance.
Add multi_st_ops that supports multiple instances. The struct_ops uses map
id as the struct_ops id and will reject attachment with an existing id.

Signed-off-by: Amery Hung <ameryhung@gmail.com>
Signed-off-by: Martin KaFai Lau <martin.lau@kernel.org>
Link: https://patch.msgid.link/20250806162540.681679-3-ameryhung@gmail.com

authored by

Amery Hung and committed by
Martin KaFai Lau
eeb52b62 d87a513d

+120
+112
tools/testing/selftests/bpf/test_kmods/bpf_testmod.c
··· 1057 1057 return args->a; 1058 1058 } 1059 1059 1060 + __bpf_kfunc int bpf_kfunc_multi_st_ops_test_1(struct st_ops_args *args, u32 id); 1061 + 1060 1062 BTF_KFUNCS_START(bpf_testmod_check_kfunc_ids) 1061 1063 BTF_ID_FLAGS(func, bpf_testmod_test_mod_kfunc) 1062 1064 BTF_ID_FLAGS(func, bpf_kfunc_call_test1) ··· 1099 1097 BTF_ID_FLAGS(func, bpf_kfunc_st_ops_test_epilogue, KF_TRUSTED_ARGS | KF_SLEEPABLE) 1100 1098 BTF_ID_FLAGS(func, bpf_kfunc_st_ops_test_pro_epilogue, KF_TRUSTED_ARGS | KF_SLEEPABLE) 1101 1099 BTF_ID_FLAGS(func, bpf_kfunc_st_ops_inc10, KF_TRUSTED_ARGS) 1100 + BTF_ID_FLAGS(func, bpf_kfunc_multi_st_ops_test_1, KF_TRUSTED_ARGS) 1102 1101 BTF_KFUNCS_END(bpf_testmod_check_kfunc_ids) 1103 1102 1104 1103 static int bpf_testmod_ops_init(struct btf *btf) ··· 1531 1528 .owner = THIS_MODULE, 1532 1529 }; 1533 1530 1531 + struct hlist_head multi_st_ops_list; 1532 + static DEFINE_SPINLOCK(multi_st_ops_lock); 1533 + 1534 + static int multi_st_ops_init(struct btf *btf) 1535 + { 1536 + spin_lock_init(&multi_st_ops_lock); 1537 + INIT_HLIST_HEAD(&multi_st_ops_list); 1538 + 1539 + return 0; 1540 + } 1541 + 1542 + static int multi_st_ops_init_member(const struct btf_type *t, 1543 + const struct btf_member *member, 1544 + void *kdata, const void *udata) 1545 + { 1546 + return 0; 1547 + } 1548 + 1549 + static struct bpf_testmod_multi_st_ops *multi_st_ops_find_nolock(u32 id) 1550 + { 1551 + struct bpf_testmod_multi_st_ops *st_ops; 1552 + 1553 + hlist_for_each_entry(st_ops, &multi_st_ops_list, node) { 1554 + if (st_ops->id == id) 1555 + return st_ops; 1556 + } 1557 + 1558 + return NULL; 1559 + } 1560 + 1561 + int bpf_kfunc_multi_st_ops_test_1(struct st_ops_args *args, u32 id) 1562 + { 1563 + struct bpf_testmod_multi_st_ops *st_ops; 1564 + unsigned long flags; 1565 + int ret = -1; 1566 + 1567 + spin_lock_irqsave(&multi_st_ops_lock, flags); 1568 + st_ops = multi_st_ops_find_nolock(id); 1569 + if (st_ops) 1570 + ret = st_ops->test_1(args); 1571 + spin_unlock_irqrestore(&multi_st_ops_lock, flags); 1572 + 1573 + return ret; 1574 + } 1575 + 1576 + static int multi_st_ops_reg(void *kdata, struct bpf_link *link) 1577 + { 1578 + struct bpf_testmod_multi_st_ops *st_ops = 1579 + (struct bpf_testmod_multi_st_ops *)kdata; 1580 + unsigned long flags; 1581 + int err = 0; 1582 + u32 id; 1583 + 1584 + if (!st_ops->test_1) 1585 + return -EINVAL; 1586 + 1587 + id = bpf_struct_ops_id(kdata); 1588 + 1589 + spin_lock_irqsave(&multi_st_ops_lock, flags); 1590 + if (multi_st_ops_find_nolock(id)) { 1591 + pr_err("multi_st_ops(id:%d) has already been registered\n", id); 1592 + err = -EEXIST; 1593 + goto unlock; 1594 + } 1595 + 1596 + st_ops->id = id; 1597 + hlist_add_head(&st_ops->node, &multi_st_ops_list); 1598 + unlock: 1599 + spin_unlock_irqrestore(&multi_st_ops_lock, flags); 1600 + 1601 + return err; 1602 + } 1603 + 1604 + static void multi_st_ops_unreg(void *kdata, struct bpf_link *link) 1605 + { 1606 + struct bpf_testmod_multi_st_ops *st_ops; 1607 + unsigned long flags; 1608 + u32 id; 1609 + 1610 + id = bpf_struct_ops_id(kdata); 1611 + 1612 + spin_lock_irqsave(&multi_st_ops_lock, flags); 1613 + st_ops = multi_st_ops_find_nolock(id); 1614 + if (st_ops) 1615 + hlist_del(&st_ops->node); 1616 + spin_unlock_irqrestore(&multi_st_ops_lock, flags); 1617 + } 1618 + 1619 + static int bpf_testmod_multi_st_ops__test_1(struct st_ops_args *args) 1620 + { 1621 + return 0; 1622 + } 1623 + 1624 + static struct bpf_testmod_multi_st_ops multi_st_ops_cfi_stubs = { 1625 + .test_1 = bpf_testmod_multi_st_ops__test_1, 1626 + }; 1627 + 1628 + struct bpf_struct_ops testmod_multi_st_ops = { 1629 + .verifier_ops = &bpf_testmod_verifier_ops, 1630 + .init = multi_st_ops_init, 1631 + .init_member = multi_st_ops_init_member, 1632 + .reg = multi_st_ops_reg, 1633 + .unreg = multi_st_ops_unreg, 1634 + .cfi_stubs = &multi_st_ops_cfi_stubs, 1635 + .name = "bpf_testmod_multi_st_ops", 1636 + .owner = THIS_MODULE, 1637 + }; 1638 + 1534 1639 extern int bpf_fentry_test1(int a); 1535 1640 1536 1641 static int bpf_testmod_init(void) ··· 1661 1550 ret = ret ?: register_bpf_struct_ops(&bpf_testmod_ops2, bpf_testmod_ops2); 1662 1551 ret = ret ?: register_bpf_struct_ops(&bpf_testmod_ops3, bpf_testmod_ops3); 1663 1552 ret = ret ?: register_bpf_struct_ops(&testmod_st_ops, bpf_testmod_st_ops); 1553 + ret = ret ?: register_bpf_struct_ops(&testmod_multi_st_ops, bpf_testmod_multi_st_ops); 1664 1554 ret = ret ?: register_btf_id_dtor_kfuncs(bpf_testmod_dtors, 1665 1555 ARRAY_SIZE(bpf_testmod_dtors), 1666 1556 THIS_MODULE);
+6
tools/testing/selftests/bpf/test_kmods/bpf_testmod.h
··· 116 116 struct module *owner; 117 117 }; 118 118 119 + struct bpf_testmod_multi_st_ops { 120 + int (*test_1)(struct st_ops_args *args); 121 + struct hlist_node node; 122 + int id; 123 + }; 124 + 119 125 #endif /* _BPF_TESTMOD_H */
+2
tools/testing/selftests/bpf/test_kmods/bpf_testmod_kfunc.h
··· 159 159 void bpf_kfunc_trusted_num_test(int *ptr) __ksym; 160 160 void bpf_kfunc_rcu_task_test(struct task_struct *ptr) __ksym; 161 161 162 + int bpf_kfunc_multi_st_ops_test_1(struct st_ops_args *args, u32 id) __ksym; 163 + 162 164 #endif /* _BPF_TESTMOD_KFUNC_H */