2
0
mirror of git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git synced 2025-09-04 20:19:47 +08:00

net: mctp: test: Add tests for gateway routes

Add a few kunit tests for the gateway routing. Because we have multiple
route types now (direct and gateway), rename mctp_test_create_route to
mctp_test_create_route_direct, and add a _gateway variant too.

Signed-off-by: Jeremy Kerr <jk@codeconstruct.com.au>
Link: https://patch.msgid.link/20250702-dev-forwarding-v5-14-1468191da8a4@codeconstruct.com.au
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
This commit is contained in:
Jeremy Kerr 2025-07-02 14:20:14 +08:00 committed by Paolo Abeni
parent ad39c12fce
commit 48e1736e5d
4 changed files with 271 additions and 10 deletions

View File

@ -141,7 +141,7 @@ static void mctp_test_rx_input(struct kunit *test)
dev = mctp_test_create_dev(); dev = mctp_test_create_dev();
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dev); KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dev);
rt = mctp_test_create_route(&init_net, dev->mdev, 8, 68); rt = mctp_test_create_route_direct(&init_net, dev->mdev, 8, 68);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, rt); KUNIT_ASSERT_NOT_ERR_OR_NULL(test, rt);
skb = mctp_test_create_skb(&params->hdr, 1); skb = mctp_test_create_skb(&params->hdr, 1);
@ -1183,6 +1183,233 @@ static void mctp_test_route_extaddr_input(struct kunit *test)
mctp_test_destroy_dev(dev); mctp_test_destroy_dev(dev);
} }
static void mctp_test_route_gw_lookup(struct kunit *test)
{
struct mctp_test_route *rt1, *rt2;
struct mctp_dst dst = { 0 };
struct mctp_test_dev *dev;
int rc;
dev = mctp_test_create_dev();
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dev);
/* 8 (local) -> 10 (gateway) via 9 (direct) */
rt1 = mctp_test_create_route_direct(&init_net, dev->mdev, 9, 0);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, rt1);
rt2 = mctp_test_create_route_gw(&init_net, dev->mdev->net, 10, 9, 0);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, rt2);
rc = mctp_route_lookup(&init_net, dev->mdev->net, 10, &dst);
KUNIT_EXPECT_EQ(test, rc, 0);
KUNIT_EXPECT_PTR_EQ(test, dst.dev, dev->mdev);
KUNIT_EXPECT_EQ(test, dst.mtu, dev->ndev->mtu);
KUNIT_EXPECT_EQ(test, dst.nexthop, 9);
KUNIT_EXPECT_EQ(test, dst.halen, 0);
mctp_dst_release(&dst);
mctp_test_route_destroy(test, rt2);
mctp_test_route_destroy(test, rt1);
mctp_test_destroy_dev(dev);
}
static void mctp_test_route_gw_loop(struct kunit *test)
{
struct mctp_test_route *rt1, *rt2;
struct mctp_dst dst = { 0 };
struct mctp_test_dev *dev;
int rc;
dev = mctp_test_create_dev();
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dev);
/* two routes using each other as the gw */
rt1 = mctp_test_create_route_gw(&init_net, dev->mdev->net, 9, 10, 0);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, rt1);
rt2 = mctp_test_create_route_gw(&init_net, dev->mdev->net, 10, 9, 0);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, rt2);
/* this should fail, rather than infinite-loop */
rc = mctp_route_lookup(&init_net, dev->mdev->net, 10, &dst);
KUNIT_EXPECT_NE(test, rc, 0);
mctp_test_route_destroy(test, rt2);
mctp_test_route_destroy(test, rt1);
mctp_test_destroy_dev(dev);
}
struct mctp_route_gw_mtu_test {
/* working away from the local stack */
unsigned int dev, neigh, gw, dst;
unsigned int exp;
};
static void mctp_route_gw_mtu_to_desc(const struct mctp_route_gw_mtu_test *t,
char *desc)
{
sprintf(desc, "dev %d, neigh %d, gw %d, dst %d -> %d",
t->dev, t->neigh, t->gw, t->dst, t->exp);
}
static const struct mctp_route_gw_mtu_test mctp_route_gw_mtu_tests[] = {
/* no route-specific MTUs */
{ 68, 0, 0, 0, 68 },
{ 100, 0, 0, 0, 100 },
/* one route MTU (smaller than dev mtu), others unrestricted */
{ 100, 68, 0, 0, 68 },
{ 100, 0, 68, 0, 68 },
{ 100, 0, 0, 68, 68 },
/* smallest applied, regardless of order */
{ 100, 99, 98, 68, 68 },
{ 99, 100, 98, 68, 68 },
{ 98, 99, 100, 68, 68 },
{ 68, 98, 99, 100, 68 },
};
KUNIT_ARRAY_PARAM(mctp_route_gw_mtu, mctp_route_gw_mtu_tests,
mctp_route_gw_mtu_to_desc);
static void mctp_test_route_gw_mtu(struct kunit *test)
{
const struct mctp_route_gw_mtu_test *mtus = test->param_value;
struct mctp_test_route *rt1, *rt2, *rt3;
struct mctp_dst dst = { 0 };
struct mctp_test_dev *dev;
struct mctp_dev *mdev;
unsigned int netid;
int rc;
dev = mctp_test_create_dev();
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dev);
dev->ndev->mtu = mtus->dev;
mdev = dev->mdev;
netid = mdev->net;
/* 8 (local) -> 11 (dst) via 10 (gw) via 9 (neigh) */
rt1 = mctp_test_create_route_direct(&init_net, mdev, 9, mtus->neigh);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, rt1);
rt2 = mctp_test_create_route_gw(&init_net, netid, 10, 9, mtus->gw);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, rt2);
rt3 = mctp_test_create_route_gw(&init_net, netid, 11, 10, mtus->dst);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, rt3);
rc = mctp_route_lookup(&init_net, dev->mdev->net, 11, &dst);
KUNIT_EXPECT_EQ(test, rc, 0);
KUNIT_EXPECT_EQ(test, dst.mtu, mtus->exp);
mctp_dst_release(&dst);
mctp_test_route_destroy(test, rt3);
mctp_test_route_destroy(test, rt2);
mctp_test_route_destroy(test, rt1);
mctp_test_destroy_dev(dev);
}
#define MCTP_TEST_LLADDR_LEN 2
struct mctp_test_llhdr {
unsigned int magic;
unsigned char src[MCTP_TEST_LLADDR_LEN];
unsigned char dst[MCTP_TEST_LLADDR_LEN];
};
static const unsigned int mctp_test_llhdr_magic = 0x5c78339c;
static int test_dev_header_create(struct sk_buff *skb, struct net_device *dev,
unsigned short type, const void *daddr,
const void *saddr, unsigned int len)
{
struct kunit *test = current->kunit_test;
struct mctp_test_llhdr *hdr;
hdr = skb_push(skb, sizeof(*hdr));
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, hdr);
skb_reset_mac_header(skb);
hdr->magic = mctp_test_llhdr_magic;
memcpy(&hdr->src, saddr, sizeof(hdr->src));
memcpy(&hdr->dst, daddr, sizeof(hdr->dst));
return 0;
}
/* Test the dst_output path for a gateway-routed skb: we should have it
* lookup the nexthop EID in the neighbour table, and call into
* header_ops->create to resolve that to a lladdr. Our mock header_ops->create
* will just set a synthetic link-layer header, which we check after transmit.
*/
static void mctp_test_route_gw_output(struct kunit *test)
{
const unsigned char haddr_self[MCTP_TEST_LLADDR_LEN] = { 0xaa, 0x03 };
const unsigned char haddr_peer[MCTP_TEST_LLADDR_LEN] = { 0xaa, 0x02 };
const struct header_ops ops = {
.create = test_dev_header_create,
};
struct mctp_neigh neigh = { 0 };
struct mctp_test_llhdr *ll_hdr;
struct mctp_dst dst = { 0 };
struct mctp_hdr hdr = { 0 };
struct mctp_test_dev *dev;
struct sk_buff *skb;
unsigned char *buf;
int i, rc;
dev = mctp_test_create_dev_lladdr(sizeof(haddr_self), haddr_self);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dev);
dev->ndev->header_ops = &ops;
dst.dev = dev->mdev;
__mctp_dev_get(dst.dev->dev);
dst.mtu = 68;
dst.nexthop = 9;
/* simple mctp_neigh_add for the gateway (not dest!) endpoint */
INIT_LIST_HEAD(&neigh.list);
neigh.dev = dev->mdev;
mctp_dev_hold(dev->mdev);
neigh.eid = 9;
neigh.source = MCTP_NEIGH_STATIC;
memcpy(neigh.ha, haddr_peer, sizeof(haddr_peer));
list_add_rcu(&neigh.list, &init_net.mctp.neighbours);
hdr.ver = 1;
hdr.src = 8;
hdr.dest = 10;
hdr.flags_seq_tag = FL_S | FL_E | FL_TO;
/* construct enough for a future link-layer header, the provided
* mctp header, and 4 bytes of data
*/
skb = alloc_skb(sizeof(*ll_hdr) + sizeof(hdr) + 4, GFP_KERNEL);
skb->dev = dev->ndev;
__mctp_cb(skb);
skb_reserve(skb, sizeof(*ll_hdr));
memcpy(skb_put(skb, sizeof(hdr)), &hdr, sizeof(hdr));
buf = skb_put(skb, 4);
for (i = 0; i < 4; i++)
buf[i] = i;
/* extra ref over the dev_xmit */
skb_get(skb);
rc = mctp_dst_output(&dst, skb);
KUNIT_EXPECT_EQ(test, rc, 0);
mctp_dst_release(&dst);
list_del_rcu(&neigh.list);
mctp_dev_put(dev->mdev);
/* check that we have our header created with the correct neighbour */
ll_hdr = (void *)skb_mac_header(skb);
KUNIT_EXPECT_EQ(test, ll_hdr->magic, mctp_test_llhdr_magic);
KUNIT_EXPECT_MEMEQ(test, ll_hdr->src, haddr_self, sizeof(haddr_self));
KUNIT_EXPECT_MEMEQ(test, ll_hdr->dst, haddr_peer, sizeof(haddr_peer));
kfree_skb(skb);
}
static struct kunit_case mctp_test_cases[] = { static struct kunit_case mctp_test_cases[] = {
KUNIT_CASE_PARAM(mctp_test_fragment, mctp_frag_gen_params), 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_rx_input, mctp_rx_input_gen_params),
@ -1200,6 +1427,10 @@ static struct kunit_case mctp_test_cases[] = {
KUNIT_CASE(mctp_test_route_output_key_create), KUNIT_CASE(mctp_test_route_output_key_create),
KUNIT_CASE(mctp_test_route_input_cloned_frag), KUNIT_CASE(mctp_test_route_input_cloned_frag),
KUNIT_CASE(mctp_test_route_extaddr_input), KUNIT_CASE(mctp_test_route_extaddr_input),
KUNIT_CASE(mctp_test_route_gw_lookup),
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),
{} {}
}; };

View File

@ -40,7 +40,7 @@ static void __mctp_sock_test_init(struct kunit *test,
kfree(addrs); kfree(addrs);
rt = mctp_test_create_route(dev_net(dev->ndev), dev->mdev, 9, 0); rt = mctp_test_create_route_direct(dev_net(dev->ndev), dev->mdev, 9, 0);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, rt); KUNIT_ASSERT_NOT_ERR_OR_NULL(test, rt);
rc = sock_create_kern(&init_net, AF_MCTP, SOCK_DGRAM, 0, &sock); rc = sock_create_kern(&init_net, AF_MCTP, SOCK_DGRAM, 0, &sock);

View File

@ -119,10 +119,10 @@ static struct mctp_test_route *mctp_route_test_alloc(void)
return rt; return rt;
} }
struct mctp_test_route *mctp_test_create_route(struct net *net, struct mctp_test_route *mctp_test_create_route_direct(struct net *net,
struct mctp_dev *dev, struct mctp_dev *dev,
mctp_eid_t eid, mctp_eid_t eid,
unsigned int mtu) unsigned int mtu)
{ {
struct mctp_test_route *rt; struct mctp_test_route *rt;
@ -144,6 +144,31 @@ struct mctp_test_route *mctp_test_create_route(struct net *net,
return rt; return rt;
} }
struct mctp_test_route *mctp_test_create_route_gw(struct net *net,
unsigned int netid,
mctp_eid_t eid,
mctp_eid_t gw,
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.dst_type = MCTP_ROUTE_GATEWAY;
rt->rt.gateway.eid = gw;
rt->rt.gateway.net = netid;
list_add_rcu(&rt->rt.list, &net->mctp.routes);
return rt;
}
/* Convenience function for our test dst; release with mctp_test_dst_release() /* Convenience function for our test dst; release with mctp_test_dst_release()
*/ */
void mctp_test_dst_setup(struct kunit *test, struct mctp_dst *dst, void mctp_test_dst_setup(struct kunit *test, struct mctp_dst *dst,

View File

@ -36,10 +36,15 @@ struct mctp_test_dev *mctp_test_create_dev_lladdr(unsigned short lladdr_len,
const unsigned char *lladdr); const unsigned char *lladdr);
void mctp_test_destroy_dev(struct mctp_test_dev *dev); void mctp_test_destroy_dev(struct mctp_test_dev *dev);
struct mctp_test_route *mctp_test_create_route(struct net *net, struct mctp_test_route *mctp_test_create_route_direct(struct net *net,
struct mctp_dev *dev, struct mctp_dev *dev,
mctp_eid_t eid, mctp_eid_t eid,
unsigned int mtu); unsigned int mtu);
struct mctp_test_route *mctp_test_create_route_gw(struct net *net,
unsigned int netid,
mctp_eid_t eid,
mctp_eid_t gw,
unsigned int mtu);
void mctp_test_dst_setup(struct kunit *test, struct mctp_dst *dst, void mctp_test_dst_setup(struct kunit *test, struct mctp_dst *dst,
struct mctp_test_dev *dev, struct mctp_test_dev *dev,
struct mctp_test_pktqueue *tpq, unsigned int mtu); struct mctp_test_pktqueue *tpq, unsigned int mtu);