Commit db2dede2 authored by Jakub Kicinski's avatar Jakub Kicinski

Merge branch 'lift-udp_segment-restriction-for-egress-via-device-w-o-csum-offload'

Jakub Sitnicki says:

====================
Lift UDP_SEGMENT restriction for egress via device w/o csum offload

This is a follow-up to an earlier question [1] if we can make UDP GSO work
with any egress device, even those with no checksum offload capability.
That's the default setup for TUN/TAP.

Because there is a change in behavior - sendmsg() does no longer return
EIO error - I'm submitting through net-next tree, rather than net,
as per Willem's advice.

[1] https://lore.kernel.org/netdev/87jzqsld6q.fsf@cloudflare.com/

v1: https://lore.kernel.org/r/20240622-linux-udpgso-v1-0-d2344157ab2a@cloudflare.com
====================

Link: https://patch.msgid.link/20240626-linux-udpgso-v2-0-422dfcbd6b48@cloudflare.comSigned-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parents 748e3bbf 3e400219
......@@ -938,8 +938,7 @@ static int udp_send_skb(struct sk_buff *skb, struct flowi4 *fl4,
kfree_skb(skb);
return -EINVAL;
}
if (skb->ip_summed != CHECKSUM_PARTIAL || is_udplite ||
dst_xfrm(skb_dst(skb))) {
if (is_udplite || dst_xfrm(skb_dst(skb))) {
kfree_skb(skb);
return -EIO;
}
......
......@@ -357,6 +357,14 @@ struct sk_buff *__udp_gso_segment(struct sk_buff *gso_skb,
else
uh->check = gso_make_checksum(seg, ~check) ? : CSUM_MANGLED_0;
/* On the TX path, CHECKSUM_NONE and CHECKSUM_UNNECESSARY have the same
* meaning. However, check for bad offloads in the GSO stack expects the
* latter, if the checksum was calculated in software. To vouch for the
* segment skbs we actually need to set it on the gso_skb.
*/
if (gso_skb->ip_summed == CHECKSUM_NONE)
gso_skb->ip_summed = CHECKSUM_UNNECESSARY;
/* update refcount for the packet */
if (copy_dtor) {
int delta = sum_truesize - gso_skb->truesize;
......
......@@ -1257,8 +1257,7 @@ static int udp_v6_send_skb(struct sk_buff *skb, struct flowi6 *fl6,
kfree_skb(skb);
return -EINVAL;
}
if (skb->ip_summed != CHECKSUM_PARTIAL || is_udplite ||
dst_xfrm(skb_dst(skb))) {
if (is_udplite || dst_xfrm(skb_dst(skb))) {
kfree_skb(skb);
return -EIO;
}
......
......@@ -53,6 +53,7 @@ static bool cfg_do_ipv6;
static bool cfg_do_connected;
static bool cfg_do_connectionless;
static bool cfg_do_msgmore;
static bool cfg_do_recv = true;
static bool cfg_do_setsockopt;
static int cfg_specific_test_id = -1;
......@@ -414,6 +415,9 @@ static void run_one(struct testcase *test, int fdt, int fdr,
if (!sent)
return;
if (!cfg_do_recv)
return;
if (test->gso_len)
mss = test->gso_len;
else
......@@ -464,8 +468,10 @@ static void run_test(struct sockaddr *addr, socklen_t alen)
if (fdr == -1)
error(1, errno, "socket r");
if (bind(fdr, addr, alen))
error(1, errno, "bind");
if (cfg_do_recv) {
if (bind(fdr, addr, alen))
error(1, errno, "bind");
}
/* Have tests fail quickly instead of hang */
if (setsockopt(fdr, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)))
......@@ -524,7 +530,7 @@ static void parse_opts(int argc, char **argv)
{
int c;
while ((c = getopt(argc, argv, "46cCmst:")) != -1) {
while ((c = getopt(argc, argv, "46cCmRst:")) != -1) {
switch (c) {
case '4':
cfg_do_ipv4 = true;
......@@ -541,6 +547,9 @@ static void parse_opts(int argc, char **argv)
case 'm':
cfg_do_msgmore = true;
break;
case 'R':
cfg_do_recv = false;
break;
case 's':
cfg_do_setsockopt = true;
break;
......
......@@ -27,6 +27,31 @@ test_route_mtu() {
ip route add local fd00::1/128 table local dev lo mtu 1500
}
setup_dummy_sink() {
ip link add name sink mtu 1500 type dummy
ip addr add dev sink 10.0.0.0/24
ip addr add dev sink fd00::2/64 nodad
ip link set dev sink up
}
test_hw_gso_hw_csum() {
setup_dummy_sink
ethtool -K sink tx-checksum-ip-generic on >/dev/null
ethtool -K sink tx-udp-segmentation on >/dev/null
}
test_sw_gso_hw_csum() {
setup_dummy_sink
ethtool -K sink tx-checksum-ip-generic on >/dev/null
ethtool -K sink tx-udp-segmentation off >/dev/null
}
test_sw_gso_sw_csum() {
setup_dummy_sink
ethtool -K sink tx-checksum-ip-generic off >/dev/null
ethtool -K sink tx-udp-segmentation off >/dev/null
}
if [ "$#" -gt 0 ]; then
"$1"
shift 2 # pop "test_*" arg and "--" delimiter
......@@ -56,3 +81,21 @@ echo "ipv4 msg_more"
echo "ipv6 msg_more"
./in_netns.sh "$0" test_dev_mtu -- ./udpgso -6 -C -m
echo "ipv4 hw-gso hw-csum"
./in_netns.sh "$0" test_hw_gso_hw_csum -- ./udpgso -4 -C -R
echo "ipv6 hw-gso hw-csum"
./in_netns.sh "$0" test_hw_gso_hw_csum -- ./udpgso -6 -C -R
echo "ipv4 sw-gso hw-csum"
./in_netns.sh "$0" test_sw_gso_hw_csum -- ./udpgso -4 -C -R
echo "ipv6 sw-gso hw-csum"
./in_netns.sh "$0" test_sw_gso_hw_csum -- ./udpgso -6 -C -R
echo "ipv4 sw-gso sw-csum"
./in_netns.sh "$0" test_sw_gso_sw_csum -- ./udpgso -4 -C -R
echo "ipv6 sw-gso sw-csum"
./in_netns.sh "$0" test_sw_gso_sw_csum -- ./udpgso -6 -C -R
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment