aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFan Du <fan.du@windriver.com>2013-11-07 04:47:50 -0500
committerSteffen Klassert <steffen.klassert@secunet.com>2013-12-06 00:45:06 -0500
commit283bc9f35bbbcb0e9ab4e6d2427da7f9f710d52d (patch)
tree8b580340bdc0d1f25f4a76dfc39c48760f3f307a
parent8d549c4f5d92d80fc6f888fd314e10972ae0ec37 (diff)
xfrm: Namespacify xfrm state/policy locks
By semantics, xfrm layer is fully name space aware, so will the locks, e.g. xfrm_state/pocliy_lock. Ensure exclusive access into state/policy link list for different name space with one global lock is not right in terms of semantics aspect at first place, as they are indeed mutually independent with each other, but also more seriously causes scalability problem. One practical scenario is on a Open Network Stack, more than hundreds of lxc tenants acts as routers within one host, a global xfrm_state/policy_lock becomes the bottleneck. But onces those locks are decoupled in a per-namespace fashion, locks contend is just with in specific name space scope, without causing additional SPD/SAD access delay for other name space. Also this patch improve scalability while as without changing original xfrm behavior. Signed-off-by: Fan Du <fan.du@windriver.com> Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>
-rw-r--r--include/net/netns/xfrm.h4
-rw-r--r--include/net/xfrm.h11
-rw-r--r--net/key/af_key.c15
-rw-r--r--net/xfrm/xfrm_policy.c104
-rw-r--r--net/xfrm/xfrm_state.c104
-rw-r--r--net/xfrm/xfrm_user.c14
6 files changed, 138 insertions, 114 deletions
diff --git a/include/net/netns/xfrm.h b/include/net/netns/xfrm.h
index 5299e69a32af..ea28404e9d79 100644
--- a/include/net/netns/xfrm.h
+++ b/include/net/netns/xfrm.h
@@ -59,6 +59,10 @@ struct netns_xfrm {
59#if IS_ENABLED(CONFIG_IPV6) 59#if IS_ENABLED(CONFIG_IPV6)
60 struct dst_ops xfrm6_dst_ops; 60 struct dst_ops xfrm6_dst_ops;
61#endif 61#endif
62 spinlock_t xfrm_state_lock;
63 spinlock_t xfrm_policy_sk_bundle_lock;
64 rwlock_t xfrm_policy_lock;
65 struct mutex xfrm_cfg_mutex;
62}; 66};
63 67
64#endif 68#endif
diff --git a/include/net/xfrm.h b/include/net/xfrm.h
index 5b522c5f0188..59f5d0a6c7f8 100644
--- a/include/net/xfrm.h
+++ b/include/net/xfrm.h
@@ -53,7 +53,6 @@
53#define XFRM_INC_STATS_USER(net, field) ((void)(net)) 53#define XFRM_INC_STATS_USER(net, field) ((void)(net))
54#endif 54#endif
55 55
56extern struct mutex xfrm_cfg_mutex;
57 56
58/* Organization of SPD aka "XFRM rules" 57/* Organization of SPD aka "XFRM rules"
59 ------------------------------------ 58 ------------------------------------
@@ -1409,7 +1408,7 @@ static inline void xfrm_sysctl_fini(struct net *net)
1409void xfrm_state_walk_init(struct xfrm_state_walk *walk, u8 proto); 1408void xfrm_state_walk_init(struct xfrm_state_walk *walk, u8 proto);
1410int xfrm_state_walk(struct net *net, struct xfrm_state_walk *walk, 1409int xfrm_state_walk(struct net *net, struct xfrm_state_walk *walk,
1411 int (*func)(struct xfrm_state *, int, void*), void *); 1410 int (*func)(struct xfrm_state *, int, void*), void *);
1412void xfrm_state_walk_done(struct xfrm_state_walk *walk); 1411void xfrm_state_walk_done(struct xfrm_state_walk *walk, struct net *net);
1413struct xfrm_state *xfrm_state_alloc(struct net *net); 1412struct xfrm_state *xfrm_state_alloc(struct net *net);
1414struct xfrm_state *xfrm_state_find(const xfrm_address_t *daddr, 1413struct xfrm_state *xfrm_state_find(const xfrm_address_t *daddr,
1415 const xfrm_address_t *saddr, 1414 const xfrm_address_t *saddr,
@@ -1436,12 +1435,12 @@ struct xfrm_state *xfrm_state_lookup_byaddr(struct net *net, u32 mark,
1436 unsigned short family); 1435 unsigned short family);
1437#ifdef CONFIG_XFRM_SUB_POLICY 1436#ifdef CONFIG_XFRM_SUB_POLICY
1438int xfrm_tmpl_sort(struct xfrm_tmpl **dst, struct xfrm_tmpl **src, int n, 1437int xfrm_tmpl_sort(struct xfrm_tmpl **dst, struct xfrm_tmpl **src, int n,
1439 unsigned short family); 1438 unsigned short family, struct net *net);
1440int xfrm_state_sort(struct xfrm_state **dst, struct xfrm_state **src, int n, 1439int xfrm_state_sort(struct xfrm_state **dst, struct xfrm_state **src, int n,
1441 unsigned short family); 1440 unsigned short family);
1442#else 1441#else
1443static inline int xfrm_tmpl_sort(struct xfrm_tmpl **dst, struct xfrm_tmpl **src, 1442static inline int xfrm_tmpl_sort(struct xfrm_tmpl **dst, struct xfrm_tmpl **src,
1444 int n, unsigned short family) 1443 int n, unsigned short family, struct net *net)
1445{ 1444{
1446 return -ENOSYS; 1445 return -ENOSYS;
1447} 1446}
@@ -1553,7 +1552,7 @@ void xfrm_policy_walk_init(struct xfrm_policy_walk *walk, u8 type);
1553int xfrm_policy_walk(struct net *net, struct xfrm_policy_walk *walk, 1552int xfrm_policy_walk(struct net *net, struct xfrm_policy_walk *walk,
1554 int (*func)(struct xfrm_policy *, int, int, void*), 1553 int (*func)(struct xfrm_policy *, int, int, void*),
1555 void *); 1554 void *);
1556void xfrm_policy_walk_done(struct xfrm_policy_walk *walk); 1555void xfrm_policy_walk_done(struct xfrm_policy_walk *walk, struct net *net);
1557int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl); 1556int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl);
1558struct xfrm_policy *xfrm_policy_bysel_ctx(struct net *net, u32 mark, 1557struct xfrm_policy *xfrm_policy_bysel_ctx(struct net *net, u32 mark,
1559 u8 type, int dir, 1558 u8 type, int dir,
@@ -1576,7 +1575,7 @@ int xfrm_sk_policy_insert(struct sock *sk, int dir, struct xfrm_policy *pol);
1576int km_migrate(const struct xfrm_selector *sel, u8 dir, u8 type, 1575int km_migrate(const struct xfrm_selector *sel, u8 dir, u8 type,
1577 const struct xfrm_migrate *m, int num_bundles, 1576 const struct xfrm_migrate *m, int num_bundles,
1578 const struct xfrm_kmaddress *k); 1577 const struct xfrm_kmaddress *k);
1579struct xfrm_state *xfrm_migrate_state_find(struct xfrm_migrate *m); 1578struct xfrm_state *xfrm_migrate_state_find(struct xfrm_migrate *m, struct net *net);
1580struct xfrm_state *xfrm_state_migrate(struct xfrm_state *x, 1579struct xfrm_state *xfrm_state_migrate(struct xfrm_state *x,
1581 struct xfrm_migrate *m); 1580 struct xfrm_migrate *m);
1582int xfrm_migrate(const struct xfrm_selector *sel, u8 dir, u8 type, 1581int xfrm_migrate(const struct xfrm_selector *sel, u8 dir, u8 type,
diff --git a/net/key/af_key.c b/net/key/af_key.c
index 3fa811c46913..9a039acf37e8 100644
--- a/net/key/af_key.c
+++ b/net/key/af_key.c
@@ -1785,7 +1785,9 @@ static int pfkey_dump_sa(struct pfkey_sock *pfk)
1785 1785
1786static void pfkey_dump_sa_done(struct pfkey_sock *pfk) 1786static void pfkey_dump_sa_done(struct pfkey_sock *pfk)
1787{ 1787{
1788 xfrm_state_walk_done(&pfk->dump.u.state); 1788 struct net *net = sock_net(&pfk->sk);
1789
1790 xfrm_state_walk_done(&pfk->dump.u.state, net);
1789} 1791}
1790 1792
1791static int pfkey_dump(struct sock *sk, struct sk_buff *skb, const struct sadb_msg *hdr, void * const *ext_hdrs) 1793static int pfkey_dump(struct sock *sk, struct sk_buff *skb, const struct sadb_msg *hdr, void * const *ext_hdrs)
@@ -1861,7 +1863,7 @@ static u32 gen_reqid(struct net *net)
1861 reqid = IPSEC_MANUAL_REQID_MAX+1; 1863 reqid = IPSEC_MANUAL_REQID_MAX+1;
1862 xfrm_policy_walk_init(&walk, XFRM_POLICY_TYPE_MAIN); 1864 xfrm_policy_walk_init(&walk, XFRM_POLICY_TYPE_MAIN);
1863 rc = xfrm_policy_walk(net, &walk, check_reqid, (void*)&reqid); 1865 rc = xfrm_policy_walk(net, &walk, check_reqid, (void*)&reqid);
1864 xfrm_policy_walk_done(&walk); 1866 xfrm_policy_walk_done(&walk, net);
1865 if (rc != -EEXIST) 1867 if (rc != -EEXIST)
1866 return reqid; 1868 return reqid;
1867 } while (reqid != start); 1869 } while (reqid != start);
@@ -2660,7 +2662,9 @@ static int pfkey_dump_sp(struct pfkey_sock *pfk)
2660 2662
2661static void pfkey_dump_sp_done(struct pfkey_sock *pfk) 2663static void pfkey_dump_sp_done(struct pfkey_sock *pfk)
2662{ 2664{
2663 xfrm_policy_walk_done(&pfk->dump.u.policy); 2665 struct net *net = sock_net((struct sock *)pfk);
2666
2667 xfrm_policy_walk_done(&pfk->dump.u.policy, net);
2664} 2668}
2665 2669
2666static int pfkey_spddump(struct sock *sk, struct sk_buff *skb, const struct sadb_msg *hdr, void * const *ext_hdrs) 2670static int pfkey_spddump(struct sock *sk, struct sk_buff *skb, const struct sadb_msg *hdr, void * const *ext_hdrs)
@@ -3570,6 +3574,7 @@ static int pfkey_sendmsg(struct kiocb *kiocb,
3570 struct sk_buff *skb = NULL; 3574 struct sk_buff *skb = NULL;
3571 struct sadb_msg *hdr = NULL; 3575 struct sadb_msg *hdr = NULL;
3572 int err; 3576 int err;
3577 struct net *net = sock_net(sk);
3573 3578
3574 err = -EOPNOTSUPP; 3579 err = -EOPNOTSUPP;
3575 if (msg->msg_flags & MSG_OOB) 3580 if (msg->msg_flags & MSG_OOB)
@@ -3592,9 +3597,9 @@ static int pfkey_sendmsg(struct kiocb *kiocb,
3592 if (!hdr) 3597 if (!hdr)
3593 goto out; 3598 goto out;
3594 3599
3595 mutex_lock(&xfrm_cfg_mutex); 3600 mutex_lock(&net->xfrm.xfrm_cfg_mutex);
3596 err = pfkey_process(sk, skb, hdr); 3601 err = pfkey_process(sk, skb, hdr);
3597 mutex_unlock(&xfrm_cfg_mutex); 3602 mutex_unlock(&net->xfrm.xfrm_cfg_mutex);
3598 3603
3599out: 3604out:
3600 if (err && hdr && pfkey_error(hdr, err, sk) == 0) 3605 if (err && hdr && pfkey_error(hdr, err, sk) == 0)
diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c
index 907fd2fa70bc..73b04d3df44e 100644
--- a/net/xfrm/xfrm_policy.c
+++ b/net/xfrm/xfrm_policy.c
@@ -39,12 +39,7 @@
39#define XFRM_QUEUE_TMO_MAX ((unsigned)(60*HZ)) 39#define XFRM_QUEUE_TMO_MAX ((unsigned)(60*HZ))
40#define XFRM_MAX_QUEUE_LEN 100 40#define XFRM_MAX_QUEUE_LEN 100
41 41
42DEFINE_MUTEX(xfrm_cfg_mutex);
43EXPORT_SYMBOL(xfrm_cfg_mutex);
44
45static DEFINE_SPINLOCK(xfrm_policy_sk_bundle_lock);
46static struct dst_entry *xfrm_policy_sk_bundles; 42static struct dst_entry *xfrm_policy_sk_bundles;
47static DEFINE_RWLOCK(xfrm_policy_lock);
48 43
49static DEFINE_SPINLOCK(xfrm_policy_afinfo_lock); 44static DEFINE_SPINLOCK(xfrm_policy_afinfo_lock);
50static struct xfrm_policy_afinfo __rcu *xfrm_policy_afinfo[NPROTO] 45static struct xfrm_policy_afinfo __rcu *xfrm_policy_afinfo[NPROTO]
@@ -438,7 +433,7 @@ static void xfrm_bydst_resize(struct net *net, int dir)
438 if (!ndst) 433 if (!ndst)
439 return; 434 return;
440 435
441 write_lock_bh(&xfrm_policy_lock); 436 write_lock_bh(&net->xfrm.xfrm_policy_lock);
442 437
443 for (i = hmask; i >= 0; i--) 438 for (i = hmask; i >= 0; i--)
444 xfrm_dst_hash_transfer(odst + i, ndst, nhashmask); 439 xfrm_dst_hash_transfer(odst + i, ndst, nhashmask);
@@ -446,7 +441,7 @@ static void xfrm_bydst_resize(struct net *net, int dir)
446 net->xfrm.policy_bydst[dir].table = ndst; 441 net->xfrm.policy_bydst[dir].table = ndst;
447 net->xfrm.policy_bydst[dir].hmask = nhashmask; 442 net->xfrm.policy_bydst[dir].hmask = nhashmask;
448 443
449 write_unlock_bh(&xfrm_policy_lock); 444 write_unlock_bh(&net->xfrm.xfrm_policy_lock);
450