net: mctp: don't require a route for null-EID ingress

Currently, if we receive a physically-addressed packet for the local
stack, we perform a route_lookup_null to find a matching device-based
route. If a route is present, it will always have the ->output fn set to
mctp_dst_input, which provides our delivery mechanism.

However, if we don't yet have any local addresses assigned, we won't
have any local routes to lookup, so this will fail. One of the use-cases
for physical addressing is initial address assignment on endpoint nodes,
where we would have no addresses, and therefore no local routes.

Instead of iterating routes (looking for one matching the dev), just
create a suitable mctp_dst for the device directly.

Add a testcase for the no-route case too.

Signed-off-by: Jeremy Kerr <jk@codeconstruct.com.au>
Link: https://patch.msgid.link/20260331-dev-mctp-null-eids-v1-3-b4d047372eaf@codeconstruct.com.au
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
This commit is contained in:
Jeremy Kerr 2026-03-31 15:41:08 +08:00 committed by Paolo Abeni
parent 8af20defc4
commit 0d8647bc74
2 changed files with 56 additions and 20 deletions

View File

@ -1017,29 +1017,22 @@ int mctp_route_lookup(struct net *net, unsigned int dnet,
return rc;
}
static int mctp_route_lookup_null(struct net *net, struct net_device *dev,
struct mctp_dst *dst)
static int mctp_dst_input_null(struct net *net, struct net_device *dev,
struct mctp_dst *dst)
{
int rc = -EHOSTUNREACH;
struct mctp_route *rt;
rcu_read_lock();
list_for_each_entry_rcu(rt, &net->mctp.routes, list) {
if (rt->dst_type != MCTP_ROUTE_DIRECT || rt->type != RTN_LOCAL)
continue;
if (rt->dev->dev != dev)
continue;
mctp_dst_from_route(dst, 0, 0, rt);
rc = 0;
break;
}
dst->dev = __mctp_dev_get(dev);
rcu_read_unlock();
return rc;
if (!dst->dev)
return -EHOSTUNREACH;
dst->mtu = READ_ONCE(dev->mtu);
dst->halen = 0;
dst->output = mctp_dst_input;
dst->nexthop = 0;
return 0;
}
static int mctp_do_fragment_route(struct mctp_dst *dst, struct sk_buff *skb,
@ -1369,7 +1362,7 @@ static int mctp_pkttype_receive(struct sk_buff *skb, struct net_device *dev,
/* NULL EID, but addressed to our physical address */
if (rc && mh->dest == MCTP_ADDR_NULL && skb->pkt_type == PACKET_HOST)
rc = mctp_route_lookup_null(net, dev, &dst);
rc = mctp_dst_input_null(net, dev, &dst);
if (rc)
goto err_drop;

View File

@ -914,6 +914,48 @@ static void mctp_test_route_input_cloned_frag(struct kunit *test)
__mctp_route_test_fini(test, dev, &dst, sock);
}
/* check we can receive an incoming packet with the null EID as daddr, when
* no RTN_LOCAL routes are present.
*/
static void mctp_test_route_input_null_eid(struct kunit *test)
{
struct mctp_hdr hdr = RX_HDR(1, 10, 0, FL_S | FL_E | FL_TO);
struct sk_buff *skb_pkt, *skb_sk;
struct mctp_test_dev *dev;
struct sockaddr_mctp addr;
struct socket *sock;
u8 type = 0;
int rc;
dev = mctp_test_create_dev();
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dev);
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 = MCTP_ADDR_ANY;
addr.smctp_type = type;
rc = kernel_bind(sock, (struct sockaddr_unsized *)&addr, sizeof(addr));
KUNIT_ASSERT_EQ(test, rc, 0);
skb_pkt = mctp_test_create_skb_data(&hdr, &type);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, skb_pkt);
skb_pkt->dev = dev->ndev;
skb_pkt->pkt_type = PACKET_HOST;
mctp_pkttype_receive(skb_pkt, dev->ndev, &mctp_packet_type, NULL);
skb_sk = skb_recv_datagram(sock->sk, MSG_DONTWAIT, &rc);
KUNIT_EXPECT_NOT_ERR_OR_NULL(test, skb_sk);
skb_free_datagram(sock->sk, skb_sk);
sock_release(sock);
mctp_test_destroy_dev(dev);
}
#if IS_ENABLED(CONFIG_MCTP_FLOWS)
static void mctp_test_flow_init(struct kunit *test,
@ -1693,6 +1735,7 @@ static struct kunit_case mctp_test_cases[] = {
KUNIT_CASE(mctp_test_route_input_sk_fail_frag),
KUNIT_CASE(mctp_test_route_input_multiple_nets_bind),
KUNIT_CASE(mctp_test_route_input_multiple_nets_key),
KUNIT_CASE(mctp_test_route_input_null_eid),
KUNIT_CASE(mctp_test_packet_flow),
KUNIT_CASE(mctp_test_fragment_flow),
KUNIT_CASE(mctp_test_route_output_key_create),