Commit d113f0f0 authored by Herbert Xu's avatar Herbert Xu Committed by David S. Miller

[XFRM]: Probe selected algorithm only.

This patch removes an annoying problem in xfrm_user.  As it is every
time an SA is added it probes every known algorithm in the universe.
Now if they all existed it would be OK.  However, for the ones which
don't actually exist this causes multiple /sbin/modprobe processes to
be spawned which slows the system down when you're adding hundreds of
SAs.

Since we know the type of algorithm required when we're adding a new
SA, we can get away with only probing the selected algorithms.  This
is what the following patch does for xfrm_user.
Signed-off-by: default avatarHerbert Xu <herbert@gondor.apana.org.au>
Signed-off-by: default avatarJames Morris <jmorris@redhat.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 7a303cfd
......@@ -16,6 +16,7 @@
#ifndef _LINUX_CRYPTO_H
#define _LINUX_CRYPTO_H
#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/types.h>
......@@ -121,7 +122,14 @@ int crypto_unregister_alg(struct crypto_alg *alg);
/*
* Algorithm query interface.
*/
#ifdef CONFIG_CRYPTO
int crypto_alg_available(const char *name, u32 flags);
#else
static inline int crypto_alg_available(const char *name, u32 flags)
{
return 0;
}
#endif
/*
* Transforms: user-instantiated objects which encapsulate algorithms
......
......@@ -873,9 +873,9 @@ extern struct xfrm_algo_desc *xfrm_ealg_get_byidx(unsigned int idx);
extern struct xfrm_algo_desc *xfrm_aalg_get_byid(int alg_id);
extern struct xfrm_algo_desc *xfrm_ealg_get_byid(int alg_id);
extern struct xfrm_algo_desc *xfrm_calg_get_byid(int alg_id);
extern struct xfrm_algo_desc *xfrm_aalg_get_byname(char *name);
extern struct xfrm_algo_desc *xfrm_ealg_get_byname(char *name);
extern struct xfrm_algo_desc *xfrm_calg_get_byname(char *name);
extern struct xfrm_algo_desc *xfrm_aalg_get_byname(char *name, int probe);
extern struct xfrm_algo_desc *xfrm_ealg_get_byname(char *name, int probe);
extern struct xfrm_algo_desc *xfrm_calg_get_byname(char *name, int probe);
struct crypto_tfm;
typedef void (icv_update_fn_t)(struct crypto_tfm *, struct scatterlist *, unsigned int);
......
......@@ -236,7 +236,7 @@ static int ah_init_state(struct xfrm_state *x, void *args)
* we need for AH processing. This lookup cannot fail here
* after a successful crypto_alloc_tfm().
*/
aalg_desc = xfrm_aalg_get_byname(x->aalg->alg_name);
aalg_desc = xfrm_aalg_get_byname(x->aalg->alg_name, 0);
BUG_ON(!aalg_desc);
if (aalg_desc->uinfo.auth.icv_fullbits/8 !=
......
......@@ -392,7 +392,7 @@ static int esp_init_state(struct xfrm_state *x, void *args)
goto error;
esp->auth.icv = esp_hmac_digest;
aalg_desc = xfrm_aalg_get_byname(x->aalg->alg_name);
aalg_desc = xfrm_aalg_get_byname(x->aalg->alg_name, 0);
BUG_ON(!aalg_desc);
if (aalg_desc->uinfo.auth.icv_fullbits/8 !=
......
......@@ -472,7 +472,7 @@ static int ipcomp_init_state(struct xfrm_state *x, void *args)
goto error_tunnel;
}
calg_desc = xfrm_calg_get_byname(x->calg->alg_name);
calg_desc = xfrm_calg_get_byname(x->calg->alg_name, 0);
BUG_ON(!calg_desc);
ipcd->threshold = calg_desc->uinfo.comp.threshold;
x->data = ipcd;
......
......@@ -375,7 +375,7 @@ static int ah6_init_state(struct xfrm_state *x, void *args)
* we need for AH processing. This lookup cannot fail here
* after a successful crypto_alloc_tfm().
*/
aalg_desc = xfrm_aalg_get_byname(x->aalg->alg_name);
aalg_desc = xfrm_aalg_get_byname(x->aalg->alg_name, 0);
BUG_ON(!aalg_desc);
if (aalg_desc->uinfo.auth.icv_fullbits/8 !=
......
......@@ -329,7 +329,7 @@ static int esp6_init_state(struct xfrm_state *x, void *args)
goto error;
esp->auth.icv = esp_hmac_digest;
aalg_desc = xfrm_aalg_get_byname(x->aalg->alg_name);
aalg_desc = xfrm_aalg_get_byname(x->aalg->alg_name, 0);
BUG_ON(!aalg_desc);
if (aalg_desc->uinfo.auth.icv_fullbits/8 !=
......
......@@ -468,7 +468,7 @@ static int ipcomp6_init_state(struct xfrm_state *x, void *args)
goto error_tunnel;
}
calg_desc = xfrm_calg_get_byname(x->calg->alg_name);
calg_desc = xfrm_calg_get_byname(x->calg->alg_name, 0);
BUG_ON(!calg_desc);
ipcd->threshold = calg_desc->uinfo.comp.threshold;
x->data = ipcd;
......
......@@ -665,18 +665,18 @@ static struct sk_buff * pfkey_xfrm_state2msg(struct xfrm_state *x, int add_keys,
sa->sadb_sa_state = SADB_SASTATE_DEAD;
sa->sadb_sa_auth = 0;
if (x->aalg) {
struct xfrm_algo_desc *a = xfrm_aalg_get_byname(x->aalg->alg_name);
struct xfrm_algo_desc *a = xfrm_aalg_get_byname(x->aalg->alg_name, 0);
sa->sadb_sa_auth = a ? a->desc.sadb_alg_id : 0;
}
sa->sadb_sa_encrypt = 0;
BUG_ON(x->ealg && x->calg);
if (x->ealg) {
struct xfrm_algo_desc *a = xfrm_ealg_get_byname(x->ealg->alg_name);
struct xfrm_algo_desc *a = xfrm_ealg_get_byname(x->ealg->alg_name, 0);
sa->sadb_sa_encrypt = a ? a->desc.sadb_alg_id : 0;
}
/* KAME compatible: sadb_sa_encrypt is overloaded with calg id */
if (x->calg) {
struct xfrm_algo_desc *a = xfrm_calg_get_byname(x->calg->alg_name);
struct xfrm_algo_desc *a = xfrm_calg_get_byname(x->calg->alg_name, 0);
sa->sadb_sa_encrypt = a ? a->desc.sadb_alg_id : 0;
}
......
......@@ -13,6 +13,7 @@
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/pfkeyv2.h>
#include <linux/crypto.h>
#include <net/xfrm.h>
#if defined(CONFIG_INET_AH) || defined(CONFIG_INET_AH_MODULE) || defined(CONFIG_INET6_AH) || defined(CONFIG_INET6_AH_MODULE)
#include <net/ah.h>
......@@ -346,58 +347,48 @@ struct xfrm_algo_desc *xfrm_calg_get_byid(int alg_id)
return NULL;
}
struct xfrm_algo_desc *xfrm_aalg_get_byname(char *name)
static struct xfrm_algo_desc *xfrm_get_byname(struct xfrm_algo_desc *list,
int entries, char *name,
int probe)
{
int i;
int i, status;
if (!name)
return NULL;
for (i=0; i < aalg_entries(); i++) {
if (strcmp(name, aalg_list[i].name) == 0) {
if (aalg_list[i].available)
return &aalg_list[i];
else
break;
}
}
return NULL;
}
for (i = 0; i < entries; i++) {
if (!strcmp(name, list[i].name))
continue;
struct xfrm_algo_desc *xfrm_ealg_get_byname(char *name)
{
int i;
if (list[i].available)
return &list[i];
if (!name)
return NULL;
if (!probe)
break;
for (i=0; i < ealg_entries(); i++) {
if (strcmp(name, ealg_list[i].name) == 0) {
if (ealg_list[i].available)
return &ealg_list[i];
else
status = crypto_alg_available(name, 0);
if (!status)
break;
}
list[i].available = status;
return &list[i];
}
return NULL;
}
struct xfrm_algo_desc *xfrm_calg_get_byname(char *name)
struct xfrm_algo_desc *xfrm_aalg_get_byname(char *name, int probe)
{
int i;
return xfrm_get_byname(aalg_list, aalg_entries(), name, probe);
}
if (!name)
return NULL;
struct xfrm_algo_desc *xfrm_ealg_get_byname(char *name, int probe)
{
return xfrm_get_byname(ealg_list, ealg_entries(), name, probe);
}
for (i=0; i < calg_entries(); i++) {
if (strcmp(name, calg_list[i].name) == 0) {
if (calg_list[i].available)
return &calg_list[i];
else
break;
}
}
return NULL;
struct xfrm_algo_desc *xfrm_calg_get_byname(char *name, int probe)
{
return xfrm_get_byname(calg_list, calg_entries(), name, probe);
}
struct xfrm_algo_desc *xfrm_aalg_get_byidx(unsigned int idx)
......
......@@ -156,7 +156,7 @@ static int verify_newsa_info(struct xfrm_usersa_info *p,
}
static int attach_one_algo(struct xfrm_algo **algpp, u8 *props,
struct xfrm_algo_desc *(*get_byname)(char *),
struct xfrm_algo_desc *(*get_byname)(char *, int),
struct rtattr *u_arg)
{
struct rtattr *rta = u_arg;
......@@ -168,7 +168,7 @@ static int attach_one_algo(struct xfrm_algo **algpp, u8 *props,
ualg = RTA_DATA(rta);
algo = get_byname(ualg->alg_name);
algo = get_byname(ualg->alg_name, 1);
if (!algo)
return -ENOSYS;
*props = algo->desc.sadb_alg_id;
......@@ -273,8 +273,6 @@ static int xfrm_add_sa(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma)
if (err)
return err;
xfrm_probe_algs();
x = xfrm_state_construct(p, (struct rtattr **) xfrma, &err);
if (!x)
return err;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment