Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 2abb7cdc authored by Tom Herbert's avatar Tom Herbert Committed by David S. Miller
Browse files

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: default avatarTom Herbert <therbert@google.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent d96535a1
Loading
Loading
Loading
Loading
+15 −1
Original line number Diff line number Diff line
@@ -49,7 +49,11 @@ struct udp_sock {
	unsigned int	 corkflag;	/* Cork is required */
	__u8		 encap_type;	/* Is this an Encapsulation socket? */
	unsigned char	 no_check6_tx:1,/* Send zero UDP6 checksums on TX? */
			 no_check6_rx:1;/* Allow zero UDP6 checksums on RX? */
			 no_check6_rx:1,/* Allow zero UDP6 checksums on RX? */
			 convert_csum:1;/* On receive, convert checksum
					 * unnecessary to checksum complete
					 * if possible.
					 */
	/*
	 * Following member retains the information to create a UDP header
	 * when the socket is uncorked.
@@ -98,6 +102,16 @@ static inline bool udp_get_no_check6_rx(struct sock *sk)
	return udp_sk(sk)->no_check6_rx;
}

static inline void udp_set_convert_csum(struct sock *sk, bool val)
{
	udp_sk(sk)->convert_csum = val;
}

static inline bool udp_get_convert_csum(struct sock *sk)
{
	return udp_sk(sk)->convert_csum;
}

#define udp_portaddr_for_each_entry(__sk, node, list) \
	hlist_nulls_for_each_entry(__sk, node, list, __sk_common.skc_portaddr_node)

+4 −0
Original line number Diff line number Diff line
@@ -1788,6 +1788,10 @@ int __udp4_lib_rcv(struct sk_buff *skb, struct udp_table *udptable,
	if (sk != NULL) {
		int ret;

		if (udp_sk(sk)->convert_csum && uh->check && !IS_UDPLITE(sk))
			skb_checksum_try_convert(skb, IPPROTO_UDP, uh->check,
						 inet_compute_pseudo);

		ret = udp_queue_rcv_skb(sk, skb);
		sock_put(sk);

+17 −8
Original line number Diff line number Diff line
@@ -290,18 +290,27 @@ static struct sk_buff **udp4_gro_receive(struct sk_buff **head,
{
	struct udphdr *uh = udp_gro_udphdr(skb);

	if (unlikely(!uh))
		goto flush;

	/* Don't bother verifying checksum if we're going to flush anyway. */
	if (unlikely(!uh) ||
	    (!NAPI_GRO_CB(skb)->flush &&
	     skb_gro_checksum_validate_zero_check(skb, IPPROTO_UDP, uh->check,
						  inet_gro_compute_pseudo))) {
	if (!NAPI_GRO_CB(skb)->flush)
		goto skip;

	if (skb_gro_checksum_validate_zero_check(skb, IPPROTO_UDP, uh->check,
						 inet_gro_compute_pseudo))
		goto flush;
	else if (uh->check)
		skb_gro_checksum_try_convert(skb, IPPROTO_UDP, uh->check,
					     inet_gro_compute_pseudo);
skip:
	return udp_gro_receive(head, skb, uh);

flush:
	NAPI_GRO_CB(skb)->flush = 1;
	return NULL;
}

	return udp_gro_receive(head, skb, uh);
}

int udp_gro_complete(struct sk_buff *skb, int nhoff)
{
	struct udp_offload_priv *uo_priv;
+4 −0
Original line number Diff line number Diff line
@@ -891,6 +891,10 @@ int __udp6_lib_rcv(struct sk_buff *skb, struct udp_table *udptable,
			goto csum_error;
		}

		if (udp_sk(sk)->convert_csum && uh->check && !IS_UDPLITE(sk))
			skb_checksum_try_convert(skb, IPPROTO_UDP, uh->check,
						 ip6_compute_pseudo);

		ret = udpv6_queue_rcv_skb(sk, skb);
		sock_put(sk);

+17 −7
Original line number Diff line number Diff line
@@ -134,16 +134,26 @@ static struct sk_buff **udp6_gro_receive(struct sk_buff **head,
{
	struct udphdr *uh = udp_gro_udphdr(skb);

	if (unlikely(!uh))
		goto flush;

	/* Don't bother verifying checksum if we're going to flush anyway. */
	if (unlikely(!uh) ||
	    (!NAPI_GRO_CB(skb)->flush &&
	     skb_gro_checksum_validate_zero_check(skb, IPPROTO_UDP, uh->check,
						  ip6_gro_compute_pseudo))) {
		NAPI_GRO_CB(skb)->flush = 1;
		return NULL;
	}
	if (!NAPI_GRO_CB(skb)->flush)
		goto skip;

	if (skb_gro_checksum_validate_zero_check(skb, IPPROTO_UDP, uh->check,
						 ip6_gro_compute_pseudo))
		goto flush;
	else if (uh->check)
		skb_gro_checksum_try_convert(skb, IPPROTO_UDP, uh->check,
					     ip6_gro_compute_pseudo);

skip:
	return udp_gro_receive(head, skb, uh);

flush:
	NAPI_GRO_CB(skb)->flush = 1;
	return NULL;
}

int udp6_gro_complete(struct sk_buff *skb, int nhoff)