This change adds some initial kunit tests for the MCTP core. We'll expand the coverage in a future series, and augment with a few selftests, but this establishes a baseline set of tests for now.
Thanks to the kunit folks for the framework!
Cheers,
Jeremy
---
Jeremy Kerr (5): mctp: Add initial test structure and fragmentation test mctp: Add test utils mctp: Add packet rx tests mctp: Add route input to socket tests mctp: Add input reassembly tests
net/mctp/Kconfig | 5 + net/mctp/Makefile | 3 + net/mctp/route.c | 5 + net/mctp/test/route-test.c | 532 +++++++++++++++++++++++++++++++++++++ net/mctp/test/utils.c | 67 +++++ net/mctp/test/utils.h | 20 ++ 6 files changed, 632 insertions(+) create mode 100644 net/mctp/test/route-test.c create mode 100644 net/mctp/test/utils.c create mode 100644 net/mctp/test/utils.h
This change adds the first kunit test for the mctp subsystem, and an initial test for the fragmentation path.
We're adding tests under a new net/mctp/test/ directory.
Signed-off-by: Jeremy Kerr jk@codeconstruct.com.au --- net/mctp/Kconfig | 5 + net/mctp/route.c | 5 + net/mctp/test/route-test.c | 206 +++++++++++++++++++++++++++++++++++++ 3 files changed, 216 insertions(+) create mode 100644 net/mctp/test/route-test.c
diff --git a/net/mctp/Kconfig b/net/mctp/Kconfig index 2cdf3d0a28c9..15267a5043d9 100644 --- a/net/mctp/Kconfig +++ b/net/mctp/Kconfig @@ -11,3 +11,8 @@ menuconfig MCTP This option enables core MCTP support. For communicating with other devices, you'll want to enable a driver for a specific hardware channel. + +config MCTP_TEST + tristate "MCTP core tests" if !KUNIT_ALL_TESTS + depends on MCTP && KUNIT + default KUNIT_ALL_TESTS diff --git a/net/mctp/route.c b/net/mctp/route.c index 9bea232cf250..b7e4e6281806 100644 --- a/net/mctp/route.c +++ b/net/mctp/route.c @@ -11,6 +11,7 @@ */
#include <linux/idr.h> +#include <linux/kconfig.h> #include <linux/mctp.h> #include <linux/netdevice.h> #include <linux/rtnetlink.h> @@ -1275,3 +1276,7 @@ void __exit mctp_routes_exit(void) rtnl_unregister(PF_MCTP, RTM_GETROUTE); dev_remove_pack(&mctp_packet_type); } + +#if IS_ENABLED(CONFIG_MCTP_TEST) +#include "test/route-test.c" +#endif diff --git a/net/mctp/test/route-test.c b/net/mctp/test/route-test.c new file mode 100644 index 000000000000..cf3b51183613 --- /dev/null +++ b/net/mctp/test/route-test.c @@ -0,0 +1,206 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include <kunit/test.h> + +struct mctp_test_route { + struct mctp_route rt; + struct sk_buff_head pkts; +}; + +static int mctp_test_route_output(struct mctp_route *rt, struct sk_buff *skb) +{ + struct mctp_test_route *test_rt = container_of(rt, struct mctp_test_route, rt); + + skb_queue_tail(&test_rt->pkts, skb); + + return 0; +} + +/* local version of mctp_route_alloc() */ +static struct mctp_test_route *mctp_route_test_alloc(void) +{ + struct mctp_test_route *rt; + + rt = kzalloc(sizeof(*rt), GFP_KERNEL); + if (!rt) + return NULL; + + INIT_LIST_HEAD(&rt->rt.list); + refcount_set(&rt->rt.refs, 1); + rt->rt.output = mctp_test_route_output; + + skb_queue_head_init(&rt->pkts); + + return rt; +} + +static struct mctp_test_route *mctp_test_create_route(struct net *net, + mctp_eid_t eid, + unsigned int mtu) +{ + struct mctp_test_route *rt; + + rt = mctp_route_test_alloc(); + if (!rt) + return NULL; + + rt->rt.min = eid; + rt->rt.max = eid; + rt->rt.mtu = mtu; + rt->rt.type = RTN_UNSPEC; + rt->rt.dev = NULL; /* somewhat illegal, but fine for current tests */ + + list_add_rcu(&rt->rt.list, &net->mctp.routes); + + return rt; +} + +static void mctp_test_route_destroy(struct mctp_test_route *rt) +{ + rtnl_lock(); + list_del_rcu(&rt->rt.list); + rtnl_unlock(); + + skb_queue_purge(&rt->pkts); + + kfree_rcu(&rt->rt, rcu); +} + +static struct sk_buff *mctp_test_create_skb(struct mctp_hdr *hdr, + unsigned int data_len) +{ + size_t hdr_len = sizeof(*hdr); + struct sk_buff *skb; + unsigned int i; + u8 *buf; + + skb = alloc_skb(hdr_len + data_len, GFP_KERNEL); + if (!skb) + return NULL; + + memcpy(skb_put(skb, hdr_len), hdr, hdr_len); + + buf = skb_put(skb, data_len); + for (i = 0; i < data_len; i++) + buf[i] = i & 0xff; + + return skb; +} + +struct mctp_frag_test { + unsigned int mtu; + unsigned int msgsize; + unsigned int n_frags; +}; + +static void mctp_test_fragment(struct kunit *test) +{ + const struct mctp_frag_test *params; + int rc, i, n, mtu, msgsize; + struct mctp_test_route *rt; + struct sk_buff *skb; + struct mctp_hdr hdr; + u8 seq; + + params = test->param_value; + mtu = params->mtu; + msgsize = params->msgsize; + + hdr.ver = 1; + hdr.src = 8; + hdr.dest = 10; + hdr.flags_seq_tag = MCTP_HDR_FLAG_TO; + + skb = mctp_test_create_skb(&hdr, msgsize); + KUNIT_ASSERT_TRUE(test, skb); + + rt = mctp_test_create_route(&init_net, 10, mtu); + KUNIT_ASSERT_TRUE(test, rt); + + rc = mctp_do_fragment_route(&rt->rt, skb, mtu, MCTP_TAG_OWNER); + KUNIT_EXPECT_FALSE(test, rc); + + n = rt->pkts.qlen; + + KUNIT_EXPECT_EQ(test, n, params->n_frags); + + for (i = 0;; i++) { + struct mctp_hdr *hdr2; + struct sk_buff *skb2; + u8 tag_mask, seq2; + bool first, last; + + first = i == 0; + last = i == (n - 1); + + skb2 = skb_dequeue(&rt->pkts); + + if (!skb2) + break; + + hdr2 = mctp_hdr(skb2); + + tag_mask = MCTP_HDR_TAG_MASK | MCTP_HDR_FLAG_TO; + + KUNIT_EXPECT_EQ(test, hdr2->ver, hdr.ver); + KUNIT_EXPECT_EQ(test, hdr2->src, hdr.src); + KUNIT_EXPECT_EQ(test, hdr2->dest, hdr.dest); + KUNIT_EXPECT_EQ(test, hdr2->flags_seq_tag & tag_mask, + hdr.flags_seq_tag & tag_mask); + + KUNIT_EXPECT_EQ(test, + !!(hdr2->flags_seq_tag & MCTP_HDR_FLAG_SOM), first); + KUNIT_EXPECT_EQ(test, + !!(hdr2->flags_seq_tag & MCTP_HDR_FLAG_EOM), last); + + seq2 = (hdr2->flags_seq_tag >> MCTP_HDR_SEQ_SHIFT) & + MCTP_HDR_SEQ_MASK; + + if (first) { + seq = seq2; + } else { + seq++; + KUNIT_EXPECT_EQ(test, seq2, seq & MCTP_HDR_SEQ_MASK); + } + + if (!last) + KUNIT_EXPECT_EQ(test, skb2->len, mtu); + else + KUNIT_EXPECT_LE(test, skb2->len, mtu); + + kfree_skb(skb2); + } + + mctp_test_route_destroy(rt); +} + +static const struct mctp_frag_test mctp_frag_tests[] = { + {.mtu = 68, .msgsize = 63, .n_frags = 1}, + {.mtu = 68, .msgsize = 64, .n_frags = 1}, + {.mtu = 68, .msgsize = 65, .n_frags = 2}, + {.mtu = 68, .msgsize = 66, .n_frags = 2}, + {.mtu = 68, .msgsize = 127, .n_frags = 2}, + {.mtu = 68, .msgsize = 128, .n_frags = 2}, + {.mtu = 68, .msgsize = 129, .n_frags = 3}, + {.mtu = 68, .msgsize = 130, .n_frags = 3}, +}; + +static void mctp_frag_test_to_desc(const struct mctp_frag_test *t, char *desc) +{ + sprintf(desc, "mtu %d len %d -> %d frags", + t->msgsize, t->mtu, t->n_frags); +} + +KUNIT_ARRAY_PARAM(mctp_frag, mctp_frag_tests, mctp_frag_test_to_desc); + +static struct kunit_case mctp_test_cases[] = { + KUNIT_CASE_PARAM(mctp_test_fragment, mctp_frag_gen_params), + {} +}; + +static struct kunit_suite mctp_test_suite = { + .name = "mctp", + .test_cases = mctp_test_cases, +}; + +kunit_test_suite(mctp_test_suite);
Hi Jeremy,
I love your patch! Yet something to improve:
[auto build test ERROR on net-next/master]
url: https://github.com/0day-ci/linux/commits/Jeremy-Kerr/MCTP-kunit-tests/202110... base: https://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next.git b05173028cc52384be42dcf81abdb4133caccfa5 config: alpha-randconfig-r026-20211001 (attached as .config) compiler: alpha-linux-gcc (GCC) 11.2.0 reproduce (this is a W=1 build): wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross chmod +x ~/bin/make.cross # https://github.com/0day-ci/linux/commit/4cc0785d056598892d81256078a62a8c5245... git remote add linux-review https://github.com/0day-ci/linux git fetch --no-tags linux-review Jeremy-Kerr/MCTP-kunit-tests/20211001-162019 git checkout 4cc0785d056598892d81256078a62a8c52458d6d # save the attached .config to linux build tree mkdir build_dir COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-11.2.0 make.cross O=build_dir ARCH=alpha SHELL=/bin/bash
If you fix the issue, kindly add following tag as appropriate Reported-by: kernel test robot lkp@intel.com
All errors (new ones prefixed by >>):
alpha-linux-ld: net/mctp/route.o: in function `kunit_test_suites_init':
(.init.text+0x198): multiple definition of `init_module'; net/mctp/af_mctp.o:(.init.text+0x0): first defined here
alpha-linux-ld: net/mctp/route.o: in function `kunit_test_suites_exit':
(.exit.text+0xa4): multiple definition of `cleanup_module'; net/mctp/af_mctp.o:(.exit.text+0x0): first defined here
--- 0-DAY CI Kernel Test Service, Intel Corporation https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org
Hi Jeremy,
I love your patch! Yet something to improve:
[auto build test ERROR on net-next/master]
url: https://github.com/0day-ci/linux/commits/Jeremy-Kerr/MCTP-kunit-tests/202110... base: https://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next.git b05173028cc52384be42dcf81abdb4133caccfa5 config: sh-allmodconfig (attached as .config) compiler: sh4-linux-gcc (GCC) 11.2.0 reproduce (this is a W=1 build): wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross chmod +x ~/bin/make.cross # https://github.com/0day-ci/linux/commit/4cc0785d056598892d81256078a62a8c5245... git remote add linux-review https://github.com/0day-ci/linux git fetch --no-tags linux-review Jeremy-Kerr/MCTP-kunit-tests/20211001-162019 git checkout 4cc0785d056598892d81256078a62a8c52458d6d # save the attached .config to linux build tree mkdir build_dir COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-11.2.0 make.cross O=build_dir ARCH=sh SHELL=/bin/bash
If you fix the issue, kindly add following tag as appropriate Reported-by: kernel test robot lkp@intel.com
All errors (new ones prefixed by >>):
sh4-linux-ld: net/mctp/route.o: in function `kunit_test_suites_exit':
route.c:(.exit.text+0x54): multiple definition of `cleanup_module'; net/mctp/af_mctp.o:af_mctp.c:(.exit.text+0x0): first defined here
sh4-linux-ld: net/mctp/route.o: in function `kunit_test_suites_init':
route.c:(.init.text+0xa0): multiple definition of `init_module'; net/mctp/af_mctp.o:af_mctp.c:(.init.text+0x0): first defined here
--- 0-DAY CI Kernel Test Service, Intel Corporation https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org
On Fri, Oct 1, 2021 at 4:19 PM Jeremy Kerr jk@codeconstruct.com.au wrote:
This change adds the first kunit test for the mctp subsystem, and an initial test for the fragmentation path.
We're adding tests under a new net/mctp/test/ directory.
Signed-off-by: Jeremy Kerr jk@codeconstruct.com.au
Thanks for writing these tests. There are (as you've probably noticed) a couple of issues with them at the moment, but it shouldn't take too much to fix.
A few comments below.
-- David
net/mctp/Kconfig | 5 + net/mctp/route.c | 5 + net/mctp/test/route-test.c | 206 +++++++++++++++++++++++++++++++++++++ 3 files changed, 216 insertions(+) create mode 100644 net/mctp/test/route-test.c
diff --git a/net/mctp/Kconfig b/net/mctp/Kconfig index 2cdf3d0a28c9..15267a5043d9 100644 --- a/net/mctp/Kconfig +++ b/net/mctp/Kconfig @@ -11,3 +11,8 @@ menuconfig MCTP This option enables core MCTP support. For communicating with other devices, you'll want to enable a driver for a specific hardware channel.
+config MCTP_TEST
tristate "MCTP core tests" if !KUNIT_ALL_TESTS
depends on MCTP && KUNIT
default KUNIT_ALL_TESTS
diff --git a/net/mctp/route.c b/net/mctp/route.c index 9bea232cf250..b7e4e6281806 100644 --- a/net/mctp/route.c +++ b/net/mctp/route.c @@ -11,6 +11,7 @@ */
#include <linux/idr.h> +#include <linux/kconfig.h> #include <linux/mctp.h> #include <linux/netdevice.h> #include <linux/rtnetlink.h> @@ -1275,3 +1276,7 @@ void __exit mctp_routes_exit(void) rtnl_unregister(PF_MCTP, RTM_GETROUTE); dev_remove_pack(&mctp_packet_type); }
+#if IS_ENABLED(CONFIG_MCTP_TEST) +#include "test/route-test.c" +#endif
FYI: This is not going to work if MCTP is built as a module.
Basically, KUnit's module support currently provides its own module_init()/module_exit(), so really needs the test to be part of its own separate module, rather than #included into the mctp module.
Hopefully we'll find a nicer way of handling this sort of thing in KUnit, but in the meantime, the options are to compile the tests separately (which would require exporting any functions being tested, at least if CONFIG_MCTP_TEST is enabled), or to just drop module support from the test (making MCTP_TEST bool, and having it depend on MCTP=y).
diff --git a/net/mctp/test/route-test.c b/net/mctp/test/route-test.c new file mode 100644 index 000000000000..cf3b51183613 --- /dev/null +++ b/net/mctp/test/route-test.c @@ -0,0 +1,206 @@ +// SPDX-License-Identifier: GPL-2.0
+#include <kunit/test.h>
+struct mctp_test_route {
struct mctp_route rt;
struct sk_buff_head pkts;
+};
+static int mctp_test_route_output(struct mctp_route *rt, struct sk_buff *skb) +{
struct mctp_test_route *test_rt = container_of(rt, struct mctp_test_route, rt);
skb_queue_tail(&test_rt->pkts, skb);
return 0;
+}
+/* local version of mctp_route_alloc() */ +static struct mctp_test_route *mctp_route_test_alloc(void) +{
struct mctp_test_route *rt;
rt = kzalloc(sizeof(*rt), GFP_KERNEL);
if (!rt)
return NULL;
INIT_LIST_HEAD(&rt->rt.list);
refcount_set(&rt->rt.refs, 1);
rt->rt.output = mctp_test_route_output;
skb_queue_head_init(&rt->pkts);
return rt;
+}
+static struct mctp_test_route *mctp_test_create_route(struct net *net,
mctp_eid_t eid,
unsigned int mtu)
+{
struct mctp_test_route *rt;
rt = mctp_route_test_alloc();
if (!rt)
return NULL;
rt->rt.min = eid;
rt->rt.max = eid;
rt->rt.mtu = mtu;
rt->rt.type = RTN_UNSPEC;
rt->rt.dev = NULL; /* somewhat illegal, but fine for current tests */
This actually causes a crash for me:
BUG: kernel NULL pointer dereference, address: 00000004 #PF: supervisor read access in kernel mode #PF: error_code(0x0000) - not-present page <snip> Call Trace: mctp_route_release+0x28/0x70 mctp_do_fragment_route+0x25a/0x2a0 mctp_test_fragment+0x150/0x770 ? kunit_fail_assert_format+0x70/0x70 ? __schedule+0x1a7/0x480 kunit_try_run_case+0x4c/0x80 kunit_generic_run_threadfn_adapter+0x11/0x20 kthread+0xe7/0x110 ? kunit_binary_str_assert_format+0x120/0x120 ? set_kthread_struct+0x40/0x40 ret_from_fork+0x1c/0x28 CR2: 0000000000000004 ---[ end trace fbe68c67c18e04a5 ]---
Only calling mctp_dev_put() if rt->dev is non-NULL in mctp_route_release() fixes it, e.g.:
diff --git a/net/mctp/route.c b/net/mctp/route.c index 04781459b2be..3692e7e8a555 100644 --- a/net/mctp/route.c +++ b/net/mctp/route.c @@ -469,7 +469,8 @@ static int mctp_route_output(struct mctp_route *route, struct sk_buff *skb) static void mctp_route_release(struct mctp_route *rt) { if (refcount_dec_and_test(&rt->refs)) { - mctp_dev_put(rt->dev); + if (rt->dev) + mctp_dev_put(rt->dev); kfree_rcu(rt, rcu);
} }
list_add_rcu(&rt->rt.list, &net->mctp.routes);
return rt;
+}
+static void mctp_test_route_destroy(struct mctp_test_route *rt) +{
rtnl_lock();
list_del_rcu(&rt->rt.list);
rtnl_unlock();
skb_queue_purge(&rt->pkts);
kfree_rcu(&rt->rt, rcu);
+}
+static struct sk_buff *mctp_test_create_skb(struct mctp_hdr *hdr,
unsigned int data_len)
+{
size_t hdr_len = sizeof(*hdr);
struct sk_buff *skb;
unsigned int i;
u8 *buf;
skb = alloc_skb(hdr_len + data_len, GFP_KERNEL);
if (!skb)
return NULL;
memcpy(skb_put(skb, hdr_len), hdr, hdr_len);
buf = skb_put(skb, data_len);
for (i = 0; i < data_len; i++)
buf[i] = i & 0xff;
return skb;
+}
+struct mctp_frag_test {
unsigned int mtu;
unsigned int msgsize;
unsigned int n_frags;
+};
+static void mctp_test_fragment(struct kunit *test) +{
const struct mctp_frag_test *params;
int rc, i, n, mtu, msgsize;
struct mctp_test_route *rt;
struct sk_buff *skb;
struct mctp_hdr hdr;
u8 seq;
params = test->param_value;
mtu = params->mtu;
msgsize = params->msgsize;
hdr.ver = 1;
hdr.src = 8;
hdr.dest = 10;
hdr.flags_seq_tag = MCTP_HDR_FLAG_TO;
skb = mctp_test_create_skb(&hdr, msgsize);
KUNIT_ASSERT_TRUE(test, skb);
rt = mctp_test_create_route(&init_net, 10, mtu);
KUNIT_ASSERT_TRUE(test, rt);
rc = mctp_do_fragment_route(&rt->rt, skb, mtu, MCTP_TAG_OWNER);
KUNIT_EXPECT_FALSE(test, rc);
n = rt->pkts.qlen;
KUNIT_EXPECT_EQ(test, n, params->n_frags);
for (i = 0;; i++) {
struct mctp_hdr *hdr2;
struct sk_buff *skb2;
u8 tag_mask, seq2;
bool first, last;
first = i == 0;
last = i == (n - 1);
skb2 = skb_dequeue(&rt->pkts);
if (!skb2)
break;
hdr2 = mctp_hdr(skb2);
tag_mask = MCTP_HDR_TAG_MASK | MCTP_HDR_FLAG_TO;
KUNIT_EXPECT_EQ(test, hdr2->ver, hdr.ver);
KUNIT_EXPECT_EQ(test, hdr2->src, hdr.src);
KUNIT_EXPECT_EQ(test, hdr2->dest, hdr.dest);
KUNIT_EXPECT_EQ(test, hdr2->flags_seq_tag & tag_mask,
hdr.flags_seq_tag & tag_mask);
KUNIT_EXPECT_EQ(test,
!!(hdr2->flags_seq_tag & MCTP_HDR_FLAG_SOM), first);
KUNIT_EXPECT_EQ(test,
!!(hdr2->flags_seq_tag & MCTP_HDR_FLAG_EOM), last);
seq2 = (hdr2->flags_seq_tag >> MCTP_HDR_SEQ_SHIFT) &
MCTP_HDR_SEQ_MASK;
if (first) {
seq = seq2;
} else {
seq++;
KUNIT_EXPECT_EQ(test, seq2, seq & MCTP_HDR_SEQ_MASK);
}
if (!last)
KUNIT_EXPECT_EQ(test, skb2->len, mtu);
else
KUNIT_EXPECT_LE(test, skb2->len, mtu);
kfree_skb(skb2);
}
mctp_test_route_destroy(rt);
+}
+static const struct mctp_frag_test mctp_frag_tests[] = {
{.mtu = 68, .msgsize = 63, .n_frags = 1},
{.mtu = 68, .msgsize = 64, .n_frags = 1},
{.mtu = 68, .msgsize = 65, .n_frags = 2},
{.mtu = 68, .msgsize = 66, .n_frags = 2},
{.mtu = 68, .msgsize = 127, .n_frags = 2},
{.mtu = 68, .msgsize = 128, .n_frags = 2},
{.mtu = 68, .msgsize = 129, .n_frags = 3},
{.mtu = 68, .msgsize = 130, .n_frags = 3},
+};
+static void mctp_frag_test_to_desc(const struct mctp_frag_test *t, char *desc) +{
sprintf(desc, "mtu %d len %d -> %d frags",
t->msgsize, t->mtu, t->n_frags);
+}
+KUNIT_ARRAY_PARAM(mctp_frag, mctp_frag_tests, mctp_frag_test_to_desc);
+static struct kunit_case mctp_test_cases[] = {
KUNIT_CASE_PARAM(mctp_test_fragment, mctp_frag_gen_params),
{}
+};
+static struct kunit_suite mctp_test_suite = {
.name = "mctp",
.test_cases = mctp_test_cases,
+};
+kunit_test_suite(mctp_test_suite);
2.33.0
Add a new object for shared test utilities
Signed-off-by: Jeremy Kerr jk@codeconstruct.com.au --- net/mctp/Makefile | 3 ++ net/mctp/test/utils.c | 67 +++++++++++++++++++++++++++++++++++++++++++ net/mctp/test/utils.h | 20 +++++++++++++ 3 files changed, 90 insertions(+) create mode 100644 net/mctp/test/utils.c create mode 100644 net/mctp/test/utils.h
diff --git a/net/mctp/Makefile b/net/mctp/Makefile index 0171333384d7..6cd55233e685 100644 --- a/net/mctp/Makefile +++ b/net/mctp/Makefile @@ -1,3 +1,6 @@ # SPDX-License-Identifier: GPL-2.0 obj-$(CONFIG_MCTP) += mctp.o mctp-objs := af_mctp.o device.o route.o neigh.o + +# tests +obj-$(CONFIG_MCTP_TEST) += test/utils.o diff --git a/net/mctp/test/utils.c b/net/mctp/test/utils.c new file mode 100644 index 000000000000..e2ab1f3da357 --- /dev/null +++ b/net/mctp/test/utils.c @@ -0,0 +1,67 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include <linux/netdevice.h> +#include <linux/mctp.h> +#include <linux/if_arp.h> + +#include <net/mctpdevice.h> +#include <net/pkt_sched.h> + +#include "utils.h" + +static netdev_tx_t mctp_test_dev_tx(struct sk_buff *skb, + struct net_device *ndev) +{ + kfree(skb); + return NETDEV_TX_OK; +} + +static const struct net_device_ops mctp_test_netdev_ops = { + .ndo_start_xmit = mctp_test_dev_tx, +}; + +static void mctp_test_dev_setup(struct net_device *ndev) +{ + ndev->type = ARPHRD_MCTP; + ndev->mtu = MCTP_DEV_TEST_MTU; + ndev->hard_header_len = 0; + ndev->addr_len = 0; + ndev->tx_queue_len = DEFAULT_TX_QUEUE_LEN; + ndev->flags = IFF_NOARP; + ndev->netdev_ops = &mctp_test_netdev_ops; + ndev->needs_free_netdev = true; +} + +struct mctp_test_dev *mctp_test_create_dev(void) +{ + struct mctp_test_dev *dev; + struct net_device *ndev; + int rc; + + ndev = alloc_netdev(sizeof(*dev), "mctptest%d", NET_NAME_ENUM, + mctp_test_dev_setup); + if (!ndev) + return NULL; + + dev = netdev_priv(ndev); + dev->ndev = ndev; + + rcu_read_lock(); + dev->mdev = __mctp_dev_get(ndev); + mctp_dev_hold(dev->mdev); + rcu_read_unlock(); + + rc = register_netdev(ndev); + if (rc) { + free_netdev(ndev); + return NULL; + } + + return dev; +} + +void mctp_test_destroy_dev(struct mctp_test_dev *dev) +{ + mctp_dev_put(dev->mdev); + unregister_netdev(dev->ndev); +} diff --git a/net/mctp/test/utils.h b/net/mctp/test/utils.h new file mode 100644 index 000000000000..df6aa1c03440 --- /dev/null +++ b/net/mctp/test/utils.h @@ -0,0 +1,20 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +#ifndef __NET_MCTP_TEST_UTILS_H +#define __NET_MCTP_TEST_UTILS_H + +#include <kunit/test.h> + +#define MCTP_DEV_TEST_MTU 68 + +struct mctp_test_dev { + struct net_device *ndev; + struct mctp_dev *mdev; +}; + +struct mctp_test_dev; + +struct mctp_test_dev *mctp_test_create_dev(void); +void mctp_test_destroy_dev(struct mctp_test_dev *dev); + +#endif /* __NET_MCTP_TEST_UTILS_H */
Add a few tests for the initial packet ingress through mctp_pkttype_receive function; mainly packet header sanity checks. Full input routing checks will be added as a separate change.
Signed-off-by: Jeremy Kerr jk@codeconstruct.com.au --- net/mctp/test/route-test.c | 67 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 64 insertions(+), 3 deletions(-)
diff --git a/net/mctp/test/route-test.c b/net/mctp/test/route-test.c index cf3b51183613..ee0422bf24ce 100644 --- a/net/mctp/test/route-test.c +++ b/net/mctp/test/route-test.c @@ -2,6 +2,8 @@
#include <kunit/test.h>
+#include "utils.h" + struct mctp_test_route { struct mctp_route rt; struct sk_buff_head pkts; @@ -35,6 +37,7 @@ static struct mctp_test_route *mctp_route_test_alloc(void) }
static struct mctp_test_route *mctp_test_create_route(struct net *net, + struct mctp_dev *dev, mctp_eid_t eid, unsigned int mtu) { @@ -48,7 +51,9 @@ static struct mctp_test_route *mctp_test_create_route(struct net *net, rt->rt.max = eid; rt->rt.mtu = mtu; rt->rt.type = RTN_UNSPEC; - rt->rt.dev = NULL; /* somewhat illegal, but fine for current tests */ + if (dev) + mctp_dev_hold(dev); + rt->rt.dev = dev;
list_add_rcu(&rt->rt.list, &net->mctp.routes);
@@ -62,11 +67,13 @@ static void mctp_test_route_destroy(struct mctp_test_route *rt) rtnl_unlock();
skb_queue_purge(&rt->pkts); + if (rt->rt.dev) + mctp_dev_put(rt->rt.dev);
kfree_rcu(&rt->rt, rcu); }
-static struct sk_buff *mctp_test_create_skb(struct mctp_hdr *hdr, +static struct sk_buff *mctp_test_create_skb(const struct mctp_hdr *hdr, unsigned int data_len) { size_t hdr_len = sizeof(*hdr); @@ -114,7 +121,7 @@ static void mctp_test_fragment(struct kunit *test) skb = mctp_test_create_skb(&hdr, msgsize); KUNIT_ASSERT_TRUE(test, skb);
- rt = mctp_test_create_route(&init_net, 10, mtu); + rt = mctp_test_create_route(&init_net, NULL, 10, mtu); KUNIT_ASSERT_TRUE(test, rt);
rc = mctp_do_fragment_route(&rt->rt, skb, mtu, MCTP_TAG_OWNER); @@ -193,8 +200,62 @@ static void mctp_frag_test_to_desc(const struct mctp_frag_test *t, char *desc)
KUNIT_ARRAY_PARAM(mctp_frag, mctp_frag_tests, mctp_frag_test_to_desc);
+struct mctp_rx_input_test { + struct mctp_hdr hdr; + bool input; +}; + +static void mctp_test_rx_input(struct kunit *test) +{ + const struct mctp_rx_input_test *params; + struct mctp_test_route *rt; + struct mctp_test_dev *dev; + struct sk_buff *skb; + + params = test->param_value; + + dev = mctp_test_create_dev(); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dev); + + rt = mctp_test_create_route(&init_net, dev->mdev, 8, 68); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, rt); + + skb = mctp_test_create_skb(¶ms->hdr, 1); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, skb); + + __mctp_cb(skb); + + mctp_pkttype_receive(skb, dev->ndev, &mctp_packet_type, NULL); + + KUNIT_EXPECT_EQ(test, !!rt->pkts.qlen, params->input); + + mctp_test_route_destroy(rt); + mctp_test_destroy_dev(dev); +} + +#define RX_HDR(_ver, _src, _dest, _fst) \ + { .ver = _ver, .src = _src, .dest = _dest, .flags_seq_tag = _fst } + +/* we have a route for EID 8 only */ +static const struct mctp_rx_input_test mctp_rx_input_tests[] = { + { .hdr = RX_HDR(1, 10, 8, 0), .input = true }, + { .hdr = RX_HDR(1, 10, 9, 0), .input = false }, /* no input route */ + { .hdr = RX_HDR(2, 10, 8, 0), .input = false }, /* invalid version */ +}; + +static void mctp_rx_input_test_to_desc(const struct mctp_rx_input_test *t, + char *desc) +{ + sprintf(desc, "{%x,%x,%x,%x}", t->hdr.ver, t->hdr.src, t->hdr.dest, + t->hdr.flags_seq_tag); +} + +KUNIT_ARRAY_PARAM(mctp_rx_input, mctp_rx_input_tests, + mctp_rx_input_test_to_desc); + static struct kunit_case mctp_test_cases[] = { KUNIT_CASE_PARAM(mctp_test_fragment, mctp_frag_gen_params), + KUNIT_CASE_PARAM(mctp_test_rx_input, mctp_rx_input_gen_params), {} };
Hi Jeremy,
I love your patch! Yet something to improve:
[auto build test ERROR on net-next/master]
url: https://github.com/0day-ci/linux/commits/Jeremy-Kerr/MCTP-kunit-tests/202110... base: https://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next.git b05173028cc52384be42dcf81abdb4133caccfa5 config: arm-randconfig-r006-20211001 (attached as .config) compiler: clang version 14.0.0 (https://github.com/llvm/llvm-project 962e503cc8bc411f7523cc393acae8aae425b1c4) reproduce (this is a W=1 build): wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross chmod +x ~/bin/make.cross # install arm cross compiling tool for clang build # apt-get install binutils-arm-linux-gnueabi # https://github.com/0day-ci/linux/commit/85da939dab5470b1f2a921867d780af5a1fd... git remote add linux-review https://github.com/0day-ci/linux git fetch --no-tags linux-review Jeremy-Kerr/MCTP-kunit-tests/20211001-162019 git checkout 85da939dab5470b1f2a921867d780af5a1fd8aab # save the attached .config to linux build tree mkdir build_dir COMPILER_INSTALL_PATH=$HOME/0day COMPILER=clang make.cross W=1 O=build_dir ARCH=arm SHELL=/bin/bash
If you fix the issue, kindly add following tag as appropriate Reported-by: kernel test robot lkp@intel.com
All errors (new ones prefixed by >>):
ld.lld: error: undefined symbol: mctp_test_create_dev
referenced by route.c mctp/route.o:(mctp_test_rx_input) in archive net/built-in.a
--
ld.lld: error: undefined symbol: mctp_test_destroy_dev
referenced by route.c mctp/route.o:(mctp_test_rx_input) in archive net/built-in.a
--- 0-DAY CI Kernel Test Service, Intel Corporation https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org
Add a few tests for single-packet route inputs, testing the mctp_route_input function.
Signed-off-by: Jeremy Kerr jk@codeconstruct.com.au --- net/mctp/test/route-test.c | 131 +++++++++++++++++++++++++++++++++++++ 1 file changed, 131 insertions(+)
diff --git a/net/mctp/test/route-test.c b/net/mctp/test/route-test.c index ee0422bf24ce..efb621317ec5 100644 --- a/net/mctp/test/route-test.c +++ b/net/mctp/test/route-test.c @@ -94,6 +94,26 @@ static struct sk_buff *mctp_test_create_skb(const struct mctp_hdr *hdr, return skb; }
+static struct sk_buff *__mctp_test_create_skb_data(const struct mctp_hdr *hdr, + const void *data, + size_t data_len) +{ + size_t hdr_len = sizeof(*hdr); + struct sk_buff *skb; + + skb = alloc_skb(hdr_len + data_len, GFP_KERNEL); + if (!skb) + return NULL; + + memcpy(skb_put(skb, hdr_len), hdr, hdr_len); + memcpy(skb_put(skb, data_len), data, data_len); + + return skb; +} + +#define mctp_test_create_skb_data(h, d) \ + __mctp_test_create_skb_data(h, d, sizeof(*d)) + struct mctp_frag_test { unsigned int mtu; unsigned int msgsize; @@ -253,9 +273,120 @@ static void mctp_rx_input_test_to_desc(const struct mctp_rx_input_test *t, KUNIT_ARRAY_PARAM(mctp_rx_input, mctp_rx_input_tests, mctp_rx_input_test_to_desc);
+/* set up a local dev, route on EID 8, and a socket listening on type 0 */ +static void __mctp_route_test_init(struct kunit *test, + struct mctp_test_dev **devp, + struct mctp_test_route **rtp, + struct socket **sockp) +{ + struct sockaddr_mctp addr; + struct mctp_test_route *rt; + struct mctp_test_dev *dev; + struct socket *sock; + int rc; + + dev = mctp_test_create_dev(); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dev); + + rt = mctp_test_create_route(&init_net, dev->mdev, 8, 68); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, rt); + + rc = sock_create_kern(&init_net, AF_MCTP, SOCK_DGRAM, 0, &sock); + KUNIT_ASSERT_EQ(test, rc, 0); + + addr.smctp_family = AF_MCTP; + addr.smctp_network = MCTP_NET_ANY; + addr.smctp_addr.s_addr = 8; + addr.smctp_type = 0; + rc = kernel_bind(sock, (struct sockaddr *)&addr, sizeof(addr)); + KUNIT_ASSERT_EQ(test, rc, 0); + + *rtp = rt; + *devp = dev; + *sockp = sock; +} + +static void __mctp_route_test_fini(struct mctp_test_dev *dev, + struct mctp_test_route *rt, + struct socket *sock) +{ + sock_release(sock); + mctp_test_route_destroy(rt); + mctp_test_destroy_dev(dev); +} + +struct mctp_route_input_sk_test { + struct mctp_hdr hdr; + u8 type; + bool deliver; +}; + +static void mctp_test_route_input_sk(struct kunit *test) +{ + const struct mctp_route_input_sk_test *params; + struct sk_buff *skb, *skb2; + struct mctp_test_route *rt; + struct mctp_test_dev *dev; + struct socket *sock; + int rc; + + params = test->param_value; + + __mctp_route_test_init(test, &dev, &rt, &sock); + + skb = mctp_test_create_skb_data(¶ms->hdr, ¶ms->type); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, skb); + + skb->dev = dev->ndev; + __mctp_cb(skb); + + rc = mctp_route_input(&rt->rt, skb); + + if (params->deliver) { + KUNIT_EXPECT_EQ(test, rc, 0); + + skb2 = skb_recv_datagram(sock->sk, 0, 1, &rc); + KUNIT_EXPECT_NOT_ERR_OR_NULL(test, skb2); + KUNIT_EXPECT_EQ(test, skb->len, 1); + + skb_free_datagram(sock->sk, skb2); + + } else { + KUNIT_EXPECT_NE(test, rc, 0); + skb2 = skb_recv_datagram(sock->sk, 0, 1, &rc); + KUNIT_EXPECT_PTR_EQ(test, skb2, NULL); + } + + __mctp_route_test_fini(dev, rt, sock); +} + +#define FL_S (MCTP_HDR_FLAG_SOM) +#define FL_E (MCTP_HDR_FLAG_EOM) +#define FL_T (MCTP_HDR_FLAG_TO) + +static const struct mctp_route_input_sk_test mctp_route_input_sk_tests[] = { + { .hdr = RX_HDR(1, 10, 8, FL_S | FL_E | FL_T), .type = 0, .deliver = true }, + { .hdr = RX_HDR(1, 10, 8, FL_S | FL_E | FL_T), .type = 1, .deliver = false }, + { .hdr = RX_HDR(1, 10, 8, FL_S | FL_E), .type = 0, .deliver = false }, + { .hdr = RX_HDR(1, 10, 8, FL_E | FL_T), .type = 0, .deliver = false }, + { .hdr = RX_HDR(1, 10, 8, FL_T), .type = 0, .deliver = false }, + { .hdr = RX_HDR(1, 10, 8, 0), .type = 0, .deliver = false }, +}; + +static void mctp_route_input_sk_to_desc(const struct mctp_route_input_sk_test *t, + char *desc) +{ + sprintf(desc, "{%x,%x,%x,%x} type %d", t->hdr.ver, t->hdr.src, + t->hdr.dest, t->hdr.flags_seq_tag, t->type); +} + +KUNIT_ARRAY_PARAM(mctp_route_input_sk, mctp_route_input_sk_tests, + mctp_route_input_sk_to_desc); + static struct kunit_case mctp_test_cases[] = { KUNIT_CASE_PARAM(mctp_test_fragment, mctp_frag_gen_params), KUNIT_CASE_PARAM(mctp_test_rx_input, mctp_rx_input_gen_params), + KUNIT_CASE_PARAM(mctp_test_route_input_sk, mctp_route_input_sk_gen_params), {} };
Add multi-packet route input tests, for message reassembly. These will feed packets to be received by a bound socket, or dropped.
Signed-off-by: Jeremy Kerr jk@codeconstruct.com.au --- net/mctp/test/route-test.c | 134 +++++++++++++++++++++++++++++++++++++ 1 file changed, 134 insertions(+)
diff --git a/net/mctp/test/route-test.c b/net/mctp/test/route-test.c index efb621317ec5..2785a8ea554c 100644 --- a/net/mctp/test/route-test.c +++ b/net/mctp/test/route-test.c @@ -383,10 +383,144 @@ static void mctp_route_input_sk_to_desc(const struct mctp_route_input_sk_test *t KUNIT_ARRAY_PARAM(mctp_route_input_sk, mctp_route_input_sk_tests, mctp_route_input_sk_to_desc);
+struct mctp_route_input_sk_reasm_test { + const char *name; + struct mctp_hdr hdrs[4]; + int n_hdrs; + int rx_len; +}; + +static void mctp_test_route_input_sk_reasm(struct kunit *test) +{ + const struct mctp_route_input_sk_reasm_test *params; + struct sk_buff *skb, *skb2; + struct mctp_test_route *rt; + struct mctp_test_dev *dev; + struct socket *sock; + int i, rc; + u8 c; + + params = test->param_value; + + __mctp_route_test_init(test, &dev, &rt, &sock); + + for (i = 0; i < params->n_hdrs; i++) { + c = i; + skb = mctp_test_create_skb_data(¶ms->hdrs[i], &c); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, skb); + + skb->dev = dev->ndev; + __mctp_cb(skb); + + rc = mctp_route_input(&rt->rt, skb); + } + + skb2 = skb_recv_datagram(sock->sk, 0, 1, &rc); + + if (params->rx_len) { + KUNIT_EXPECT_NOT_ERR_OR_NULL(test, skb2); + KUNIT_EXPECT_EQ(test, skb2->len, params->rx_len); + skb_free_datagram(sock->sk, skb2); + + } else { + KUNIT_EXPECT_PTR_EQ(test, skb2, NULL); + } + + __mctp_route_test_fini(dev, rt, sock); +} + +#define RX_FRAG(f, s) RX_HDR(1, 10, 8, FL_T | (f) | ((s) << MCTP_HDR_SEQ_SHIFT)) + +static const struct mctp_route_input_sk_reasm_test mctp_route_input_sk_reasm_tests[] = { + { + .name = "single packet", + .hdrs = { + RX_FRAG(FL_S | FL_E, 0), + }, + .n_hdrs = 1, + .rx_len = 1, + }, + { + .name = "single packet, offset seq", + .hdrs = { + RX_FRAG(FL_S | FL_E, 1), + }, + .n_hdrs = 1, + .rx_len = 1, + }, + { + .name = "start & end packets", + .hdrs = { + RX_FRAG(FL_S, 0), + RX_FRAG(FL_E, 1), + }, + .n_hdrs = 2, + .rx_len = 2, + }, + { + .name = "start & end packets, offset seq", + .hdrs = { + RX_FRAG(FL_S, 1), + RX_FRAG(FL_E, 2), + }, + .n_hdrs = 2, + .rx_len = 2, + }, + { + .name = "start & end packets, out of order", + .hdrs = { + RX_FRAG(FL_E, 1), + RX_FRAG(FL_S, 0), + }, + .n_hdrs = 2, + .rx_len = 0, + }, + { + .name = "start, middle & end packets", + .hdrs = { + RX_FRAG(FL_S, 0), + RX_FRAG(0, 1), + RX_FRAG(FL_E, 2), + }, + .n_hdrs = 3, + .rx_len = 3, + }, + { + .name = "missing seq", + .hdrs = { + RX_FRAG(FL_S, 0), + RX_FRAG(FL_E, 2), + }, + .n_hdrs = 2, + .rx_len = 0, + }, + { + .name = "seq wrap", + .hdrs = { + RX_FRAG(FL_S, 3), + RX_FRAG(FL_E, 0), + }, + .n_hdrs = 2, + .rx_len = 2, + }, +}; + +static void mctp_route_input_sk_reasm_to_desc( + const struct mctp_route_input_sk_reasm_test *t, + char *desc) +{ + sprintf(desc, "%s", t->name); +} + +KUNIT_ARRAY_PARAM(mctp_route_input_sk_reasm, mctp_route_input_sk_reasm_tests, + mctp_route_input_sk_reasm_to_desc); + static struct kunit_case mctp_test_cases[] = { KUNIT_CASE_PARAM(mctp_test_fragment, mctp_frag_gen_params), KUNIT_CASE_PARAM(mctp_test_rx_input, mctp_rx_input_gen_params), KUNIT_CASE_PARAM(mctp_test_route_input_sk, mctp_route_input_sk_gen_params), + KUNIT_CASE_PARAM(mctp_test_route_input_sk_reasm, + mctp_route_input_sk_reasm_gen_params), {} };
Hello:
This series was applied to netdev/net-next.git (refs/heads/master):
On Fri, 1 Oct 2021 16:18:39 +0800 you wrote:
This change adds some initial kunit tests for the MCTP core. We'll expand the coverage in a future series, and augment with a few selftests, but this establishes a baseline set of tests for now.
Thanks to the kunit folks for the framework!
Cheers,
[...]
Here is the summary with links: - [net-next,1/5] mctp: Add initial test structure and fragmentation test https://git.kernel.org/netdev/net-next/c/8c02066b053d - [net-next,2/5] mctp: Add test utils https://git.kernel.org/netdev/net-next/c/077b6d52df6d - [net-next,3/5] mctp: Add packet rx tests https://git.kernel.org/netdev/net-next/c/925c01afb06a - [net-next,4/5] mctp: Add route input to socket tests https://git.kernel.org/netdev/net-next/c/d04dcc2d67ef - [net-next,5/5] mctp: Add input reassembly tests https://git.kernel.org/netdev/net-next/c/bbde430319ee
You are awesome, thank you! -- Deet-doot-dot, I am a bot. https://korg.docs.kernel.org/patchwork/pwbot.html
linux-kselftest-mirror@lists.linaro.org