Commit 221ddb72 authored by Steffen Klassert's avatar Steffen Klassert
Browse files

xfrm: Support GRO for IPv6 ESP in UDP encapsulation



This patch enables the GRO codepath for IPv6 ESP in UDP encapsulated
packets. Decapsulation happens at L2 and saves a full round through
the stack for each packet. This is also needed to support HW offload
for ESP in UDP encapsulation.

Signed-off-by: default avatarSteffen Klassert <steffen.klassert@secunet.com>
Co-developed-by: default avatarAntony Antony <antony.antony@secunet.com>
Signed-off-by: default avatarAntony Antony <antony.antony@secunet.com>
Reviewed-by: default avatarEyal Birger <eyal.birger@gmail.com>
parent 172bf009
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -60,6 +60,9 @@ struct ipv6_stub {
#if IS_ENABLED(CONFIG_XFRM)
	void (*xfrm6_local_rxpmtu)(struct sk_buff *skb, u32 mtu);
	int (*xfrm6_udp_encap_rcv)(struct sock *sk, struct sk_buff *skb);
	struct sk_buff *(*xfrm6_gro_udp_encap_rcv)(struct sock *sk,
						   struct list_head *head,
						   struct sk_buff *skb);
	int (*xfrm6_rcv_encap)(struct sk_buff *skb, int nexthdr, __be32 spi,
			       int encap_type);
#endif
+2 −0
Original line number Diff line number Diff line
@@ -1712,6 +1712,8 @@ int xfrm4_udp_encap_rcv(struct sock *sk, struct sk_buff *skb);
int xfrm6_udp_encap_rcv(struct sock *sk, struct sk_buff *skb);
struct sk_buff *xfrm4_gro_udp_encap_rcv(struct sock *sk, struct list_head *head,
					struct sk_buff *skb);
struct sk_buff *xfrm6_gro_udp_encap_rcv(struct sock *sk, struct list_head *head,
					struct sk_buff *skb);
int xfrm_user_policy(struct sock *sk, int optname, sockptr_t optval,
		     int optlen);
#else
+2 −0
Original line number Diff line number Diff line
@@ -2632,6 +2632,8 @@ static void set_xfrm_gro_udp_encap_rcv(__u16 encap_type, unsigned short family,
	if (udp_test_bit(GRO_ENABLED, sk) && encap_type == UDP_ENCAP_ESPINUDP) {
		if (family == AF_INET)
			WRITE_ONCE(udp_sk(sk)->gro_receive, xfrm4_gro_udp_encap_rcv);
		else if (IS_ENABLED(CONFIG_IPV6) && family == AF_INET6)
			WRITE_ONCE(udp_sk(sk)->gro_receive, ipv6_stub->xfrm6_gro_udp_encap_rcv);
	}
#endif
}
+1 −0
Original line number Diff line number Diff line
@@ -1049,6 +1049,7 @@ static const struct ipv6_stub ipv6_stub_impl = {
#if IS_ENABLED(CONFIG_XFRM)
	.xfrm6_local_rxpmtu = xfrm6_local_rxpmtu,
	.xfrm6_udp_encap_rcv = xfrm6_udp_encap_rcv,
	.xfrm6_gro_udp_encap_rcv = xfrm6_gro_udp_encap_rcv,
	.xfrm6_rcv_encap = xfrm6_rcv_encap,
#endif
	.nd_tbl	= &nd_tbl,
+8 −2
Original line number Diff line number Diff line
@@ -34,7 +34,9 @@ static __u16 esp6_nexthdr_esp_offset(struct ipv6hdr *ipv6_hdr, int nhlen)
	int off = sizeof(struct ipv6hdr);
	struct ipv6_opt_hdr *exthdr;

	if (likely(ipv6_hdr->nexthdr == NEXTHDR_ESP))
	/* ESP or ESPINUDP */
	if (likely(ipv6_hdr->nexthdr == NEXTHDR_ESP ||
		   ipv6_hdr->nexthdr == NEXTHDR_UDP))
		return offsetof(struct ipv6hdr, nexthdr);

	while (off < nhlen) {
@@ -54,10 +56,14 @@ static struct sk_buff *esp6_gro_receive(struct list_head *head,
	int offset = skb_gro_offset(skb);
	struct xfrm_offload *xo;
	struct xfrm_state *x;
	int encap_type = 0;
	__be32 seq;
	__be32 spi;
	int nhoff;

	if (NAPI_GRO_CB(skb)->proto == IPPROTO_UDP)
		encap_type = UDP_ENCAP_ESPINUDP;

	if (!pskb_pull(skb, offset))
		return NULL;

@@ -104,7 +110,7 @@ static struct sk_buff *esp6_gro_receive(struct list_head *head,

	/* We don't need to handle errors from xfrm_input, it does all
	 * the error handling and frees the resources on error. */
	xfrm_input(skb, IPPROTO_ESP, spi, 0);
	xfrm_input(skb, IPPROTO_ESP, spi, encap_type);

	return ERR_PTR(-EINPROGRESS);
out_reset:
Loading