net: mctp: Add bind lookup test

Test the preference order of bound socket matches with a series of test
packets.

Signed-off-by: Matt Johnston <matt@codeconstruct.com.au>
Link: https://patch.msgid.link/20250710-mctp-bind-v4-8-8ec2f6460c56@codeconstruct.com.au
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
This commit is contained in:
Matt Johnston 2025-07-10 16:56:01 +08:00 committed by Paolo Abeni
parent b7e28129b6
commit e6d8e7dbc5
2 changed files with 191 additions and 0 deletions

View file

@ -1408,6 +1408,193 @@ static void mctp_test_route_gw_output(struct kunit *test)
kfree_skb(skb);
}
struct mctp_bind_lookup_test {
/* header of incoming message */
struct mctp_hdr hdr;
u8 ty;
/* mctp network of incoming interface (smctp_network) */
unsigned int net;
/* expected socket, matches .name in lookup_binds, NULL for dropped */
const char *expect;
};
/* Single-packet TO-set message */
#define LK(src, dst) RX_HDR(1, (src), (dst), FL_S | FL_E | FL_TO)
/* Input message test cases for bind lookup tests.
*
* 10 and 11 are local EIDs.
* 20 and 21 are remote EIDs.
*/
static const struct mctp_bind_lookup_test mctp_bind_lookup_tests[] = {
/* both local-eid and remote-eid binds, remote eid is preferenced */
{ .hdr = LK(20, 10), .ty = 1, .net = 1, .expect = "remote20" },
{ .hdr = LK(20, 255), .ty = 1, .net = 1, .expect = "remote20" },
{ .hdr = LK(20, 0), .ty = 1, .net = 1, .expect = "remote20" },
{ .hdr = LK(0, 255), .ty = 1, .net = 1, .expect = "any" },
{ .hdr = LK(0, 11), .ty = 1, .net = 1, .expect = "any" },
{ .hdr = LK(0, 0), .ty = 1, .net = 1, .expect = "any" },
{ .hdr = LK(0, 10), .ty = 1, .net = 1, .expect = "local10" },
{ .hdr = LK(21, 10), .ty = 1, .net = 1, .expect = "local10" },
{ .hdr = LK(21, 11), .ty = 1, .net = 1, .expect = "remote21local11" },
/* both src and dest set to eid=99. unusual, but accepted
* by MCTP stack currently.
*/
{ .hdr = LK(99, 99), .ty = 1, .net = 1, .expect = "any" },
/* unbound smctp_type */
{ .hdr = LK(20, 10), .ty = 3, .net = 1, .expect = NULL },
/* smctp_network tests */
{ .hdr = LK(0, 0), .ty = 1, .net = 7, .expect = "any" },
{ .hdr = LK(21, 10), .ty = 1, .net = 2, .expect = "any" },
/* remote EID 20 matches, but MCTP_NET_ANY in "remote20" resolved
* to net=1, so lookup doesn't match "remote20"
*/
{ .hdr = LK(20, 10), .ty = 1, .net = 3, .expect = "any" },
{ .hdr = LK(21, 10), .ty = 1, .net = 3, .expect = "remote21net3" },
{ .hdr = LK(21, 10), .ty = 1, .net = 4, .expect = "remote21net4" },
{ .hdr = LK(21, 10), .ty = 1, .net = 5, .expect = "remote21net5" },
{ .hdr = LK(21, 10), .ty = 1, .net = 5, .expect = "remote21net5" },
{ .hdr = LK(99, 10), .ty = 1, .net = 8, .expect = "local10net8" },
{ .hdr = LK(99, 10), .ty = 1, .net = 9, .expect = "anynet9" },
{ .hdr = LK(0, 0), .ty = 1, .net = 9, .expect = "anynet9" },
{ .hdr = LK(99, 99), .ty = 1, .net = 9, .expect = "anynet9" },
{ .hdr = LK(20, 10), .ty = 1, .net = 9, .expect = "anynet9" },
};
/* Binds to create during the lookup tests */
static const struct mctp_test_bind_setup lookup_binds[] = {
/* any address and net, type 1 */
{ .name = "any", .bind_addr = MCTP_ADDR_ANY,
.bind_net = MCTP_NET_ANY, .bind_type = 1, },
/* local eid 10, net 1 (resolved from MCTP_NET_ANY) */
{ .name = "local10", .bind_addr = 10,
.bind_net = MCTP_NET_ANY, .bind_type = 1, },
/* local eid 10, net 8 */
{ .name = "local10net8", .bind_addr = 10,
.bind_net = 8, .bind_type = 1, },
/* any EID, net 9 */
{ .name = "anynet9", .bind_addr = MCTP_ADDR_ANY,
.bind_net = 9, .bind_type = 1, },
/* remote eid 20, net 1, any local eid */
{ .name = "remote20", .bind_addr = MCTP_ADDR_ANY,
.bind_net = MCTP_NET_ANY, .bind_type = 1,
.have_peer = true, .peer_addr = 20, .peer_net = MCTP_NET_ANY, },
/* remote eid 20, net 1, local eid 11 */
{ .name = "remote21local11", .bind_addr = 11,
.bind_net = MCTP_NET_ANY, .bind_type = 1,
.have_peer = true, .peer_addr = 21, .peer_net = MCTP_NET_ANY, },
/* remote eid 21, specific net=3 for connect() */
{ .name = "remote21net3", .bind_addr = MCTP_ADDR_ANY,
.bind_net = MCTP_NET_ANY, .bind_type = 1,
.have_peer = true, .peer_addr = 21, .peer_net = 3, },
/* remote eid 21, net 4 for bind, specific net=4 for connect() */
{ .name = "remote21net4", .bind_addr = MCTP_ADDR_ANY,
.bind_net = 4, .bind_type = 1,
.have_peer = true, .peer_addr = 21, .peer_net = 4, },
/* remote eid 21, net 5 for bind, specific net=5 for connect() */
{ .name = "remote21net5", .bind_addr = MCTP_ADDR_ANY,
.bind_net = 5, .bind_type = 1,
.have_peer = true, .peer_addr = 21, .peer_net = 5, },
};
static void mctp_bind_lookup_desc(const struct mctp_bind_lookup_test *t,
char *desc)
{
snprintf(desc, KUNIT_PARAM_DESC_SIZE,
"{src %d dst %d ty %d net %d expect %s}",
t->hdr.src, t->hdr.dest, t->ty, t->net, t->expect);
}
KUNIT_ARRAY_PARAM(mctp_bind_lookup, mctp_bind_lookup_tests,
mctp_bind_lookup_desc);
static void mctp_test_bind_lookup(struct kunit *test)
{
const struct mctp_bind_lookup_test *rx;
struct socket *socks[ARRAY_SIZE(lookup_binds)];
struct sk_buff *skb_pkt = NULL, *skb_sock = NULL;
struct socket *sock_ty0, *sock_expect = NULL;
struct mctp_test_pktqueue tpq;
struct mctp_test_dev *dev;
struct mctp_dst dst;
int rc;
rx = test->param_value;
__mctp_route_test_init(test, &dev, &dst, &tpq, &sock_ty0, rx->net);
/* Create all binds */
for (size_t i = 0; i < ARRAY_SIZE(lookup_binds); i++) {
mctp_test_bind_run(test, &lookup_binds[i],
&rc, &socks[i]);
KUNIT_ASSERT_EQ(test, rc, 0);
/* Record the expected receive socket */
if (rx->expect &&
strcmp(rx->expect, lookup_binds[i].name) == 0) {
KUNIT_ASSERT_NULL(test, sock_expect);
sock_expect = socks[i];
}
}
KUNIT_ASSERT_EQ(test, !!sock_expect, !!rx->expect);
/* Create test message */
skb_pkt = mctp_test_create_skb_data(&rx->hdr, &rx->ty);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, skb_pkt);
mctp_test_skb_set_dev(skb_pkt, dev);
mctp_test_pktqueue_init(&tpq);
rc = mctp_dst_input(&dst, skb_pkt);
if (rx->expect) {
/* Test the message is received on the expected socket */
KUNIT_EXPECT_EQ(test, rc, 0);
skb_sock = skb_recv_datagram(sock_expect->sk,
MSG_DONTWAIT, &rc);
if (!skb_sock) {
/* Find which socket received it instead */
for (size_t i = 0; i < ARRAY_SIZE(lookup_binds); i++) {
skb_sock = skb_recv_datagram(socks[i]->sk,
MSG_DONTWAIT, &rc);
if (skb_sock) {
KUNIT_FAIL(test,
"received on incorrect socket '%s', expect '%s'",
lookup_binds[i].name,
rx->expect);
goto cleanup;
}
}
KUNIT_FAIL(test, "no message received");
}
} else {
KUNIT_EXPECT_NE(test, rc, 0);
}
cleanup:
kfree_skb(skb_sock);
kfree_skb(skb_pkt);
/* Drop all binds */
for (size_t i = 0; i < ARRAY_SIZE(lookup_binds); i++)
sock_release(socks[i]);
__mctp_route_test_fini(test, dev, &dst, &tpq, sock_ty0);
}
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),
@ -1429,6 +1616,7 @@ static struct kunit_case mctp_test_cases[] = {
KUNIT_CASE(mctp_test_route_gw_loop),
KUNIT_CASE_PARAM(mctp_test_route_gw_mtu, mctp_route_gw_mtu_gen_params),
KUNIT_CASE(mctp_test_route_gw_output),
KUNIT_CASE_PARAM(mctp_test_bind_lookup, mctp_bind_lookup_gen_params),
{}
};

View file

@ -39,6 +39,9 @@ struct mctp_test_bind_setup {
bool have_peer;
mctp_eid_t peer_addr;
int peer_net;
/* optional name. Used for comparison in "lookup" tests */
const char *name;
};
struct mctp_test_dev *mctp_test_create_dev(void);