Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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>

authored by

Jeremy Kerr and committed by
Jakub Kicinski
e1877cf6 2b8e147c

+15 -15
+11 -15
net/mctp/route.c
··· 1037 1037 return -EMSGSIZE; 1038 1038 } 1039 1039 1040 + /* within MTU? avoid the copy, send original skb */ 1041 + if (skb->len <= mtu) { 1042 + hdr->flags_seq_tag = MCTP_HDR_FLAG_SOM | 1043 + MCTP_HDR_FLAG_EOM | tag; 1044 + return dst->output(dst, skb); 1045 + } 1046 + 1040 1047 /* keep same headroom as the original skb */ 1041 1048 headroom = skb_headroom(skb); 1042 1049 ··· 1118 1111 struct mctp_hdr *hdr; 1119 1112 unsigned long flags; 1120 1113 unsigned int netid; 1121 - unsigned int mtu; 1122 1114 mctp_eid_t saddr; 1123 1115 int rc; 1124 1116 u8 tag; ··· 1139 1133 netid = READ_ONCE(dst->dev->net); 1140 1134 1141 1135 if (rc) 1142 - goto out_release; 1136 + goto err_free; 1143 1137 1144 1138 if (req_tag & MCTP_TAG_OWNER) { 1145 1139 if (req_tag & MCTP_TAG_PREALLOC) ··· 1151 1145 1152 1146 if (IS_ERR(key)) { 1153 1147 rc = PTR_ERR(key); 1154 - goto out_release; 1148 + goto err_free; 1155 1149 } 1156 1150 mctp_skb_set_flow(skb, key); 1157 1151 /* done with the key in this scope */ ··· 1176 1170 hdr->dest = daddr; 1177 1171 hdr->src = saddr; 1178 1172 1179 - mtu = dst->mtu; 1180 - 1181 - if (skb->len + sizeof(struct mctp_hdr) <= mtu) { 1182 - hdr->flags_seq_tag = MCTP_HDR_FLAG_SOM | 1183 - MCTP_HDR_FLAG_EOM | tag; 1184 - rc = dst->output(dst, skb); 1185 - } else { 1186 - rc = mctp_do_fragment_route(dst, skb, mtu, tag); 1187 - } 1188 - 1189 1173 /* route output functions consume the skb, even on error */ 1190 - skb = NULL; 1174 + return mctp_do_fragment_route(dst, skb, dst->mtu, tag); 1191 1175 1192 - out_release: 1176 + err_free: 1193 1177 kfree_skb(skb); 1194 1178 return rc; 1195 1179 }
+4
net/mctp/test/route-test.c
··· 63 63 if (!skb2) 64 64 break; 65 65 66 + /* avoid copying single-skb messages */ 67 + if (first && last) 68 + KUNIT_EXPECT_PTR_EQ(test, skb, skb2); 69 + 66 70 hdr2 = mctp_hdr(skb2); 67 71 68 72 tag_mask = MCTP_HDR_TAG_MASK | MCTP_HDR_FLAG_TO;