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: Leon Romanovsky <leonro@nvidia.com>
Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>
This commit is contained in:
Leon Romanovsky 2025-02-19 15:51:01 +02:00 committed by Steffen Klassert
parent cc18f482e8
commit ca70c104e1
3 changed files with 21 additions and 4 deletions

View File

@ -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);

View File

@ -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;

View File

@ -786,7 +786,7 @@ out:
}
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)