Commit 48e1736e authored by Jeremy Kerr's avatar Jeremy Kerr Committed by Paolo Abeni
Browse files

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: default avatarJeremy Kerr <jk@codeconstruct.com.au>
Link: https://patch.msgid.link/20250702-dev-forwarding-v5-14-1468191da8a4@codeconstruct.com.au


Signed-off-by: default avatarPaolo Abeni <pabeni@redhat.com>
parent ad39c12f
Loading
Loading
Loading
Loading
+232 −1
Original line number Diff line number Diff line
@@ -141,7 +141,7 @@ static void mctp_test_rx_input(struct kunit *test)
	dev = mctp_test_create_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);

	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);
}

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[] = {
	KUNIT_CASE_PARAM(mctp_test_fragment, mctp_frag_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_input_cloned_frag),
	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),
	{}
};

+1 −1
Original line number Diff line number Diff line
@@ -40,7 +40,7 @@ static void __mctp_sock_test_init(struct kunit *test,

	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);

	rc = sock_create_kern(&init_net, AF_MCTP, SOCK_DGRAM, 0, &sock);
+29 −4
Original line number Diff line number Diff line
@@ -119,7 +119,7 @@ static struct mctp_test_route *mctp_route_test_alloc(void)
	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,
						      mctp_eid_t eid,
						      unsigned int mtu)
@@ -144,6 +144,31 @@ struct mctp_test_route *mctp_test_create_route(struct net *net,
	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()
 */
void mctp_test_dst_setup(struct kunit *test, struct mctp_dst *dst,
+9 −4
Original line number Diff line number Diff line
@@ -36,10 +36,15 @@ struct mctp_test_dev *mctp_test_create_dev_lladdr(unsigned short lladdr_len,
						  const unsigned char *lladdr);
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,
						      mctp_eid_t eid,
						      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,
			 struct mctp_test_dev *dev,
			 struct mctp_test_pktqueue *tpq, unsigned int mtu);