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.

udp: Remove partial csum code in RX.

UDP-Lite supports the partial checksum and the coverage is
stored in the position of the length field of struct udphdr.

In RX paths, udp4_csum_init() / udp6_csum_init() save the value
in UDP_SKB_CB(skb)->cscov and set UDP_SKB_CB(skb)->partial_cov
to 1 if the coverage is not full.

The subsequent processing diverges depending on the value,
but such paths are now dead.

Also, these functions have some code guarded for UDP:

* udp_unicast_rcv_skb / udp6_unicast_rcv_skb
* __udp4_lib_rcv() and __udp6_lib_rcv().

Let's remove the partial csum code and the unnecessary
guard for UDP-Lite in RX.

Signed-off-by: Kuniyuki Iwashima <kuniyu@google.com>
Reviewed-by: Willem de Bruijn <willemb@google.com>
Link: https://patch.msgid.link/20260311052020.1213705-8-kuniyu@google.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>

authored by

Kuniyuki Iwashima and committed by
Jakub Kicinski
c2539d4f b972cb5d

+39 -179
+3 -14
include/net/udp.h
··· 32 32 #include <linux/math.h> 33 33 34 34 /** 35 - * struct udp_skb_cb - UDP(-Lite) private variables 35 + * struct udp_skb_cb - UDP private variables 36 36 * 37 37 * @header: private variables used by IPv4/IPv6 38 - * @cscov: checksum coverage length (UDP-Lite only) 39 - * @partial_cov: if set indicates partial csum coverage 40 38 */ 41 39 struct udp_skb_cb { 42 40 union { ··· 43 45 struct inet6_skb_parm h6; 44 46 #endif 45 47 } header; 46 - __u16 cscov; 47 - __u8 partial_cov; 48 48 }; 49 49 #define UDP_SKB_CB(__skb) ((struct udp_skb_cb *)((__skb)->cb)) 50 50 ··· 212 216 struct sk_buff; 213 217 214 218 /* 215 - * Generic checksumming routines for UDP(-Lite) v4 and v6 219 + * Generic checksumming routines for UDP v4 and v6 216 220 */ 217 221 static inline __sum16 __udp_lib_checksum_complete(struct sk_buff *skb) 218 222 { 219 - return (UDP_SKB_CB(skb)->cscov == skb->len ? 220 - __skb_checksum_complete(skb) : 221 - __skb_checksum_complete_head(skb, UDP_SKB_CB(skb)->cscov)); 223 + return __skb_checksum_complete(skb); 222 224 } 223 225 224 226 static inline int udp_lib_checksum_complete(struct sk_buff *skb) ··· 267 273 skb->csum = csum_partial(skb->data, sizeof(struct udphdr), 268 274 skb->csum); 269 275 skb_pull_rcsum(skb, sizeof(struct udphdr)); 270 - UDP_SKB_CB(skb)->cscov -= sizeof(struct udphdr); 271 276 } 272 277 273 278 typedef struct sock *(*udp_lookup_t)(const struct sk_buff *skb, __be16 sport, ··· 634 641 635 642 static inline void udp_post_segment_fix_csum(struct sk_buff *skb) 636 643 { 637 - /* UDP-lite can't land here - no GRO */ 638 - WARN_ON_ONCE(UDP_SKB_CB(skb)->partial_cov); 639 - 640 644 /* UDP packets generated with UDP_SEGMENT and traversing: 641 645 * 642 646 * UDP tunnel(xmit) -> veth (segmentation) -> veth (gro) -> UDP tunnel (rx) ··· 647 657 * a valid csum after the segmentation. 648 658 * Additionally fixup the UDP CB. 649 659 */ 650 - UDP_SKB_CB(skb)->cscov = skb->len; 651 660 if (skb->ip_summed == CHECKSUM_NONE && !skb->csum_valid) 652 661 skb->csum_valid = 1; 653 662 }
-34
include/net/udplite.h
··· 25 25 /* 26 26 * Checksumming routines 27 27 */ 28 - static inline int udplite_checksum_init(struct sk_buff *skb, struct udphdr *uh) 29 - { 30 - u16 cscov; 31 - 32 - /* In UDPv4 a zero checksum means that the transmitter generated no 33 - * checksum. UDP-Lite (like IPv6) mandates checksums, hence packets 34 - * with a zero checksum field are illegal. */ 35 - if (uh->check == 0) { 36 - net_dbg_ratelimited("UDPLite: zeroed checksum field\n"); 37 - return 1; 38 - } 39 - 40 - cscov = ntohs(uh->len); 41 - 42 - if (cscov == 0) /* Indicates that full coverage is required. */ 43 - ; 44 - else if (cscov < 8 || cscov > skb->len) { 45 - /* 46 - * Coverage length violates RFC 3828: log and discard silently. 47 - */ 48 - net_dbg_ratelimited("UDPLite: bad csum coverage %d/%d\n", 49 - cscov, skb->len); 50 - return 1; 51 - 52 - } else if (cscov < skb->len) { 53 - UDP_SKB_CB(skb)->partial_cov = 1; 54 - UDP_SKB_CB(skb)->cscov = cscov; 55 - if (skb->ip_summed == CHECKSUM_COMPLETE) 56 - skb->ip_summed = CHECKSUM_NONE; 57 - skb->csum_valid = 0; 58 - } 59 - 60 - return 0; 61 - } 62 28 63 29 /* Fast-path computation of checksum. Socket may not be locked. */ 64 30 static inline __wsum udplite_csum(struct sk_buff *skb)
+16 -69
net/ipv4/udp.c
··· 2072 2072 INDIRECT_CALLABLE_SCOPE 2073 2073 int udp_recvmsg(struct sock *sk, struct msghdr *msg, size_t len, int flags) 2074 2074 { 2075 - struct inet_sock *inet = inet_sk(sk); 2076 2075 DECLARE_SOCKADDR(struct sockaddr_in *, sin, msg->msg_name); 2077 - struct sk_buff *skb; 2078 - unsigned int ulen, copied; 2079 2076 int off, err, peeking = flags & MSG_PEEK; 2080 - int is_udplite = IS_UDPLITE(sk); 2077 + struct inet_sock *inet = inet_sk(sk); 2081 2078 struct net *net = sock_net(sk); 2082 2079 bool checksum_valid = false; 2080 + unsigned int ulen, copied; 2081 + struct sk_buff *skb; 2083 2082 2084 2083 if (flags & MSG_ERRQUEUE) 2085 2084 return ip_recv_error(sk, msg, len); ··· 2096 2097 else if (copied < ulen) 2097 2098 msg->msg_flags |= MSG_TRUNC; 2098 2099 2099 - /* 2100 - * If checksum is needed at all, try to do it while copying the 2101 - * data. If the data is truncated, or if we only want a partial 2102 - * coverage checksum (UDP-Lite), do it before the copy. 2100 + /* If checksum is needed at all, try to do it while copying the 2101 + * data. If the data is truncated, do it before the copy. 2103 2102 */ 2104 - 2105 - if (copied < ulen || peeking || 2106 - (is_udplite && UDP_SKB_CB(skb)->partial_cov)) { 2103 + if (copied < ulen || peeking) { 2107 2104 checksum_valid = udp_skb_csum_unnecessary(skb) || 2108 2105 !__udp_lib_checksum_complete(skb); 2109 2106 if (!checksum_valid) ··· 2439 2444 /* FALLTHROUGH -- it's a UDP Packet */ 2440 2445 } 2441 2446 2442 - /* 2443 - * UDP-Lite specific tests, ignored on UDP sockets 2444 - */ 2445 - if (unlikely(udp_test_bit(UDPLITE_RECV_CC, sk) && 2446 - UDP_SKB_CB(skb)->partial_cov)) { 2447 - u16 pcrlen = READ_ONCE(up->pcrlen); 2448 - 2449 - /* 2450 - * MIB statistics other than incrementing the error count are 2451 - * disabled for the following two types of errors: these depend 2452 - * on the application settings, not on the functioning of the 2453 - * protocol stack as such. 2454 - * 2455 - * RFC 3828 here recommends (sec 3.3): "There should also be a 2456 - * way ... to ... at least let the receiving application block 2457 - * delivery of packets with coverage values less than a value 2458 - * provided by the application." 2459 - */ 2460 - if (pcrlen == 0) { /* full coverage was set */ 2461 - net_dbg_ratelimited("UDPLite: partial coverage %d while full coverage %d requested\n", 2462 - UDP_SKB_CB(skb)->cscov, skb->len); 2463 - goto drop; 2464 - } 2465 - /* The next case involves violating the min. coverage requested 2466 - * by the receiver. This is subtle: if receiver wants x and x is 2467 - * greater than the buffersize/MTU then receiver will complain 2468 - * that it wants x while sender emits packets of smaller size y. 2469 - * Therefore the above ...()->partial_cov statement is essential. 2470 - */ 2471 - if (UDP_SKB_CB(skb)->cscov < pcrlen) { 2472 - net_dbg_ratelimited("UDPLite: coverage %d too small, need min %d\n", 2473 - UDP_SKB_CB(skb)->cscov, pcrlen); 2474 - goto drop; 2475 - } 2476 - } 2477 - 2478 2447 prefetch(&sk->sk_rmem_alloc); 2479 2448 if (rcu_access_pointer(sk->sk_filter) && 2480 2449 udp_lib_checksum_complete(skb)) ··· 2572 2613 * Otherwise, csum completion requires checksumming packet body, 2573 2614 * including udp header and folding it to skb->csum. 2574 2615 */ 2575 - static inline int udp4_csum_init(struct sk_buff *skb, struct udphdr *uh, 2576 - int proto) 2616 + static inline int udp4_csum_init(struct sk_buff *skb, struct udphdr *uh) 2577 2617 { 2578 2618 int err; 2579 - 2580 - UDP_SKB_CB(skb)->partial_cov = 0; 2581 - UDP_SKB_CB(skb)->cscov = skb->len; 2582 - 2583 - if (proto == IPPROTO_UDPLITE) { 2584 - err = udplite_checksum_init(skb, uh); 2585 - if (err) 2586 - return err; 2587 - 2588 - if (UDP_SKB_CB(skb)->partial_cov) { 2589 - skb->csum = inet_compute_pseudo(skb, proto); 2590 - return 0; 2591 - } 2592 - } 2593 2619 2594 2620 /* Note, we are only interested in != 0 or == 0, thus the 2595 2621 * force to int. 2596 2622 */ 2597 - err = (__force int)skb_checksum_init_zero_check(skb, proto, uh->check, 2623 + err = (__force int)skb_checksum_init_zero_check(skb, IPPROTO_UDP, uh->check, 2598 2624 inet_compute_pseudo); 2599 2625 if (err) 2600 2626 return err; ··· 2607 2663 { 2608 2664 int ret; 2609 2665 2610 - if (inet_get_convert_csum(sk) && uh->check && !IS_UDPLITE(sk)) 2666 + if (inet_get_convert_csum(sk) && uh->check) 2611 2667 skb_checksum_try_convert(skb, IPPROTO_UDP, inet_compute_pseudo); 2612 2668 2613 2669 ret = udp_queue_rcv_skb(sk, skb); ··· 2652 2708 if (ulen > skb->len) 2653 2709 goto short_packet; 2654 2710 2655 - if (proto == IPPROTO_UDP) { 2656 - /* UDP validates ulen. */ 2657 - if (ulen < sizeof(*uh) || pskb_trim_rcsum(skb, ulen)) 2711 + if (ulen < sizeof(*uh)) 2712 + goto short_packet; 2713 + 2714 + if (ulen < skb->len) { 2715 + if (pskb_trim_rcsum(skb, ulen)) 2658 2716 goto short_packet; 2717 + 2659 2718 uh = udp_hdr(skb); 2660 2719 } 2661 2720 2662 - if (udp4_csum_init(skb, uh, proto)) 2721 + if (udp4_csum_init(skb, uh)) 2663 2722 goto csum_error; 2664 2723 2665 2724 sk = inet_steal_sock(net, skb, sizeof(struct udphdr), saddr, uh->source, daddr, uh->dest,
+20 -62
net/ipv6/udp.c
··· 469 469 int udpv6_recvmsg(struct sock *sk, struct msghdr *msg, size_t len, 470 470 int flags) 471 471 { 472 + int off, is_udp4, err, peeking = flags & MSG_PEEK; 472 473 struct ipv6_pinfo *np = inet6_sk(sk); 473 474 struct inet_sock *inet = inet_sk(sk); 474 - struct sk_buff *skb; 475 - unsigned int ulen, copied; 476 - int off, err, peeking = flags & MSG_PEEK; 477 - int is_udplite = IS_UDPLITE(sk); 478 475 struct udp_mib __percpu *mib; 479 476 bool checksum_valid = false; 480 - int is_udp4; 477 + unsigned int ulen, copied; 478 + struct sk_buff *skb; 481 479 482 480 if (flags & MSG_ERRQUEUE) 483 481 return ipv6_recv_error(sk, msg, len); ··· 499 501 is_udp4 = (skb->protocol == htons(ETH_P_IP)); 500 502 mib = __UDPX_MIB(sk, is_udp4); 501 503 502 - /* 503 - * If checksum is needed at all, try to do it while copying the 504 - * data. If the data is truncated, or if we only want a partial 505 - * coverage checksum (UDP-Lite), do it before the copy. 504 + /* If checksum is needed at all, try to do it while copying the 505 + * data. If the data is truncated, do it before the copy. 506 506 */ 507 - 508 - if (copied < ulen || peeking || 509 - (is_udplite && UDP_SKB_CB(skb)->partial_cov)) { 507 + if (copied < ulen || peeking) { 510 508 checksum_valid = udp_skb_csum_unnecessary(skb) || 511 509 !__udp_lib_checksum_complete(skb); 512 510 if (!checksum_valid) ··· 864 870 /* FALLTHROUGH -- it's a UDP Packet */ 865 871 } 866 872 867 - /* 868 - * UDP-Lite specific tests, ignored on UDP sockets (see net/ipv4/udp.c). 869 - */ 870 - if (unlikely(udp_test_bit(UDPLITE_RECV_CC, sk) && 871 - UDP_SKB_CB(skb)->partial_cov)) { 872 - u16 pcrlen = READ_ONCE(up->pcrlen); 873 - 874 - if (pcrlen == 0) { /* full coverage was set */ 875 - net_dbg_ratelimited("UDPLITE6: partial coverage %d while full coverage %d requested\n", 876 - UDP_SKB_CB(skb)->cscov, skb->len); 877 - goto drop; 878 - } 879 - if (UDP_SKB_CB(skb)->cscov < pcrlen) { 880 - net_dbg_ratelimited("UDPLITE6: coverage %d too small, need min %d\n", 881 - UDP_SKB_CB(skb)->cscov, pcrlen); 882 - goto drop; 883 - } 884 - } 885 - 886 873 prefetch(&sk->sk_rmem_alloc); 887 874 if (rcu_access_pointer(sk->sk_filter) && 888 875 udp_lib_checksum_complete(skb)) ··· 1028 1053 { 1029 1054 int ret; 1030 1055 1031 - if (inet_get_convert_csum(sk) && uh->check && !IS_UDPLITE(sk)) 1056 + if (inet_get_convert_csum(sk) && uh->check) 1032 1057 skb_checksum_try_convert(skb, IPPROTO_UDP, ip6_compute_pseudo); 1033 1058 1034 1059 ret = udpv6_queue_rcv_skb(sk, skb); ··· 1039 1064 return 0; 1040 1065 } 1041 1066 1042 - static int udp6_csum_init(struct sk_buff *skb, struct udphdr *uh, int proto) 1067 + static int udp6_csum_init(struct sk_buff *skb, struct udphdr *uh) 1043 1068 { 1044 1069 int err; 1045 - 1046 - UDP_SKB_CB(skb)->partial_cov = 0; 1047 - UDP_SKB_CB(skb)->cscov = skb->len; 1048 - 1049 - if (proto == IPPROTO_UDPLITE) { 1050 - err = udplite_checksum_init(skb, uh); 1051 - if (err) 1052 - return err; 1053 - 1054 - if (UDP_SKB_CB(skb)->partial_cov) { 1055 - skb->csum = ip6_compute_pseudo(skb, proto); 1056 - return 0; 1057 - } 1058 - } 1059 1070 1060 1071 /* To support RFC 6936 (allow zero checksum in UDP/IPV6 for tunnels) 1061 1072 * we accept a checksum of zero here. When we find the socket ··· 1051 1090 * Note, we are only interested in != 0 or == 0, thus the 1052 1091 * force to int. 1053 1092 */ 1054 - err = (__force int)skb_checksum_init_zero_check(skb, proto, uh->check, 1093 + err = (__force int)skb_checksum_init_zero_check(skb, IPPROTO_UDP, uh->check, 1055 1094 ip6_compute_pseudo); 1056 1095 if (err) 1057 1096 return err; ··· 1093 1132 if (ulen > skb->len) 1094 1133 goto short_packet; 1095 1134 1096 - if (proto == IPPROTO_UDP) { 1097 - /* UDP validates ulen. */ 1135 + /* Check for jumbo payload */ 1136 + if (ulen == 0) 1137 + ulen = skb->len; 1098 1138 1099 - /* Check for jumbo payload */ 1100 - if (ulen == 0) 1101 - ulen = skb->len; 1139 + if (ulen < sizeof(*uh)) 1140 + goto short_packet; 1102 1141 1103 - if (ulen < sizeof(*uh)) 1142 + if (ulen < skb->len) { 1143 + if (pskb_trim_rcsum(skb, ulen)) 1104 1144 goto short_packet; 1105 1145 1106 - if (ulen < skb->len) { 1107 - if (pskb_trim_rcsum(skb, ulen)) 1108 - goto short_packet; 1109 - saddr = &ipv6_hdr(skb)->saddr; 1110 - daddr = &ipv6_hdr(skb)->daddr; 1111 - uh = udp_hdr(skb); 1112 - } 1146 + saddr = &ipv6_hdr(skb)->saddr; 1147 + daddr = &ipv6_hdr(skb)->daddr; 1148 + uh = udp_hdr(skb); 1113 1149 } 1114 1150 1115 - if (udp6_csum_init(skb, uh, proto)) 1151 + if (udp6_csum_init(skb, uh)) 1116 1152 goto csum_error; 1117 1153 1118 1154 /* Check if the socket is already available, e.g. due to early demux */