diff options
-rw-r--r-- | include/net/xfrm.h | 15 | ||||
-rw-r--r-- | net/key/af_key.c | 19 | ||||
-rw-r--r-- | net/xfrm/xfrm_state.c | 31 | ||||
-rw-r--r-- | net/xfrm/xfrm_user.c | 6 |
4 files changed, 71 insertions, 0 deletions
diff --git a/include/net/xfrm.h b/include/net/xfrm.h index afa5730fb3bd..5313ccfdeedf 100644 --- a/include/net/xfrm.h +++ b/include/net/xfrm.h | |||
@@ -594,6 +594,7 @@ struct xfrm_mgr { | |||
594 | const struct xfrm_migrate *m, | 594 | const struct xfrm_migrate *m, |
595 | int num_bundles, | 595 | int num_bundles, |
596 | const struct xfrm_kmaddress *k); | 596 | const struct xfrm_kmaddress *k); |
597 | bool (*is_alive)(const struct km_event *c); | ||
597 | }; | 598 | }; |
598 | 599 | ||
599 | int xfrm_register_km(struct xfrm_mgr *km); | 600 | int xfrm_register_km(struct xfrm_mgr *km); |
@@ -1646,6 +1647,20 @@ static inline int xfrm_aevent_is_on(struct net *net) | |||
1646 | rcu_read_unlock(); | 1647 | rcu_read_unlock(); |
1647 | return ret; | 1648 | return ret; |
1648 | } | 1649 | } |
1650 | |||
1651 | static inline int xfrm_acquire_is_on(struct net *net) | ||
1652 | { | ||
1653 | struct sock *nlsk; | ||
1654 | int ret = 0; | ||
1655 | |||
1656 | rcu_read_lock(); | ||
1657 | nlsk = rcu_dereference(net->xfrm.nlsk); | ||
1658 | if (nlsk) | ||
1659 | ret = netlink_has_listeners(nlsk, XFRMNLGRP_ACQUIRE); | ||
1660 | rcu_read_unlock(); | ||
1661 | |||
1662 | return ret; | ||
1663 | } | ||
1649 | #endif | 1664 | #endif |
1650 | 1665 | ||
1651 | static inline int xfrm_alg_len(const struct xfrm_algo *alg) | 1666 | static inline int xfrm_alg_len(const struct xfrm_algo *alg) |
diff --git a/net/key/af_key.c b/net/key/af_key.c index 1a04c1329362..e1c69d024197 100644 --- a/net/key/af_key.c +++ b/net/key/af_key.c | |||
@@ -3059,6 +3059,24 @@ static u32 get_acqseq(void) | |||
3059 | return res; | 3059 | return res; |
3060 | } | 3060 | } |
3061 | 3061 | ||
3062 | static bool pfkey_is_alive(const struct km_event *c) | ||
3063 | { | ||
3064 | struct netns_pfkey *net_pfkey = net_generic(c->net, pfkey_net_id); | ||
3065 | struct sock *sk; | ||
3066 | bool is_alive = false; | ||
3067 | |||
3068 | rcu_read_lock(); | ||
3069 | sk_for_each_rcu(sk, &net_pfkey->table) { | ||
3070 | if (pfkey_sk(sk)->registered) { | ||
3071 | is_alive = true; | ||
3072 | break; | ||
3073 | } | ||
3074 | } | ||
3075 | rcu_read_unlock(); | ||
3076 | |||
3077 | return is_alive; | ||
3078 | } | ||
3079 | |||
3062 | static int pfkey_send_acquire(struct xfrm_state *x, struct xfrm_tmpl *t, struct xfrm_policy *xp) | 3080 | static int pfkey_send_acquire(struct xfrm_state *x, struct xfrm_tmpl *t, struct xfrm_policy *xp) |
3063 | { | 3081 | { |
3064 | struct sk_buff *skb; | 3082 | struct sk_buff *skb; |
@@ -3784,6 +3802,7 @@ static struct xfrm_mgr pfkeyv2_mgr = | |||
3784 | .new_mapping = pfkey_send_new_mapping, | 3802 | .new_mapping = pfkey_send_new_mapping, |
3785 | .notify_policy = pfkey_send_policy_notify, | 3803 | .notify_policy = pfkey_send_policy_notify, |
3786 | .migrate = pfkey_send_migrate, | 3804 | .migrate = pfkey_send_migrate, |
3805 | .is_alive = pfkey_is_alive, | ||
3787 | }; | 3806 | }; |
3788 | 3807 | ||
3789 | static int __net_init pfkey_net_init(struct net *net) | 3808 | static int __net_init pfkey_net_init(struct net *net) |
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); | |||
161 | int __xfrm_state_delete(struct xfrm_state *x); | 161 | int __xfrm_state_delete(struct xfrm_state *x); |
162 | 162 | ||
163 | int km_query(struct xfrm_state *x, struct xfrm_tmpl *t, struct xfrm_policy *pol); | 163 | int km_query(struct xfrm_state *x, struct xfrm_tmpl *t, struct xfrm_policy *pol); |
164 | bool km_is_alive(const struct km_event *c); | ||
164 | void km_state_expired(struct xfrm_state *x, int hard, u32 portid); | 165 | void km_state_expired(struct xfrm_state *x, int hard, u32 portid); |
165 | 166 | ||
166 | static DEFINE_SPINLOCK(xfrm_type_lock); | 167 | static 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 | } |
1794 | EXPORT_SYMBOL(km_report); | 1807 | EXPORT_SYMBOL(km_report); |
1795 | 1808 | ||
1809 | bool 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 | } | ||
1825 | EXPORT_SYMBOL(km_is_alive); | ||
1826 | |||
1796 | int xfrm_user_policy(struct sock *sk, int optname, u8 __user *optval, int optlen) | 1827 | int 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 | ||
2985 | static bool xfrm_is_alive(const struct km_event *c) | ||
2986 | { | ||
2987 | return (bool)xfrm_acquire_is_on(c->net); | ||
2988 | } | ||
2989 | |||
2985 | static struct xfrm_mgr netlink_mgr = { | 2990 | static 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 | ||
2996 | static int __net_init xfrm_user_net_init(struct net *net) | 3002 | static int __net_init xfrm_user_net_init(struct net *net) |