xfrm: Prepare the GRO codepath for hardware offloading.
authorSteffen Klassert <steffen.klassert@secunet.com>
Fri, 14 Apr 2017 08:07:49 +0000 (10:07 +0200)
committerSteffen Klassert <steffen.klassert@secunet.com>
Fri, 14 Apr 2017 08:07:49 +0000 (10:07 +0200)
On IPsec hardware offloading, we already get a secpath with
valid state attached when the packet enters the GRO handlers.
So check for hardware offload and skip the state lookup in this
case.

Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>
net/ipv4/esp4_offload.c
net/ipv6/esp6_offload.c
net/xfrm/xfrm_input.c

index 1e39564..f3e33c2 100644 (file)
@@ -43,27 +43,31 @@ static struct sk_buff **esp4_gro_receive(struct sk_buff **head,
        if ((err = xfrm_parse_spi(skb, IPPROTO_ESP, &spi, &seq)) != 0)
                goto out;
 
-       err = secpath_set(skb);
-       if (err)
-               goto out;
-
-       if (skb->sp->len == XFRM_MAX_DEPTH)
-               goto out;
-
-       x = xfrm_state_lookup(dev_net(skb->dev), skb->mark,
-                             (xfrm_address_t *)&ip_hdr(skb)->daddr,
-                             spi, IPPROTO_ESP, AF_INET);
-       if (!x)
-               goto out;
-
-       skb->sp->xvec[skb->sp->len++] = x;
-       skb->sp->olen++;
-
        xo = xfrm_offload(skb);
-       if (!xo) {
-               xfrm_state_put(x);
-               goto out;
+       if (!xo || !(xo->flags & CRYPTO_DONE)) {
+               err = secpath_set(skb);
+               if (err)
+                       goto out;
+
+               if (skb->sp->len == XFRM_MAX_DEPTH)
+                       goto out;
+
+               x = xfrm_state_lookup(dev_net(skb->dev), skb->mark,
+                                     (xfrm_address_t *)&ip_hdr(skb)->daddr,
+                                     spi, IPPROTO_ESP, AF_INET);
+               if (!x)
+                       goto out;
+
+               skb->sp->xvec[skb->sp->len++] = x;
+               skb->sp->olen++;
+
+               xo = xfrm_offload(skb);
+               if (!xo) {
+                       xfrm_state_put(x);
+                       goto out;
+               }
        }
+
        xo->flags |= XFRM_GRO;
 
        XFRM_TUNNEL_SKB_CB(skb)->tunnel.ip4 = NULL;
index 06e9721..1cceeee 100644 (file)
@@ -45,27 +45,31 @@ static struct sk_buff **esp6_gro_receive(struct sk_buff **head,
        if ((err = xfrm_parse_spi(skb, IPPROTO_ESP, &spi, &seq)) != 0)
                goto out;
 
-       err = secpath_set(skb);
-       if (err)
-               goto out;
-
-       if (skb->sp->len == XFRM_MAX_DEPTH)
-               goto out;
-
-       x = xfrm_state_lookup(dev_net(skb->dev), skb->mark,
-                             (xfrm_address_t *)&ipv6_hdr(skb)->daddr,
-                             spi, IPPROTO_ESP, AF_INET6);
-       if (!x)
-               goto out;
-
-       skb->sp->xvec[skb->sp->len++] = x;
-       skb->sp->olen++;
-
        xo = xfrm_offload(skb);
-       if (!xo) {
-               xfrm_state_put(x);
-               goto out;
+       if (!xo || !(xo->flags & CRYPTO_DONE)) {
+               err = secpath_set(skb);
+               if (err)
+                       goto out;
+
+               if (skb->sp->len == XFRM_MAX_DEPTH)
+                       goto out;
+
+               x = xfrm_state_lookup(dev_net(skb->dev), skb->mark,
+                                     (xfrm_address_t *)&ipv6_hdr(skb)->daddr,
+                                     spi, IPPROTO_ESP, AF_INET6);
+               if (!x)
+                       goto out;
+
+               skb->sp->xvec[skb->sp->len++] = x;
+               skb->sp->olen++;
+
+               xo = xfrm_offload(skb);
+               if (!xo) {
+                       xfrm_state_put(x);
+                       goto out;
+               }
        }
+
        xo->flags |= XFRM_GRO;
 
        XFRM_TUNNEL_SKB_CB(skb)->tunnel.ip6 = NULL;
index 362d655..21c6cc9 100644 (file)
@@ -223,38 +223,38 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type)
                        seq = XFRM_SKB_CB(skb)->seq.input.low;
                        goto resume;
                }
+
                /* encap_type < -1 indicates a GRO call. */
                encap_type = 0;
                seq = XFRM_SPI_SKB_CB(skb)->seq;
-               goto lock;
-       }
-
-       if (xo && (xo->flags & CRYPTO_DONE)) {
-               crypto_done = true;
-               x = xfrm_input_state(skb);
-               family = XFRM_SPI_SKB_CB(skb)->family;
 
-               if (!(xo->status & CRYPTO_SUCCESS)) {
-                       if (xo->status &
-                           (CRYPTO_TRANSPORT_AH_AUTH_FAILED |
-                            CRYPTO_TRANSPORT_ESP_AUTH_FAILED |
-                            CRYPTO_TUNNEL_AH_AUTH_FAILED |
-                            CRYPTO_TUNNEL_ESP_AUTH_FAILED)) {
-
-                               xfrm_audit_state_icvfail(x, skb,
-                                                        x->type->proto);
-                               x->stats.integrity_failed++;
-                               XFRM_INC_STATS(net, LINUX_MIB_XFRMINSTATEPROTOERROR);
+               if (xo && (xo->flags & CRYPTO_DONE)) {
+                       crypto_done = true;
+                       x = xfrm_input_state(skb);
+                       family = XFRM_SPI_SKB_CB(skb)->family;
+
+                       if (!(xo->status & CRYPTO_SUCCESS)) {
+                               if (xo->status &
+                                   (CRYPTO_TRANSPORT_AH_AUTH_FAILED |
+                                    CRYPTO_TRANSPORT_ESP_AUTH_FAILED |
+                                    CRYPTO_TUNNEL_AH_AUTH_FAILED |
+                                    CRYPTO_TUNNEL_ESP_AUTH_FAILED)) {
+
+                                       xfrm_audit_state_icvfail(x, skb,
+                                                                x->type->proto);
+                                       x->stats.integrity_failed++;
+                                       XFRM_INC_STATS(net, LINUX_MIB_XFRMINSTATEPROTOERROR);
+                                       goto drop;
+                               }
+
+                               XFRM_INC_STATS(net, LINUX_MIB_XFRMINBUFFERERROR);
                                goto drop;
                        }
 
-                       XFRM_INC_STATS(net, LINUX_MIB_XFRMINBUFFERERROR);
-                       goto drop;
-               }
-
-               if ((err = xfrm_parse_spi(skb, nexthdr, &spi, &seq)) != 0) {
-                       XFRM_INC_STATS(net, LINUX_MIB_XFRMINHDRERROR);
-                       goto drop;
+                       if ((err = xfrm_parse_spi(skb, nexthdr, &spi, &seq)) != 0) {
+                               XFRM_INC_STATS(net, LINUX_MIB_XFRMINHDRERROR);
+                               goto drop;
+                       }
                }
 
                goto lock;