Skip to content

Commit 2abb7cd

Browse files
Tom Herbertdavem330
authored andcommitted
udp: Add support for doing checksum unnecessary conversion
Add support for doing CHECKSUM_UNNECESSARY to CHECKSUM_COMPLETE conversion in UDP tunneling path. In the normal UDP path, we call skb_checksum_try_convert after locating the UDP socket. The check is that checksum conversion is enabled for the socket (new flag in UDP socket) and that checksum field is non-zero. In the UDP GRO path, we call skb_gro_checksum_try_convert after checksum is validated and checksum field is non-zero. Since this is already in GRO we assume that checksum conversion is always wanted. Signed-off-by: Tom Herbert <therbert@google.com> Signed-off-by: David S. Miller <davem@davemloft.net>
1 parent d96535a commit 2abb7cd

File tree

5 files changed

+57
-16
lines changed

5 files changed

+57
-16
lines changed

include/linux/udp.h

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,11 @@ struct udp_sock {
4949
unsigned int corkflag; /* Cork is required */
5050
__u8 encap_type; /* Is this an Encapsulation socket? */
5151
unsigned char no_check6_tx:1,/* Send zero UDP6 checksums on TX? */
52-
no_check6_rx:1;/* Allow zero UDP6 checksums on RX? */
52+
no_check6_rx:1,/* Allow zero UDP6 checksums on RX? */
53+
convert_csum:1;/* On receive, convert checksum
54+
* unnecessary to checksum complete
55+
* if possible.
56+
*/
5357
/*
5458
* Following member retains the information to create a UDP header
5559
* when the socket is uncorked.
@@ -98,6 +102,16 @@ static inline bool udp_get_no_check6_rx(struct sock *sk)
98102
return udp_sk(sk)->no_check6_rx;
99103
}
100104

105+
static inline void udp_set_convert_csum(struct sock *sk, bool val)
106+
{
107+
udp_sk(sk)->convert_csum = val;
108+
}
109+
110+
static inline bool udp_get_convert_csum(struct sock *sk)
111+
{
112+
return udp_sk(sk)->convert_csum;
113+
}
114+
101115
#define udp_portaddr_for_each_entry(__sk, node, list) \
102116
hlist_nulls_for_each_entry(__sk, node, list, __sk_common.skc_portaddr_node)
103117

net/ipv4/udp.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1788,6 +1788,10 @@ int __udp4_lib_rcv(struct sk_buff *skb, struct udp_table *udptable,
17881788
if (sk != NULL) {
17891789
int ret;
17901790

1791+
if (udp_sk(sk)->convert_csum && uh->check && !IS_UDPLITE(sk))
1792+
skb_checksum_try_convert(skb, IPPROTO_UDP, uh->check,
1793+
inet_compute_pseudo);
1794+
17911795
ret = udp_queue_rcv_skb(sk, skb);
17921796
sock_put(sk);
17931797

net/ipv4/udp_offload.c

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -290,16 +290,25 @@ static struct sk_buff **udp4_gro_receive(struct sk_buff **head,
290290
{
291291
struct udphdr *uh = udp_gro_udphdr(skb);
292292

293-
/* Don't bother verifying checksum if we're going to flush anyway. */
294-
if (unlikely(!uh) ||
295-
(!NAPI_GRO_CB(skb)->flush &&
296-
skb_gro_checksum_validate_zero_check(skb, IPPROTO_UDP, uh->check,
297-
inet_gro_compute_pseudo))) {
298-
NAPI_GRO_CB(skb)->flush = 1;
299-
return NULL;
300-
}
293+
if (unlikely(!uh))
294+
goto flush;
301295

296+
/* Don't bother verifying checksum if we're going to flush anyway. */
297+
if (!NAPI_GRO_CB(skb)->flush)
298+
goto skip;
299+
300+
if (skb_gro_checksum_validate_zero_check(skb, IPPROTO_UDP, uh->check,
301+
inet_gro_compute_pseudo))
302+
goto flush;
303+
else if (uh->check)
304+
skb_gro_checksum_try_convert(skb, IPPROTO_UDP, uh->check,
305+
inet_gro_compute_pseudo);
306+
skip:
302307
return udp_gro_receive(head, skb, uh);
308+
309+
flush:
310+
NAPI_GRO_CB(skb)->flush = 1;
311+
return NULL;
303312
}
304313

305314
int udp_gro_complete(struct sk_buff *skb, int nhoff)

net/ipv6/udp.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -891,6 +891,10 @@ int __udp6_lib_rcv(struct sk_buff *skb, struct udp_table *udptable,
891891
goto csum_error;
892892
}
893893

894+
if (udp_sk(sk)->convert_csum && uh->check && !IS_UDPLITE(sk))
895+
skb_checksum_try_convert(skb, IPPROTO_UDP, uh->check,
896+
ip6_compute_pseudo);
897+
894898
ret = udpv6_queue_rcv_skb(sk, skb);
895899
sock_put(sk);
896900

net/ipv6/udp_offload.c

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -134,16 +134,26 @@ static struct sk_buff **udp6_gro_receive(struct sk_buff **head,
134134
{
135135
struct udphdr *uh = udp_gro_udphdr(skb);
136136

137+
if (unlikely(!uh))
138+
goto flush;
139+
137140
/* Don't bother verifying checksum if we're going to flush anyway. */
138-
if (unlikely(!uh) ||
139-
(!NAPI_GRO_CB(skb)->flush &&
140-
skb_gro_checksum_validate_zero_check(skb, IPPROTO_UDP, uh->check,
141-
ip6_gro_compute_pseudo))) {
142-
NAPI_GRO_CB(skb)->flush = 1;
143-
return NULL;
144-
}
141+
if (!NAPI_GRO_CB(skb)->flush)
142+
goto skip;
145143

144+
if (skb_gro_checksum_validate_zero_check(skb, IPPROTO_UDP, uh->check,
145+
ip6_gro_compute_pseudo))
146+
goto flush;
147+
else if (uh->check)
148+
skb_gro_checksum_try_convert(skb, IPPROTO_UDP, uh->check,
149+
ip6_gro_compute_pseudo);
150+
151+
skip:
146152
return udp_gro_receive(head, skb, uh);
153+
154+
flush:
155+
NAPI_GRO_CB(skb)->flush = 1;
156+
return NULL;
147157
}
148158

149159
int udp6_gro_complete(struct sk_buff *skb, int nhoff)

0 commit comments

Comments
 (0)