Commit 4f518e80 authored by Florian Westphal's avatar Florian Westphal Committed by Steffen Klassert

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: default avatarFlorian Westphal <fw@strlen.de>
Signed-off-by: default avatarSteffen Klassert <steffen.klassert@secunet.com>
parent 4c203b04
...@@ -348,8 +348,16 @@ int __xfrm_state_delete(struct xfrm_state *x); ...@@ -348,8 +348,16 @@ int __xfrm_state_delete(struct xfrm_state *x);
struct xfrm_state_afinfo { struct xfrm_state_afinfo {
u8 family; u8 family;
u8 proto; 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)(struct net *net, struct sock *sk, struct sk_buff *skb);
int (*output_finish)(struct sock *sk, struct sk_buff *skb); int (*output_finish)(struct sock *sk, struct sk_buff *skb);
...@@ -401,7 +409,7 @@ struct xfrm_type { ...@@ -401,7 +409,7 @@ struct xfrm_type {
}; };
int xfrm_register_type(const struct xfrm_type *type, unsigned short family); 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 { struct xfrm_type_offload {
char *description; char *description;
...@@ -413,7 +421,7 @@ struct xfrm_type_offload { ...@@ -413,7 +421,7 @@ struct xfrm_type_offload {
}; };
int xfrm_register_type_offload(const struct xfrm_type_offload *type, unsigned short family); 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) static inline int xfrm_af2proto(unsigned int family)
{ {
......
...@@ -590,8 +590,7 @@ static void __exit ah4_fini(void) ...@@ -590,8 +590,7 @@ static void __exit ah4_fini(void)
{ {
if (xfrm4_protocol_deregister(&ah4_protocol, IPPROTO_AH) < 0) if (xfrm4_protocol_deregister(&ah4_protocol, IPPROTO_AH) < 0)
pr_info("%s: can't remove protocol\n", __func__); pr_info("%s: can't remove protocol\n", __func__);
if (xfrm_unregister_type(&ah_type, AF_INET) < 0) xfrm_unregister_type(&ah_type, AF_INET);
pr_info("%s: can't remove xfrm type\n", __func__);
} }
module_init(ah4_init); module_init(ah4_init);
......
...@@ -1066,8 +1066,7 @@ static void __exit esp4_fini(void) ...@@ -1066,8 +1066,7 @@ static void __exit esp4_fini(void)
{ {
if (xfrm4_protocol_deregister(&esp4_protocol, IPPROTO_ESP) < 0) if (xfrm4_protocol_deregister(&esp4_protocol, IPPROTO_ESP) < 0)
pr_info("%s: can't remove protocol\n", __func__); pr_info("%s: can't remove protocol\n", __func__);
if (xfrm_unregister_type(&esp_type, AF_INET) < 0) xfrm_unregister_type(&esp_type, AF_INET);
pr_info("%s: can't remove xfrm type\n", __func__);
} }
module_init(esp4_init); module_init(esp4_init);
......
...@@ -315,9 +315,7 @@ static int __init esp4_offload_init(void) ...@@ -315,9 +315,7 @@ static int __init esp4_offload_init(void)
static void __exit esp4_offload_exit(void) static void __exit esp4_offload_exit(void)
{ {
if (xfrm_unregister_type_offload(&esp_type_offload, AF_INET) < 0) xfrm_unregister_type_offload(&esp_type_offload, AF_INET);
pr_info("%s: can't remove xfrm type offload\n", __func__);
inet_del_offload(&esp4_offload, IPPROTO_ESP); inet_del_offload(&esp4_offload, IPPROTO_ESP);
} }
......
...@@ -190,8 +190,7 @@ static void __exit ipcomp4_fini(void) ...@@ -190,8 +190,7 @@ static void __exit ipcomp4_fini(void)
{ {
if (xfrm4_protocol_deregister(&ipcomp4_protocol, IPPROTO_COMP) < 0) if (xfrm4_protocol_deregister(&ipcomp4_protocol, IPPROTO_COMP) < 0)
pr_info("%s: can't remove protocol\n", __func__); pr_info("%s: can't remove protocol\n", __func__);
if (xfrm_unregister_type(&ipcomp_type, AF_INET) < 0) xfrm_unregister_type(&ipcomp_type, AF_INET);
pr_info("%s: can't remove xfrm type\n", __func__);
} }
module_init(ipcomp4_init); module_init(ipcomp4_init);
......
...@@ -108,8 +108,7 @@ static void __exit ipip_fini(void) ...@@ -108,8 +108,7 @@ static void __exit ipip_fini(void)
if (xfrm4_tunnel_deregister(&xfrm_tunnel_handler, AF_INET)) if (xfrm4_tunnel_deregister(&xfrm_tunnel_handler, AF_INET))
pr_info("%s: can't remove xfrm handler for AF_INET\n", pr_info("%s: can't remove xfrm handler for AF_INET\n",
__func__); __func__);
if (xfrm_unregister_type(&ipip_type, AF_INET) < 0) xfrm_unregister_type(&ipip_type, AF_INET);
pr_info("%s: can't remove xfrm type\n", __func__);
} }
module_init(ipip_init); module_init(ipip_init);
......
...@@ -793,9 +793,7 @@ static void __exit ah6_fini(void) ...@@ -793,9 +793,7 @@ static void __exit ah6_fini(void)
if (xfrm6_protocol_deregister(&ah6_protocol, IPPROTO_AH) < 0) if (xfrm6_protocol_deregister(&ah6_protocol, IPPROTO_AH) < 0)
pr_info("%s: can't remove protocol\n", __func__); pr_info("%s: can't remove protocol\n", __func__);
if (xfrm_unregister_type(&ah6_type, AF_INET6) < 0) xfrm_unregister_type(&ah6_type, AF_INET6);
pr_info("%s: can't remove xfrm type\n", __func__);
} }
module_init(ah6_init); module_init(ah6_init);
......
...@@ -951,8 +951,7 @@ static void __exit esp6_fini(void) ...@@ -951,8 +951,7 @@ static void __exit esp6_fini(void)
{ {
if (xfrm6_protocol_deregister(&esp6_protocol, IPPROTO_ESP) < 0) if (xfrm6_protocol_deregister(&esp6_protocol, IPPROTO_ESP) < 0)
pr_info("%s: can't remove protocol\n", __func__); pr_info("%s: can't remove protocol\n", __func__);
if (xfrm_unregister_type(&esp6_type, AF_INET6) < 0) xfrm_unregister_type(&esp6_type, AF_INET6);
pr_info("%s: can't remove xfrm type\n", __func__);
} }
module_init(esp6_init); module_init(esp6_init);
......
...@@ -339,9 +339,7 @@ static int __init esp6_offload_init(void) ...@@ -339,9 +339,7 @@ static int __init esp6_offload_init(void)
static void __exit esp6_offload_exit(void) static void __exit esp6_offload_exit(void)
{ {
if (xfrm_unregister_type_offload(&esp6_type_offload, AF_INET6) < 0) xfrm_unregister_type_offload(&esp6_type_offload, AF_INET6);
pr_info("%s: can't remove xfrm type offload\n", __func__);
inet6_del_offload(&esp6_offload, IPPROTO_ESP); inet6_del_offload(&esp6_offload, IPPROTO_ESP);
} }
......
...@@ -206,8 +206,7 @@ static void __exit ipcomp6_fini(void) ...@@ -206,8 +206,7 @@ static void __exit ipcomp6_fini(void)
{ {
if (xfrm6_protocol_deregister(&ipcomp6_protocol, IPPROTO_COMP) < 0) if (xfrm6_protocol_deregister(&ipcomp6_protocol, IPPROTO_COMP) < 0)
pr_info("%s: can't remove protocol\n", __func__); pr_info("%s: can't remove protocol\n", __func__);
if (xfrm_unregister_type(&ipcomp6_type, AF_INET6) < 0) xfrm_unregister_type(&ipcomp6_type, AF_INET6);
pr_info("%s: can't remove xfrm type\n", __func__);
} }
module_init(ipcomp6_init); module_init(ipcomp6_init);
......
...@@ -499,10 +499,8 @@ static void __exit mip6_fini(void) ...@@ -499,10 +499,8 @@ static void __exit mip6_fini(void)
{ {
if (rawv6_mh_filter_unregister(mip6_mh_filter) < 0) if (rawv6_mh_filter_unregister(mip6_mh_filter) < 0)
pr_info("%s: can't remove rawv6 mh filter\n", __func__); pr_info("%s: can't remove rawv6 mh filter\n", __func__);
if (xfrm_unregister_type(&mip6_rthdr_type, AF_INET6) < 0) xfrm_unregister_type(&mip6_rthdr_type, AF_INET6);
pr_info("%s: can't remove xfrm type(rthdr)\n", __func__); xfrm_unregister_type(&mip6_destopt_type, AF_INET6);
if (xfrm_unregister_type(&mip6_destopt_type, AF_INET6) < 0)
pr_info("%s: can't remove xfrm type(destopt)\n", __func__);
} }
module_init(mip6_init); module_init(mip6_init);
......
...@@ -177,63 +177,132 @@ int km_query(struct xfrm_state *x, struct xfrm_tmpl *t, struct xfrm_policy *pol) ...@@ -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); static bool km_is_alive(const struct km_event *c);
void km_state_expired(struct xfrm_state *x, int hard, u32 portid); 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) int xfrm_register_type(const struct xfrm_type *type, unsigned short family)
{ {
struct xfrm_state_afinfo *afinfo = xfrm_state_get_afinfo(family); struct xfrm_state_afinfo *afinfo = xfrm_state_get_afinfo(family);
const struct xfrm_type **typemap;
int err = 0; int err = 0;
if (unlikely(afinfo == NULL)) if (!afinfo)
return -EAFNOSUPPORT; return -EAFNOSUPPORT;
typemap = afinfo->type_map;
spin_lock_bh(&xfrm_type_lock);
if (likely(typemap[type->proto] == NULL)) #define X(afi, T, name) do { \
typemap[type->proto] = type; WARN_ON((afi)->type_ ## name); \
else (afi)->type_ ## name = (T); \
err = -EEXIST; } while (0)
spin_unlock_bh(&xfrm_type_lock);
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(); rcu_read_unlock();
return err; return err;
} }
EXPORT_SYMBOL(xfrm_register_type); 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); struct xfrm_state_afinfo *afinfo = xfrm_state_get_afinfo(family);
const struct xfrm_type **typemap;
int err = 0;
if (unlikely(afinfo == NULL)) if (unlikely(afinfo == NULL))
return -EAFNOSUPPORT; return;
typemap = afinfo->type_map;
spin_lock_bh(&xfrm_type_lock);
if (unlikely(typemap[type->proto] != type)) #define X(afi, T, name) do { \
err = -ENOENT; WARN_ON((afi)->type_ ## name != (T)); \
else (afi)->type_ ## name = NULL; \
typemap[type->proto] = NULL; } while (0)
spin_unlock_bh(&xfrm_type_lock);
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(); rcu_read_unlock();
return err;
} }
EXPORT_SYMBOL(xfrm_unregister_type); EXPORT_SYMBOL(xfrm_unregister_type);
static const struct xfrm_type *xfrm_get_type(u8 proto, unsigned short family) static const struct xfrm_type *xfrm_get_type(u8 proto, unsigned short family)
{ {
const struct xfrm_type *type = NULL;
struct xfrm_state_afinfo *afinfo; struct xfrm_state_afinfo *afinfo;
const struct xfrm_type **typemap;
const struct xfrm_type *type;
int modload_attempted = 0; int modload_attempted = 0;
retry: retry:
afinfo = xfrm_state_get_afinfo(family); afinfo = xfrm_state_get_afinfo(family);
if (unlikely(afinfo == NULL)) if (unlikely(afinfo == NULL))
return 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))) if (unlikely(type && !try_module_get(type->owner)))
type = NULL; type = NULL;
...@@ -253,65 +322,71 @@ static void xfrm_put_type(const struct xfrm_type *type) ...@@ -253,65 +322,71 @@ static void xfrm_put_type(const struct xfrm_type *type)
module_put(type->owner); module_put(type->owner);
} }
static DEFINE_SPINLOCK(xfrm_type_offload_lock);
int xfrm_register_type_offload(const struct xfrm_type_offload *type, int xfrm_register_type_offload(const struct xfrm_type_offload *type,
unsigned short family) unsigned short family)
{ {
struct xfrm_state_afinfo *afinfo = xfrm_state_get_afinfo(family); struct xfrm_state_afinfo *afinfo = xfrm_state_get_afinfo(family);
const struct xfrm_type_offload **typemap;
int err = 0; int err = 0;
if (unlikely(afinfo == NULL)) if (unlikely(afinfo == NULL))
return -EAFNOSUPPORT; return -EAFNOSUPPORT;
typemap = afinfo->type_offload_map;
spin_lock_bh(&xfrm_type_offload_lock);
if (likely(typemap[type->proto] == NULL)) switch (type->proto) {
typemap[type->proto] = type; case IPPROTO_ESP:
else WARN_ON(afinfo->type_offload_esp);
err = -EEXIST; afinfo->type_offload_esp = type;
spin_unlock_bh(&xfrm_type_offload_lock); break;
default:
WARN_ON(1);
err = -EPROTONOSUPPORT;
break;
}
rcu_read_unlock(); rcu_read_unlock();
return err; return err;
} }
EXPORT_SYMBOL(xfrm_register_type_offload); EXPORT_SYMBOL(xfrm_register_type_offload);
int xfrm_unregister_type_offload(const struct xfrm_type_offload *type, void xfrm_unregister_type_offload(const struct xfrm_type_offload *type,
unsigned short family) unsigned short family)
{ {
struct xfrm_state_afinfo *afinfo = xfrm_state_get_afinfo(family); struct xfrm_state_afinfo *afinfo = xfrm_state_get_afinfo(family);
const struct xfrm_type_offload **typemap;
int err = 0;
if (unlikely(afinfo == NULL)) if (unlikely(afinfo == NULL))
return -EAFNOSUPPORT; return;
typemap = afinfo->type_offload_map;
spin_lock_bh(&xfrm_type_offload_lock);
if (unlikely(typemap[type->proto] != type)) switch (type->proto) {
err = -ENOENT; case IPPROTO_ESP:
else WARN_ON(afinfo->type_offload_esp != type);
typemap[type->proto] = NULL; afinfo->type_offload_esp = NULL;
spin_unlock_bh(&xfrm_type_offload_lock); break;
default:
WARN_ON(1);
break;
}
rcu_read_unlock(); rcu_read_unlock();
return err;
} }
EXPORT_SYMBOL(xfrm_unregister_type_offload); EXPORT_SYMBOL(xfrm_unregister_type_offload);
static const struct xfrm_type_offload * static const struct xfrm_type_offload *
xfrm_get_type_offload(u8 proto, unsigned short family, bool try_load) xfrm_get_type_offload(u8 proto, unsigned short family, bool try_load)
{ {
const struct xfrm_type_offload *type = NULL;
struct xfrm_state_afinfo *afinfo; struct xfrm_state_afinfo *afinfo;
const struct xfrm_type_offload **typemap;
const struct xfrm_type_offload *type;
retry: retry:
afinfo = xfrm_state_get_afinfo(family); afinfo = xfrm_state_get_afinfo(family);
if (unlikely(afinfo == NULL)) if (unlikely(afinfo == NULL))
return 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))) if ((type && !try_module_get(type->owner)))
type = NULL; type = NULL;
......
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