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

mctp: Add initial test structure and fragmentation test

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.

Incorporates a fix for module configs:

Reported-by: kernel test robot <lkp@intel.com>

Signed-off-by: Jeremy Kerr <jk@codeconstruct.com.au>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Jeremy Kerr and committed by
David S. Miller
161eba50 b8aa1654

+227
+5
net/mctp/Kconfig
··· 11 11 This option enables core MCTP support. For communicating with other 12 12 devices, you'll want to enable a driver for a specific hardware 13 13 channel. 14 + 15 + config MCTP_TEST 16 + bool "MCTP core tests" if !KUNIT_ALL_TESTS 17 + depends on MCTP=y && KUNIT=y 18 + default KUNIT_ALL_TESTS
+5
net/mctp/route.c
··· 11 11 */ 12 12 13 13 #include <linux/idr.h> 14 + #include <linux/kconfig.h> 14 15 #include <linux/mctp.h> 15 16 #include <linux/netdevice.h> 16 17 #include <linux/rtnetlink.h> ··· 1229 1228 rtnl_unregister(PF_MCTP, RTM_GETROUTE); 1230 1229 dev_remove_pack(&mctp_packet_type); 1231 1230 } 1231 + 1232 + #if IS_ENABLED(CONFIG_MCTP_TEST) 1233 + #include "test/route-test.c" 1234 + #endif
+217
net/mctp/test/route-test.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + 3 + #include <kunit/test.h> 4 + 5 + struct mctp_test_route { 6 + struct mctp_route rt; 7 + struct sk_buff_head pkts; 8 + }; 9 + 10 + static int mctp_test_route_output(struct mctp_route *rt, struct sk_buff *skb) 11 + { 12 + struct mctp_test_route *test_rt = container_of(rt, struct mctp_test_route, rt); 13 + 14 + skb_queue_tail(&test_rt->pkts, skb); 15 + 16 + return 0; 17 + } 18 + 19 + /* local version of mctp_route_alloc() */ 20 + static struct mctp_test_route *mctp_route_test_alloc(void) 21 + { 22 + struct mctp_test_route *rt; 23 + 24 + rt = kzalloc(sizeof(*rt), GFP_KERNEL); 25 + if (!rt) 26 + return NULL; 27 + 28 + INIT_LIST_HEAD(&rt->rt.list); 29 + refcount_set(&rt->rt.refs, 1); 30 + rt->rt.output = mctp_test_route_output; 31 + 32 + skb_queue_head_init(&rt->pkts); 33 + 34 + return rt; 35 + } 36 + 37 + static struct mctp_test_route *mctp_test_create_route(struct net *net, 38 + mctp_eid_t eid, 39 + unsigned int mtu) 40 + { 41 + struct mctp_test_route *rt; 42 + 43 + rt = mctp_route_test_alloc(); 44 + if (!rt) 45 + return NULL; 46 + 47 + rt->rt.min = eid; 48 + rt->rt.max = eid; 49 + rt->rt.mtu = mtu; 50 + rt->rt.type = RTN_UNSPEC; 51 + rt->rt.dev = NULL; /* somewhat illegal, but fine for current tests */ 52 + 53 + list_add_rcu(&rt->rt.list, &net->mctp.routes); 54 + 55 + return rt; 56 + } 57 + 58 + static void mctp_test_route_destroy(struct kunit *test, 59 + struct mctp_test_route *rt) 60 + { 61 + unsigned int refs; 62 + 63 + rtnl_lock(); 64 + list_del_rcu(&rt->rt.list); 65 + rtnl_unlock(); 66 + 67 + skb_queue_purge(&rt->pkts); 68 + 69 + refs = refcount_read(&rt->rt.refs); 70 + KUNIT_ASSERT_EQ_MSG(test, refs, 1, "route ref imbalance"); 71 + 72 + kfree_rcu(&rt->rt, rcu); 73 + } 74 + 75 + static struct sk_buff *mctp_test_create_skb(struct mctp_hdr *hdr, 76 + unsigned int data_len) 77 + { 78 + size_t hdr_len = sizeof(*hdr); 79 + struct sk_buff *skb; 80 + unsigned int i; 81 + u8 *buf; 82 + 83 + skb = alloc_skb(hdr_len + data_len, GFP_KERNEL); 84 + if (!skb) 85 + return NULL; 86 + 87 + memcpy(skb_put(skb, hdr_len), hdr, hdr_len); 88 + 89 + buf = skb_put(skb, data_len); 90 + for (i = 0; i < data_len; i++) 91 + buf[i] = i & 0xff; 92 + 93 + return skb; 94 + } 95 + 96 + struct mctp_frag_test { 97 + unsigned int mtu; 98 + unsigned int msgsize; 99 + unsigned int n_frags; 100 + }; 101 + 102 + static void mctp_test_fragment(struct kunit *test) 103 + { 104 + const struct mctp_frag_test *params; 105 + int rc, i, n, mtu, msgsize; 106 + struct mctp_test_route *rt; 107 + struct sk_buff *skb; 108 + struct mctp_hdr hdr; 109 + u8 seq; 110 + 111 + params = test->param_value; 112 + mtu = params->mtu; 113 + msgsize = params->msgsize; 114 + 115 + hdr.ver = 1; 116 + hdr.src = 8; 117 + hdr.dest = 10; 118 + hdr.flags_seq_tag = MCTP_HDR_FLAG_TO; 119 + 120 + skb = mctp_test_create_skb(&hdr, msgsize); 121 + KUNIT_ASSERT_TRUE(test, skb); 122 + 123 + rt = mctp_test_create_route(&init_net, 10, mtu); 124 + KUNIT_ASSERT_TRUE(test, rt); 125 + 126 + /* The refcount would usually be incremented as part of a route lookup, 127 + * but we're setting the route directly here. 128 + */ 129 + refcount_inc(&rt->rt.refs); 130 + 131 + rc = mctp_do_fragment_route(&rt->rt, skb, mtu, MCTP_TAG_OWNER); 132 + KUNIT_EXPECT_FALSE(test, rc); 133 + 134 + n = rt->pkts.qlen; 135 + 136 + KUNIT_EXPECT_EQ(test, n, params->n_frags); 137 + 138 + for (i = 0;; i++) { 139 + struct mctp_hdr *hdr2; 140 + struct sk_buff *skb2; 141 + u8 tag_mask, seq2; 142 + bool first, last; 143 + 144 + first = i == 0; 145 + last = i == (n - 1); 146 + 147 + skb2 = skb_dequeue(&rt->pkts); 148 + 149 + if (!skb2) 150 + break; 151 + 152 + hdr2 = mctp_hdr(skb2); 153 + 154 + tag_mask = MCTP_HDR_TAG_MASK | MCTP_HDR_FLAG_TO; 155 + 156 + KUNIT_EXPECT_EQ(test, hdr2->ver, hdr.ver); 157 + KUNIT_EXPECT_EQ(test, hdr2->src, hdr.src); 158 + KUNIT_EXPECT_EQ(test, hdr2->dest, hdr.dest); 159 + KUNIT_EXPECT_EQ(test, hdr2->flags_seq_tag & tag_mask, 160 + hdr.flags_seq_tag & tag_mask); 161 + 162 + KUNIT_EXPECT_EQ(test, 163 + !!(hdr2->flags_seq_tag & MCTP_HDR_FLAG_SOM), first); 164 + KUNIT_EXPECT_EQ(test, 165 + !!(hdr2->flags_seq_tag & MCTP_HDR_FLAG_EOM), last); 166 + 167 + seq2 = (hdr2->flags_seq_tag >> MCTP_HDR_SEQ_SHIFT) & 168 + MCTP_HDR_SEQ_MASK; 169 + 170 + if (first) { 171 + seq = seq2; 172 + } else { 173 + seq++; 174 + KUNIT_EXPECT_EQ(test, seq2, seq & MCTP_HDR_SEQ_MASK); 175 + } 176 + 177 + if (!last) 178 + KUNIT_EXPECT_EQ(test, skb2->len, mtu); 179 + else 180 + KUNIT_EXPECT_LE(test, skb2->len, mtu); 181 + 182 + kfree_skb(skb2); 183 + } 184 + 185 + mctp_test_route_destroy(test, rt); 186 + } 187 + 188 + static const struct mctp_frag_test mctp_frag_tests[] = { 189 + {.mtu = 68, .msgsize = 63, .n_frags = 1}, 190 + {.mtu = 68, .msgsize = 64, .n_frags = 1}, 191 + {.mtu = 68, .msgsize = 65, .n_frags = 2}, 192 + {.mtu = 68, .msgsize = 66, .n_frags = 2}, 193 + {.mtu = 68, .msgsize = 127, .n_frags = 2}, 194 + {.mtu = 68, .msgsize = 128, .n_frags = 2}, 195 + {.mtu = 68, .msgsize = 129, .n_frags = 3}, 196 + {.mtu = 68, .msgsize = 130, .n_frags = 3}, 197 + }; 198 + 199 + static void mctp_frag_test_to_desc(const struct mctp_frag_test *t, char *desc) 200 + { 201 + sprintf(desc, "mtu %d len %d -> %d frags", 202 + t->msgsize, t->mtu, t->n_frags); 203 + } 204 + 205 + KUNIT_ARRAY_PARAM(mctp_frag, mctp_frag_tests, mctp_frag_test_to_desc); 206 + 207 + static struct kunit_case mctp_test_cases[] = { 208 + KUNIT_CASE_PARAM(mctp_test_fragment, mctp_frag_gen_params), 209 + {} 210 + }; 211 + 212 + static struct kunit_suite mctp_test_suite = { 213 + .name = "mctp", 214 + .test_cases = mctp_test_cases, 215 + }; 216 + 217 + kunit_test_suite(mctp_test_suite);