summaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorJeremy Kerr <jk@codeconstruct.com.au>2026-03-24 15:19:56 +0800
committerJakub Kicinski <kuba@kernel.org>2026-03-26 18:47:29 -0700
commite1877cf6231152ff4686bd9900a6a88ffdd90f84 (patch)
treee59160a7e8e5357756e8e9c02fa89bc75471078f /net
parent2b8e147c006ef2b40863be1911e29dd5731c205d (diff)
downloadlinux-e1877cf6231152ff4686bd9900a6a88ffdd90f84.tar.gz
linux-e1877cf6231152ff4686bd9900a6a88ffdd90f84.zip
net: mctp: avoid copy in fragmentation loop for near-MTU messages
Currently, we incorrectly send messages that are within 4 bytes (a struct mctp_hdr) smaller than the MTU through mctp_do_fragment_route(). This has no effect on the actual fragmentation, as we will still send as one packet, but unnecessarily copies the original skb into a new single-fragment skb. Instead of having the MTU comparisons in both mctp_local_output() and mctp_do_fragment_route(), feed all local messages through the latter, and add the single-packet optimisation there. This means we can coalesce the routing path of mctp_local_output, so our out_release path is now solely for errors, so rename the label accordingly. Include a check in the route tests for the single-packet case too. Reported-by: yuanzhaoming <yuanzm2@lenovo.com> Closes: https://github.com/openbmc/linux/commit/269936db5eb3962fe290b1dc4dbf1859cd5a04dd#r175836230 Signed-off-by: Jeremy Kerr <jk@codeconstruct.com.au> Reviewed-by: Simon Horman <horms@kernel.org> Link: https://patch.msgid.link/20260324-dev-mtu-copy-v1-1-7af6bd7027d3@codeconstruct.com.au Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Diffstat (limited to 'net')
-rw-r--r--net/mctp/route.c26
-rw-r--r--net/mctp/test/route-test.c4
2 files changed, 15 insertions, 15 deletions
diff --git a/net/mctp/route.c b/net/mctp/route.c
index 59ad60b88563..021e04f1ea7c 100644
--- a/net/mctp/route.c
+++ b/net/mctp/route.c
@@ -1037,6 +1037,13 @@ static int mctp_do_fragment_route(struct mctp_dst *dst, struct sk_buff *skb,
return -EMSGSIZE;
}
+ /* within MTU? avoid the copy, send original skb */
+ if (skb->len <= mtu) {
+ hdr->flags_seq_tag = MCTP_HDR_FLAG_SOM |
+ MCTP_HDR_FLAG_EOM | tag;
+ return dst->output(dst, skb);
+ }
+
/* keep same headroom as the original skb */
headroom = skb_headroom(skb);
@@ -1111,7 +1118,6 @@ int mctp_local_output(struct sock *sk, struct mctp_dst *dst,
struct mctp_hdr *hdr;
unsigned long flags;
unsigned int netid;
- unsigned int mtu;
mctp_eid_t saddr;
int rc;
u8 tag;
@@ -1133,7 +1139,7 @@ int mctp_local_output(struct sock *sk, struct mctp_dst *dst,
netid = READ_ONCE(dst->dev->net);
if (rc)
- goto out_release;
+ goto err_free;
if (req_tag & MCTP_TAG_OWNER) {
if (req_tag & MCTP_TAG_PREALLOC)
@@ -1145,7 +1151,7 @@ int mctp_local_output(struct sock *sk, struct mctp_dst *dst,
if (IS_ERR(key)) {
rc = PTR_ERR(key);
- goto out_release;
+ goto err_free;
}
mctp_skb_set_flow(skb, key);
/* done with the key in this scope */
@@ -1170,20 +1176,10 @@ int mctp_local_output(struct sock *sk, struct mctp_dst *dst,
hdr->dest = daddr;
hdr->src = saddr;
- mtu = dst->mtu;
-
- if (skb->len + sizeof(struct mctp_hdr) <= mtu) {
- hdr->flags_seq_tag = MCTP_HDR_FLAG_SOM |
- MCTP_HDR_FLAG_EOM | tag;
- rc = dst->output(dst, skb);
- } else {
- rc = mctp_do_fragment_route(dst, skb, mtu, tag);
- }
-
/* route output functions consume the skb, even on error */
- skb = NULL;
+ return mctp_do_fragment_route(dst, skb, dst->mtu, tag);
-out_release:
+err_free:
kfree_skb(skb);
return rc;
}
diff --git a/net/mctp/test/route-test.c b/net/mctp/test/route-test.c
index 75ea96c10e49..61c989c43ec0 100644
--- a/net/mctp/test/route-test.c
+++ b/net/mctp/test/route-test.c
@@ -63,6 +63,10 @@ static void mctp_test_fragment(struct kunit *test)
if (!skb2)
break;
+ /* avoid copying single-skb messages */
+ if (first && last)
+ KUNIT_EXPECT_PTR_EQ(test, skb, skb2);
+
hdr2 = mctp_hdr(skb2);
tag_mask = MCTP_HDR_TAG_MASK | MCTP_HDR_FLAG_TO;