Commit ca70c104 authored by Leon Romanovsky's avatar Leon Romanovsky Committed by Steffen Klassert
Browse files

xfrm: check for PMTU in tunnel mode for packet offload



In tunnel mode, for the packet offload, there were no PMTU signaling
to the upper level about need to fragment the packet. As a solution,
call to already existing xfrm[4|6]_tunnel_check_size() to perform that.

Signed-off-by: default avatarLeon Romanovsky <leonro@nvidia.com>
Signed-off-by: default avatarSteffen Klassert <steffen.klassert@secunet.com>
parent cc18f482
Loading
Loading
Loading
Loading
+9 −0
Original line number Diff line number Diff line
@@ -1781,6 +1781,15 @@ int xfrm_trans_queue(struct sk_buff *skb,
				   struct sk_buff *));
int xfrm_output_resume(struct sock *sk, struct sk_buff *skb, int err);
int xfrm_output(struct sock *sk, struct sk_buff *skb);
int xfrm4_tunnel_check_size(struct sk_buff *skb);
#if IS_ENABLED(CONFIG_IPV6)
int xfrm6_tunnel_check_size(struct sk_buff *skb);
#else
static inline int xfrm6_tunnel_check_size(struct sk_buff *skb)
{
	return -EMSGSIZE;
}
#endif

#if IS_ENABLED(CONFIG_NET_PKTGEN)
int pktgen_xfrm_outer_mode_output(struct xfrm_state *x, struct sk_buff *skb);
+8 −2
Original line number Diff line number Diff line
@@ -418,12 +418,12 @@ bool xfrm_dev_offload_ok(struct sk_buff *skb, struct xfrm_state *x)
	struct dst_entry *dst = skb_dst(skb);
	struct xfrm_dst *xdst = (struct xfrm_dst *)dst;
	struct net_device *dev = x->xso.dev;
	bool check_tunnel_size;

	if (x->xso.type == XFRM_DEV_OFFLOAD_UNSPECIFIED)
		return false;

	if (x->xso.type == XFRM_DEV_OFFLOAD_PACKET ||
	    ((dev == xfrm_dst_path(dst)->dev) && !xdst->child->xfrm)) {
	if ((dev == xfrm_dst_path(dst)->dev) && !xdst->child->xfrm) {
		mtu = xfrm_state_mtu(x, xdst->child_mtu_cached);
		if (skb->len <= mtu)
			goto ok;
@@ -435,16 +435,22 @@ bool xfrm_dev_offload_ok(struct sk_buff *skb, struct xfrm_state *x)
	return false;

ok:
	check_tunnel_size = x->xso.type == XFRM_DEV_OFFLOAD_PACKET &&
			    x->props.mode == XFRM_MODE_TUNNEL;
	switch (x->props.family) {
	case AF_INET:
		/* Check for IPv4 options */
		if (ip_hdr(skb)->ihl != 5)
			return false;
		if (check_tunnel_size && xfrm4_tunnel_check_size(skb))
			return false;
		break;
	case AF_INET6:
		/* Check for IPv6 extensions */
		if (ipv6_ext_hdr(ipv6_hdr(skb)->nexthdr))
			return false;
		if (check_tunnel_size && xfrm6_tunnel_check_size(skb))
			return false;
		break;
	default:
		break;
+4 −2
Original line number Diff line number Diff line
@@ -786,7 +786,7 @@ int xfrm_output(struct sock *sk, struct sk_buff *skb)
}
EXPORT_SYMBOL_GPL(xfrm_output);

static int xfrm4_tunnel_check_size(struct sk_buff *skb)
int xfrm4_tunnel_check_size(struct sk_buff *skb)
{
	int mtu, ret = 0;

@@ -812,6 +812,7 @@ static int xfrm4_tunnel_check_size(struct sk_buff *skb)
out:
	return ret;
}
EXPORT_SYMBOL_GPL(xfrm4_tunnel_check_size);

static int xfrm4_extract_output(struct xfrm_state *x, struct sk_buff *skb)
{
@@ -834,7 +835,7 @@ static int xfrm4_extract_output(struct xfrm_state *x, struct sk_buff *skb)
}

#if IS_ENABLED(CONFIG_IPV6)
static int xfrm6_tunnel_check_size(struct sk_buff *skb)
int xfrm6_tunnel_check_size(struct sk_buff *skb)
{
	int mtu, ret = 0;
	struct dst_entry *dst = skb_dst(skb);
@@ -864,6 +865,7 @@ static int xfrm6_tunnel_check_size(struct sk_buff *skb)
out:
	return ret;
}
EXPORT_SYMBOL_GPL(xfrm6_tunnel_check_size);
#endif

static int xfrm6_extract_output(struct xfrm_state *x, struct sk_buff *skb)