aboutsummaryrefslogtreecommitdiffstats
path: root/net/xfrm
diff options
context:
space:
mode:
authorHoria Geanta <horia.geanta@freescale.com>2014-02-12 09:20:06 -0500
committerSteffen Klassert <steffen.klassert@secunet.com>2014-02-13 01:40:30 -0500
commit0f24558e91563888d51e9be5b70981da920c37ac (patch)
tree31aba2926b9f641fe30e235acc5a87b1b4dab73b /net/xfrm
parent5826bdd1816fa2baa122b62e14905c0ad8e7b96a (diff)
xfrm: avoid creating temporary SA when there are no listeners
In the case when KMs have no listeners, km_query() will fail and temporary SAs are garbage collected immediately after their allocation. This causes strain on memory allocation, leading even to OOM since temporary SA alloc/free cycle is performed for every packet and garbage collection does not keep up the pace. The sane thing to do is to make sure we have audience before temporary SA allocation. Signed-off-by: Horia Geanta <horia.geanta@freescale.com> Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>
Diffstat (limited to 'net/xfrm')
-rw-r--r--net/xfrm/xfrm_state.c31
-rw-r--r--net/xfrm/xfrm_user.c6
2 files changed, 37 insertions, 0 deletions
diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c
index a26b7aa79475..0bf12f665b9b 100644
--- a/net/xfrm/xfrm_state.c
+++ b/net/xfrm/xfrm_state.c
@@ -161,6 +161,7 @@ static DEFINE_SPINLOCK(xfrm_state_gc_lock);
161int __xfrm_state_delete(struct xfrm_state *x); 161int __xfrm_state_delete(struct xfrm_state *x);
162 162
163int km_query(struct xfrm_state *x, struct xfrm_tmpl *t, struct xfrm_policy *pol); 163int km_query(struct xfrm_state *x, struct xfrm_tmpl *t, struct xfrm_policy *pol);
164bool km_is_alive(const struct km_event *c);
164void km_state_expired(struct xfrm_state *x, int hard, u32 portid); 165void km_state_expired(struct xfrm_state *x, int hard, u32 portid);
165 166
166static DEFINE_SPINLOCK(xfrm_type_lock); 167static DEFINE_SPINLOCK(xfrm_type_lock);
@@ -788,6 +789,7 @@ xfrm_state_find(const xfrm_address_t *daddr, const xfrm_address_t *saddr,
788 struct xfrm_state *best = NULL; 789 struct xfrm_state *best = NULL;
789 u32 mark = pol->mark.v & pol->mark.m; 790 u32 mark = pol->mark.v & pol->mark.m;
790 unsigned short encap_family = tmpl->encap_family; 791 unsigned short encap_family = tmpl->encap_family;
792 struct km_event c;
791 793
792 to_put = NULL; 794 to_put = NULL;
793 795
@@ -832,6 +834,17 @@ found:
832 error = -EEXIST; 834 error = -EEXIST;
833 goto out; 835 goto out;
834 } 836 }
837
838 c.net = net;
839 /* If the KMs have no listeners (yet...), avoid allocating an SA
840 * for each and every packet - garbage collection might not
841 * handle the flood.
842 */
843 if (!km_is_alive(&c)) {
844 error = -ESRCH;
845 goto out;
846 }
847
835 x = xfrm_state_alloc(net); 848 x = xfrm_state_alloc(net);
836 if (x == NULL) { 849 if (x == NULL) {
837 error = -ENOMEM; 850 error = -ENOMEM;
@@ -1793,6 +1806,24 @@ int km_report(struct net *net, u8 proto, struct xfrm_selector *sel, xfrm_address
1793} 1806}
1794EXPORT_SYMBOL(km_report); 1807EXPORT_SYMBOL(km_report);
1795 1808
1809bool km_is_alive(const struct km_event *c)
1810{
1811 struct xfrm_mgr *km;
1812 bool is_alive = false;
1813
1814 rcu_read_lock();
1815 list_for_each_entry_rcu(km, &xfrm_km_list, list) {
1816 if (km->is_alive && km->is_alive(c)) {
1817 is_alive = true;
1818 break;
1819 }
1820 }
1821 rcu_read_unlock();
1822
1823 return is_alive;
1824}
1825EXPORT_SYMBOL(km_is_alive);
1826
1796int xfrm_user_policy(struct sock *sk, int optname, u8 __user *optval, int optlen) 1827int xfrm_user_policy(struct sock *sk, int optname, u8 __user *optval, int optlen)
1797{ 1828{
1798 int err; 1829 int err;
diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c
index ade9988f6e33..d7694f258294 100644
--- a/net/xfrm/xfrm_user.c
+++ b/net/xfrm/xfrm_user.c
@@ -2982,6 +2982,11 @@ static int xfrm_send_mapping(struct xfrm_state *x, xfrm_address_t *ipaddr,
2982 return nlmsg_multicast(net->xfrm.nlsk, skb, 0, XFRMNLGRP_MAPPING, GFP_ATOMIC); 2982 return nlmsg_multicast(net->xfrm.nlsk, skb, 0, XFRMNLGRP_MAPPING, GFP_ATOMIC);
2983} 2983}
2984 2984
2985static bool xfrm_is_alive(const struct km_event *c)
2986{
2987 return (bool)xfrm_acquire_is_on(c->net);
2988}
2989
2985static struct xfrm_mgr netlink_mgr = { 2990static struct xfrm_mgr netlink_mgr = {
2986 .id = "netlink", 2991 .id = "netlink",
2987 .notify = xfrm_send_state_notify, 2992 .notify = xfrm_send_state_notify,
@@ -2991,6 +2996,7 @@ static struct xfrm_mgr netlink_mgr = {
2991 .report = xfrm_send_report, 2996 .report = xfrm_send_report,
2992 .migrate = xfrm_send_migrate, 2997 .migrate = xfrm_send_migrate,
2993 .new_mapping = xfrm_send_mapping, 2998 .new_mapping = xfrm_send_mapping,
2999 .is_alive = xfrm_is_alive,
2994}; 3000};
2995 3001
2996static int __net_init xfrm_user_net_init(struct net *net) 3002static int __net_init xfrm_user_net_init(struct net *net)