[11/16] esp: Use a synchronous crypto algorithm on offloading.

Message ID 1492678515-14347-12-git-send-email-steffen.klassert@secunet.com
State Accepted
Delegated to: David Miller
Headers show

Commit Message

Steffen Klassert April 20, 2017, 8:55 a.m.
We need a fallback algorithm for crypto offloading to a NIC.
This is because packets can be rerouted to other NICs that
don't support crypto offloading. The fallback is going to be
implemented at layer2 where we know the final output device
but can't handle asynchronous returns fron the crypto layer.

Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>
---
 net/ipv4/esp4.c | 12 ++++++++++--
 net/ipv6/esp6.c | 12 ++++++++++--
 2 files changed, 20 insertions(+), 4 deletions(-)

Comments

Herbert Xu April 20, 2017, 9:06 a.m. | #1
On Thu, Apr 20, 2017 at 10:55:10AM +0200, Steffen Klassert wrote:
> We need a fallback algorithm for crypto offloading to a NIC.
> This is because packets can be rerouted to other NICs that
> don't support crypto offloading. The fallback is going to be
> implemented at layer2 where we know the final output device
> but can't handle asynchronous returns fron the crypto layer.

Can you explain why we can't handle async algorithms on the fallback
path?

Thanks,
Steffen Klassert April 20, 2017, 9:17 a.m. | #2
On Thu, Apr 20, 2017 at 05:06:17PM +0800, Herbert Xu wrote:
> On Thu, Apr 20, 2017 at 10:55:10AM +0200, Steffen Klassert wrote:
> > We need a fallback algorithm for crypto offloading to a NIC.
> > This is because packets can be rerouted to other NICs that
> > don't support crypto offloading. The fallback is going to be
> > implemented at layer2 where we know the final output device
> > but can't handle asynchronous returns fron the crypto layer.
> 
> Can you explain why we can't handle async algorithms on the fallback
> path?

I tried to use async algorithms but it lead to serveral problems.
The GSO layer can't handle async returns, we'd need callbacks
for all the GSO handlers. Also we need something where we can
requeue packets if the driver is busy etc.

This would require a lot of changes in the generic code,
so I decided to use a synchronous fallback algorithm for
now.
Herbert Xu April 20, 2017, 9:52 a.m. | #3
On Thu, Apr 20, 2017 at 11:17:52AM +0200, Steffen Klassert wrote:
>
> I tried to use async algorithms but it lead to serveral problems.
> The GSO layer can't handle async returns, we'd need callbacks
> for all the GSO handlers. Also we need something where we can
> requeue packets if the driver is busy etc.

Why would we need to requeue? As it is if you get an EBUSY on
an IPsec packet it's simply dropped.

The main AES implementation on x86 is now async so I think it's
pretty important that we support it out-of-the-box.

Cheers,
Steffen Klassert April 20, 2017, 10:50 a.m. | #4
On Thu, Apr 20, 2017 at 05:52:35PM +0800, Herbert Xu wrote:
> On Thu, Apr 20, 2017 at 11:17:52AM +0200, Steffen Klassert wrote:
> >
> > I tried to use async algorithms but it lead to serveral problems.
> > The GSO layer can't handle async returns, we'd need callbacks
> > for all the GSO handlers. Also we need something where we can
> > requeue packets if the driver is busy etc.
> 
> Why would we need to requeue? As it is if you get an EBUSY on
> an IPsec packet it's simply dropped.

Yes we could do this, but the GSO problem remain.

We discussed this last year at netdevconf but could not come
up with an acceptable solutuion.

> 
> The main AES implementation on x86 is now async so I think it's
> pretty important that we support it out-of-the-box.

For now this is just a fallback to make hardware offloading
possible at all, so this is slowpath anyway. Allowing async
algorithms can (and should) be done in a second step once we
found a not too intrusive solution.
Herbert Xu April 21, 2017, 5:29 a.m. | #5
On Thu, Apr 20, 2017 at 12:50:29PM +0200, Steffen Klassert wrote:
> On Thu, Apr 20, 2017 at 05:52:35PM +0800, Herbert Xu wrote:
> > On Thu, Apr 20, 2017 at 11:17:52AM +0200, Steffen Klassert wrote:
> > >
> > > I tried to use async algorithms but it lead to serveral problems.
> > > The GSO layer can't handle async returns, we'd need callbacks
> > > for all the GSO handlers. Also we need something where we can
> > > requeue packets if the driver is busy etc.
> > 
> > Why would we need to requeue? As it is if you get an EBUSY on
> > an IPsec packet it's simply dropped.
> 
> Yes we could do this, but the GSO problem remain.
> 
> We discussed this last year at netdevconf but could not come
> up with an acceptable solutuion.

Why is it a problem exactly?

> For now this is just a fallback to make hardware offloading
> possible at all, so this is slowpath anyway. Allowing async
> algorithms can (and should) be done in a second step once we
> found a not too intrusive solution.

OK, as long as nobody gets silently switched from async to sync
then it's fine with me.

Cheers,
Steffen Klassert April 21, 2017, 8:33 a.m. | #6
On Fri, Apr 21, 2017 at 01:29:34PM +0800, Herbert Xu wrote:
> On Thu, Apr 20, 2017 at 12:50:29PM +0200, Steffen Klassert wrote:
> > On Thu, Apr 20, 2017 at 05:52:35PM +0800, Herbert Xu wrote:
> > > On Thu, Apr 20, 2017 at 11:17:52AM +0200, Steffen Klassert wrote:
> > > >
> > > > I tried to use async algorithms but it lead to serveral problems.
> > > > The GSO layer can't handle async returns, we'd need callbacks
> > > > for all the GSO handlers. Also we need something where we can
> > > > requeue packets if the driver is busy etc.
> > > 
> > > Why would we need to requeue? As it is if you get an EBUSY on
> > > an IPsec packet it's simply dropped.
> > 
> > Yes we could do this, but the GSO problem remain.
> > 
> > We discussed this last year at netdevconf but could not come
> > up with an acceptable solutuion.
> 
> Why is it a problem exactly?

My solution for this added some extra code to the generic networking
path, this was seen as too intrusive for this very special usecase.

I still think we can get this to work, but it needs some extra care.

> 
> > For now this is just a fallback to make hardware offloading
> > possible at all, so this is slowpath anyway. Allowing async
> > algorithms can (and should) be done in a second step once we
> > found a not too intrusive solution.
> 
> OK, as long as nobody gets silently switched from async to sync
> then it's fine with me.

The user has to explicitely ask for a offloaded state, so
we don't hide anything here. In this case the user wants
to use the crypto engine of the NIC, we just need a software
fallback to catch some corner cases where the NIC can't
do the crypto operation.

Patch

diff --git a/net/ipv4/esp4.c b/net/ipv4/esp4.c
index 4382f30..7e501ad 100644
--- a/net/ipv4/esp4.c
+++ b/net/ipv4/esp4.c
@@ -783,13 +783,17 @@  static int esp_init_aead(struct xfrm_state *x)
 	char aead_name[CRYPTO_MAX_ALG_NAME];
 	struct crypto_aead *aead;
 	int err;
+	u32 mask = 0;
 
 	err = -ENAMETOOLONG;
 	if (snprintf(aead_name, CRYPTO_MAX_ALG_NAME, "%s(%s)",
 		     x->geniv, x->aead->alg_name) >= CRYPTO_MAX_ALG_NAME)
 		goto error;
 
-	aead = crypto_alloc_aead(aead_name, 0, 0);
+	if (x->xso.offload_handle)
+		mask |= CRYPTO_ALG_ASYNC;
+
+	aead = crypto_alloc_aead(aead_name, 0, mask);
 	err = PTR_ERR(aead);
 	if (IS_ERR(aead))
 		goto error;
@@ -819,6 +823,7 @@  static int esp_init_authenc(struct xfrm_state *x)
 	char authenc_name[CRYPTO_MAX_ALG_NAME];
 	unsigned int keylen;
 	int err;
+	u32 mask = 0;
 
 	err = -EINVAL;
 	if (!x->ealg)
@@ -844,7 +849,10 @@  static int esp_init_authenc(struct xfrm_state *x)
 			goto error;
 	}
 
-	aead = crypto_alloc_aead(authenc_name, 0, 0);
+	if (x->xso.offload_handle)
+		mask |= CRYPTO_ALG_ASYNC;
+
+	aead = crypto_alloc_aead(authenc_name, 0, mask);
 	err = PTR_ERR(aead);
 	if (IS_ERR(aead))
 		goto error;
diff --git a/net/ipv6/esp6.c b/net/ipv6/esp6.c
index 82d3da8..8b55abf 100644
--- a/net/ipv6/esp6.c
+++ b/net/ipv6/esp6.c
@@ -704,13 +704,17 @@  static int esp_init_aead(struct xfrm_state *x)
 	char aead_name[CRYPTO_MAX_ALG_NAME];
 	struct crypto_aead *aead;
 	int err;
+	u32 mask = 0;
 
 	err = -ENAMETOOLONG;
 	if (snprintf(aead_name, CRYPTO_MAX_ALG_NAME, "%s(%s)",
 		     x->geniv, x->aead->alg_name) >= CRYPTO_MAX_ALG_NAME)
 		goto error;
 
-	aead = crypto_alloc_aead(aead_name, 0, 0);
+	if (x->xso.offload_handle)
+		mask |= CRYPTO_ALG_ASYNC;
+
+	aead = crypto_alloc_aead(aead_name, 0, mask);
 	err = PTR_ERR(aead);
 	if (IS_ERR(aead))
 		goto error;
@@ -740,6 +744,7 @@  static int esp_init_authenc(struct xfrm_state *x)
 	char authenc_name[CRYPTO_MAX_ALG_NAME];
 	unsigned int keylen;
 	int err;
+	u32 mask = 0;
 
 	err = -EINVAL;
 	if (!x->ealg)
@@ -765,7 +770,10 @@  static int esp_init_authenc(struct xfrm_state *x)
 			goto error;
 	}
 
-	aead = crypto_alloc_aead(authenc_name, 0, 0);
+	if (x->xso.offload_handle)
+		mask |= CRYPTO_ALG_ASYNC;
+
+	aead = crypto_alloc_aead(authenc_name, 0, mask);
 	err = PTR_ERR(aead);
 	if (IS_ERR(aead))
 		goto error;