xfrm: remove type and offload_type map from xfrm_state_afinfo

Only a handful of xfrm_types exist, no need to have 512 pointers for them.

Reduces size of afinfo struct from 4k to 120 bytes on 64bit platforms.

Also, the unregister function doesn't need to return an error, no single
caller does anything useful with it.

Just place a WARN_ON() where needed instead.

Signed-off-by: Florian Westphal <fw@strlen.de>
Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>
This commit is contained in:
Florian Westphal 2019-05-03 17:46:19 +02:00 committed by Steffen Klassert
parent 4c203b0454
commit 4f518e802c
12 changed files with 150 additions and 81 deletions

View File

@ -348,8 +348,16 @@ int __xfrm_state_delete(struct xfrm_state *x);
struct xfrm_state_afinfo {
u8 family;
u8 proto;
const struct xfrm_type *type_map[IPPROTO_MAX];
const struct xfrm_type_offload *type_offload_map[IPPROTO_MAX];
const struct xfrm_type_offload *type_offload_esp;
const struct xfrm_type *type_esp;
const struct xfrm_type *type_ipip;
const struct xfrm_type *type_ipip6;
const struct xfrm_type *type_comp;
const struct xfrm_type *type_ah;
const struct xfrm_type *type_routing;
const struct xfrm_type *type_dstopts;
int (*output)(struct net *net, struct sock *sk, struct sk_buff *skb);
int (*output_finish)(struct sock *sk, struct sk_buff *skb);
@ -401,7 +409,7 @@ struct xfrm_type {
};
int xfrm_register_type(const struct xfrm_type *type, unsigned short family);
int xfrm_unregister_type(const struct xfrm_type *type, unsigned short family);
void xfrm_unregister_type(const struct xfrm_type *type, unsigned short family);
struct xfrm_type_offload {
char *description;
@ -413,7 +421,7 @@ struct xfrm_type_offload {
};
int xfrm_register_type_offload(const struct xfrm_type_offload *type, unsigned short family);
int xfrm_unregister_type_offload(const struct xfrm_type_offload *type, unsigned short family);
void xfrm_unregister_type_offload(const struct xfrm_type_offload *type, unsigned short family);
static inline int xfrm_af2proto(unsigned int family)
{

View File

@ -590,8 +590,7 @@ static void __exit ah4_fini(void)
{
if (xfrm4_protocol_deregister(&ah4_protocol, IPPROTO_AH) < 0)
pr_info("%s: can't remove protocol\n", __func__);
if (xfrm_unregister_type(&ah_type, AF_INET) < 0)
pr_info("%s: can't remove xfrm type\n", __func__);
xfrm_unregister_type(&ah_type, AF_INET);
}
module_init(ah4_init);

View File

@ -1066,8 +1066,7 @@ static void __exit esp4_fini(void)
{
if (xfrm4_protocol_deregister(&esp4_protocol, IPPROTO_ESP) < 0)
pr_info("%s: can't remove protocol\n", __func__);
if (xfrm_unregister_type(&esp_type, AF_INET) < 0)
pr_info("%s: can't remove xfrm type\n", __func__);
xfrm_unregister_type(&esp_type, AF_INET);
}
module_init(esp4_init);

View File

@ -315,9 +315,7 @@ static int __init esp4_offload_init(void)
static void __exit esp4_offload_exit(void)
{
if (xfrm_unregister_type_offload(&esp_type_offload, AF_INET) < 0)
pr_info("%s: can't remove xfrm type offload\n", __func__);
xfrm_unregister_type_offload(&esp_type_offload, AF_INET);
inet_del_offload(&esp4_offload, IPPROTO_ESP);
}

View File

@ -190,8 +190,7 @@ static void __exit ipcomp4_fini(void)
{
if (xfrm4_protocol_deregister(&ipcomp4_protocol, IPPROTO_COMP) < 0)
pr_info("%s: can't remove protocol\n", __func__);
if (xfrm_unregister_type(&ipcomp_type, AF_INET) < 0)
pr_info("%s: can't remove xfrm type\n", __func__);
xfrm_unregister_type(&ipcomp_type, AF_INET);
}
module_init(ipcomp4_init);

View File

@ -108,8 +108,7 @@ static void __exit ipip_fini(void)
if (xfrm4_tunnel_deregister(&xfrm_tunnel_handler, AF_INET))
pr_info("%s: can't remove xfrm handler for AF_INET\n",
__func__);
if (xfrm_unregister_type(&ipip_type, AF_INET) < 0)
pr_info("%s: can't remove xfrm type\n", __func__);
xfrm_unregister_type(&ipip_type, AF_INET);
}
module_init(ipip_init);

View File

@ -793,9 +793,7 @@ static void __exit ah6_fini(void)
if (xfrm6_protocol_deregister(&ah6_protocol, IPPROTO_AH) < 0)
pr_info("%s: can't remove protocol\n", __func__);
if (xfrm_unregister_type(&ah6_type, AF_INET6) < 0)
pr_info("%s: can't remove xfrm type\n", __func__);
xfrm_unregister_type(&ah6_type, AF_INET6);
}
module_init(ah6_init);

View File

@ -951,8 +951,7 @@ static void __exit esp6_fini(void)
{
if (xfrm6_protocol_deregister(&esp6_protocol, IPPROTO_ESP) < 0)
pr_info("%s: can't remove protocol\n", __func__);
if (xfrm_unregister_type(&esp6_type, AF_INET6) < 0)
pr_info("%s: can't remove xfrm type\n", __func__);
xfrm_unregister_type(&esp6_type, AF_INET6);
}
module_init(esp6_init);

View File

@ -339,9 +339,7 @@ static int __init esp6_offload_init(void)
static void __exit esp6_offload_exit(void)
{
if (xfrm_unregister_type_offload(&esp6_type_offload, AF_INET6) < 0)
pr_info("%s: can't remove xfrm type offload\n", __func__);
xfrm_unregister_type_offload(&esp6_type_offload, AF_INET6);
inet6_del_offload(&esp6_offload, IPPROTO_ESP);
}

View File

@ -206,8 +206,7 @@ static void __exit ipcomp6_fini(void)
{
if (xfrm6_protocol_deregister(&ipcomp6_protocol, IPPROTO_COMP) < 0)
pr_info("%s: can't remove protocol\n", __func__);
if (xfrm_unregister_type(&ipcomp6_type, AF_INET6) < 0)
pr_info("%s: can't remove xfrm type\n", __func__);
xfrm_unregister_type(&ipcomp6_type, AF_INET6);
}
module_init(ipcomp6_init);

View File

@ -499,10 +499,8 @@ static void __exit mip6_fini(void)
{
if (rawv6_mh_filter_unregister(mip6_mh_filter) < 0)
pr_info("%s: can't remove rawv6 mh filter\n", __func__);
if (xfrm_unregister_type(&mip6_rthdr_type, AF_INET6) < 0)
pr_info("%s: can't remove xfrm type(rthdr)\n", __func__);
if (xfrm_unregister_type(&mip6_destopt_type, AF_INET6) < 0)
pr_info("%s: can't remove xfrm type(destopt)\n", __func__);
xfrm_unregister_type(&mip6_rthdr_type, AF_INET6);
xfrm_unregister_type(&mip6_destopt_type, AF_INET6);
}
module_init(mip6_init);

View File

@ -177,63 +177,132 @@ int km_query(struct xfrm_state *x, struct xfrm_tmpl *t, struct xfrm_policy *pol)
static bool km_is_alive(const struct km_event *c);
void km_state_expired(struct xfrm_state *x, int hard, u32 portid);
static DEFINE_SPINLOCK(xfrm_type_lock);
int xfrm_register_type(const struct xfrm_type *type, unsigned short family)
{
struct xfrm_state_afinfo *afinfo = xfrm_state_get_afinfo(family);
const struct xfrm_type **typemap;
int err = 0;
if (unlikely(afinfo == NULL))
if (!afinfo)
return -EAFNOSUPPORT;
typemap = afinfo->type_map;
spin_lock_bh(&xfrm_type_lock);
if (likely(typemap[type->proto] == NULL))
typemap[type->proto] = type;
else
err = -EEXIST;
spin_unlock_bh(&xfrm_type_lock);
#define X(afi, T, name) do { \
WARN_ON((afi)->type_ ## name); \
(afi)->type_ ## name = (T); \
} while (0)
switch (type->proto) {
case IPPROTO_COMP:
X(afinfo, type, comp);
break;
case IPPROTO_AH:
X(afinfo, type, ah);
break;
case IPPROTO_ESP:
X(afinfo, type, esp);
break;
case IPPROTO_IPIP:
X(afinfo, type, ipip);
break;
case IPPROTO_DSTOPTS:
X(afinfo, type, dstopts);
break;
case IPPROTO_ROUTING:
X(afinfo, type, routing);
break;
case IPPROTO_IPV6:
X(afinfo, type, ipip6);
break;
default:
WARN_ON(1);
err = -EPROTONOSUPPORT;
break;
}
#undef X
rcu_read_unlock();
return err;
}
EXPORT_SYMBOL(xfrm_register_type);
int xfrm_unregister_type(const struct xfrm_type *type, unsigned short family)
void xfrm_unregister_type(const struct xfrm_type *type, unsigned short family)
{
struct xfrm_state_afinfo *afinfo = xfrm_state_get_afinfo(family);
const struct xfrm_type **typemap;
int err = 0;
if (unlikely(afinfo == NULL))
return -EAFNOSUPPORT;
typemap = afinfo->type_map;
spin_lock_bh(&xfrm_type_lock);
return;
if (unlikely(typemap[type->proto] != type))
err = -ENOENT;
else
typemap[type->proto] = NULL;
spin_unlock_bh(&xfrm_type_lock);
#define X(afi, T, name) do { \
WARN_ON((afi)->type_ ## name != (T)); \
(afi)->type_ ## name = NULL; \
} while (0)
switch (type->proto) {
case IPPROTO_COMP:
X(afinfo, type, comp);
break;
case IPPROTO_AH:
X(afinfo, type, ah);
break;
case IPPROTO_ESP:
X(afinfo, type, esp);
break;
case IPPROTO_IPIP:
X(afinfo, type, ipip);
break;
case IPPROTO_DSTOPTS:
X(afinfo, type, dstopts);
break;
case IPPROTO_ROUTING:
X(afinfo, type, routing);
break;
case IPPROTO_IPV6:
X(afinfo, type, ipip6);
break;
default:
WARN_ON(1);
break;
}
#undef X
rcu_read_unlock();
return err;
}
EXPORT_SYMBOL(xfrm_unregister_type);
static const struct xfrm_type *xfrm_get_type(u8 proto, unsigned short family)
{
const struct xfrm_type *type = NULL;
struct xfrm_state_afinfo *afinfo;
const struct xfrm_type **typemap;
const struct xfrm_type *type;
int modload_attempted = 0;
retry:
afinfo = xfrm_state_get_afinfo(family);
if (unlikely(afinfo == NULL))
return NULL;
typemap = afinfo->type_map;
type = READ_ONCE(typemap[proto]);
switch (proto) {
case IPPROTO_COMP:
type = afinfo->type_comp;
break;
case IPPROTO_AH:
type = afinfo->type_ah;
break;
case IPPROTO_ESP:
type = afinfo->type_esp;
break;
case IPPROTO_IPIP:
type = afinfo->type_ipip;
break;
case IPPROTO_DSTOPTS:
type = afinfo->type_dstopts;
break;
case IPPROTO_ROUTING:
type = afinfo->type_routing;
break;
case IPPROTO_IPV6:
type = afinfo->type_ipip6;
break;
default:
break;
}
if (unlikely(type && !try_module_get(type->owner)))
type = NULL;
@ -253,65 +322,71 @@ static void xfrm_put_type(const struct xfrm_type *type)
module_put(type->owner);
}
static DEFINE_SPINLOCK(xfrm_type_offload_lock);
int xfrm_register_type_offload(const struct xfrm_type_offload *type,
unsigned short family)
{
struct xfrm_state_afinfo *afinfo = xfrm_state_get_afinfo(family);
const struct xfrm_type_offload **typemap;
int err = 0;
if (unlikely(afinfo == NULL))
return -EAFNOSUPPORT;
typemap = afinfo->type_offload_map;
spin_lock_bh(&xfrm_type_offload_lock);
if (likely(typemap[type->proto] == NULL))
typemap[type->proto] = type;
else
err = -EEXIST;
spin_unlock_bh(&xfrm_type_offload_lock);
switch (type->proto) {
case IPPROTO_ESP:
WARN_ON(afinfo->type_offload_esp);
afinfo->type_offload_esp = type;
break;
default:
WARN_ON(1);
err = -EPROTONOSUPPORT;
break;
}
rcu_read_unlock();
return err;
}
EXPORT_SYMBOL(xfrm_register_type_offload);
int xfrm_unregister_type_offload(const struct xfrm_type_offload *type,
unsigned short family)
void xfrm_unregister_type_offload(const struct xfrm_type_offload *type,
unsigned short family)
{
struct xfrm_state_afinfo *afinfo = xfrm_state_get_afinfo(family);
const struct xfrm_type_offload **typemap;
int err = 0;
if (unlikely(afinfo == NULL))
return -EAFNOSUPPORT;
typemap = afinfo->type_offload_map;
spin_lock_bh(&xfrm_type_offload_lock);
return;
if (unlikely(typemap[type->proto] != type))
err = -ENOENT;
else
typemap[type->proto] = NULL;
spin_unlock_bh(&xfrm_type_offload_lock);
switch (type->proto) {
case IPPROTO_ESP:
WARN_ON(afinfo->type_offload_esp != type);
afinfo->type_offload_esp = NULL;
break;
default:
WARN_ON(1);
break;
}
rcu_read_unlock();
return err;
}
EXPORT_SYMBOL(xfrm_unregister_type_offload);
static const struct xfrm_type_offload *
xfrm_get_type_offload(u8 proto, unsigned short family, bool try_load)
{
const struct xfrm_type_offload *type = NULL;
struct xfrm_state_afinfo *afinfo;
const struct xfrm_type_offload **typemap;
const struct xfrm_type_offload *type;
retry:
afinfo = xfrm_state_get_afinfo(family);
if (unlikely(afinfo == NULL))
return NULL;
typemap = afinfo->type_offload_map;
type = typemap[proto];
switch (proto) {
case IPPROTO_ESP:
type = afinfo->type_offload_esp;
break;
default:
break;
}
if ((type && !try_module_get(type->owner)))
type = NULL;