]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
net: mctp: avoid copy in fragmentation loop for near-MTU messages
authorJeremy Kerr <jk@codeconstruct.com.au>
Tue, 24 Mar 2026 07:19:56 +0000 (15:19 +0800)
committerJakub Kicinski <kuba@kernel.org>
Fri, 27 Mar 2026 01:47:29 +0000 (18:47 -0700)
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>
net/mctp/route.c
net/mctp/test/route-test.c

index 59ad60b885631c4de4f859284bc8c0f71201f8f8..021e04f1ea7c950af4c4e21d7afbc8c98d093186 100644 (file)
@@ -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;
 }
index 75ea96c10e497e73b55e20a30934679b7e24fdeb..61c989c43ec09c9e105de4e51b295d07bb93d6da 100644 (file)
@@ -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;