On Thu, May 28, 2020 at 10:07 AM Willem de Bruijn
<willemdebruijn.ker...@gmail.com> wrote:
>
> From: Willem de Bruijn <will...@google.com>
>
> Tun in IFF_NAPI_FRAGS mode calls napi_gro_frags. Unlike netif_rx and
> netif_gro_receive, this expects skb->data to point to the mac layer.
>
> But skb_probe_transport_header, __skb_get_hash_symmetric, and
> xdp_do_generic in tun_get_user need skb->data to point to the network
> header. Flow dissection also needs skb->protocol set, so
> eth_type_trans has to be called.
>
> Temporarily pull ETH_HLEN to make control flow the same for frags and
> not frags. Then push the header just before calling napi_gro_frags.
>
> Fixes: 90e33d459407 ("tun: enable napi_gro_frags() for TUN/TAP driver")
> Signed-off-by: Willem de Bruijn <will...@google.com>

Acked-by: Petar Penkov <ppen...@google.com>

> ---
>  drivers/net/tun.c | 14 ++++++++++----
>  1 file changed, 10 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/net/tun.c b/drivers/net/tun.c
> index 44889eba1dbc..b984733c6c31 100644
> --- a/drivers/net/tun.c
> +++ b/drivers/net/tun.c
> @@ -1871,8 +1871,11 @@ static ssize_t tun_get_user(struct tun_struct *tun, 
> struct tun_file *tfile,
>                 skb->dev = tun->dev;
>                 break;
>         case IFF_TAP:
> -               if (!frags)
> -                       skb->protocol = eth_type_trans(skb, tun->dev);
> +               if (frags && !pskb_may_pull(skb, ETH_HLEN)) {
> +                       err = -ENOMEM;
> +                       goto drop;
> +               }
> +               skb->protocol = eth_type_trans(skb, tun->dev);
>                 break;
>         }
>
> @@ -1929,9 +1932,12 @@ static ssize_t tun_get_user(struct tun_struct *tun, 
> struct tun_file *tfile,
>         }
>
>         if (frags) {
> +               u32 headlen;
> +
>                 /* Exercise flow dissector code path. */
> -               u32 headlen = eth_get_headlen(tun->dev, skb->data,
> -                                             skb_headlen(skb));
> +               skb_push(skb, ETH_HLEN);
> +               headlen = eth_get_headlen(tun->dev, skb->data,
> +                                         skb_headlen(skb));
>
>                 if (unlikely(headlen > skb_headlen(skb))) {
>                         this_cpu_inc(tun->pcpu_stats->rx_dropped);
> --
> 2.27.0.rc0.183.gde8f92d652-goog
>

Reply via email to