Commit 283bc9f3 authored by Fan Du's avatar Fan Du Committed by Steffen Klassert

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: default avatarFan Du <fan.du@windriver.com>
Signed-off-by: default avatarSteffen Klassert <steffen.klassert@secunet.com>
parent 8d549c4f
...@@ -59,6 +59,10 @@ struct netns_xfrm { ...@@ -59,6 +59,10 @@ struct netns_xfrm {
#if IS_ENABLED(CONFIG_IPV6) #if IS_ENABLED(CONFIG_IPV6)
struct dst_ops xfrm6_dst_ops; struct dst_ops xfrm6_dst_ops;
#endif #endif
spinlock_t xfrm_state_lock;
spinlock_t xfrm_policy_sk_bundle_lock;
rwlock_t xfrm_policy_lock;
struct mutex xfrm_cfg_mutex;
}; };
#endif #endif
...@@ -53,7 +53,6 @@ ...@@ -53,7 +53,6 @@
#define XFRM_INC_STATS_USER(net, field) ((void)(net)) #define XFRM_INC_STATS_USER(net, field) ((void)(net))
#endif #endif
extern struct mutex xfrm_cfg_mutex;
/* Organization of SPD aka "XFRM rules" /* Organization of SPD aka "XFRM rules"
------------------------------------ ------------------------------------
...@@ -1409,7 +1408,7 @@ static inline void xfrm_sysctl_fini(struct net *net) ...@@ -1409,7 +1408,7 @@ static inline void xfrm_sysctl_fini(struct net *net)
void xfrm_state_walk_init(struct xfrm_state_walk *walk, u8 proto); void xfrm_state_walk_init(struct xfrm_state_walk *walk, u8 proto);
int xfrm_state_walk(struct net *net, struct xfrm_state_walk *walk, int xfrm_state_walk(struct net *net, struct xfrm_state_walk *walk,
int (*func)(struct xfrm_state *, int, void*), void *); int (*func)(struct xfrm_state *, int, void*), void *);
void xfrm_state_walk_done(struct xfrm_state_walk *walk); void xfrm_state_walk_done(struct xfrm_state_walk *walk, struct net *net);
struct xfrm_state *xfrm_state_alloc(struct net *net); struct xfrm_state *xfrm_state_alloc(struct net *net);
struct xfrm_state *xfrm_state_find(const xfrm_address_t *daddr, struct xfrm_state *xfrm_state_find(const xfrm_address_t *daddr,
const xfrm_address_t *saddr, const xfrm_address_t *saddr,
...@@ -1436,12 +1435,12 @@ struct xfrm_state *xfrm_state_lookup_byaddr(struct net *net, u32 mark, ...@@ -1436,12 +1435,12 @@ struct xfrm_state *xfrm_state_lookup_byaddr(struct net *net, u32 mark,
unsigned short family); unsigned short family);
#ifdef CONFIG_XFRM_SUB_POLICY #ifdef CONFIG_XFRM_SUB_POLICY
int xfrm_tmpl_sort(struct xfrm_tmpl **dst, struct xfrm_tmpl **src, int n, int xfrm_tmpl_sort(struct xfrm_tmpl **dst, struct xfrm_tmpl **src, int n,
unsigned short family); unsigned short family, struct net *net);
int xfrm_state_sort(struct xfrm_state **dst, struct xfrm_state **src, int n, int xfrm_state_sort(struct xfrm_state **dst, struct xfrm_state **src, int n,
unsigned short family); unsigned short family);
#else #else
static inline int xfrm_tmpl_sort(struct xfrm_tmpl **dst, struct xfrm_tmpl **src, static inline int xfrm_tmpl_sort(struct xfrm_tmpl **dst, struct xfrm_tmpl **src,
int n, unsigned short family) int n, unsigned short family, struct net *net)
{ {
return -ENOSYS; return -ENOSYS;
} }
...@@ -1553,7 +1552,7 @@ void xfrm_policy_walk_init(struct xfrm_policy_walk *walk, u8 type); ...@@ -1553,7 +1552,7 @@ void xfrm_policy_walk_init(struct xfrm_policy_walk *walk, u8 type);
int xfrm_policy_walk(struct net *net, struct xfrm_policy_walk *walk, int xfrm_policy_walk(struct net *net, struct xfrm_policy_walk *walk,
int (*func)(struct xfrm_policy *, int, int, void*), int (*func)(struct xfrm_policy *, int, int, void*),
void *); void *);
void xfrm_policy_walk_done(struct xfrm_policy_walk *walk); void xfrm_policy_walk_done(struct xfrm_policy_walk *walk, struct net *net);
int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl); int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl);
struct xfrm_policy *xfrm_policy_bysel_ctx(struct net *net, u32 mark, struct xfrm_policy *xfrm_policy_bysel_ctx(struct net *net, u32 mark,
u8 type, int dir, u8 type, int dir,
...@@ -1576,7 +1575,7 @@ int xfrm_sk_policy_insert(struct sock *sk, int dir, struct xfrm_policy *pol); ...@@ -1576,7 +1575,7 @@ int xfrm_sk_policy_insert(struct sock *sk, int dir, struct xfrm_policy *pol);
int km_migrate(const struct xfrm_selector *sel, u8 dir, u8 type, int km_migrate(const struct xfrm_selector *sel, u8 dir, u8 type,
const struct xfrm_migrate *m, int num_bundles, const struct xfrm_migrate *m, int num_bundles,
const struct xfrm_kmaddress *k); const struct xfrm_kmaddress *k);
struct xfrm_state *xfrm_migrate_state_find(struct xfrm_migrate *m); struct xfrm_state *xfrm_migrate_state_find(struct xfrm_migrate *m, struct net *net);
struct xfrm_state *xfrm_state_migrate(struct xfrm_state *x, struct xfrm_state *xfrm_state_migrate(struct xfrm_state *x,
struct xfrm_migrate *m); struct xfrm_migrate *m);
int xfrm_migrate(const struct xfrm_selector *sel, u8 dir, u8 type, int xfrm_migrate(const struct xfrm_selector *sel, u8 dir, u8 type,
......
...@@ -1785,7 +1785,9 @@ static int pfkey_dump_sa(struct pfkey_sock *pfk) ...@@ -1785,7 +1785,9 @@ static int pfkey_dump_sa(struct pfkey_sock *pfk)
static void pfkey_dump_sa_done(struct pfkey_sock *pfk) static void pfkey_dump_sa_done(struct pfkey_sock *pfk)
{ {
xfrm_state_walk_done(&pfk->dump.u.state); struct net *net = sock_net(&pfk->sk);
xfrm_state_walk_done(&pfk->dump.u.state, net);
} }
static int pfkey_dump(struct sock *sk, struct sk_buff *skb, const struct sadb_msg *hdr, void * const *ext_hdrs) static 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,7 +1863,7 @@ static u32 gen_reqid(struct net *net)
reqid = IPSEC_MANUAL_REQID_MAX+1; reqid = IPSEC_MANUAL_REQID_MAX+1;
xfrm_policy_walk_init(&walk, XFRM_POLICY_TYPE_MAIN); xfrm_policy_walk_init(&walk, XFRM_POLICY_TYPE_MAIN);
rc = xfrm_policy_walk(net, &walk, check_reqid, (void*)&reqid); rc = xfrm_policy_walk(net, &walk, check_reqid, (void*)&reqid);
xfrm_policy_walk_done(&walk); xfrm_policy_walk_done(&walk, net);
if (rc != -EEXIST) if (rc != -EEXIST)
return reqid; return reqid;
} while (reqid != start); } while (reqid != start);
...@@ -2660,7 +2662,9 @@ static int pfkey_dump_sp(struct pfkey_sock *pfk) ...@@ -2660,7 +2662,9 @@ static int pfkey_dump_sp(struct pfkey_sock *pfk)
static void pfkey_dump_sp_done(struct pfkey_sock *pfk) static void pfkey_dump_sp_done(struct pfkey_sock *pfk)
{ {
xfrm_policy_walk_done(&pfk->dump.u.policy); struct net *net = sock_net((struct sock *)pfk);
xfrm_policy_walk_done(&pfk->dump.u.policy, net);
} }
static int pfkey_spddump(struct sock *sk, struct sk_buff *skb, const struct sadb_msg *hdr, void * const *ext_hdrs) static 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,6 +3574,7 @@ static int pfkey_sendmsg(struct kiocb *kiocb,
struct sk_buff *skb = NULL; struct sk_buff *skb = NULL;
struct sadb_msg *hdr = NULL; struct sadb_msg *hdr = NULL;
int err; int err;
struct net *net = sock_net(sk);
err = -EOPNOTSUPP; err = -EOPNOTSUPP;
if (msg->msg_flags & MSG_OOB) if (msg->msg_flags & MSG_OOB)
...@@ -3592,9 +3597,9 @@ static int pfkey_sendmsg(struct kiocb *kiocb, ...@@ -3592,9 +3597,9 @@ static int pfkey_sendmsg(struct kiocb *kiocb,
if (!hdr) if (!hdr)
goto out; goto out;
mutex_lock(&xfrm_cfg_mutex); mutex_lock(&net->xfrm.xfrm_cfg_mutex);
err = pfkey_process(sk, skb, hdr); err = pfkey_process(sk, skb, hdr);
mutex_unlock(&xfrm_cfg_mutex); mutex_unlock(&net->xfrm.xfrm_cfg_mutex);
out: out:
if (err && hdr && pfkey_error(hdr, err, sk) == 0) if (err && hdr && pfkey_error(hdr, err, sk) == 0)
......
...@@ -39,12 +39,7 @@ ...@@ -39,12 +39,7 @@
#define XFRM_QUEUE_TMO_MAX ((unsigned)(60*HZ)) #define XFRM_QUEUE_TMO_MAX ((unsigned)(60*HZ))
#define XFRM_MAX_QUEUE_LEN 100 #define XFRM_MAX_QUEUE_LEN 100
DEFINE_MUTEX(xfrm_cfg_mutex);
EXPORT_SYMBOL(xfrm_cfg_mutex);
static DEFINE_SPINLOCK(xfrm_policy_sk_bundle_lock);
static struct dst_entry *xfrm_policy_sk_bundles; static struct dst_entry *xfrm_policy_sk_bundles;
static DEFINE_RWLOCK(xfrm_policy_lock);
static DEFINE_SPINLOCK(xfrm_policy_afinfo_lock); static DEFINE_SPINLOCK(xfrm_policy_afinfo_lock);
static struct xfrm_policy_afinfo __rcu *xfrm_policy_afinfo[NPROTO] static struct xfrm_policy_afinfo __rcu *xfrm_policy_afinfo[NPROTO]
...@@ -438,7 +433,7 @@ static void xfrm_bydst_resize(struct net *net, int dir) ...@@ -438,7 +433,7 @@ static void xfrm_bydst_resize(struct net *net, int dir)
if (!ndst) if (!ndst)
return; return;
write_lock_bh(&xfrm_policy_lock); write_lock_bh(&net->xfrm.xfrm_policy_lock);
for (i = hmask; i >= 0; i--) for (i = hmask; i >= 0; i--)
xfrm_dst_hash_transfer(odst + i, ndst, nhashmask); xfrm_dst_hash_transfer(odst + i, ndst, nhashmask);
...@@ -446,7 +441,7 @@ static void xfrm_bydst_resize(struct net *net, int dir) ...@@ -446,7 +441,7 @@ static void xfrm_bydst_resize(struct net *net, int dir)
net->xfrm.policy_bydst[dir].table = ndst; net->xfrm.policy_bydst[dir].table = ndst;
net->xfrm.policy_bydst[dir].hmask = nhashmask; net->xfrm.policy_bydst[dir].hmask = nhashmask;
write_unlock_bh(&xfrm_policy_lock); write_unlock_bh(&net->xfrm.xfrm_policy_lock);
xfrm_hash_free(odst, (hmask + 1) * sizeof(struct hlist_head)); xfrm_hash_free(odst, (hmask + 1) * sizeof(struct hlist_head));
} }
...@@ -463,7 +458,7 @@ static void xfrm_byidx_resize(struct net *net, int total) ...@@ -463,7 +458,7 @@ static void xfrm_byidx_resize(struct net *net, int total)
if (!nidx) if (!nidx)
return; return;
write_lock_bh(&xfrm_policy_lock); write_lock_bh(&net->xfrm.xfrm_policy_lock);
for (i = hmask; i >= 0; i--) for (i = hmask; i >= 0; i--)
xfrm_idx_hash_transfer(oidx + i, nidx, nhashmask); xfrm_idx_hash_transfer(oidx + i, nidx, nhashmask);
...@@ -471,7 +466,7 @@ static void xfrm_byidx_resize(struct net *net, int total) ...@@ -471,7 +466,7 @@ static void xfrm_byidx_resize(struct net *net, int total)
net->xfrm.policy_byidx = nidx; net->xfrm.policy_byidx = nidx;
net->xfrm.policy_idx_hmask = nhashmask; net->xfrm.policy_idx_hmask = nhashmask;
write_unlock_bh(&xfrm_policy_lock); write_unlock_bh(&net->xfrm.xfrm_policy_lock);
xfrm_hash_free(oidx, (hmask + 1) * sizeof(struct hlist_head)); xfrm_hash_free(oidx, (hmask + 1) * sizeof(struct hlist_head));
} }
...@@ -504,7 +499,7 @@ static inline int xfrm_byidx_should_resize(struct net *net, int total) ...@@ -504,7 +499,7 @@ static inline int xfrm_byidx_should_resize(struct net *net, int total)
void xfrm_spd_getinfo(struct net *net, struct xfrmk_spdinfo *si) void xfrm_spd_getinfo(struct net *net, struct xfrmk_spdinfo *si)
{ {
read_lock_bh(&xfrm_policy_lock); read_lock_bh(&net->xfrm.xfrm_policy_lock);
si->incnt = net->xfrm.policy_count[XFRM_POLICY_IN]; si->incnt = net->xfrm.policy_count[XFRM_POLICY_IN];
si->outcnt = net->xfrm.policy_count[XFRM_POLICY_OUT]; si->outcnt = net->xfrm.policy_count[XFRM_POLICY_OUT];
si->fwdcnt = net->xfrm.policy_count[XFRM_POLICY_FWD]; si->fwdcnt = net->xfrm.policy_count[XFRM_POLICY_FWD];
...@@ -513,7 +508,7 @@ void xfrm_spd_getinfo(struct net *net, struct xfrmk_spdinfo *si) ...@@ -513,7 +508,7 @@ void xfrm_spd_getinfo(struct net *net, struct xfrmk_spdinfo *si)
si->fwdscnt = net->xfrm.policy_count[XFRM_POLICY_FWD+XFRM_POLICY_MAX]; si->fwdscnt = net->xfrm.policy_count[XFRM_POLICY_FWD+XFRM_POLICY_MAX];
si->spdhcnt = net->xfrm.policy_idx_hmask; si->spdhcnt = net->xfrm.policy_idx_hmask;
si->spdhmcnt = xfrm_policy_hashmax; si->spdhmcnt = xfrm_policy_hashmax;
read_unlock_bh(&xfrm_policy_lock); read_unlock_bh(&net->xfrm.xfrm_policy_lock);
} }
EXPORT_SYMBOL(xfrm_spd_getinfo); EXPORT_SYMBOL(xfrm_spd_getinfo);
...@@ -636,7 +631,7 @@ int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl) ...@@ -636,7 +631,7 @@ int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl)
struct hlist_head *chain; struct hlist_head *chain;
struct hlist_node *newpos; struct hlist_node *newpos;
write_lock_bh(&xfrm_policy_lock); write_lock_bh(&net->xfrm.xfrm_policy_lock);
chain = policy_hash_bysel(net, &policy->selector, policy->family, dir); chain = policy_hash_bysel(net, &policy->selector, policy->family, dir);
delpol = NULL; delpol = NULL;
newpos = NULL; newpos = NULL;
...@@ -647,7 +642,7 @@ int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl) ...@@ -647,7 +642,7 @@ int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl)
xfrm_sec_ctx_match(pol->security, policy->security) && xfrm_sec_ctx_match(pol->security, policy->security) &&
!WARN_ON(delpol)) { !WARN_ON(delpol)) {
if (excl) { if (excl) {
write_unlock_bh(&xfrm_policy_lock); write_unlock_bh(&net->xfrm.xfrm_policy_lock);
return -EEXIST; return -EEXIST;
} }
delpol = pol; delpol = pol;
...@@ -685,7 +680,7 @@ int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl) ...@@ -685,7 +680,7 @@ int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl)
if (!mod_timer(&policy->timer, jiffies + HZ)) if (!mod_timer(&policy->timer, jiffies + HZ))
xfrm_pol_hold(policy); xfrm_pol_hold(policy);
list_add(&policy->walk.all, &net->xfrm.policy_all); list_add(&policy->walk.all, &net->xfrm.policy_all);
write_unlock_bh(&xfrm_policy_lock); write_unlock_bh(&net->xfrm.xfrm_policy_lock);
if (delpol) if (delpol)
xfrm_policy_kill(delpol); xfrm_policy_kill(delpol);
...@@ -705,7 +700,7 @@ struct xfrm_policy *xfrm_policy_bysel_ctx(struct net *net, u32 mark, u8 type, ...@@ -705,7 +700,7 @@ struct xfrm_policy *xfrm_policy_bysel_ctx(struct net *net, u32 mark, u8 type,
struct hlist_head *chain; struct hlist_head *chain;
*err = 0; *err = 0;
write_lock_bh(&xfrm_policy_lock); write_lock_bh(&net->xfrm.xfrm_policy_lock);
chain = policy_hash_bysel(net, sel, sel->family, dir); chain = policy_hash_bysel(net, sel, sel->family, dir);
ret = NULL; ret = NULL;
hlist_for_each_entry(pol, chain, bydst) { hlist_for_each_entry(pol, chain, bydst) {
...@@ -718,7 +713,7 @@ struct xfrm_policy *xfrm_policy_bysel_ctx(struct net *net, u32 mark, u8 type, ...@@ -718,7 +713,7 @@ struct xfrm_policy *xfrm_policy_bysel_ctx(struct net *net, u32 mark, u8 type,
*err = security_xfrm_policy_delete( *err = security_xfrm_policy_delete(
pol->security); pol->security);
if (*err) { if (*err) {
write_unlock_bh(&xfrm_policy_lock); write_unlock_bh(&net->xfrm.xfrm_policy_lock);
return pol; return pol;
} }
__xfrm_policy_unlink(pol, dir); __xfrm_policy_unlink(pol, dir);
...@@ -727,7 +722,7 @@ struct xfrm_policy *xfrm_policy_bysel_ctx(struct net *net, u32 mark, u8 type, ...@@ -727,7 +722,7 @@ struct xfrm_policy *xfrm_policy_bysel_ctx(struct net *net, u32 mark, u8 type,
break; break;
} }
} }
write_unlock_bh(&xfrm_policy_lock); write_unlock_bh(&net->xfrm.xfrm_policy_lock);
if (ret && delete) if (ret && delete)
xfrm_policy_kill(ret); xfrm_policy_kill(ret);
...@@ -746,7 +741,7 @@ struct xfrm_policy *xfrm_policy_byid(struct net *net, u32 mark, u8 type, ...@@ -746,7 +741,7 @@ struct xfrm_policy *xfrm_policy_byid(struct net *net, u32 mark, u8 type,
return NULL; return NULL;
*err = 0; *err = 0;
write_lock_bh(&xfrm_policy_lock); write_lock_bh(&net->xfrm.xfrm_policy_lock);
chain = net->xfrm.policy_byidx + idx_hash(net, id); chain = net->xfrm.policy_byidx + idx_hash(net, id);
ret = NULL; ret = NULL;
hlist_for_each_entry(pol, chain, byidx) { hlist_for_each_entry(pol, chain, byidx) {
...@@ -757,7 +752,7 @@ struct xfrm_policy *xfrm_policy_byid(struct net *net, u32 mark, u8 type, ...@@ -757,7 +752,7 @@ struct xfrm_policy *xfrm_policy_byid(struct net *net, u32 mark, u8 type,
*err = security_xfrm_policy_delete( *err = security_xfrm_policy_delete(
pol->security); pol->security);
if (*err) { if (*err) {
write_unlock_bh(&xfrm_policy_lock); write_unlock_bh(&net->xfrm.xfrm_policy_lock);
return pol; return pol;
} }
__xfrm_policy_unlink(pol, dir); __xfrm_policy_unlink(pol, dir);
...@@ -766,7 +761,7 @@ struct xfrm_policy *xfrm_policy_byid(struct net *net, u32 mark, u8 type, ...@@ -766,7 +761,7 @@ struct xfrm_policy *xfrm_policy_byid(struct net *net, u32 mark, u8 type,
break; break;
} }
} }
write_unlock_bh(&xfrm_policy_lock); write_unlock_bh(&net->xfrm.xfrm_policy_lock);
if (ret && delete) if (ret && delete)
xfrm_policy_kill(ret); xfrm_policy_kill(ret);
...@@ -829,7 +824,7 @@ int xfrm_policy_flush(struct net *net, u8 type, struct xfrm_audit *audit_info) ...@@ -829,7 +824,7 @@ int xfrm_policy_flush(struct net *net, u8 type, struct xfrm_audit *audit_info)
{ {
int dir, err = 0, cnt = 0; int dir, err = 0, cnt = 0;
write_lock_bh(&xfrm_policy_lock); write_lock_bh(&net->xfrm.xfrm_policy_lock);
err = xfrm_policy_flush_secctx_check(net, type, audit_info); err = xfrm_policy_flush_secctx_check(net, type, audit_info);
if (err) if (err)
...@@ -845,7 +840,7 @@ int xfrm_policy_flush(struct net *net, u8 type, struct xfrm_audit *audit_info) ...@@ -845,7 +840,7 @@ int xfrm_policy_flush(struct net *net, u8 type, struct xfrm_audit *audit_info)
if (pol->type != type) if (pol->type != type)
continue; continue;
__xfrm_policy_unlink(pol, dir); __xfrm_policy_unlink(pol, dir);
write_unlock_bh(&xfrm_policy_lock); write_unlock_bh(&net->xfrm.xfrm_policy_lock);
cnt++; cnt++;
xfrm_audit_policy_delete(pol, 1, audit_info->loginuid, xfrm_audit_policy_delete(pol, 1, audit_info->loginuid,
...@@ -854,7 +849,7 @@ int xfrm_policy_flush(struct net *net, u8 type, struct xfrm_audit *audit_info) ...@@ -854,7 +849,7 @@ int xfrm_policy_flush(struct net *net, u8 type, struct xfrm_audit *audit_info)
xfrm_policy_kill(pol); xfrm_policy_kill(pol);
write_lock_bh(&xfrm_policy_lock); write_lock_bh(&net->xfrm.xfrm_policy_lock);
goto again1; goto again1;
} }
...@@ -866,7 +861,7 @@ int xfrm_policy_flush(struct net *net, u8 type, struct xfrm_audit *audit_info) ...@@ -866,7 +861,7 @@ int xfrm_policy_flush(struct net *net, u8 type, struct xfrm_audit *audit_info)
if (pol->type != type) if (pol->type != type)
continue; continue;
__xfrm_policy_unlink(pol, dir); __xfrm_policy_unlink(pol, dir);
write_unlock_bh(&xfrm_policy_lock); write_unlock_bh(&net->xfrm.xfrm_policy_lock);
cnt++; cnt++;
xfrm_audit_policy_delete(pol, 1, xfrm_audit_policy_delete(pol, 1,
...@@ -875,7 +870,7 @@ int xfrm_policy_flush(struct net *net, u8 type, struct xfrm_audit *audit_info) ...@@ -875,7 +870,7 @@ int xfrm_policy_flush(struct net *net, u8 type, struct xfrm_audit *audit_info)
audit_info->secid); audit_info->secid);
xfrm_policy_kill(pol); xfrm_policy_kill(pol);
write_lock_bh(&xfrm_policy_lock); write_lock_bh(&net->xfrm.xfrm_policy_lock);
goto again2; goto again2;
} }
} }
...@@ -884,7 +879,7 @@ int xfrm_policy_flush(struct net *net, u8 type, struct xfrm_audit *audit_info) ...@@ -884,7 +879,7 @@ int xfrm_policy_flush(struct net *net, u8 type, struct xfrm_audit *audit_info)
if (!cnt) if (!cnt)
err = -ESRCH; err = -ESRCH;
out: out:
write_unlock_bh(&xfrm_policy_lock); write_unlock_bh(&net->xfrm.xfrm_policy_lock);
return err; return err;
} }
EXPORT_SYMBOL(xfrm_policy_flush); EXPORT_SYMBOL(xfrm_policy_flush);
...@@ -904,7 +899,7 @@ int xfrm_policy_walk(struct net *net, struct xfrm_policy_walk *walk, ...@@ -904,7 +899,7 @@ int xfrm_policy_walk(struct net *net, struct xfrm_policy_walk *walk,
if (list_empty(&walk->walk.all) && walk->seq != 0) if (list_empty(&walk->walk.all) && walk->seq != 0)
return 0; return 0;
write_lock_bh(&xfrm_policy_lock); write_lock_bh(&net->xfrm.xfrm_policy_lock);
if (list_empty(&walk->walk.all)) if (list_empty(&walk->walk.all))
x = list_first_entry(&net->xfrm.policy_all, struct xfrm_policy_walk_entry, all); x = list_first_entry(&net->xfrm.policy_all, struct xfrm_policy_walk_entry, all);
else else
...@@ -930,7 +925,7 @@ int xfrm_policy_walk(struct net *net, struct xfrm_policy_walk *walk, ...@@ -930,7 +925,7 @@ int xfrm_policy_walk(struct net *net, struct xfrm_policy_walk *walk,
} }
list_del_init(&walk->walk.all); list_del_init(&walk->walk.all);
out: out:
write_unlock_bh(&xfrm_policy_lock); write_unlock_bh(&net->xfrm.xfrm_policy_lock);
return error; return error;
} }
EXPORT_SYMBOL(xfrm_policy_walk); EXPORT_SYMBOL(xfrm_policy_walk);
...@@ -944,14 +939,14 @@ void xfrm_policy_walk_init(struct xfrm_policy_walk *walk, u8 type) ...@@ -944,14 +939,14 @@ void xfrm_policy_walk_init(struct xfrm_policy_walk *walk, u8 type)
} }
EXPORT_SYMBOL(xfrm_policy_walk_init); EXPORT_SYMBOL(xfrm_policy_walk_init);
void xfrm_policy_walk_done(struct xfrm_policy_walk *walk) void xfrm_policy_walk_done(struct xfrm_policy_walk *walk, struct net *net)
{ {
if (list_empty(&walk->walk.all)) if (list_empty(&walk->walk.all))
return; return;
write_lock_bh(&xfrm_policy_lock); write_lock_bh(&net->xfrm.xfrm_policy_lock); /*FIXME where is net? */
list_del(&walk->walk.all); list_del(&walk->walk.all);
write_unlock_bh(&xfrm_policy_lock); write_unlock_bh(&net->xfrm.xfrm_policy_lock);
} }
EXPORT_SYMBOL(xfrm_policy_walk_done); EXPORT_SYMBOL(xfrm_policy_walk_done);
...@@ -996,7 +991,7 @@ static struct xfrm_policy *xfrm_policy_lookup_bytype(struct net *net, u8 type, ...@@ -996,7 +991,7 @@ static struct xfrm_policy *xfrm_policy_lookup_bytype(struct net *net, u8 type,
if (unlikely(!daddr || !saddr)) if (unlikely(!daddr || !saddr))
return NULL; return NULL;
read_lock_bh(&xfrm_policy_lock); read_lock_bh(&net->xfrm.xfrm_policy_lock);
chain = policy_hash_direct(net, daddr, saddr, family, dir); chain = policy_hash_direct(net, daddr, saddr, family, dir);
ret = NULL; ret = NULL;
hlist_for_each_entry(pol, chain, bydst) { hlist_for_each_entry(pol, chain, bydst) {
...@@ -1032,7 +1027,7 @@ static struct xfrm_policy *xfrm_policy_lookup_bytype(struct net *net, u8 type, ...@@ -1032,7 +1027,7 @@ static struct xfrm_policy *xfrm_policy_lookup_bytype(struct net *net, u8 type,
if (ret) if (ret)
xfrm_pol_hold(ret); xfrm_pol_hold(ret);
fail: fail:
read_unlock_bh(&xfrm_policy_lock); read_unlock_bh(&net->xfrm.xfrm_policy_lock);
return ret; return ret;
} }
...@@ -1109,8 +1104,9 @@ static struct xfrm_policy *xfrm_sk_policy_lookup(struct sock *sk, int dir, ...@@ -1109,8 +1104,9 @@ static struct xfrm_policy *xfrm_sk_policy_lookup(struct sock *sk, int dir,
const struct flowi *fl) const struct flowi *fl)
{ {
struct xfrm_policy *pol; struct xfrm_policy *pol;
struct net *net = sock_net(sk);
read_lock_bh(&xfrm_policy_lock); read_lock_bh(&net->xfrm.xfrm_policy_lock);
if ((pol = sk->sk_policy[dir]) != NULL) { if ((pol = sk->sk_policy[dir]) != NULL) {
bool match = xfrm_selector_match(&pol->selector, fl, bool match = xfrm_selector_match(&pol->selector, fl,
sk->sk_family); sk->sk_family);
...@@ -1134,7 +1130,7 @@ static struct xfrm_policy *xfrm_sk_policy_lookup(struct sock *sk, int dir, ...@@ -1134,7 +1130,7 @@ static struct xfrm_policy *xfrm_sk_policy_lookup(struct sock *sk, int dir,
pol = NULL; pol = NULL;
} }
out: out:
read_unlock_bh(&xfrm_policy_lock); read_unlock_bh(&net->xfrm.xfrm_policy_lock);
return pol; return pol;
} }
...@@ -1172,9 +1168,11 @@ static struct xfrm_policy *__xfrm_policy_unlink(struct xfrm_policy *pol, ...@@ -1172,9 +1168,11 @@ static struct xfrm_policy *__xfrm_policy_unlink(struct xfrm_policy *pol,
int xfrm_policy_delete(struct xfrm_policy *pol, int dir) int xfrm_policy_delete(struct xfrm_policy *pol, int dir)
{ {
write_lock_bh(&xfrm_policy_lock); struct net *net = xp_net(pol);
write_lock_bh(&net->xfrm.xfrm_policy_lock);
pol = __xfrm_policy_unlink(pol, dir); pol = __xfrm_policy_unlink(pol, dir);
write_unlock_bh(&xfrm_policy_lock); write_unlock_bh(&net->xfrm.xfrm_policy_lock);
if (pol) { if (pol) {
xfrm_policy_kill(pol); xfrm_policy_kill(pol);
return 0; return 0;
...@@ -1193,7 +1191,7 @@ int xfrm_sk_policy_insert(struct sock *sk, int dir, struct xfrm_policy *pol) ...@@ -1193,7 +1191,7 @@ int xfrm_sk_policy_insert(struct sock *sk, int dir, struct xfrm_policy *pol)
return -EINVAL; return -EINVAL;
#endif #endif
write_lock_bh(&xfrm_policy_lock); write_lock_bh(&net->xfrm.xfrm_policy_lock);
old_pol = sk->sk_policy[dir]; old_pol = sk->sk_policy[dir];
sk->sk_policy[dir] = pol; sk->sk_policy[dir] = pol;
if (pol) { if (pol) {
...@@ -1210,7 +1208,7 @@ int xfrm_sk_policy_insert(struct sock *sk, int dir, struct xfrm_policy *pol) ...@@ -1210,7 +1208,7 @@ int xfrm_sk_policy_insert(struct sock *sk, int dir, struct xfrm_policy *pol)
*/ */
__xfrm_policy_unlink(old_pol, XFRM_POLICY_MAX+dir); __xfrm_policy_unlink(old_pol, XFRM_POLICY_MAX+dir);
} }
write_unlock_bh(&xfrm_policy_lock); write_unlock_bh(&net->xfrm.xfrm_policy_lock);
if (old_pol) { if (old_pol) {
xfrm_policy_kill(old_pol); xfrm_policy_kill(old_pol);
...@@ -1221,6 +1219,7 @@ int xfrm_sk_policy_insert(struct sock *sk, int dir, struct xfrm_policy *pol) ...@@ -1221,6 +1219,7 @@ int xfrm_sk_policy_insert(struct sock *sk, int dir, struct xfrm_policy *pol)
static struct xfrm_policy *clone_policy(const struct xfrm_policy *old, int dir) static struct xfrm_policy *clone_policy(const struct xfrm_policy *old, int dir)
{ {
struct xfrm_policy *newp = xfrm_policy_alloc(xp_net(old), GFP_ATOMIC); struct xfrm_policy *newp = xfrm_policy_alloc(xp_net(old), GFP_ATOMIC);
struct net *net = xp_net(old);
if (newp) { if (newp) {
newp->selector = old->selector; newp->selector = old->selector;
...@@ -1239,9 +1238,9 @@ static struct xfrm_policy *clone_policy(const struct xfrm_policy *old, int dir) ...@@ -1239,9 +1238,9 @@ static struct xfrm_policy *clone_policy(const struct xfrm_policy *old, int dir)
newp->type = old->type; newp->type = old->type;
memcpy(newp->xfrm_vec, old->xfrm_vec, memcpy(newp->xfrm_vec, old->xfrm_vec,
newp->xfrm_nr*sizeof(struct xfrm_tmpl)); newp->xfrm_nr*sizeof(struct xfrm_tmpl));
write_lock_bh(&xfrm_policy_lock); write_lock_bh(&net->xfrm.xfrm_policy_lock);
__xfrm_policy_link(newp, XFRM_POLICY_MAX+dir); __xfrm_policy_link(newp, XFRM_POLICY_MAX+dir);
write_unlock_bh(&xfrm_policy_lock); write_unlock_bh(&net->xfrm.xfrm_policy_lock);
xfrm_pol_put(newp); xfrm_pol_put(newp);
} }
return newp; return newp;
...@@ -2112,10 +2111,10 @@ struct dst_entry *xfrm_lookup(struct net *net, struct dst_entry *dst_orig, ...@@ -2112,10 +2111,10 @@ struct dst_entry *xfrm_lookup(struct net *net, struct dst_entry *dst_orig,
dst_hold(&xdst->u.dst); dst_hold(&xdst->u.dst);
spin_lock_bh(&xfrm_policy_sk_bundle_lock); spin_lock_bh(&net->xfrm.xfrm_policy_sk_bundle_lock);
xdst->u.dst.next = xfrm_policy_sk_bundles; xdst->u.dst.next = xfrm_policy_sk_bundles;
xfrm_policy_sk_bundles = &xdst->u.dst; xfrm_policy_sk_bundles = &xdst->u.dst;
spin_unlock_bh(&xfrm_policy_sk_bundle_lock); spin_unlock_bh(&net->xfrm.xfrm_policy_sk_bundle_lock);
route = xdst->route; route = xdst->route;
} }
...@@ -2440,7 +2439,7 @@ int __xfrm_policy_check(struct sock *sk, int dir, struct sk_buff *skb, ...@@ -2440,7 +2439,7 @@ int __xfrm_policy_check(struct sock *sk, int dir, struct sk_buff *skb,
} }
xfrm_nr = ti; xfrm_nr = ti;
if (npols > 1) { if (npols > 1) {
xfrm_tmpl_sort(stp, tpp, xfrm_nr, family); xfrm_tmpl_sort(stp, tpp, xfrm_nr, family, net);
tpp = stp; tpp = stp;
} }
...@@ -2569,10 +2568,10 @@ static void __xfrm_garbage_collect(struct net *net) ...@@ -2569,10 +2568,10 @@ static void __xfrm_garbage_collect(struct net *net)
{ {
struct dst_entry *head, *next; struct dst_entry *head, *next;
spin_lock_bh(&xfrm_policy_sk_bundle_lock); spin_lock_bh(&net->xfrm.xfrm_policy_sk_bundle_lock);
head = xfrm_policy_sk_bundles; head = xfrm_policy_sk_bundles;
xfrm_policy_sk_bundles = NULL; xfrm_policy_sk_bundles = NULL;
spin_unlock_bh(&xfrm_policy_sk_bundle_lock); spin_unlock_bh(&net->xfrm.xfrm_policy_sk_bundle_lock);
while (head) { while (head) {
next = head->next; next = head->next;
...@@ -2956,6 +2955,13 @@ static int __net_init xfrm_net_init(struct net *net) ...@@ -2956,6 +2955,13 @@ static int __net_init xfrm_net_init(struct net *net)
rv = xfrm_sysctl_init(net); rv = xfrm_sysctl_init(net);
if (rv < 0) if (rv < 0)
goto out_sysctl; goto out_sysctl;
/* Initialize the per-net locks here */
spin_lock_init(&net->xfrm.xfrm_state_lock);
rwlock_init(&net->xfrm.xfrm_policy_lock);
spin_lock_init(&net->xfrm.xfrm_policy_sk_bundle_lock);
mutex_init(&net->xfrm.xfrm_cfg_mutex);
return 0; return 0;
out_sysctl: out_sysctl:
...@@ -3082,7 +3088,7 @@ static struct xfrm_policy * xfrm_migrate_policy_find(const struct xfrm_selector ...@@ -3082,7 +3088,7 @@ static struct xfrm_policy * xfrm_migrate_policy_find(const struct xfrm_selector
struct hlist_head *chain; struct hlist_head *chain;
u32 priority = ~0U; u32 priority = ~0U;
read_lock_bh(&xfrm_policy_lock); read_lock_bh(&net->xfrm.xfrm_policy_lock); /*FIXME*/
chain = policy_hash_direct(net, &sel->daddr, &sel->saddr, sel->family, dir); chain = policy_hash_direct(net, &sel->daddr, &sel->saddr, sel->family, dir);
hlist_for_each_entry(pol, chain, bydst) { hlist_for_each_entry(pol, chain, bydst) {
if (xfrm_migrate_selector_match(sel, &pol->selector) && if (xfrm_migrate_selector_match(sel, &pol->selector) &&
...@@ -3105,7 +3111,7 @@ static struct xfrm_policy * xfrm_migrate_policy_find(const struct xfrm_selector ...@@ -3105,7 +3111,7 @@ static struct xfrm_policy * xfrm_migrate_policy_find(const struct xfrm_selector
if (ret) if (ret)
xfrm_pol_hold(ret); xfrm_pol_hold(ret);
read_unlock_bh(&xfrm_policy_lock); read_unlock_bh(&net->xfrm.xfrm_policy_lock);
return ret; return ret;
} }
...@@ -3236,7 +3242,7 @@ int xfrm_migrate(const struct xfrm_selector *sel, u8 dir, u8 type, ...@@ -3236,7 +3242,7 @@ int xfrm_migrate(const struct xfrm_selector *sel, u8 dir, u8 type,
/* Stage 2 - find and update state(s) */ /* Stage 2 - find and update state(s) */
for (i = 0, mp = m; i < num_migrate; i++, mp++) { for (i = 0, mp = m; i < num_migrate; i++, mp++) {
if ((x = xfrm_migrate_state_find(mp))) { if ((x = xfrm_migrate_state_find(mp, net))) {
x_cur[nx_cur] = x; x_cur[nx_cur] = x;
nx_cur++; nx_cur++;
if ((xc = xfrm_state_migrate(x, mp))) { if ((xc = xfrm_state_migrate(x, mp))) {
......
...@@ -35,8 +35,6 @@ ...@@ -35,8 +35,6 @@
destination/tunnel endpoint. (output) destination/tunnel endpoint. (output)
*/ */
static DEFINE_SPINLOCK(xfrm_state_lock);
static unsigned int xfrm_state_hashmax __read_mostly = 1 * 1024 * 1024; static unsigned int xfrm_state_hashmax __read_mostly = 1 * 1024 * 1024;
static inline unsigned int xfrm_dst_hash(struct net *net, static inline unsigned int xfrm_dst_hash(struct net *net,
...@@ -127,7 +125,7 @@ static void xfrm_hash_resize(struct work_struct *work) ...@@ -127,7 +125,7 @@ static void xfrm_hash_resize(struct work_struct *work)
goto out_unlock; goto out_unlock;
} }
spin_lock_bh(&xfrm_state_lock); spin_lock_bh(&net->xfrm.xfrm_state_lock);
nhashmask = (nsize / sizeof(struct hlist_head)) - 1U; nhashmask = (nsize / sizeof(struct hlist_head)) - 1U;
for (i = net->xfrm.state_hmask; i >= 0; i--) for (i = net->xfrm.state_hmask; i >= 0; i--)
...@@ -144,7 +142,7 @@ static void xfrm_hash_resize(struct work_struct *work) ...@@ -144,7 +142,7 @@ static void xfrm_hash_resize(struct work_struct *work)
net->xfrm.state_byspi = nspi; net->xfrm.state_byspi = nspi;
net->xfrm.state_hmask = nhashmask; net->xfrm.state_hmask = nhashmask;
spin_unlock_bh(&xfrm_state_lock); spin_unlock_bh(&net->xfrm.xfrm_state_lock);
osize = (ohashmask + 1) * sizeof(struct hlist_head); osize = (ohashmask + 1) * sizeof(struct hlist_head);
xfrm_hash_free(odst, osize); xfrm_hash_free(odst, osize);
...@@ -535,14 +533,14 @@ int __xfrm_state_delete(struct xfrm_state *x) ...@@ -535,14 +533,14 @@ int __xfrm_state_delete(struct xfrm_state *x)
if (x->km.state != XFRM_STATE_DEAD) { if (x->km.state != XFRM_STATE_DEAD) {
x->km.state = XFRM_STATE_DEAD; x->km.state = XFRM_STATE_DEAD;
spin_lock(&xfrm_state_lock); spin_lock(&net->xfrm.xfrm_state_lock);
list_del(&x->km.all); list_del(&x->km.all);
hlist_del(&x->bydst); hlist_del(&x->bydst);
hlist_del(&x->bysrc); hlist_del(&x->bysrc);
if (x->id.spi) if (x->id.spi)
hlist_del(&x->byspi); hlist_del(&x->byspi);
net->xfrm.state_num--; net->xfrm.state_num--;
spin_unlock(&xfrm_state_lock); spin_unlock(&net->xfrm.xfrm_state_lock);
/* All xfrm_state objects are created by xfrm_state_alloc. /* All xfrm_state objects are created by xfrm_state_alloc.
* The xfrm_state_alloc call gives a reference, and that * The xfrm_state_alloc call gives a reference, and that
...@@ -603,7 +601,7 @@ int xfrm_state_flush(struct net *net, u8 proto, struct xfrm_audit *audit_info) ...@@ -603,7 +601,7 @@ int xfrm_state_flush(struct net *net, u8 proto, struct xfrm_audit *audit_info)
{ {
int i, err = 0, cnt = 0; int i, err = 0, cnt = 0;
spin_lock_bh(&xfrm_state_lock); spin_lock_bh(&net->xfrm.xfrm_state_lock);
err = xfrm_state_flush_secctx_check(net, proto, audit_info); err = xfrm_state_flush_secctx_check(net, proto, audit_info);
if (err) if (err)
goto out; goto out;
...@@ -616,7 +614,7 @@ int xfrm_state_flush(struct net *net, u8 proto, struct xfrm_audit *audit_info) ...@@ -616,7 +614,7 @@ int xfrm_state_flush(struct net *net, u8 proto, struct xfrm_audit *audit_info)
if (!xfrm_state_kern(x) && if (!xfrm_state_kern(x) &&
xfrm_id_proto_match(x->id.proto, proto)) { xfrm_id_proto_match(x->id.proto, proto)) {
xfrm_state_hold(x); xfrm_state_hold(x);
spin_unlock_bh(&xfrm_state_lock); spin_unlock_bh(&net->xfrm.xfrm_state_lock);
err = xfrm_state_delete(x); err = xfrm_state_delete(x);
xfrm_audit_state_delete(x, err ? 0 : 1, xfrm_audit_state_delete(x, err ? 0 : 1,
...@@ -627,7 +625,7 @@ int xfrm_state_flush(struct net *net, u8 proto, struct xfrm_audit *audit_info) ...@@ -627,7 +625,7 @@ int xfrm_state_flush(struct net *net, u8 proto, struct xfrm_audit *audit_info)
if (!err) if (!err)
cnt++; cnt++;
spin_lock_bh(&xfrm_state_lock); spin_lock_bh(&net->xfrm.xfrm_state_lock);
goto restart; goto restart;
} }
} }
...@@ -636,7 +634,7 @@ int xfrm_state_flush(struct net *net, u8 proto, struct xfrm_audit *audit_info) ...@@ -636,7 +634,7 @@ int xfrm_state_flush(struct net *net, u8 proto, struct xfrm_audit *audit_info)
err = 0; err = 0;
out: out:
spin_unlock_bh(&xfrm_state_lock); spin_unlock_bh(&net->xfrm.xfrm_state_lock);
wake_up(&net->xfrm.km_waitq); wake_up(&net->xfrm.km_waitq);
return err; return err;
} }
...@@ -644,11 +642,11 @@ EXPORT_SYMBOL(xfrm_state_flush); ...@@ -644,11 +642,11 @@ EXPORT_SYMBOL(xfrm_state_flush);
void xfrm_sad_getinfo(struct net *net, struct xfrmk_sadinfo *si) void xfrm_sad_getinfo(struct net *net, struct xfrmk_sadinfo *si)
{ {
spin_lock_bh(&xfrm_state_lock); spin_lock_bh(&net->xfrm.xfrm_state_lock);
si->sadcnt = net->xfrm.state_num; si->sadcnt = net->xfrm.state_num;
si->sadhcnt = net->xfrm.state_hmask; si->sadhcnt = net->xfrm.state_hmask;
si->sadhmcnt = xfrm_state_hashmax; si->sadhmcnt = xfrm_state_hashmax;
spin_unlock_bh(&xfrm_state_lock); spin_unlock_bh(&net->xfrm.xfrm_state_lock);
} }
EXPORT_SYMBOL(xfrm_sad_getinfo); EXPORT_SYMBOL(xfrm_sad_getinfo);
...@@ -801,7 +799,7 @@ xfrm_state_find(const xfrm_address_t *daddr, const xfrm_address_t *saddr, ...@@ -801,7 +799,7 @@ xfrm_state_find(const xfrm_address_t *daddr, const xfrm_address_t *saddr,
to_put = NULL; to_put = NULL;
spin_lock_bh(&xfrm_state_lock); spin_lock_bh(&net->xfrm.xfrm_state_lock);
h = xfrm_dst_hash(net, daddr, saddr, tmpl->reqid, encap_family); h = xfrm_dst_hash(net, daddr, saddr, tmpl->reqid, encap_family);
hlist_for_each_entry(x, net->xfrm.state_bydst+h, bydst) { hlist_for_each_entry(x, net->xfrm.state_bydst+h, bydst) {
if (x->props.family == encap_family && if (x->props.family == encap_family &&
...@@ -886,7 +884,7 @@ xfrm_state_find(const xfrm_address_t *daddr, const xfrm_address_t *saddr, ...@@ -886,7 +884,7 @@ xfrm_state_find(const xfrm_address_t *daddr, const xfrm_address_t *saddr,
xfrm_state_hold(x); xfrm_state_hold(x);
else else
*err = acquire_in_progress ? -EAGAIN : error; *err = acquire_in_progress ? -EAGAIN : error;
spin_unlock_bh(&xfrm_state_lock); spin_unlock_bh(&net->xfrm.xfrm_state_lock);
if (to_put) if (to_put)
xfrm_state_put(to_put); xfrm_state_put(to_put);
return x; return x;
...@@ -900,7 +898,7 @@ xfrm_stateonly_find(struct net *net, u32 mark, ...@@ -900,7 +898,7 @@ xfrm_stateonly_find(struct net *net, u32 mark,
unsigned int h; unsigned int h;
struct xfrm_state *rx = NULL, *x = NULL; struct xfrm_state *rx = NULL, *x = NULL;
spin_lock(&xfrm_state_lock); spin_lock(&net->xfrm.xfrm_state_lock);
h = xfrm_dst_hash(net, daddr, saddr, reqid, family); h = xfrm_dst_hash(net, daddr, saddr, reqid, family);
hlist_for_each_entry(x, net->xfrm.state_bydst+h, bydst) { hlist_for_each_entry(x, net->xfrm.state_bydst+h, bydst) {
if (x->props.family == family && if (x->props.family == family &&
...@@ -918,7 +916,7 @@ xfrm_stateonly_find(struct net *net, u32 mark, ...@@ -918,7 +916,7 @@ xfrm_stateonly_find(struct net *net, u32 mark,
if (rx) if (rx)
xfrm_state_hold(rx); xfrm_state_hold(rx);
spin_unlock(&xfrm_state_lock); spin_unlock(&net->xfrm.xfrm_state_lock);
return rx; return rx;
...@@ -957,7 +955,7 @@ static void __xfrm_state_insert(struct xfrm_state *x) ...@@ -957,7 +955,7 @@ static void __xfrm_state_insert(struct xfrm_state *x)
xfrm_hash_grow_check(net, x->bydst.next != NULL); xfrm_hash_grow_check(net, x->bydst.next != NULL);
} }
/* xfrm_state_lock is held */ /* net->xfrm.xfrm_state_lock is held */
static void __xfrm_state_bump_genids(struct xfrm_state *xnew) static void __xfrm_state_bump_genids(struct xfrm_state *xnew)
{ {
struct net *net = xs_net(xnew); struct net *net = xs_net(xnew);
...@@ -980,14 +978,16 @@ static void __xfrm_state_bump_genids(struct xfrm_state *xnew) ...@@ -980,14 +978,16 @@ static void __xfrm_state_bump_genids(struct xfrm_state *xnew)
void xfrm_state_insert(struct xfrm_state *x) void xfrm_state_insert(struct xfrm_state *x)
{ {
spin_lock_bh(&xfrm_state_lock); struct net *net = xs_net(x);
spin_lock_bh(&net->xfrm.xfrm_state_lock);
__xfrm_state_bump_genids(x); __xfrm_state_bump_genids(x);
__xfrm_state_insert(x); __xfrm_state_insert(x);
spin_unlock_bh(&xfrm_state_lock); spin_unlock_bh(&net->xfrm.xfrm_state_lock);
} }
EXPORT_SYMBOL(xfrm_state_insert); EXPORT_SYMBOL(xfrm_state_insert);
/* xfrm_state_lock is held */ /* net->xfrm.xfrm_state_lock is held */
static struct xfrm_state *__find_acq_core(struct net *net, static struct xfrm_state *__find_acq_core(struct net *net,
const struct xfrm_mark *m, const struct xfrm_mark *m,
unsigned short family, u8 mode, unsigned short family, u8 mode,
...@@ -1079,7 +1079,7 @@ int xfrm_state_add(struct xfrm_state *x) ...@@ -1079,7 +1079,7 @@ int xfrm_state_add(struct xfrm_state *x)
to_put = NULL; to_put = NULL;
spin_lock_bh(&xfrm_state_lock); spin_lock_bh(&net->xfrm.xfrm_state_lock);
x1 = __xfrm_state_locate(x, use_spi, family); x1 = __xfrm_state_locate(x, use_spi, family);
if (x1) { if (x1) {
...@@ -1108,7 +1108,7 @@ int xfrm_state_add(struct xfrm_state *x) ...@@ -1108,7 +1108,7 @@ int xfrm_state_add(struct xfrm_state *x)
err = 0; err = 0;
out: out:
spin_unlock_bh(&xfrm_state_lock); spin_unlock_bh(&net->xfrm.xfrm_state_lock);
if (x1) { if (x1) {
xfrm_state_delete(x1); xfrm_state_delete(x1);
...@@ -1203,16 +1203,16 @@ static struct xfrm_state *xfrm_state_clone(struct xfrm_state *orig, int *errp) ...@@ -1203,16 +1203,16 @@ static struct xfrm_state *xfrm_state_clone(struct xfrm_state *orig, int *errp)
return NULL; return NULL;
} }
/* xfrm_state_lock is held */ /* net->xfrm.xfrm_state_lock is held */
struct xfrm_state * xfrm_migrate_state_find(struct xfrm_migrate *m) struct xfrm_state *xfrm_migrate_state_find(struct xfrm_migrate *m, struct net *net)
{ {
unsigned int h; unsigned int h;
struct xfrm_state *x; struct xfrm_state *x;
if (m->reqid) { if (m->reqid) {
h = xfrm_dst_hash(&init_net, &m->old_daddr, &m->old_saddr, h = xfrm_dst_hash(net, &m->old_daddr, &m->old_saddr,
m->reqid, m->old_family); m->reqid, m->old_family);
hlist_for_each_entry(x, init_net.xfrm.state_bydst+h, bydst) { hlist_for_each_entry(x, net->xfrm.state_bydst+h, bydst) {
if (x->props.mode != m->mode || if (x->props.mode != m->mode ||
x->id.proto != m->proto) x->id.proto != m->proto)
continue; continue;
...@@ -1227,9 +1227,9 @@ struct xfrm_state * xfrm_migrate_state_find(struct xfrm_migrate *m) ...@@ -1227,9 +1227,9 @@ struct xfrm_state * xfrm_migrate_state_find(struct xfrm_migrate *m)
return x; return x;
} }
} else { } else {
h = xfrm_src_hash(&init_net, &m->old_daddr, &m->old_saddr, h = xfrm_src_hash(net, &m->old_daddr, &m->old_saddr,
m->old_family); m->old_family);
hlist_for_each_entry(x, init_net.xfrm.state_bysrc+h, bysrc) { hlist_for_each_entry(x, net->xfrm.state_bysrc+h, bysrc) {
if (x->props.mode != m->mode || if (x->props.mode != m->mode ||
x->id.proto != m->proto) x->id.proto != m->proto)
continue; continue;
...@@ -1283,10 +1283,11 @@ int xfrm_state_update(struct xfrm_state *x) ...@@ -1283,10 +1283,11 @@ int xfrm_state_update(struct xfrm_state *x)
struct xfrm_state *x1, *to_put; struct xfrm_state *x1, *to_put;
int err; int err;
int use_spi = xfrm_id_proto_match(x->id.proto, IPSEC_PROTO_ANY); int use_spi = xfrm_id_proto_match(x->id.proto, IPSEC_PROTO_ANY);
struct net *net = xs_net(x);
to_put = NULL; to_put = NULL;
spin_lock_bh(&xfrm_state_lock); spin_lock_bh(&net->xfrm.xfrm_state_lock);
x1 = __xfrm_state_locate(x, use_spi, x->props.family); x1 = __xfrm_state_locate(x, use_spi, x->props.family);
err = -ESRCH; err = -ESRCH;
...@@ -1306,7 +1307,7 @@ int xfrm_state_update(struct xfrm_state *x) ...@@ -1306,7 +1307,7 @@ int xfrm_state_update(struct xfrm_state *x)
err = 0; err = 0;
out: out:
spin_unlock_bh(&xfrm_state_lock); spin_unlock_bh(&net->xfrm.xfrm_state_lock);
if (to_put) if (to_put)
xfrm_state_put(to_put); xfrm_state_put(to_put);
...@@ -1377,9 +1378,9 @@ xfrm_state_lookup(struct net *net, u32 mark, const xfrm_address_t *daddr, __be32 ...@@ -1377,9 +1378,9 @@ xfrm_state_lookup(struct net *net, u32 mark, const xfrm_address_t *daddr, __be32
{ {
struct xfrm_state *x; struct xfrm_state *x;
spin_lock_bh(&xfrm_state_lock); spin_lock_bh(&net->xfrm.xfrm_state_lock);
x = __xfrm_state_lookup(net, mark, daddr, spi, proto, family); x = __xfrm_state_lookup(net, mark, daddr, spi, proto, family);
spin_unlock_bh(&xfrm_state_lock); spin_unlock_bh(&net->xfrm.xfrm_state_lock);
return x; return x;
} }
EXPORT_SYMBOL(xfrm_state_lookup); EXPORT_SYMBOL(xfrm_state_lookup);
...@@ -1391,9 +1392,9 @@ xfrm_state_lookup_byaddr(struct net *net, u32 mark, ...@@ -1391,9 +1392,9 @@ xfrm_state_lookup_byaddr(struct net *net, u32 mark,
{ {
struct xfrm_state *x; struct xfrm_state *x;
spin_lock_bh(&xfrm_state_lock); spin_lock_bh(&net->xfrm.xfrm_state_lock);
x = __xfrm_state_lookup_byaddr(net, mark, daddr, saddr, proto, family); x = __xfrm_state_lookup_byaddr(net, mark, daddr, saddr, proto, family);
spin_unlock_bh(&xfrm_state_lock); spin_unlock_bh(&net->xfrm.xfrm_state_lock);
return x; return x;
} }
EXPORT_SYMBOL(xfrm_state_lookup_byaddr); EXPORT_SYMBOL(xfrm_state_lookup_byaddr);
...@@ -1405,9 +1406,9 @@ xfrm_find_acq(struct net *net, const struct xfrm_mark *mark, u8 mode, u32 reqid, ...@@ -1405,9 +1406,9 @@ xfrm_find_acq(struct net *net, const struct xfrm_mark *mark, u8 mode, u32 reqid,
{ {
struct xfrm_state *x; struct xfrm_state *x;
spin_lock_bh(&xfrm_state_lock); spin_lock_bh(&net->xfrm.xfrm_state_lock);
x = __find_acq_core(net, mark, family, mode, reqid, proto, daddr, saddr, create); x = __find_acq_core(net, mark, family, mode, reqid, proto, daddr, saddr, create);
spin_unlock_bh(&xfrm_state_lock); spin_unlock_bh(&net->xfrm.xfrm_state_lock);
return x; return x;
} }
...@@ -1416,17 +1417,17 @@ EXPORT_SYMBOL(xfrm_find_acq); ...@@ -1416,17 +1417,17 @@ EXPORT_SYMBOL(xfrm_find_acq);
#ifdef CONFIG_XFRM_SUB_POLICY #ifdef CONFIG_XFRM_SUB_POLICY
int int
xfrm_tmpl_sort(struct xfrm_tmpl **dst, struct xfrm_tmpl **src, int n, xfrm_tmpl_sort(struct xfrm_tmpl **dst, struct xfrm_tmpl **src, int n,
unsigned short family) unsigned short family, struct net *net)
{ {
int err = 0; int err = 0;
struct xfrm_state_afinfo *afinfo = xfrm_state_get_afinfo(family); struct xfrm_state_afinfo *afinfo = xfrm_state_get_afinfo(family);
if (!afinfo) if (!afinfo)
return -EAFNOSUPPORT; return -EAFNOSUPPORT;
spin_lock_bh(&xfrm_state_lock); spin_lock_bh(&net->xfrm.xfrm_state_lock); /*FIXME*/
if (afinfo->tmpl_sort) if (afinfo->tmpl_sort)
err = afinfo->tmpl_sort(dst, src, n); err = afinfo->tmpl_sort(dst, src, n);
spin_unlock_bh(&xfrm_state_lock); spin_unlock_bh(&net->xfrm.xfrm_state_lock);
xfrm_state_put_afinfo(afinfo); xfrm_state_put_afinfo(afinfo);
return err; return err;
} }
...@@ -1438,13 +1439,15 @@ xfrm_state_sort(struct xfrm_state **dst, struct xfrm_state **src, int n, ...@@ -1438,13 +1439,15 @@ xfrm_state_sort(struct xfrm_state **dst, struct xfrm_state **src, int n,
{ {
int err = 0; int err = 0;
struct xfrm_state_afinfo *afinfo = xfrm_state_get_afinfo(family); struct xfrm_state_afinfo *afinfo = xfrm_state_get_afinfo(family);
struct net *net = xs_net(*dst);
if (!afinfo) if (!afinfo)
return -EAFNOSUPPORT; return -EAFNOSUPPORT;
spin_lock_bh(&xfrm_state_lock); spin_lock_bh(&net->xfrm.xfrm_state_lock);
if (afinfo->state_sort) if (afinfo->state_sort)
err = afinfo->state_sort(dst, src, n); err = afinfo->state_sort(dst, src, n);
spin_unlock_bh(&xfrm_state_lock); spin_unlock_bh(&net->xfrm.xfrm_state_lock);
xfrm_state_put_afinfo(afinfo); xfrm_state_put_afinfo(afinfo);
return err; return err;
} }
...@@ -1476,9 +1479,9 @@ struct xfrm_state *xfrm_find_acq_byseq(struct net *net, u32 mark, u32 seq) ...@@ -1476,9 +1479,9 @@ struct xfrm_state *xfrm_find_acq_byseq(struct net *net, u32 mark, u32 seq)
{ {
struct xfrm_state *x; struct xfrm_state *x;
spin_lock_bh(&xfrm_state_lock); spin_lock_bh(&net->xfrm.xfrm_state_lock);
x = __xfrm_find_acq_byseq(net, mark, seq); x = __xfrm_find_acq_byseq(net, mark, seq);
spin_unlock_bh(&xfrm_state_lock); spin_unlock_bh(&net->xfrm.xfrm_state_lock);
return x; return x;
} }
EXPORT_SYMBOL(xfrm_find_acq_byseq); EXPORT_SYMBOL(xfrm_find_acq_byseq);
...@@ -1536,10 +1539,10 @@ int xfrm_alloc_spi(struct xfrm_state *x, u32 low, u32 high) ...@@ -1536,10 +1539,10 @@ int xfrm_alloc_spi(struct xfrm_state *x, u32 low, u32 high)
} }
} }
if (x->id.spi) { if (x->id.spi) {
spin_lock_bh(&xfrm_state_lock); spin_lock_bh(&net->xfrm.xfrm_state_lock);
h = xfrm_spi_hash(net, &x->id.daddr, x->id.spi, x->id.proto, x->props.family); h = xfrm_spi_hash(net, &x->id.daddr, x->id.spi, x->id.proto, x->props.family);
hlist_add_head(&x->byspi, net->xfrm.state_byspi+h); hlist_add_head(&x->byspi, net->xfrm.state_byspi+h);
spin_unlock_bh(&xfrm_state_lock); spin_unlock_bh(&net->xfrm.xfrm_state_lock);
err = 0; err = 0;
} }
...@@ -1562,7 +1565,7 @@ int xfrm_state_walk(struct net *net, struct xfrm_state_walk *walk, ...@@ -1562,7 +1565,7 @@ int xfrm_state_walk(struct net *net, struct xfrm_state_walk *walk,
if (walk->seq != 0 && list_empty(&walk->all)) if (walk->seq != 0 && list_empty(&walk->all))
return 0; return 0;
spin_lock_bh(&xfrm_state_lock); spin_lock_bh(&net->xfrm.xfrm_state_lock);
if (list_empty(&walk->all)) if (list_empty(&walk->all))
x = list_first_entry(&net->xfrm.state_all, struct xfrm_state_walk, all); x = list_first_entry(&net->xfrm.state_all, struct xfrm_state_walk, all);
else else
...@@ -1586,7 +1589,7 @@ int xfrm_state_walk(struct net *net, struct xfrm_state_walk *walk, ...@@ -1586,7 +1589,7 @@ int xfrm_state_walk(struct net *net, struct xfrm_state_walk *walk,
} }
list_del_init(&walk->all); list_del_init(&walk->all);
out: out:
spin_unlock_bh(&xfrm_state_lock); spin_unlock_bh(&net->xfrm.xfrm_state_lock);
return err; return err;
} }
EXPORT_SYMBOL(xfrm_state_walk); EXPORT_SYMBOL(xfrm_state_walk);
...@@ -1600,14 +1603,14 @@ void xfrm_state_walk_init(struct xfrm_state_walk *walk, u8 proto) ...@@ -1600,14 +1603,14 @@ void xfrm_state_walk_init(struct xfrm_state_walk *walk, u8 proto)
} }
EXPORT_SYMBOL(xfrm_state_walk_init); EXPORT_SYMBOL(xfrm_state_walk_init);
void xfrm_state_walk_done(struct xfrm_state_walk *walk) void xfrm_state_walk_done(struct xfrm_state_walk *walk, struct net *net)
{ {
if (list_empty(&walk->all)) if (list_empty(&walk->all))
return; return;
spin_lock_bh(&xfrm_state_lock); spin_lock_bh(&net->xfrm.xfrm_state_lock);
list_del(&walk->all); list_del(&walk->all);
spin_unlock_bh(&xfrm_state_lock); spin_unlock_bh(&net->xfrm.xfrm_state_lock);
} }
EXPORT_SYMBOL(xfrm_state_walk_done); EXPORT_SYMBOL(xfrm_state_walk_done);
...@@ -2026,6 +2029,7 @@ int __net_init xfrm_state_init(struct net *net) ...@@ -2026,6 +2029,7 @@ int __net_init xfrm_state_init(struct net *net)
INIT_HLIST_HEAD(&net->xfrm.state_gc_list); INIT_HLIST_HEAD(&net->xfrm.state_gc_list);
INIT_WORK(&net->xfrm.state_gc_work, xfrm_state_gc_task); INIT_WORK(&net->xfrm.state_gc_work, xfrm_state_gc_task);
init_waitqueue_head(&net->xfrm.km_waitq); init_waitqueue_head(&net->xfrm.km_waitq);
spin_lock_init(&net->xfrm.xfrm_state_lock);
return 0; return 0;
out_byspi: out_byspi:
......
...@@ -877,7 +877,10 @@ static int dump_one_state(struct xfrm_state *x, int count, void *ptr) ...@@ -877,7 +877,10 @@ static int dump_one_state(struct xfrm_state *x, int count, void *ptr)
static int xfrm_dump_sa_done(struct netlink_callback *cb) static int xfrm_dump_sa_done(struct netlink_callback *cb)
{ {
struct xfrm_state_walk *walk = (struct xfrm_state_walk *) &cb->args[1]; struct xfrm_state_walk *walk = (struct xfrm_state_walk *) &cb->args[1];
xfrm_state_walk_done(walk); struct sock *sk = cb->skb->sk;
struct net *net = sock_net(sk);
xfrm_state_walk_done(walk, net);
return 0; return 0;
} }
...@@ -1555,8 +1558,9 @@ static int dump_one_policy(struct xfrm_policy *xp, int dir, int count, void *ptr ...@@ -1555,8 +1558,9 @@ static int dump_one_policy(struct xfrm_policy *xp, int dir, int count, void *ptr
static int xfrm_dump_policy_done(struct netlink_callback *cb) static int xfrm_dump_policy_done(struct netlink_callback *cb)
{ {
struct xfrm_policy_walk *walk = (struct xfrm_policy_walk *) &cb->args[1]; struct xfrm_policy_walk *walk = (struct xfrm_policy_walk *) &cb->args[1];
struct net *net = sock_net(cb->skb->sk);
xfrm_policy_walk_done(walk); xfrm_policy_walk_done(walk, net);
return 0; return 0;
} }
...@@ -2403,9 +2407,11 @@ static int xfrm_user_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) ...@@ -2403,9 +2407,11 @@ static int xfrm_user_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
static void xfrm_netlink_rcv(struct sk_buff *skb) static void xfrm_netlink_rcv(struct sk_buff *skb)
{ {
mutex_lock(&xfrm_cfg_mutex); struct net *net = sock_net(skb->sk);
mutex_lock(&net->xfrm.xfrm_cfg_mutex);
netlink_rcv_skb(skb, &xfrm_user_rcv_msg); netlink_rcv_skb(skb, &xfrm_user_rcv_msg);
mutex_unlock(&xfrm_cfg_mutex); mutex_unlock(&net->xfrm.xfrm_cfg_mutex);
} }
static inline size_t xfrm_expire_msgsize(void) static inline size_t xfrm_expire_msgsize(void)
......
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