* [PATCH net-next 3/3] xfrm: Namespacify xfrm state/policy locks
From: Fan Du @ 2013-11-06 10:14 UTC (permalink / raw)
To: steffen.klassert, davem, herbert; +Cc: netdev
In-Reply-To: <1383732856-18323-1-git-send-email-fan.du@windriver.com>
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 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>
---
include/net/netns/xfrm.h | 4 ++
include/net/xfrm.h | 11 +++--
net/key/af_key.c | 15 ++++---
net/xfrm/xfrm_policy.c | 104 ++++++++++++++++++++++++----------------------
net/xfrm/xfrm_state.c | 104 ++++++++++++++++++++++++----------------------
net/xfrm/xfrm_user.c | 14 +++++--
6 files changed, 138 insertions(+), 114 deletions(-)
diff --git a/include/net/netns/xfrm.h b/include/net/netns/xfrm.h
index 5299e69..ea28404 100644
--- a/include/net/netns/xfrm.h
+++ b/include/net/netns/xfrm.h
@@ -59,6 +59,10 @@ struct netns_xfrm {
#if IS_ENABLED(CONFIG_IPV6)
struct dst_ops xfrm6_dst_ops;
#endif
+ spinlock_t xfrm_state_lock;
+ spinlock_t xfrm_policy_sk_bundle_lock;
+ rwlock_t xfrm_policy_lock;
+ struct mutex xfrm_cfg_mutex;
};
#endif
diff --git a/include/net/xfrm.h b/include/net/xfrm.h
index 5b522c5..59f5d0a 100644
--- a/include/net/xfrm.h
+++ b/include/net/xfrm.h
@@ -53,7 +53,6 @@
#define XFRM_INC_STATS_USER(net, field) ((void)(net))
#endif
-extern struct mutex xfrm_cfg_mutex;
/* Organization of SPD aka "XFRM rules"
------------------------------------
@@ -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);
int xfrm_state_walk(struct net *net, struct xfrm_state_walk *walk,
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_find(const xfrm_address_t *daddr,
const xfrm_address_t *saddr,
@@ -1436,12 +1435,12 @@ struct xfrm_state *xfrm_state_lookup_byaddr(struct net *net, u32 mark,
unsigned short family);
#ifdef CONFIG_XFRM_SUB_POLICY
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,
unsigned short family);
#else
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;
}
@@ -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 (*func)(struct xfrm_policy *, int, int, 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);
struct xfrm_policy *xfrm_policy_bysel_ctx(struct net *net, u32 mark,
u8 type, int dir,
@@ -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,
const struct xfrm_migrate *m, int num_bundles,
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_migrate *m);
int 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 33480b3..537a4d4 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)
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)
@@ -1861,7 +1863,7 @@ static u32 gen_reqid(struct net *net)
reqid = IPSEC_MANUAL_REQID_MAX+1;
xfrm_policy_walk_init(&walk, XFRM_POLICY_TYPE_MAIN);
rc = xfrm_policy_walk(net, &walk, check_reqid, (void*)&reqid);
- xfrm_policy_walk_done(&walk);
+ xfrm_policy_walk_done(&walk, net);
if (rc != -EEXIST)
return reqid;
} while (reqid != start);
@@ -2660,7 +2662,9 @@ static int pfkey_dump_sp(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)
@@ -3570,6 +3574,7 @@ static int pfkey_sendmsg(struct kiocb *kiocb,
struct sk_buff *skb = NULL;
struct sadb_msg *hdr = NULL;
int err;
+ struct net *net = sock_net(sk);
err = -EOPNOTSUPP;
if (msg->msg_flags & MSG_OOB)
@@ -3592,9 +3597,9 @@ static int pfkey_sendmsg(struct kiocb *kiocb,
if (!hdr)
goto out;
- mutex_lock(&xfrm_cfg_mutex);
+ mutex_lock(&net->xfrm.xfrm_cfg_mutex);
err = pfkey_process(sk, skb, hdr);
- mutex_unlock(&xfrm_cfg_mutex);
+ mutex_unlock(&net->xfrm.xfrm_cfg_mutex);
out:
if (err && hdr && pfkey_error(hdr, err, sk) == 0)
diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c
index 907fd2f..73b04d3 100644
--- a/net/xfrm/xfrm_policy.c
+++ b/net/xfrm/xfrm_policy.c
@@ -39,12 +39,7 @@
#define XFRM_QUEUE_TMO_MAX ((unsigned)(60*HZ))
#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 DEFINE_RWLOCK(xfrm_policy_lock);
static DEFINE_SPINLOCK(xfrm_policy_afinfo_lock);
static struct xfrm_policy_afinfo __rcu *xfrm_policy_afinfo[NPROTO]
@@ -438,7 +433,7 @@ static void xfrm_bydst_resize(struct net *net, int dir)
if (!ndst)
return;
- write_lock_bh(&xfrm_policy_lock);
+ write_lock_bh(&net->xfrm.xfrm_policy_lock);
for (i = hmask; i >= 0; i--)
xfrm_dst_hash_transfer(odst + i, ndst, nhashmask);
@@ -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].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));
}
@@ -463,7 +458,7 @@ static void xfrm_byidx_resize(struct net *net, int total)
if (!nidx)
return;
- write_lock_bh(&xfrm_policy_lock);
+ write_lock_bh(&net->xfrm.xfrm_policy_lock);
for (i = hmask; i >= 0; i--)
xfrm_idx_hash_transfer(oidx + i, nidx, nhashmask);
@@ -471,7 +466,7 @@ static void xfrm_byidx_resize(struct net *net, int total)
net->xfrm.policy_byidx = nidx;
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));
}
@@ -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)
{
- read_lock_bh(&xfrm_policy_lock);
+ read_lock_bh(&net->xfrm.xfrm_policy_lock);
si->incnt = net->xfrm.policy_count[XFRM_POLICY_IN];
si->outcnt = net->xfrm.policy_count[XFRM_POLICY_OUT];
si->fwdcnt = net->xfrm.policy_count[XFRM_POLICY_FWD];
@@ -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->spdhcnt = net->xfrm.policy_idx_hmask;
si->spdhmcnt = xfrm_policy_hashmax;
- read_unlock_bh(&xfrm_policy_lock);
+ read_unlock_bh(&net->xfrm.xfrm_policy_lock);
}
EXPORT_SYMBOL(xfrm_spd_getinfo);
@@ -636,7 +631,7 @@ int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl)
struct hlist_head *chain;
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);
delpol = NULL;
newpos = NULL;
@@ -647,7 +642,7 @@ int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl)
xfrm_sec_ctx_match(pol->security, policy->security) &&
!WARN_ON(delpol)) {
if (excl) {
- write_unlock_bh(&xfrm_policy_lock);
+ write_unlock_bh(&net->xfrm.xfrm_policy_lock);
return -EEXIST;
}
delpol = pol;
@@ -685,7 +680,7 @@ int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl)
if (!mod_timer(&policy->timer, jiffies + HZ))
xfrm_pol_hold(policy);
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)
xfrm_policy_kill(delpol);
@@ -705,7 +700,7 @@ struct xfrm_policy *xfrm_policy_bysel_ctx(struct net *net, u32 mark, u8 type,
struct hlist_head *chain;
*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);
ret = NULL;
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,
*err = security_xfrm_policy_delete(
pol->security);
if (*err) {
- write_unlock_bh(&xfrm_policy_lock);
+ write_unlock_bh(&net->xfrm.xfrm_policy_lock);
return pol;
}
__xfrm_policy_unlink(pol, dir);
@@ -727,7 +722,7 @@ struct xfrm_policy *xfrm_policy_bysel_ctx(struct net *net, u32 mark, u8 type,
break;
}
}
- write_unlock_bh(&xfrm_policy_lock);
+ write_unlock_bh(&net->xfrm.xfrm_policy_lock);
if (ret && delete)
xfrm_policy_kill(ret);
@@ -746,7 +741,7 @@ struct xfrm_policy *xfrm_policy_byid(struct net *net, u32 mark, u8 type,
return NULL;
*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);
ret = NULL;
hlist_for_each_entry(pol, chain, byidx) {
@@ -757,7 +752,7 @@ struct xfrm_policy *xfrm_policy_byid(struct net *net, u32 mark, u8 type,
*err = security_xfrm_policy_delete(
pol->security);
if (*err) {
- write_unlock_bh(&xfrm_policy_lock);
+ write_unlock_bh(&net->xfrm.xfrm_policy_lock);
return pol;
}
__xfrm_policy_unlink(pol, dir);
@@ -766,7 +761,7 @@ struct xfrm_policy *xfrm_policy_byid(struct net *net, u32 mark, u8 type,
break;
}
}
- write_unlock_bh(&xfrm_policy_lock);
+ write_unlock_bh(&net->xfrm.xfrm_policy_lock);
if (ret && delete)
xfrm_policy_kill(ret);
@@ -829,7 +824,7 @@ int xfrm_policy_flush(struct net *net, u8 type, struct xfrm_audit *audit_info)
{
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);
if (err)
@@ -845,7 +840,7 @@ int xfrm_policy_flush(struct net *net, u8 type, struct xfrm_audit *audit_info)
if (pol->type != type)
continue;
__xfrm_policy_unlink(pol, dir);
- write_unlock_bh(&xfrm_policy_lock);
+ write_unlock_bh(&net->xfrm.xfrm_policy_lock);
cnt++;
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)
xfrm_policy_kill(pol);
- write_lock_bh(&xfrm_policy_lock);
+ write_lock_bh(&net->xfrm.xfrm_policy_lock);
goto again1;
}
@@ -866,7 +861,7 @@ int xfrm_policy_flush(struct net *net, u8 type, struct xfrm_audit *audit_info)
if (pol->type != type)
continue;
__xfrm_policy_unlink(pol, dir);
- write_unlock_bh(&xfrm_policy_lock);
+ write_unlock_bh(&net->xfrm.xfrm_policy_lock);
cnt++;
xfrm_audit_policy_delete(pol, 1,
@@ -875,7 +870,7 @@ int xfrm_policy_flush(struct net *net, u8 type, struct xfrm_audit *audit_info)
audit_info->secid);
xfrm_policy_kill(pol);
- write_lock_bh(&xfrm_policy_lock);
+ write_lock_bh(&net->xfrm.xfrm_policy_lock);
goto again2;
}
}
@@ -884,7 +879,7 @@ int xfrm_policy_flush(struct net *net, u8 type, struct xfrm_audit *audit_info)
if (!cnt)
err = -ESRCH;
out:
- write_unlock_bh(&xfrm_policy_lock);
+ write_unlock_bh(&net->xfrm.xfrm_policy_lock);
return err;
}
EXPORT_SYMBOL(xfrm_policy_flush);
@@ -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)
return 0;
- write_lock_bh(&xfrm_policy_lock);
+ write_lock_bh(&net->xfrm.xfrm_policy_lock);
if (list_empty(&walk->walk.all))
x = list_first_entry(&net->xfrm.policy_all, struct xfrm_policy_walk_entry, all);
else
@@ -930,7 +925,7 @@ int xfrm_policy_walk(struct net *net, struct xfrm_policy_walk *walk,
}
list_del_init(&walk->walk.all);
out:
- write_unlock_bh(&xfrm_policy_lock);
+ write_unlock_bh(&net->xfrm.xfrm_policy_lock);
return error;
}
EXPORT_SYMBOL(xfrm_policy_walk);
@@ -944,14 +939,14 @@ void xfrm_policy_walk_init(struct xfrm_policy_walk *walk, u8 type)
}
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))
return;
- write_lock_bh(&xfrm_policy_lock);
+ write_lock_bh(&net->xfrm.xfrm_policy_lock); /*FIXME where is net? */
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);
@@ -996,7 +991,7 @@ static struct xfrm_policy *xfrm_policy_lookup_bytype(struct net *net, u8 type,
if (unlikely(!daddr || !saddr))
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);
ret = NULL;
hlist_for_each_entry(pol, chain, bydst) {
@@ -1032,7 +1027,7 @@ static struct xfrm_policy *xfrm_policy_lookup_bytype(struct net *net, u8 type,
if (ret)
xfrm_pol_hold(ret);
fail:
- read_unlock_bh(&xfrm_policy_lock);
+ read_unlock_bh(&net->xfrm.xfrm_policy_lock);
return ret;
}
@@ -1109,8 +1104,9 @@ static struct xfrm_policy *xfrm_sk_policy_lookup(struct sock *sk, int dir,
const struct flowi *fl)
{
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) {
bool match = xfrm_selector_match(&pol->selector, fl,
sk->sk_family);
@@ -1134,7 +1130,7 @@ static struct xfrm_policy *xfrm_sk_policy_lookup(struct sock *sk, int dir,
pol = NULL;
}
out:
- read_unlock_bh(&xfrm_policy_lock);
+ read_unlock_bh(&net->xfrm.xfrm_policy_lock);
return 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)
{
- 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);
- write_unlock_bh(&xfrm_policy_lock);
+ write_unlock_bh(&net->xfrm.xfrm_policy_lock);
if (pol) {
xfrm_policy_kill(pol);
return 0;
@@ -1193,7 +1191,7 @@ int xfrm_sk_policy_insert(struct sock *sk, int dir, struct xfrm_policy *pol)
return -EINVAL;
#endif
- write_lock_bh(&xfrm_policy_lock);
+ write_lock_bh(&net->xfrm.xfrm_policy_lock);
old_pol = sk->sk_policy[dir];
sk->sk_policy[dir] = pol;
if (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);
}
- write_unlock_bh(&xfrm_policy_lock);
+ write_unlock_bh(&net->xfrm.xfrm_policy_lock);
if (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)
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 net *net = xp_net(old);
if (newp) {
newp->selector = old->selector;
@@ -1239,9 +1238,9 @@ static struct xfrm_policy *clone_policy(const struct xfrm_policy *old, int dir)
newp->type = old->type;
memcpy(newp->xfrm_vec, old->xfrm_vec,
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);
- write_unlock_bh(&xfrm_policy_lock);
+ write_unlock_bh(&net->xfrm.xfrm_policy_lock);
xfrm_pol_put(newp);
}
return newp;
@@ -2112,10 +2111,10 @@ restart:
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;
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;
}
@@ -2440,7 +2439,7 @@ int __xfrm_policy_check(struct sock *sk, int dir, struct sk_buff *skb,
}
xfrm_nr = ti;
if (npols > 1) {
- xfrm_tmpl_sort(stp, tpp, xfrm_nr, family);
+ xfrm_tmpl_sort(stp, tpp, xfrm_nr, family, net);
tpp = stp;
}
@@ -2569,10 +2568,10 @@ static void __xfrm_garbage_collect(struct net *net)
{
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;
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) {
next = head->next;
@@ -2956,6 +2955,13 @@ static int __net_init xfrm_net_init(struct net *net)
rv = xfrm_sysctl_init(net);
if (rv < 0)
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;
out_sysctl:
@@ -3082,7 +3088,7 @@ static struct xfrm_policy * xfrm_migrate_policy_find(const struct xfrm_selector
struct hlist_head *chain;
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);
hlist_for_each_entry(pol, chain, bydst) {
if (xfrm_migrate_selector_match(sel, &pol->selector) &&
@@ -3105,7 +3111,7 @@ static struct xfrm_policy * xfrm_migrate_policy_find(const struct xfrm_selector
if (ret)
xfrm_pol_hold(ret);
- read_unlock_bh(&xfrm_policy_lock);
+ read_unlock_bh(&net->xfrm.xfrm_policy_lock);
return ret;
}
@@ -3236,7 +3242,7 @@ int xfrm_migrate(const struct xfrm_selector *sel, u8 dir, u8 type,
/* Stage 2 - find and update state(s) */
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;
nx_cur++;
if ((xc = xfrm_state_migrate(x, mp))) {
diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c
index 68c2f35..290479d 100644
--- a/net/xfrm/xfrm_state.c
+++ b/net/xfrm/xfrm_state.c
@@ -35,8 +35,6 @@
destination/tunnel endpoint. (output)
*/
-static DEFINE_SPINLOCK(xfrm_state_lock);
-
static unsigned int xfrm_state_hashmax __read_mostly = 1 * 1024 * 1024;
static inline unsigned int xfrm_dst_hash(struct net *net,
@@ -127,7 +125,7 @@ static void xfrm_hash_resize(struct work_struct *work)
goto out_unlock;
}
- spin_lock_bh(&xfrm_state_lock);
+ spin_lock_bh(&net->xfrm.xfrm_state_lock);
nhashmask = (nsize / sizeof(struct hlist_head)) - 1U;
for (i = net->xfrm.state_hmask; i >= 0; i--)
@@ -144,7 +142,7 @@ static void xfrm_hash_resize(struct work_struct *work)
net->xfrm.state_byspi = nspi;
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);
xfrm_hash_free(odst, osize);
@@ -535,14 +533,14 @@ int __xfrm_state_delete(struct xfrm_state *x)
if (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);
hlist_del(&x->bydst);
hlist_del(&x->bysrc);
if (x->id.spi)
hlist_del(&x->byspi);
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.
* 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)
{
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);
if (err)
goto out;
@@ -616,7 +614,7 @@ restart:
if (!xfrm_state_kern(x) &&
xfrm_id_proto_match(x->id.proto, proto)) {
xfrm_state_hold(x);
- spin_unlock_bh(&xfrm_state_lock);
+ spin_unlock_bh(&net->xfrm.xfrm_state_lock);
err = xfrm_state_delete(x);
xfrm_audit_state_delete(x, err ? 0 : 1,
@@ -627,7 +625,7 @@ restart:
if (!err)
cnt++;
- spin_lock_bh(&xfrm_state_lock);
+ spin_lock_bh(&net->xfrm.xfrm_state_lock);
goto restart;
}
}
@@ -636,7 +634,7 @@ restart:
err = 0;
out:
- spin_unlock_bh(&xfrm_state_lock);
+ spin_unlock_bh(&net->xfrm.xfrm_state_lock);
wake_up(&net->xfrm.km_waitq);
return err;
}
@@ -644,11 +642,11 @@ EXPORT_SYMBOL(xfrm_state_flush);
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->sadhcnt = net->xfrm.state_hmask;
si->sadhmcnt = xfrm_state_hashmax;
- spin_unlock_bh(&xfrm_state_lock);
+ spin_unlock_bh(&net->xfrm.xfrm_state_lock);
}
EXPORT_SYMBOL(xfrm_sad_getinfo);
@@ -801,7 +799,7 @@ xfrm_state_find(const xfrm_address_t *daddr, const xfrm_address_t *saddr,
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);
hlist_for_each_entry(x, net->xfrm.state_bydst+h, bydst) {
if (x->props.family == encap_family &&
@@ -886,7 +884,7 @@ out:
xfrm_state_hold(x);
else
*err = acquire_in_progress ? -EAGAIN : error;
- spin_unlock_bh(&xfrm_state_lock);
+ spin_unlock_bh(&net->xfrm.xfrm_state_lock);
if (to_put)
xfrm_state_put(to_put);
return x;
@@ -900,7 +898,7 @@ xfrm_stateonly_find(struct net *net, u32 mark,
unsigned int h;
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);
hlist_for_each_entry(x, net->xfrm.state_bydst+h, bydst) {
if (x->props.family == family &&
@@ -918,7 +916,7 @@ xfrm_stateonly_find(struct net *net, u32 mark,
if (rx)
xfrm_state_hold(rx);
- spin_unlock(&xfrm_state_lock);
+ spin_unlock(&net->xfrm.xfrm_state_lock);
return rx;
@@ -957,7 +955,7 @@ static void __xfrm_state_insert(struct xfrm_state *x)
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)
{
struct net *net = xs_net(xnew);
@@ -980,14 +978,16 @@ static void __xfrm_state_bump_genids(struct xfrm_state *xnew)
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_insert(x);
- spin_unlock_bh(&xfrm_state_lock);
+ spin_unlock_bh(&net->xfrm.xfrm_state_lock);
}
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,
const struct xfrm_mark *m,
unsigned short family, u8 mode,
@@ -1079,7 +1079,7 @@ int xfrm_state_add(struct xfrm_state *x)
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);
if (x1) {
@@ -1108,7 +1108,7 @@ int xfrm_state_add(struct xfrm_state *x)
err = 0;
out:
- spin_unlock_bh(&xfrm_state_lock);
+ spin_unlock_bh(&net->xfrm.xfrm_state_lock);
if (x1) {
xfrm_state_delete(x1);
@@ -1203,16 +1203,16 @@ out:
return NULL;
}
-/* xfrm_state_lock is held */
-struct xfrm_state * xfrm_migrate_state_find(struct xfrm_migrate *m)
+/* net->xfrm.xfrm_state_lock is held */
+struct xfrm_state *xfrm_migrate_state_find(struct xfrm_migrate *m, struct net *net)
{
unsigned int h;
struct xfrm_state *x;
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);
- 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 ||
x->id.proto != m->proto)
continue;
@@ -1227,9 +1227,9 @@ struct xfrm_state * xfrm_migrate_state_find(struct xfrm_migrate *m)
return x;
}
} 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);
- 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 ||
x->id.proto != m->proto)
continue;
@@ -1283,10 +1283,11 @@ int xfrm_state_update(struct xfrm_state *x)
struct xfrm_state *x1, *to_put;
int err;
int use_spi = xfrm_id_proto_match(x->id.proto, IPSEC_PROTO_ANY);
+ struct net *net = xs_net(x);
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);
err = -ESRCH;
@@ -1306,7 +1307,7 @@ int xfrm_state_update(struct xfrm_state *x)
err = 0;
out:
- spin_unlock_bh(&xfrm_state_lock);
+ spin_unlock_bh(&net->xfrm.xfrm_state_lock);
if (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
{
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);
- spin_unlock_bh(&xfrm_state_lock);
+ spin_unlock_bh(&net->xfrm.xfrm_state_lock);
return x;
}
EXPORT_SYMBOL(xfrm_state_lookup);
@@ -1391,9 +1392,9 @@ xfrm_state_lookup_byaddr(struct net *net, u32 mark,
{
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);
- spin_unlock_bh(&xfrm_state_lock);
+ spin_unlock_bh(&net->xfrm.xfrm_state_lock);
return x;
}
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,
{
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);
- spin_unlock_bh(&xfrm_state_lock);
+ spin_unlock_bh(&net->xfrm.xfrm_state_lock);
return x;
}
@@ -1416,17 +1417,17 @@ EXPORT_SYMBOL(xfrm_find_acq);
#ifdef CONFIG_XFRM_SUB_POLICY
int
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;
struct xfrm_state_afinfo *afinfo = xfrm_state_get_afinfo(family);
if (!afinfo)
return -EAFNOSUPPORT;
- spin_lock_bh(&xfrm_state_lock);
+ spin_lock_bh(&net->xfrm.xfrm_state_lock); /*FIXME*/
if (afinfo->tmpl_sort)
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);
return err;
}
@@ -1438,13 +1439,15 @@ xfrm_state_sort(struct xfrm_state **dst, struct xfrm_state **src, int n,
{
int err = 0;
struct xfrm_state_afinfo *afinfo = xfrm_state_get_afinfo(family);
+ struct net *net = xs_net(*dst);
+
if (!afinfo)
return -EAFNOSUPPORT;
- spin_lock_bh(&xfrm_state_lock);
+ spin_lock_bh(&net->xfrm.xfrm_state_lock);
if (afinfo->state_sort)
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);
return err;
}
@@ -1476,9 +1479,9 @@ struct xfrm_state *xfrm_find_acq_byseq(struct net *net, u32 mark, u32 seq)
{
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);
- spin_unlock_bh(&xfrm_state_lock);
+ spin_unlock_bh(&net->xfrm.xfrm_state_lock);
return x;
}
EXPORT_SYMBOL(xfrm_find_acq_byseq);
@@ -1536,10 +1539,10 @@ int xfrm_alloc_spi(struct xfrm_state *x, u32 low, u32 high)
}
}
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);
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;
}
@@ -1562,7 +1565,7 @@ int xfrm_state_walk(struct net *net, struct xfrm_state_walk *walk,
if (walk->seq != 0 && list_empty(&walk->all))
return 0;
- spin_lock_bh(&xfrm_state_lock);
+ spin_lock_bh(&net->xfrm.xfrm_state_lock);
if (list_empty(&walk->all))
x = list_first_entry(&net->xfrm.state_all, struct xfrm_state_walk, all);
else
@@ -1586,7 +1589,7 @@ int xfrm_state_walk(struct net *net, struct xfrm_state_walk *walk,
}
list_del_init(&walk->all);
out:
- spin_unlock_bh(&xfrm_state_lock);
+ spin_unlock_bh(&net->xfrm.xfrm_state_lock);
return err;
}
EXPORT_SYMBOL(xfrm_state_walk);
@@ -1600,14 +1603,14 @@ void xfrm_state_walk_init(struct xfrm_state_walk *walk, u8 proto)
}
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))
return;
- spin_lock_bh(&xfrm_state_lock);
+ spin_lock_bh(&net->xfrm.xfrm_state_lock);
list_del(&walk->all);
- spin_unlock_bh(&xfrm_state_lock);
+ spin_unlock_bh(&net->xfrm.xfrm_state_lock);
}
EXPORT_SYMBOL(xfrm_state_walk_done);
@@ -2026,6 +2029,7 @@ int __net_init xfrm_state_init(struct net *net)
INIT_HLIST_HEAD(&net->xfrm.state_gc_list);
INIT_WORK(&net->xfrm.state_gc_work, xfrm_state_gc_task);
init_waitqueue_head(&net->xfrm.km_waitq);
+ spin_lock_init(&net->xfrm.xfrm_state_lock);
return 0;
out_byspi:
diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c
index 840cc8d..1f0b04e 100644
--- a/net/xfrm/xfrm_user.c
+++ b/net/xfrm/xfrm_user.c
@@ -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)
{
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 = sk->sk_net;
+
+ xfrm_state_walk_done(walk, net);
return 0;
}
@@ -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)
{
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;
}
@@ -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)
{
- 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);
- mutex_unlock(&xfrm_cfg_mutex);
+ mutex_unlock(&net->xfrm.xfrm_cfg_mutex);
}
static inline size_t xfrm_expire_msgsize(void)
--
1.7.9.5
^ permalink raw reply related
* [PATCH net-next 2/3] xfrm: Using the right namespace to migrate key info
From: Fan Du @ 2013-11-06 10:14 UTC (permalink / raw)
To: steffen.klassert, davem, herbert; +Cc: netdev
In-Reply-To: <1383732856-18323-1-git-send-email-fan.du@windriver.com>
because the home agent could surely be run on a different
net namespace other than init_net. The original behavior
could lead into inconsistent of key info.
Signed-off-by: Fan Du <fan.du@windriver.com>
---
include/net/xfrm.h | 2 +-
net/key/af_key.c | 3 ++-
net/xfrm/xfrm_policy.c | 10 +++++-----
net/xfrm/xfrm_user.c | 3 ++-
4 files changed, 10 insertions(+), 8 deletions(-)
diff --git a/include/net/xfrm.h b/include/net/xfrm.h
index 6b82fdf..5b522c5 100644
--- a/include/net/xfrm.h
+++ b/include/net/xfrm.h
@@ -1581,7 +1581,7 @@ struct xfrm_state *xfrm_state_migrate(struct xfrm_state *x,
struct xfrm_migrate *m);
int xfrm_migrate(const struct xfrm_selector *sel, u8 dir, u8 type,
struct xfrm_migrate *m, int num_bundles,
- struct xfrm_kmaddress *k);
+ struct xfrm_kmaddress *k, struct net *net);
#endif
int km_new_mapping(struct xfrm_state *x, xfrm_address_t *ipaddr, __be16 sport);
diff --git a/net/key/af_key.c b/net/key/af_key.c
index 911ef03..33480b3 100644
--- a/net/key/af_key.c
+++ b/net/key/af_key.c
@@ -2485,6 +2485,7 @@ static int pfkey_migrate(struct sock *sk, struct sk_buff *skb,
struct xfrm_selector sel;
struct xfrm_migrate m[XFRM_MAX_DEPTH];
struct xfrm_kmaddress k;
+ struct net *net = sock_net(sk);
if (!present_and_same_family(ext_hdrs[SADB_EXT_ADDRESS_SRC - 1],
ext_hdrs[SADB_EXT_ADDRESS_DST - 1]) ||
@@ -2558,7 +2559,7 @@ static int pfkey_migrate(struct sock *sk, struct sk_buff *skb,
}
return xfrm_migrate(&sel, dir, XFRM_POLICY_TYPE_MAIN, m, i,
- kma ? &k : NULL);
+ kma ? &k : NULL, net);
out:
return err;
diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c
index a5bbdfb..907fd2f 100644
--- a/net/xfrm/xfrm_policy.c
+++ b/net/xfrm/xfrm_policy.c
@@ -3076,14 +3076,14 @@ static bool xfrm_migrate_selector_match(const struct xfrm_selector *sel_cmp,
}
static struct xfrm_policy * xfrm_migrate_policy_find(const struct xfrm_selector *sel,
- u8 dir, u8 type)
+ u8 dir, u8 type, struct net *net)
{
struct xfrm_policy *pol, *ret = NULL;
struct hlist_head *chain;
u32 priority = ~0U;
read_lock_bh(&xfrm_policy_lock);
- chain = policy_hash_direct(&init_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) {
if (xfrm_migrate_selector_match(sel, &pol->selector) &&
pol->type == type) {
@@ -3092,7 +3092,7 @@ static struct xfrm_policy * xfrm_migrate_policy_find(const struct xfrm_selector
break;
}
}
- chain = &init_net.xfrm.policy_inexact[dir];
+ chain = &net->xfrm.policy_inexact[dir];
hlist_for_each_entry(pol, chain, bydst) {
if (xfrm_migrate_selector_match(sel, &pol->selector) &&
pol->type == type &&
@@ -3216,7 +3216,7 @@ static int xfrm_migrate_check(const struct xfrm_migrate *m, int num_migrate)
int xfrm_migrate(const struct xfrm_selector *sel, u8 dir, u8 type,
struct xfrm_migrate *m, int num_migrate,
- struct xfrm_kmaddress *k)
+ struct xfrm_kmaddress *k, struct net *net)
{
int i, err, nx_cur = 0, nx_new = 0;
struct xfrm_policy *pol = NULL;
@@ -3229,7 +3229,7 @@ int xfrm_migrate(const struct xfrm_selector *sel, u8 dir, u8 type,
goto out;
/* Stage 1 - find policy */
- if ((pol = xfrm_migrate_policy_find(sel, dir, type)) == NULL) {
+ if ((pol = xfrm_migrate_policy_find(sel, dir, type, net)) == NULL) {
err = -ENOENT;
goto out;
}
diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c
index 4e0546e..840cc8d 100644
--- a/net/xfrm/xfrm_user.c
+++ b/net/xfrm/xfrm_user.c
@@ -2137,6 +2137,7 @@ static int xfrm_do_migrate(struct sk_buff *skb, struct nlmsghdr *nlh,
u8 type;
int err;
int n = 0;
+ struct net *net = sock_net(skb->sk);
if (attrs[XFRMA_MIGRATE] == NULL)
return -EINVAL;
@@ -2154,7 +2155,7 @@ static int xfrm_do_migrate(struct sk_buff *skb, struct nlmsghdr *nlh,
if (!n)
return 0;
- xfrm_migrate(&pi->sel, pi->dir, type, m, n, kmp);
+ xfrm_migrate(&pi->sel, pi->dir, type, m, n, kmp, net);
return 0;
}
--
1.7.9.5
^ permalink raw reply related
* [PATCH net-next 1/3] xfrm: Try to honor policy index if it's supplied by user
From: Fan Du @ 2013-11-06 10:14 UTC (permalink / raw)
To: steffen.klassert, davem, herbert; +Cc: netdev
In-Reply-To: <1383732856-18323-1-git-send-email-fan.du@windriver.com>
xfrm code always searches for unused policy index for
newly created policy regardless whether or not user
space policy index hint supplied.
This patch enables such feature so that using
"ip xfrm ... index=xxx" can be used by user to set
specific policy index.
Currently this beahvior is broken, so this patch make
it happen as expected.
Signed-off-by: Fan Du <fan.du@windriver.com>
---
net/xfrm/xfrm_policy.c | 16 +++++++++++-----
net/xfrm/xfrm_user.c | 10 +++++++++-
2 files changed, 20 insertions(+), 6 deletions(-)
diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c
index 9a91f74..a5bbdfb 100644
--- a/net/xfrm/xfrm_policy.c
+++ b/net/xfrm/xfrm_policy.c
@@ -538,7 +538,7 @@ static void xfrm_hash_resize(struct work_struct *work)
/* Generate new index... KAME seems to generate them ordered by cost
* of an absolute inpredictability of ordering of rules. This will not pass. */
-static u32 xfrm_gen_index(struct net *net, int dir)
+static u32 xfrm_gen_index(struct net *net, int dir, u32 index)
{
static u32 idx_generator;
@@ -548,8 +548,14 @@ static u32 xfrm_gen_index(struct net *net, int dir)
u32 idx;
int found;
- idx = (idx_generator | dir);
- idx_generator += 8;
+ if (!index) {
+ idx = (idx_generator | dir);
+ idx_generator += 8;
+ } else {
+ idx = index;
+ index = 0;
+ }
+
if (idx == 0)
idx = 8;
list = net->xfrm.policy_byidx + idx_hash(net, idx);
@@ -672,7 +678,7 @@ int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl)
xfrm_policy_requeue(delpol, policy);
__xfrm_policy_unlink(delpol, dir);
}
- policy->index = delpol ? delpol->index : xfrm_gen_index(net, dir);
+ policy->index = delpol ? delpol->index : xfrm_gen_index(net, dir, policy->index);
hlist_add_head(&policy->byidx, net->xfrm.policy_byidx+idx_hash(net, policy->index));
policy->curlft.add_time = get_seconds();
policy->curlft.use_time = 0;
@@ -1192,7 +1198,7 @@ int xfrm_sk_policy_insert(struct sock *sk, int dir, struct xfrm_policy *pol)
sk->sk_policy[dir] = pol;
if (pol) {
pol->curlft.add_time = get_seconds();
- pol->index = xfrm_gen_index(net, XFRM_POLICY_MAX+dir);
+ pol->index = xfrm_gen_index(net, XFRM_POLICY_MAX+dir, 0);
__xfrm_policy_link(pol, XFRM_POLICY_MAX+dir);
}
if (old_pol) {
diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c
index f964d4c..4e0546e 100644
--- a/net/xfrm/xfrm_user.c
+++ b/net/xfrm/xfrm_user.c
@@ -1189,6 +1189,8 @@ static int verify_policy_type(u8 type)
static int verify_newpolicy_info(struct xfrm_userpolicy_info *p)
{
+ int ret;
+
switch (p->share) {
case XFRM_SHARE_ANY:
case XFRM_SHARE_SESSION:
@@ -1224,7 +1226,13 @@ static int verify_newpolicy_info(struct xfrm_userpolicy_info *p)
return -EINVAL;
}
- return verify_policy_dir(p->dir);
+ ret = verify_policy_dir(p->dir);
+ if (ret)
+ return ret;
+ if (p->index && ((p->index & XFRM_POLICY_MAX) != p->dir))
+ return -EINVAL;
+
+ return 0;
}
static int copy_from_user_sec_ctx(struct xfrm_policy *pol, struct nlattr **attrs)
--
1.7.9.5
^ permalink raw reply related
* [PATCH net-next 0/3] Small IPsec fix
From: Fan Du @ 2013-11-06 10:14 UTC (permalink / raw)
To: steffen.klassert, davem, herbert; +Cc: netdev
Hi
This patchset made below modifications:
- Fix setting policy index with "ip xfrm ... index=xx"
which is currently broken
- Using correct name space for home agent when migrating
key info.
- Put xfrm locks into per namespace to improve scalability.
Fan Du (3):
xfrm: Try to honor policy index if it's supplied by user
xfrm: Using the right namespace to migrate key info
xfrm: Namespacify xfrm state/policy locks
include/net/netns/xfrm.h | 4 ++
include/net/xfrm.h | 13 +++--
net/key/af_key.c | 18 ++++---
net/xfrm/xfrm_policy.c | 130 +++++++++++++++++++++++++---------------------
net/xfrm/xfrm_state.c | 104 +++++++++++++++++++------------------
net/xfrm/xfrm_user.c | 27 +++++++---
6 files changed, 168 insertions(+), 128 deletions(-)
--
1.7.9.5
^ permalink raw reply
* Re: Realtek RTL8102E registers
From: Ivan Frederiks @ 2013-11-06 10:13 UTC (permalink / raw)
To: Francois Romieu; +Cc: Linux r8169 crew
In-Reply-To: <20131029214059.GA26496@electric-eye.fr.zoreil.com>
Hello Francois,
I found solution for the issue that I described earlier: one has to set
correct MAC-address before bringing up the interface.
On my board RTL8102E works without EEPROM, so initial MAC-address value
is unpredictable. In many cases this value has multicast bit set to 1.
This fact breaks driver and (or) TCP stack operation:
* r8169 reports that link is down
* r8101 reports that link is OK, but Linux TCP stack ignores packets
with multicast destination MAC
Hope this info would be useful. BTW, I suppose that driver could have
some kind of protection against such situations.
On 30.10.2013 01:40, Francois Romieu wrote:
> Ivan Frederiks <frederiks@speechpro.com> :
> [...]
>> Maybe you have access to RTL8102E register description ?
>
> No.
>
> Realtek's hardware documentation policy isn't exactly opened. Your hardware
> vendor may help.
>
> [...]
>> Issue description:
> [snip]
>
> kernel version and r81xx XID value as it should appear in dmesg would
> be welcome.
>
--
Best regards,
Ivan Frederiks
Embedded developer
Speech Technology Center
Phone: +7-812-331-0665, ext. 6123, 6942
Fax: +7-812-327-9297
^ permalink raw reply
* Re: [PATCH net-next 3/3] net: allow to leave the buffer fragmented in skb_cow_data()
From: Herbert Xu @ 2013-11-06 9:52 UTC (permalink / raw)
To: Mathias Krause
Cc: David S. Miller, Steffen Klassert, Dmitry Tarnyagin, netdev
In-Reply-To: <527A109E.5040000@secunet.com>
On Wed, Nov 06, 2013 at 10:49:18AM +0100, Mathias Krause wrote:
> On 06.11.2013 10:30, Herbert Xu wrote:
>
> > Hang on, you haven't explained why it is OK to write to pages.
>
> Why wouldn't it if the skb isn't cloned?
Because if it's owned by an entity outside our stack (e.g., virt
host or app) then the skb itself won't be cloned.
> > What if said page is owned by the virt host or some app?
>
> How would one detect such a case. I could image not by testing
> skb_shinfo(skb)->nr_frags as it is right now?
You can't. That's why we always copy. If you want to do this
properly then we'll need to add at least a bit to indicate whether
the page originated from within the network stack and we have
full ownership.
Cheers,
--
Email: Herbert Xu <herbert@gondor.apana.org.au>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt
^ permalink raw reply
* [PATCH net] MAINTAINERS: Update bnx2x maintainer
From: Eilon Greenstein @ 2013-11-06 9:51 UTC (permalink / raw)
To: David Miller; +Cc: netdev, Eilon Greenstein, Ariel Elior
From: Eilon Greenstein <eilong@broadcom.com>
Ariel Elior will take over the bnx2x maintenance.
It's been a pleasure!
Signed-off-by: Eilon Greenstein <eilong@broadcom.com>
Acked-by: Ariel Elior <ariele@broadcom.com>
---
MAINTAINERS | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/MAINTAINERS b/MAINTAINERS
index ffcaf97..315a48a 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1822,7 +1822,7 @@ F: drivers/net/ethernet/broadcom/bnx2.*
F: drivers/net/ethernet/broadcom/bnx2_*
BROADCOM BNX2X 10 GIGABIT ETHERNET DRIVER
-M: Eilon Greenstein <eilong@broadcom.com>
+M: Ariel Elior <ariele@broadcom.com>
L: netdev@vger.kernel.org
S: Supported
F: drivers/net/ethernet/broadcom/bnx2x/
--
1.8.3.1
^ permalink raw reply related
* Re: [PATCH net-next 3/3] net: allow to leave the buffer fragmented in skb_cow_data()
From: Mathias Krause @ 2013-11-06 9:49 UTC (permalink / raw)
To: Herbert Xu; +Cc: David S. Miller, Steffen Klassert, Dmitry Tarnyagin, netdev
In-Reply-To: <20131106093028.GA18435@gondor.apana.org.au>
On 06.11.2013 10:30, Herbert Xu wrote:
> On Tue, Nov 05, 2013 at 02:54:11PM +0100, Mathias Krause wrote:
>> - /* If skb is cloned or its head is paged, reallocate
>> - * head pulling out all the pages (pages are considered not writable
>> - * at the moment even if they are anonymous).
>> + /* If skb is cloned reallocate head pulling out all the pages (pages are
>> + * considered not writable at the moment even if they are anonymous).
>> */
>
> Hang on, you haven't explained why it is OK to write to pages.
Why wouldn't it if the skb isn't cloned?
> What if said page is owned by the virt host or some app?
How would one detect such a case. I could image not by testing
skb_shinfo(skb)->nr_frags as it is right now?
Regards,
Mathias
^ permalink raw reply
* Re: [PATCH net-next 3/3] net: allow to leave the buffer fragmented in skb_cow_data()
From: Herbert Xu @ 2013-11-06 9:30 UTC (permalink / raw)
To: Mathias Krause
Cc: David S. Miller, Steffen Klassert, Dmitry Tarnyagin, netdev
In-Reply-To: <14f30e8f5f8405c1ca73b6d3a554441c1736142d.1381923854.git.mathias.krause@secunet.com>
On Tue, Nov 05, 2013 at 02:54:11PM +0100, Mathias Krause wrote:
>
> - /* If skb is cloned or its head is paged, reallocate
> - * head pulling out all the pages (pages are considered not writable
> - * at the moment even if they are anonymous).
> + /* If skb is cloned reallocate head pulling out all the pages (pages are
> + * considered not writable at the moment even if they are anonymous).
> */
Hang on, you haven't explained why it is OK to write to pages.
What if said page is owned by the virt host or some app?
Cheers,
--
Email: Herbert Xu <herbert@gondor.apana.org.au>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt
^ permalink raw reply
* RE: [patch net-next] ipv6: allow userspace to create address with IFLA_F_TEMPORARY flag
From: David Laight @ 2013-11-06 9:23 UTC (permalink / raw)
To: Hannes Frederic Sowa
Cc: nicolas.dichtel, David Miller, jiri, vyasevich, netdev, kuznet,
jmorris, yoshfuji, kaber, thaller, stephen
In-Reply-To: <20131105211158.GL8832@order.stressinduktion.org>
> By the way:
> Although dhclient uses an AF_PACKET socket, it never does request
> additional multicast addresses or promisc mode. So the only overhead is
> that we have to run the socket filter on each incoming packet.
Just creating the AF_PACKET socket requires that every receive
frame be duplicated.
On Linux this is a reference counted but the cost is still non-zero.
On some other OS (I first saw this with VxWorks) it is a full data copy.
David
^ permalink raw reply
* Re: [PATCH net-next 0/3] IPsec improvements
From: Mathias Krause @ 2013-11-06 9:02 UTC (permalink / raw)
To: David Miller; +Cc: steffen.klassert, herbert, dmitry.tarnyagin, netdev
In-Reply-To: <20131105.234831.2190193542602272571.davem@davemloft.net>
On 06.11.2013 05:48, David Miller wrote:
> From: Mathias Krause <mathias.krause@secunet.com>
> Date: Tue, 5 Nov 2013 14:54:08 +0100
>
>> This series moves pskb_put() to the core code -- making the code
>> duplication in caif obsolete (patches 1 and 2).
>>
>> Additionally does this series optimize the IPsec receive path in patch 3
>> by allowing skb_cow_data() to leave the buffer fragmented. I noticed the
>> linearization to be a bottleneck when doing some VPN gateway benchmarks.
>> Linearization of the buffer isn't needed in the receive path as the
>> crypto API (and all other users of skb_cow_data) can handle sg.
>>
>> With patch 3 applied I was able to increase the throughput of an IPsec
>> gateway from 7.12 Gbit/s to 7.28 Gbit/s.
>
> Please deal with the feedback given to you by Ben about referring to
> variables with the '@' prefix consistently in comments, then resend
> this entire patch series.
Will do. Thanks, Dave.
>
> Thanks.
^ permalink raw reply
* Re: [PATCH net-next 1/3] net: move pskb_put() to core code
From: Mathias Krause @ 2013-11-06 9:01 UTC (permalink / raw)
To: Ben Hutchings
Cc: David S. Miller, Steffen Klassert, Herbert Xu, Dmitry Tarnyagin,
netdev
In-Reply-To: <1383676424.2868.11.camel@bwh-desktop.uk.level5networks.com>
On 05.11.2013 19:33, Ben Hutchings wrote:
> On Tue, 2013-11-05 at 14:54 +0100, Mathias Krause wrote:
>> This function has usage beside IPsec so move it to the core skbuff code.
>> While doing so, give it some documentation and change its return type to
>> 'unsigned char *' to be in line with skb_put().
> [...]
>> --- a/net/core/skbuff.c
>> +++ b/net/core/skbuff.c
>> @@ -1257,6 +1257,29 @@ free_skb:
>> EXPORT_SYMBOL(skb_pad);
>>
>> /**
>> + * pskb_put - add data to the tail of a potentially fragmented buffer
>> + * @skb: start of the buffer to use
>> + * @tail: tail fragment of the buffer to use
>> + * @len: amount of data to add
>> + *
>> + * This function extends the used data area of the potentially
>> + * fragmented buffer. &tail must be the last fragment of &skb -- or
>> + * &skb itself. If this would exceed the total buffer size the kernel
>
> Keep using @ to refer to the parameters in this description.
>
> Ben.
Thanks Ben. Looks like I looked at the wrong examples on how to do it.
Will fix those as well.
>
>> + * will panic. A pointer to the first byte of the extra data is
>> + * returned.
>> + */
> [...]
>
^ permalink raw reply
* linux-next: manual merge of the akpm tree with the net-next tree
From: Stephen Rothwell @ 2013-11-06 9:00 UTC (permalink / raw)
To: Andrew Morton
Cc: linux-next, linux-kernel, Jozsef Kadlecsik, Pablo Neira Ayuso,
David Miller, netdev
[-- Attachment #1: Type: text/plain, Size: 511 bytes --]
Hi Andrew,
Today's linux-next merge of the akpm tree got a conflict in
net/netfilter/ipset/ip_set_hash_netportnet.c between commit 1a869205c75c
("netfilter: ipset: The unnamed union initialization may lead to
compilation error") from the net-next tree and commit
"net/netfilter/ipset/ip_set_hash_netportnet.c: fix build with older gccs"
from the akpm tree.
The latter is just a subset of the former, so I dropped the latter.
--
Cheers,
Stephen Rothwell sfr@canb.auug.org.au
[-- Attachment #2: Type: application/pgp-signature, Size: 836 bytes --]
^ permalink raw reply
* linux-next: manual merge of the akpm tree with the net-next tree
From: Stephen Rothwell @ 2013-11-06 8:55 UTC (permalink / raw)
To: Andrew Morton
Cc: linux-next, linux-kernel, Jozsef Kadlecsik, Pablo Neira Ayuso,
David Miller, netdev
[-- Attachment #1: Type: text/plain, Size: 502 bytes --]
Hi Andrew,
Today's linux-next merge of the akpm tree got a conflict in
net/netfilter/ipset/ip_set_hash_netnet.c between commit 1a869205c75c
("netfilter: ipset: The unnamed union initialization may lead to
compilation error") from the net-next tree and commit
"net/netfilter/ipset/ip_set_hash_netnet.c: fix build with older gcc" from
the akpm tree.
The latter is a subset of the former. so I just dropped the latter.
--
Cheers,
Stephen Rothwell sfr@canb.auug.org.au
[-- Attachment #2: Type: application/pgp-signature, Size: 836 bytes --]
^ permalink raw reply
* [PATCH net-next v3 3/3] tipc: reassembly failures should cause link reset
From: erik.hugne @ 2013-11-06 8:28 UTC (permalink / raw)
To: netdev, jon.maloy, maloy, paul.gortmaker
Cc: ying.xue, tipc-discussion, Erik Hugne
In-Reply-To: <1383726487-27929-1-git-send-email-erik.hugne@ericsson.com>
From: Erik Hugne <erik.hugne@ericsson.com>
If appending a received fragment to the pending fragment chain
in a unicast link fails, the current code tries to force a retransmission
of the fragment by decrementing the 'next received sequence number'
field in the link. This is done under the assumption that the failure
is caused by an out-of-memory situation, an assumption that does
not hold true after the previous patch in this series.
A failure to append a fragment can now only be caused by a protocol
violation by the sending peer, and it must hence be assumed that it
is either malicious or buggy. Either way, the correct behavior is now
to reset the link instead of trying to revert its sequence number.
So, this is what we do in this commit.
Signed-off-by: Erik Hugne <erik.hugne@ericsson.com>
Reviewed-by: Paul Gortmaker <paul.gortmaker@windriver.com>
Signed-off-by: Jon Maloy <jon.maloy@ericsson.com>
---
net/tipc/link.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/net/tipc/link.c b/net/tipc/link.c
index a63646e..cf465d6 100644
--- a/net/tipc/link.c
+++ b/net/tipc/link.c
@@ -1652,7 +1652,7 @@ deliver:
goto deliver;
}
if (ret == LINK_REASM_ERROR)
- l_ptr->next_in_no--;
+ tipc_link_reset(l_ptr);
tipc_node_unlock(n_ptr);
continue;
case CHANGEOVER_PROTOCOL:
--
1.7.9.5
^ permalink raw reply related
* [PATCH net-next v3 2/3] tipc: message reassembly using fragment chain
From: erik.hugne @ 2013-11-06 8:28 UTC (permalink / raw)
To: netdev, jon.maloy, maloy, paul.gortmaker
Cc: ying.xue, tipc-discussion, Erik Hugne
In-Reply-To: <1383726487-27929-1-git-send-email-erik.hugne@ericsson.com>
From: Erik Hugne <erik.hugne@ericsson.com>
When the first fragment of a long data data message is received on a link, a
reassembly buffer large enough to hold the data from this and all subsequent
fragments of the message is allocated. The payload of each new fragment is
copied into this buffer upon arrival. When the last fragment is received, the
reassembled message is delivered upwards to the port/socket layer.
Not only is this an inefficient approach, but it may also cause bursts of
reassembly failures in low memory situations. since we may fail to allocate
the necessary large buffer in the first place. Furthermore, after 100 subsequent
such failures the link will be reset, something that in reality aggravates the
situation.
To remedy this problem, this patch introduces a different approach. Instead of
allocating a big reassembly buffer, we now append the arriving fragments
to a reassembly chain on the link, and deliver the whole chain up to the
socket layer once the last fragment has been received. This is safe because
the retransmission layer of a TIPC link always delivers packets in strict
uninterrupted order, to the reassembly layer as to all other upper layers.
Hence there can never be more than one fragment chain pending reassembly at
any given time in a link, and we can trust (but still verify) that the
fragments will be chained up in the correct order.
Signed-off-by: Erik Hugne <erik.hugne@ericsson.com>
Reviewed-by: Paul Gortmaker <paul.gortmaker@windriver.com>
Signed-off-by: Jon Maloy <jon.maloy@ericsson.com>
---
net/tipc/bcast.c | 12 +++--
net/tipc/link.c | 159 +++++++++++++++---------------------------------------
net/tipc/link.h | 20 ++++---
net/tipc/msg.h | 12 -----
net/tipc/node.c | 7 +--
net/tipc/node.h | 6 ++-
6 files changed, 74 insertions(+), 142 deletions(-)
diff --git a/net/tipc/bcast.c b/net/tipc/bcast.c
index 766a6eb..0d44025 100644
--- a/net/tipc/bcast.c
+++ b/net/tipc/bcast.c
@@ -480,15 +480,19 @@ receive:
tipc_node_unlock(node);
tipc_link_recv_bundle(buf);
} else if (msg_user(msg) == MSG_FRAGMENTER) {
- int ret = tipc_link_recv_fragment(&node->bclink.defragm,
- &buf, &msg);
- if (ret < 0)
+ int ret;
+ ret = tipc_link_recv_fragment(&node->bclink.reasm_head,
+ &node->bclink.reasm_tail,
+ &buf);
+ if (ret == LINK_REASM_ERROR)
goto unlock;
spin_lock_bh(&bc_lock);
bclink_accept_pkt(node, seqno);
bcl->stats.recv_fragments++;
- if (ret > 0) {
+ if (ret == LINK_REASM_COMPLETE) {
bcl->stats.recv_fragmented++;
+ /* Point msg to inner header */
+ msg = buf_msg(buf);
spin_unlock_bh(&bc_lock);
goto receive;
}
diff --git a/net/tipc/link.c b/net/tipc/link.c
index ada8cad..a63646e 100644
--- a/net/tipc/link.c
+++ b/net/tipc/link.c
@@ -404,15 +404,9 @@ static void link_release_outqueue(struct tipc_link *l_ptr)
*/
void tipc_link_reset_fragments(struct tipc_link *l_ptr)
{
- struct sk_buff *buf = l_ptr->defragm_buf;
- struct sk_buff *next;
-
- while (buf) {
- next = buf->next;
- kfree_skb(buf);
- buf = next;
- }
- l_ptr->defragm_buf = NULL;
+ kfree_skb(l_ptr->reasm_head);
+ l_ptr->reasm_head = NULL;
+ l_ptr->reasm_tail = NULL;
}
/**
@@ -1649,13 +1643,15 @@ deliver:
continue;
case MSG_FRAGMENTER:
l_ptr->stats.recv_fragments++;
- ret = tipc_link_recv_fragment(&l_ptr->defragm_buf,
- &buf, &msg);
- if (ret == 1) {
+ ret = tipc_link_recv_fragment(&l_ptr->reasm_head,
+ &l_ptr->reasm_tail,
+ &buf);
+ if (ret == LINK_REASM_COMPLETE) {
l_ptr->stats.recv_fragmented++;
+ msg = buf_msg(buf);
goto deliver;
}
- if (ret == -1)
+ if (ret == LINK_REASM_ERROR)
l_ptr->next_in_no--;
tipc_node_unlock(n_ptr);
continue;
@@ -2343,114 +2339,47 @@ static int link_send_long_buf(struct tipc_link *l_ptr, struct sk_buff *buf)
}
/*
- * A pending message being re-assembled must store certain values
- * to handle subsequent fragments correctly. The following functions
- * help storing these values in unused, available fields in the
- * pending message. This makes dynamic memory allocation unnecessary.
- */
-static void set_long_msg_seqno(struct sk_buff *buf, u32 seqno)
-{
- msg_set_seqno(buf_msg(buf), seqno);
-}
-
-static u32 get_fragm_size(struct sk_buff *buf)
-{
- return msg_ack(buf_msg(buf));
-}
-
-static void set_fragm_size(struct sk_buff *buf, u32 sz)
-{
- msg_set_ack(buf_msg(buf), sz);
-}
-
-static u32 get_expected_frags(struct sk_buff *buf)
-{
- return msg_bcast_ack(buf_msg(buf));
-}
-
-static void set_expected_frags(struct sk_buff *buf, u32 exp)
-{
- msg_set_bcast_ack(buf_msg(buf), exp);
-}
-
-/*
* tipc_link_recv_fragment(): Called with node lock on. Returns
* the reassembled buffer if message is complete.
*/
-int tipc_link_recv_fragment(struct sk_buff **pending, struct sk_buff **fb,
- struct tipc_msg **m)
-{
- struct sk_buff *prev = NULL;
- struct sk_buff *fbuf = *fb;
- struct tipc_msg *fragm = buf_msg(fbuf);
- struct sk_buff *pbuf = *pending;
- u32 long_msg_seq_no = msg_long_msgno(fragm);
-
- *fb = NULL;
-
- /* Is there an incomplete message waiting for this fragment? */
- while (pbuf && ((buf_seqno(pbuf) != long_msg_seq_no) ||
- (msg_orignode(fragm) != msg_orignode(buf_msg(pbuf))))) {
- prev = pbuf;
- pbuf = pbuf->next;
- }
-
- if (!pbuf && (msg_type(fragm) == FIRST_FRAGMENT)) {
- struct tipc_msg *imsg = (struct tipc_msg *)msg_data(fragm);
- u32 msg_sz = msg_size(imsg);
- u32 fragm_sz = msg_data_sz(fragm);
- u32 exp_fragm_cnt;
- u32 max = TIPC_MAX_USER_MSG_SIZE + NAMED_H_SIZE;
-
- if (msg_type(imsg) == TIPC_MCAST_MSG)
- max = TIPC_MAX_USER_MSG_SIZE + MCAST_H_SIZE;
- if (fragm_sz == 0 || msg_size(imsg) > max) {
- kfree_skb(fbuf);
- return 0;
- }
- exp_fragm_cnt = msg_sz / fragm_sz + !!(msg_sz % fragm_sz);
- pbuf = tipc_buf_acquire(msg_size(imsg));
- if (pbuf != NULL) {
- pbuf->next = *pending;
- *pending = pbuf;
- skb_copy_to_linear_data(pbuf, imsg,
- msg_data_sz(fragm));
- /* Prepare buffer for subsequent fragments. */
- set_long_msg_seqno(pbuf, long_msg_seq_no);
- set_fragm_size(pbuf, fragm_sz);
- set_expected_frags(pbuf, exp_fragm_cnt - 1);
- } else {
- pr_debug("Link unable to reassemble fragmented message\n");
- kfree_skb(fbuf);
- return -1;
- }
- kfree_skb(fbuf);
- return 0;
- } else if (pbuf && (msg_type(fragm) != FIRST_FRAGMENT)) {
- u32 dsz = msg_data_sz(fragm);
- u32 fsz = get_fragm_size(pbuf);
- u32 crs = ((msg_fragm_no(fragm) - 1) * fsz);
- u32 exp_frags = get_expected_frags(pbuf) - 1;
- skb_copy_to_linear_data_offset(pbuf, crs,
- msg_data(fragm), dsz);
- kfree_skb(fbuf);
-
- /* Is message complete? */
- if (exp_frags == 0) {
- if (prev)
- prev->next = pbuf->next;
- else
- *pending = pbuf->next;
- msg_reset_reroute_cnt(buf_msg(pbuf));
- *fb = pbuf;
- *m = buf_msg(pbuf);
- return 1;
- }
- set_expected_frags(pbuf, exp_frags);
+int tipc_link_recv_fragment(struct sk_buff **head, struct sk_buff **tail,
+ struct sk_buff **fbuf)
+{
+ struct sk_buff *frag = *fbuf;
+ struct tipc_msg *msg = buf_msg(frag);
+ u32 fragid = msg_type(msg);
+ bool headstolen;
+ int delta;
+
+ skb_pull(frag, msg_hdr_sz(msg));
+ if (fragid == FIRST_FRAGMENT) {
+ if (*head || skb_unclone(frag, GFP_ATOMIC))
+ goto out_free;
+ *head = frag;
+ skb_frag_list_init(*head);
return 0;
+ } else if (skb_try_coalesce(*head, frag, &headstolen, &delta)) {
+ kfree_skb_partial(frag, headstolen);
+ } else {
+ if (!*head)
+ goto out_free;
+ if (!skb_has_frag_list(*head))
+ skb_shinfo(*head)->frag_list = frag;
+ else
+ (*tail)->next = frag;
+ *tail = frag;
+ (*head)->truesize += frag->truesize;
+ }
+ if (fragid == LAST_FRAGMENT) {
+ *fbuf = *head;
+ *tail = *head = NULL;
+ return LINK_REASM_COMPLETE;
}
- kfree_skb(fbuf);
return 0;
+out_free:
+ pr_warn_ratelimited("Link unable to reassemble fragmented message\n");
+ kfree_skb(*fbuf);
+ return LINK_REASM_ERROR;
}
static void link_set_supervision_props(struct tipc_link *l_ptr, u32 tolerance)
diff --git a/net/tipc/link.h b/net/tipc/link.h
index 55cf855..8a6c102 100644
--- a/net/tipc/link.h
+++ b/net/tipc/link.h
@@ -41,6 +41,12 @@
#include "node.h"
/*
+ * Link reassembly status codes
+ */
+#define LINK_REASM_ERROR -1
+#define LINK_REASM_COMPLETE 1
+
+/*
* Out-of-range value for link sequence numbers
*/
#define INVALID_LINK_SEQ 0x10000
@@ -134,7 +140,8 @@ struct tipc_stats {
* @next_out: ptr to first unsent outbound message in queue
* @waiting_ports: linked list of ports waiting for link congestion to abate
* @long_msg_seq_no: next identifier to use for outbound fragmented messages
- * @defragm_buf: list of partially reassembled inbound message fragments
+ * @reasm_head: list head of partially reassembled inbound message fragments
+ * @reasm_tail: last fragment received
* @stats: collects statistics regarding link activity
*/
struct tipc_link {
@@ -196,9 +203,10 @@ struct tipc_link {
struct sk_buff *next_out;
struct list_head waiting_ports;
- /* Fragmentation/defragmentation */
+ /* Fragmentation/reassembly */
u32 long_msg_seq_no;
- struct sk_buff *defragm_buf;
+ struct sk_buff *reasm_head;
+ struct sk_buff *reasm_tail;
/* Statistics */
struct tipc_stats stats;
@@ -229,9 +237,9 @@ int tipc_link_send_sections_fast(struct tipc_port *sender,
struct iovec const *msg_sect,
unsigned int len, u32 destnode);
void tipc_link_recv_bundle(struct sk_buff *buf);
-int tipc_link_recv_fragment(struct sk_buff **pending,
- struct sk_buff **fb,
- struct tipc_msg **msg);
+int tipc_link_recv_fragment(struct sk_buff **reasm_head,
+ struct sk_buff **reasm_tail,
+ struct sk_buff **fbuf);
void tipc_link_send_proto_msg(struct tipc_link *l_ptr, u32 msg_typ, int prob,
u32 gap, u32 tolerance, u32 priority,
u32 acked_mtu);
diff --git a/net/tipc/msg.h b/net/tipc/msg.h
index 559b73a..76d1269 100644
--- a/net/tipc/msg.h
+++ b/net/tipc/msg.h
@@ -554,12 +554,6 @@ static inline void msg_set_last_bcast(struct tipc_msg *m, u32 n)
msg_set_bits(m, 4, 16, 0xffff, n);
}
-
-static inline u32 msg_fragm_no(struct tipc_msg *m)
-{
- return msg_bits(m, 4, 16, 0xffff);
-}
-
static inline void msg_set_fragm_no(struct tipc_msg *m, u32 n)
{
msg_set_bits(m, 4, 16, 0xffff, n);
@@ -576,12 +570,6 @@ static inline void msg_set_next_sent(struct tipc_msg *m, u32 n)
msg_set_bits(m, 4, 0, 0xffff, n);
}
-
-static inline u32 msg_long_msgno(struct tipc_msg *m)
-{
- return msg_bits(m, 4, 0, 0xffff);
-}
-
static inline void msg_set_long_msgno(struct tipc_msg *m, u32 n)
{
msg_set_bits(m, 4, 0, 0xffff, n);
diff --git a/net/tipc/node.c b/net/tipc/node.c
index 6e6c434..25100c0 100644
--- a/net/tipc/node.c
+++ b/net/tipc/node.c
@@ -298,9 +298,10 @@ static void node_lost_contact(struct tipc_node *n_ptr)
}
n_ptr->bclink.deferred_size = 0;
- if (n_ptr->bclink.defragm) {
- kfree_skb(n_ptr->bclink.defragm);
- n_ptr->bclink.defragm = NULL;
+ if (n_ptr->bclink.reasm_head) {
+ kfree_skb(n_ptr->bclink.reasm_head);
+ n_ptr->bclink.reasm_head = NULL;
+ n_ptr->bclink.reasm_tail = NULL;
}
tipc_bclink_remove_node(n_ptr->addr);
diff --git a/net/tipc/node.h b/net/tipc/node.h
index 3c189b3..e5e96c0 100644
--- a/net/tipc/node.h
+++ b/net/tipc/node.h
@@ -74,7 +74,8 @@
* @deferred_size: number of OOS b'cast messages in deferred queue
* @deferred_head: oldest OOS b'cast message received from node
* @deferred_tail: newest OOS b'cast message received from node
- * @defragm: list of partially reassembled b'cast message fragments from node
+ * @reasm_head: broadcast reassembly queue head from node
+ * @reasm_tail: last broadcast fragment received from node
* @recv_permitted: true if node is allowed to receive b'cast messages
*/
struct tipc_node {
@@ -98,7 +99,8 @@ struct tipc_node {
u32 deferred_size;
struct sk_buff *deferred_head;
struct sk_buff *deferred_tail;
- struct sk_buff *defragm;
+ struct sk_buff *reasm_head;
+ struct sk_buff *reasm_tail;
bool recv_permitted;
} bclink;
};
--
1.7.9.5
^ permalink raw reply related
* [PATCH net-next v3 1/3] tipc: don't reroute message fragments
From: erik.hugne @ 2013-11-06 8:28 UTC (permalink / raw)
To: netdev, jon.maloy, maloy, paul.gortmaker
Cc: ying.xue, tipc-discussion, Erik Hugne
In-Reply-To: <1383726487-27929-1-git-send-email-erik.hugne@ericsson.com>
From: Erik Hugne <erik.hugne@ericsson.com>
When a message fragment is received in a broadcast or unicast link,
the reception code will append the fragment payload to a big reassembly
buffer through a call to the function tipc_recv_fragm(). However, after
the return of that call, the logics goes on and passes the fragment
buffer to the function tipc_net_route_msg(), which will simply drop it.
This behavior is a remnant from the now obsolete multi-cluster
functionality, and has no relevance in the current code base.
Although currently harmless, this unnecessary call would be fatal
after applying the next patch in this series, which introduces
a completely new reassembly algorithm. So we change the code to
eliminate the redundant call.
Signed-off-by: Erik Hugne <erik.hugne@ericsson.com>
Reviewed-by: Paul Gortmaker <paul.gortmaker@windriver.com>
Signed-off-by: Jon Maloy <jon.maloy@ericsson.com>
---
net/tipc/bcast.c | 6 ++++--
net/tipc/link.c | 3 ++-
2 files changed, 6 insertions(+), 3 deletions(-)
diff --git a/net/tipc/bcast.c b/net/tipc/bcast.c
index 716de1a..766a6eb 100644
--- a/net/tipc/bcast.c
+++ b/net/tipc/bcast.c
@@ -487,11 +487,13 @@ receive:
spin_lock_bh(&bc_lock);
bclink_accept_pkt(node, seqno);
bcl->stats.recv_fragments++;
- if (ret > 0)
+ if (ret > 0) {
bcl->stats.recv_fragmented++;
+ spin_unlock_bh(&bc_lock);
+ goto receive;
+ }
spin_unlock_bh(&bc_lock);
tipc_node_unlock(node);
- tipc_net_route_msg(buf);
} else if (msg_user(msg) == NAME_DISTRIBUTOR) {
spin_lock_bh(&bc_lock);
bclink_accept_pkt(node, seqno);
diff --git a/net/tipc/link.c b/net/tipc/link.c
index 54163f9..ada8cad 100644
--- a/net/tipc/link.c
+++ b/net/tipc/link.c
@@ -1657,7 +1657,8 @@ deliver:
}
if (ret == -1)
l_ptr->next_in_no--;
- break;
+ tipc_node_unlock(n_ptr);
+ continue;
case CHANGEOVER_PROTOCOL:
type = msg_type(msg);
if (link_recv_changeover_msg(&l_ptr, &buf)) {
--
1.7.9.5
^ permalink raw reply related
* [PATCH net-next v3 0/3] tipc: message reassembly using fragment chain
From: erik.hugne @ 2013-11-06 8:28 UTC (permalink / raw)
To: netdev, jon.maloy, maloy, paul.gortmaker
Cc: ying.xue, tipc-discussion, Erik Hugne
From: Erik Hugne <erik.hugne@ericsson.com>
We introduce a new reassembly algorithm that improves performance
and eliminates the risk of causing out-of-memory situations.
v3: -Use skb_try_coalesce, and revert to fraglist if this does not succeed.
-Make sure reassembly list head is uncloned.
v2: -Rebased on Ying's indentation fix.
-Node unlock call in msg_fragmenter case moved from patch #2 to #1.
('continue' with this lock held would cause spinlock recursion if only
patch #1 is used)
Erik Hugne (3):
tipc: don't reroute message fragments
tipc: message reassembly using fragment chain
tipc: reassembly failures should cause link reset
net/tipc/bcast.c | 16 ++++--
net/tipc/link.c | 164 ++++++++++++++++--------------------------------------
net/tipc/link.h | 20 +++++--
net/tipc/msg.h | 12 ----
net/tipc/node.c | 7 ++-
net/tipc/node.h | 6 +-
6 files changed, 80 insertions(+), 145 deletions(-)
--
1.7.9.5
^ permalink raw reply
* Re: gso: Attempt to handle mega-GRO packets
From: Herbert Xu @ 2013-11-06 8:16 UTC (permalink / raw)
To: Eric Dumazet
Cc: Ben Hutchings, David Miller, christoph.paasch, netdev, hkchu,
mwdalton, mst
In-Reply-To: <20131106080425.GA17556@gondor.apana.org.au>
On Wed, Nov 06, 2013 at 04:04:25PM +0800, Herbert Xu wrote:
> On Tue, Nov 05, 2013 at 09:20:22PM -0800, Eric Dumazet wrote:
> > On Wed, 2013-11-06 at 12:28 +0800, Herbert Xu wrote:
> > > On Tue, Nov 05, 2013 at 08:23:05PM -0800, Eric Dumazet wrote:
> > > >
> > > > Nope, I already mentioned this :
> > > >
> > > > Please take a look at 2613af0ed18a11d5c566a81f9a6510b73180660a
> > > > ("virtio_net: migrate mergeable rx buffers to page frag allocators")
> > >
> > > This patch should simply be reverted. You guys steam-rolled over
> > > the virtio_net people's concerns that this seriously impacts virt
> > > performance.
> > >
> >
> > Have you followed netdev traffic lately ?
> >
> > virtio_net performance is better than before, and we did no revert,
> > thank you.
>
> The last email I saw from Michael Tsirkin he still wasn't happy
> that your patch does not degrade virt performance. Where is the
> reply to that?
I just looked at the aformentioned patch again and it is seriously
broken! How on earth did it get merged?
Instead of using perfectly sane 4K pages per frag to store guest to
guest traffic, we now end up using 1.5K frags, which that's why you
end up having to use the frag_list, WTF?
Dave, please revert the above commit as it is seriously broken.
Whatever performance problem it is trying to address can surely
be fixed without being so stupid as to break up perfectly sized
4K pages into 1.5K chunks.
Thanks!
--
Email: Herbert Xu <herbert@gondor.apana.org.au>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt
^ permalink raw reply
* Re: [patch net-next] ipv6: allow userspace to create address with IFLA_F_TEMPORARY flag
From: Nicolas Dichtel @ 2013-11-06 8:11 UTC (permalink / raw)
To: David Laight, David Miller, jiri, vyasevich, netdev, kuznet,
jmorris, yoshfuji, kaber, thaller, stephen
In-Reply-To: <20131105205744.GK8832@order.stressinduktion.org>
Le 05/11/2013 21:57, Hannes Frederic Sowa a écrit :
> On Tue, Nov 05, 2013 at 06:02:17PM +0100, Nicolas Dichtel wrote:
>> Le 29/10/2013 13:40, Hannes Frederic Sowa a écrit :
>>> On Tue, Oct 29, 2013 at 09:37:06AM -0000, David Laight wrote:
>>>>> Note that you don't even need to put the DHCP protocol core into the
>>>>> kernel to fix the promiscuous problem. You just have to use the
>>>>> current kernel interfaces correctly.
>>>>>
>>>>> It used to be the case a very long time ago that you couldn't even
>>>>> receive broadcast UDP datagrams on a socket until an address was
>>>>> configured on it.
>>>>>
>>>>> So everyone turns on promiscuous mode and uses RAW sockets or
>>>>> AF_PACKET.
>>>>>
>>>>> Stupid? yes.
>>>>
>>>> Not only that, but the dhcp client could use a normal UDP socket
>>>> to keep the lease renewed - I suspect it has only ever needed
>>>> to use the BPF interface (I didn't think it set promiscuous)
>>>> when acquiring the initial lease.
>>>
>>> Yes, this is a very unfortunate situation. From my experience it is not
>>> that
>>> easy to get a patch merged into isc-dhcp.
>>>
>>> It seems not that invasive to switch from af_packet to an udp socket with
>>> SO_BROADCAST set.
>> If I remember well, another problem is to be able to send these packets with
>> 0.0.0.0 when another IP address is available on the system:
>>
>> RFC2131
>> 4.1 Constructing and sending DHCP messages
>> ...
>> DHCP messages broadcast by a client prior to that client obtaining
>> its IP address must have the source address field in the IP header
>> set to 0.
>>
>> We made a patch (never proposed upstream) to add a socket option to keep
>> this 0.0.0.0 address.
>> If people are interested, I can try to port it on net-next.
>
> Yes, this indeed is a problem for a socket only dhcp client. I would make the
> appropriate changes to isc-dhcp if you submit such a patch.
Ok, I will try to do this for the end of the week.
Nicolas
^ permalink raw reply
* Re: [PATCH v2] can: add Renesas R-Car CAN driver
From: Wolfgang Grandegger @ 2013-11-06 8:08 UTC (permalink / raw)
To: Sergei Shtylyov; +Cc: netdev, mkl, linux-can, linux-sh, vksavl
In-Reply-To: <5279784E.1010205@cogentembedded.com>
On Wed, 06 Nov 2013 01:59:26 +0300, Sergei Shtylyov
<sergei.shtylyov@cogentembedded.com> wrote:
> Hello.
>
> On 11/03/2013 10:38 PM, Wolfgang Grandegger wrote:
>
>>>>> Add support for the CAN controller found in Renesas R-Car SoCs.
>
>>>>> Signed-off-by: Sergei Shtylyov <sergei.shtylyov@cogentembedded.com>
>
>>> [...]
>
>>>>> Index: linux-can-next/drivers/net/can/rcar_can.c
>>>>> ===================================================================
>>>>> --- /dev/null
>>>>> +++ linux-can-next/drivers/net/can/rcar_can.c
>>>>> @@ -0,0 +1,920 @@
>>> [...]
>
>>>>> + rcar_can_writeb(priv, RCAR_CAN_ECSR, (u8)~ECSR_ADEF);
>
>>>> Please avoid casts here and below.
>
>>> These casts help avoid compiler warnings.
>
>> Well instead of using casts the declaration of ECSR_ADEF and otheres
>> should be fixed. I think the problem is that BIT is declared as shown
>> below:
>
>> #define BIT(nr) (1UL << (nr))
>
>> Using BIT seems not appropriate here.
>
> Well, I thought it was designed to replace explicit (1 << (nr))
> #define's.
Me too.
> Hopefully those are good for you then...
Yes, of course.
Wolfgang.
^ permalink raw reply
* [PATCH net-next 1/3] net_sched: tbf: support of 64bit rates
From: Yang Yingliang @ 2013-11-06 8:05 UTC (permalink / raw)
To: davem, netdev; +Cc: eric.dumazet, jhs
In-Reply-To: <1383725109-37348-1-git-send-email-yangyingliang@huawei.com>
With psched_ratecfg_precompute(), tbf can deal with 64bit rates.
Add two new attributes so that tc can use them to break the 32bit
limit.
Signed-off-by: Yang Yingliang <yangyingliang@huawei.com>
---
include/uapi/linux/pkt_sched.h | 2 ++
net/sched/sch_tbf.c | 22 ++++++++++++++++++----
2 files changed, 20 insertions(+), 4 deletions(-)
diff --git a/include/uapi/linux/pkt_sched.h b/include/uapi/linux/pkt_sched.h
index f2624b5..307f293 100644
--- a/include/uapi/linux/pkt_sched.h
+++ b/include/uapi/linux/pkt_sched.h
@@ -171,6 +171,8 @@ enum {
TCA_TBF_PARMS,
TCA_TBF_RTAB,
TCA_TBF_PTAB,
+ TCA_TBF_RATE64,
+ TCA_TBF_PRATE64,
__TCA_TBF_MAX,
};
diff --git a/net/sched/sch_tbf.c b/net/sched/sch_tbf.c
index b057122..b736517 100644
--- a/net/sched/sch_tbf.c
+++ b/net/sched/sch_tbf.c
@@ -266,20 +266,23 @@ static const struct nla_policy tbf_policy[TCA_TBF_MAX + 1] = {
[TCA_TBF_PARMS] = { .len = sizeof(struct tc_tbf_qopt) },
[TCA_TBF_RTAB] = { .type = NLA_BINARY, .len = TC_RTAB_SIZE },
[TCA_TBF_PTAB] = { .type = NLA_BINARY, .len = TC_RTAB_SIZE },
+ [TCA_TBF_RATE64] = { .type = NLA_U64 },
+ [TCA_TBF_PRATE64] = { .type = NLA_U64 },
};
static int tbf_change(struct Qdisc *sch, struct nlattr *opt)
{
int err;
struct tbf_sched_data *q = qdisc_priv(sch);
- struct nlattr *tb[TCA_TBF_PTAB + 1];
+ struct nlattr *tb[TCA_TBF_MAX + 1];
struct tc_tbf_qopt *qopt;
struct qdisc_rate_table *rtab = NULL;
struct qdisc_rate_table *ptab = NULL;
struct Qdisc *child = NULL;
int max_size, n;
+ u64 rate64 = 0, prate64 = 0;
- err = nla_parse_nested(tb, TCA_TBF_PTAB, opt, tbf_policy);
+ err = nla_parse_nested(tb, TCA_TBF_MAX, opt, tbf_policy);
if (err < 0)
return err;
@@ -341,9 +344,13 @@ static int tbf_change(struct Qdisc *sch, struct nlattr *opt)
q->tokens = q->buffer;
q->ptokens = q->mtu;
- psched_ratecfg_precompute(&q->rate, &rtab->rate, 0);
+ if (tb[TCA_TBF_RATE64])
+ rate64 = nla_get_u64(tb[TCA_TBF_RATE64]);
+ psched_ratecfg_precompute(&q->rate, &rtab->rate, rate64);
if (ptab) {
- psched_ratecfg_precompute(&q->peak, &ptab->rate, 0);
+ if (tb[TCA_TBF_PRATE64])
+ prate64 = nla_get_u64(tb[TCA_TBF_PRATE64]);
+ psched_ratecfg_precompute(&q->peak, &ptab->rate, prate64);
q->peak_present = true;
} else {
q->peak_present = false;
@@ -402,6 +409,13 @@ static int tbf_dump(struct Qdisc *sch, struct sk_buff *skb)
opt.buffer = PSCHED_NS2TICKS(q->buffer);
if (nla_put(skb, TCA_TBF_PARMS, sizeof(opt), &opt))
goto nla_put_failure;
+ if ((q->rate.rate_bytes_ps >= (1ULL << 32)) &&
+ nla_put_u64(skb, TCA_TBF_RATE64, q->rate.rate_bytes_ps))
+ goto nla_put_failure;
+ if (q->peak_present &&
+ (q->peak.rate_bytes_ps >= (1ULL << 32)) &&
+ nla_put_u64(skb, TCA_TBF_PRATE64, q->peak.rate_bytes_ps))
+ goto nla_put_failure;
nla_nest_end(skb, nest);
return skb->len;
--
1.7.12
^ permalink raw reply related
* [PATCH net v3] vti: fix spd lookup: match plaintext pkt, not ipsec pkt
From: Christophe Gouault @ 2013-11-06 8:05 UTC (permalink / raw)
To: christophe.gouault, Steffen Klassert, David S. Miller
Cc: Herbert Xu, netdev, Saurabh Mohan, Sergei Shtylyov, Eric Dumazet
In-Reply-To: <1383646612-30103-1-git-send-email-christophe.gouault@6wind.com>
The vti interface inbound and outbound SPD lookups are based on the
ipsec packet instead of the plaintext packet.
Not only is it counterintuitive, it also restricts vti interfaces
to a single policy (whose selector must match the tunnel local and
remote addresses).
The policy selector is supposed to match the plaintext packet, before
encryption or after decryption.
This patch performs the SPD lookup based on the plaintext packet. It
enables to create several polices bound to the vti interface (via a
mark equal to the vti interface okey).
It remains possible to apply the same policy to all packets entering
the vti interface, by setting an any-to-any selector (src 0.0.0.0/0
dst 0.0.0.0/0 proto any mark OKEY).
Signed-off-by: Christophe Gouault <christophe.gouault@6wind.com>
---
v2:
- Fixed comment style
- Checked with checkpatch.pl and sparse
v3:
- vti_rcv: optimized skb network header shift and restore
- Checked with checkpatch.pl and sparse
---
net/ipv4/ip_vti.c | 29 ++++++++++++++++++++++++++++-
1 file changed, 28 insertions(+), 1 deletion(-)
diff --git a/net/ipv4/ip_vti.c b/net/ipv4/ip_vti.c
index 6e87f85..2368262 100644
--- a/net/ipv4/ip_vti.c
+++ b/net/ipv4/ip_vti.c
@@ -126,6 +126,7 @@ static int vti_rcv(struct sk_buff *skb)
if (tunnel != NULL) {
struct pcpu_tstats *tstats;
u32 oldmark = skb->mark;
+ unsigned int old_nh = skb->network_header;
int ret;
@@ -133,7 +134,13 @@ static int vti_rcv(struct sk_buff *skb)
* only match policies with this mark.
*/
skb->mark = be32_to_cpu(tunnel->parms.o_key);
+ /* The packet is decrypted, but not yet decapsulated.
+ * Temporarily make network_header point to the inner header
+ * for policy check.
+ */
+ skb_reset_network_header(skb);
ret = xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb);
+ skb->network_header = old_nh;
skb->mark = oldmark;
if (!ret)
return -1;
@@ -166,6 +173,8 @@ static netdev_tx_t vti_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
struct iphdr *old_iph = ip_hdr(skb);
__be32 dst = tiph->daddr;
struct flowi4 fl4;
+ struct flowi fl;
+ u32 oldmark = skb->mark;
int err;
if (skb->protocol != htons(ETH_P_IP))
@@ -173,17 +182,35 @@ static netdev_tx_t vti_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
tos = old_iph->tos;
+ /* SPD lookup: we must provide a dst_entry to xfrm_lookup, normally the
+ * route to the final destination. However this route is a route via
+ * the vti interface. Now vti interfaces typically have the NOXFRM
+ * flag, hence xfrm_lookup would bypass IPsec.
+ *
+ * Therefore, we feed xfrm_lookup with a route to the vti tunnel remote
+ * endpoint instead.
+ */
memset(&fl4, 0, sizeof(fl4));
flowi4_init_output(&fl4, tunnel->parms.link,
be32_to_cpu(tunnel->parms.o_key), RT_TOS(tos),
RT_SCOPE_UNIVERSE,
IPPROTO_IPIP, 0,
dst, tiph->saddr, 0, 0);
- rt = ip_route_output_key(dev_net(dev), &fl4);
+ rt = __ip_route_output_key(tunnel->net, &fl4);
if (IS_ERR(rt)) {
dev->stats.tx_carrier_errors++;
goto tx_error_icmp;
}
+
+ memset(&fl, 0, sizeof(fl));
+ /* Temporarily mark the skb with the tunnel o_key, to look up
+ * for a policy with this mark, matching the plaintext traffic.
+ */
+ skb->mark = be32_to_cpu(tunnel->parms.o_key);
+ __xfrm_decode_session(skb, &fl, AF_INET, 0);
+ skb->mark = oldmark;
+ rt = (struct rtable *)xfrm_lookup(tunnel->net, &rt->dst, &fl, NULL, 0);
+
/* if there is no transform then this tunnel is not functional.
* Or if the xfrm is not mode tunnel.
*/
--
1.7.10.4
^ permalink raw reply related
* [PATCH net-next 3/3] net_sched: Use pr_debug replace printk(KERN_DEBUG ...)
From: Yang Yingliang @ 2013-11-06 8:05 UTC (permalink / raw)
To: davem, netdev; +Cc: eric.dumazet, jhs
In-Reply-To: <1383725109-37348-1-git-send-email-yangyingliang@huawei.com>
Replace printk(KERN_DEBUG ...) with pr_debug() and
replace pr_warning() with pr_warn().
Signed-off-by: Yang Yingliang <yangyingliang@huawei.com>
---
net/sched/sch_cbq.c | 2 +-
net/sched/sch_dsmark.c | 2 +-
net/sched/sch_gred.c | 4 ++--
net/sched/sch_htb.c | 6 +++---
4 files changed, 7 insertions(+), 7 deletions(-)
diff --git a/net/sched/sch_cbq.c b/net/sched/sch_cbq.c
index a8f40f5..9e3a9dc 100644
--- a/net/sched/sch_cbq.c
+++ b/net/sched/sch_cbq.c
@@ -1060,7 +1060,7 @@ static void cbq_normalize_quanta(struct cbq_sched_data *q, int prio)
}
if (cl->quantum <= 0 ||
cl->quantum > 32*qdisc_dev(cl->qdisc)->mtu) {
- pr_warning("CBQ: class %08x has bad quantum==%ld, repaired.\n",
+ pr_warn("CBQ: class %08x has bad quantum==%ld, repaired.\n",
cl->common.classid, cl->quantum);
cl->quantum = qdisc_dev(cl->qdisc)->mtu/2 + 1;
}
diff --git a/net/sched/sch_dsmark.c b/net/sched/sch_dsmark.c
index 3886365..190cf65 100644
--- a/net/sched/sch_dsmark.c
+++ b/net/sched/sch_dsmark.c
@@ -303,7 +303,7 @@ static struct sk_buff *dsmark_dequeue(struct Qdisc *sch)
* and don't need yet another qdisc as a bypass.
*/
if (p->mask[index] != 0xff || p->value[index])
- pr_warning("dsmark_dequeue: unsupported protocol %d\n",
+ pr_warn("dsmark_dequeue: unsupported protocol %d\n",
ntohs(skb->protocol));
break;
}
diff --git a/net/sched/sch_gred.c b/net/sched/sch_gred.c
index d42234c..19fa4dc 100644
--- a/net/sched/sch_gred.c
+++ b/net/sched/sch_gred.c
@@ -370,7 +370,7 @@ static inline int gred_change_table_def(struct Qdisc *sch, struct nlattr *dps)
for (i = table->DPs; i < MAX_DPs; i++) {
if (table->tab[i]) {
- pr_warning("GRED: Warning: Destroying "
+ pr_warn("GRED: Warning: Destroying "
"shadowed VQ 0x%x\n", i);
gred_destroy_vq(table->tab[i]);
table->tab[i] = NULL;
@@ -456,7 +456,7 @@ static int gred_change(struct Qdisc *sch, struct nlattr *opt)
if (table->tab[table->def])
def_prio = table->tab[table->def]->prio;
- printk(KERN_DEBUG "GRED: DP %u does not have a prio "
+ pr_debug("GRED: DP %u does not have a prio "
"setting default to %d\n", ctl->DP, def_prio);
prio = def_prio;
diff --git a/net/sched/sch_htb.c b/net/sched/sch_htb.c
index f6e8a74..6586f3b 100644
--- a/net/sched/sch_htb.c
+++ b/net/sched/sch_htb.c
@@ -712,7 +712,7 @@ static s64 htb_do_events(struct htb_sched *q, const int level,
/* too much load - let's continue after a break for scheduling */
if (!(q->warned & HTB_WARN_TOOMANYEVENTS)) {
- pr_warning("htb: too many events!\n");
+ pr_warn("htb: too many events!\n");
q->warned |= HTB_WARN_TOOMANYEVENTS;
}
@@ -1484,13 +1484,13 @@ static int htb_change_class(struct Qdisc *sch, u32 classid,
if (!cl->level) {
cl->quantum = hopt->rate.rate / q->rate2quantum;
if (!hopt->quantum && cl->quantum < 1000) {
- pr_warning(
+ pr_warn(
"HTB: quantum of class %X is small. Consider r2q change.\n",
cl->common.classid);
cl->quantum = 1000;
}
if (!hopt->quantum && cl->quantum > 200000) {
- pr_warning(
+ pr_warn(
"HTB: quantum of class %X is big. Consider r2q change.\n",
cl->common.classid);
cl->quantum = 200000;
--
1.7.12
^ permalink raw reply related
* [PATCH net-next 2/3] net_sched: fix some checkpatch errors
From: Yang Yingliang @ 2013-11-06 8:05 UTC (permalink / raw)
To: davem, netdev; +Cc: eric.dumazet, jhs
In-Reply-To: <1383725109-37348-1-git-send-email-yangyingliang@huawei.com>
There are some checkpatch errors, fix them.
Signed-off-by: Yang Yingliang <yangyingliang@huawei.com>
---
net/sched/act_api.c | 4 ++--
net/sched/cls_bpf.c | 2 +-
net/sched/cls_u32.c | 2 +-
net/sched/sch_cbq.c | 3 ++-
net/sched/sch_generic.c | 4 ++--
net/sched/sch_htb.c | 13 +++++++------
net/sched/sch_netem.c | 2 +-
net/sched/sch_sfq.c | 10 ++++++----
8 files changed, 22 insertions(+), 18 deletions(-)
diff --git a/net/sched/act_api.c b/net/sched/act_api.c
index fd70728..c8aadfa 100644
--- a/net/sched/act_api.c
+++ b/net/sched/act_api.c
@@ -191,7 +191,7 @@ u32 tcf_hash_new_index(u32 *idx_gen, struct tcf_hashinfo *hinfo)
val = 1;
} while (tcf_hash_lookup(val, hinfo));
- return (*idx_gen = val);
+ return *idx_gen = val;
}
EXPORT_SYMBOL(tcf_hash_new_index);
@@ -263,7 +263,7 @@ void tcf_hash_insert(struct tcf_common *p, struct tcf_hashinfo *hinfo)
}
EXPORT_SYMBOL(tcf_hash_insert);
-static struct tc_action_ops *act_base = NULL;
+static struct tc_action_ops *act_base;
static DEFINE_RWLOCK(act_mod_lock);
int tcf_register_action(struct tc_action_ops *act)
diff --git a/net/sched/cls_bpf.c b/net/sched/cls_bpf.c
index 1002a82..d7c72be 100644
--- a/net/sched/cls_bpf.c
+++ b/net/sched/cls_bpf.c
@@ -323,7 +323,7 @@ static int cls_bpf_dump(struct tcf_proto *tp, unsigned long fh,
if (nla == NULL)
goto nla_put_failure;
- memcpy(nla_data(nla), prog->bpf_ops, nla_len(nla));
+ memcpy(nla_data(nla), prog->bpf_ops, nla_len(nla));
if (tcf_exts_dump(skb, &prog->exts, &bpf_ext_map) < 0)
goto nla_put_failure;
diff --git a/net/sched/cls_u32.c b/net/sched/cls_u32.c
index eb07a1e..59e546c 100644
--- a/net/sched/cls_u32.c
+++ b/net/sched/cls_u32.c
@@ -352,7 +352,7 @@ static int u32_destroy_key(struct tcf_proto *tp, struct tc_u_knode *n)
return 0;
}
-static int u32_delete_key(struct tcf_proto *tp, struct tc_u_knode* key)
+static int u32_delete_key(struct tcf_proto *tp, struct tc_u_knode *key)
{
struct tc_u_knode **kp;
struct tc_u_hnode *ht = key->ht_up;
diff --git a/net/sched/sch_cbq.c b/net/sched/sch_cbq.c
index 7a42c81..a8f40f5 100644
--- a/net/sched/sch_cbq.c
+++ b/net/sched/sch_cbq.c
@@ -1058,7 +1058,8 @@ static void cbq_normalize_quanta(struct cbq_sched_data *q, int prio)
cl->quantum = (cl->weight*cl->allot*q->nclasses[prio])/
q->quanta[prio];
}
- if (cl->quantum <= 0 || cl->quantum>32*qdisc_dev(cl->qdisc)->mtu) {
+ if (cl->quantum <= 0 ||
+ cl->quantum > 32*qdisc_dev(cl->qdisc)->mtu) {
pr_warning("CBQ: class %08x has bad quantum==%ld, repaired.\n",
cl->common.classid, cl->quantum);
cl->quantum = qdisc_dev(cl->qdisc)->mtu/2 + 1;
diff --git a/net/sched/sch_generic.c b/net/sched/sch_generic.c
index 7fc899a..9421350 100644
--- a/net/sched/sch_generic.c
+++ b/net/sched/sch_generic.c
@@ -338,13 +338,13 @@ EXPORT_SYMBOL(netif_carrier_off);
cheaper.
*/
-static int noop_enqueue(struct sk_buff *skb, struct Qdisc * qdisc)
+static int noop_enqueue(struct sk_buff *skb, struct Qdisc *qdisc)
{
kfree_skb(skb);
return NET_XMIT_CN;
}
-static struct sk_buff *noop_dequeue(struct Qdisc * qdisc)
+static struct sk_buff *noop_dequeue(struct Qdisc *qdisc)
{
return NULL;
}
diff --git a/net/sched/sch_htb.c b/net/sched/sch_htb.c
index 0e1e38b..f6e8a74 100644
--- a/net/sched/sch_htb.c
+++ b/net/sched/sch_htb.c
@@ -54,7 +54,7 @@
one less than their parent.
*/
-static int htb_hysteresis __read_mostly = 0; /* whether to use mode hysteresis for speedup */
+static int htb_hysteresis __read_mostly; /* whether to use mode hysteresis for speedup */
#define HTB_VER 0x30011 /* major must be matched with number suplied by TC as version */
#if HTB_VER >> 16 != TC_HTB_PROTOVER
@@ -65,7 +65,7 @@ static int htb_hysteresis __read_mostly = 0; /* whether to use mode hysteresis f
module_param (htb_hysteresis, int, 0640);
MODULE_PARM_DESC(htb_hysteresis, "Hysteresis mode, less CPU load, less accurate");
-static int htb_rate_est = 0; /* htb classes have a default rate estimator */
+static int htb_rate_est; /* htb classes have a default rate estimator */
module_param(htb_rate_est, int, 0640);
MODULE_PARM_DESC(htb_rate_est, "setup a default rate estimator (4sec 16sec) for htb classes");
@@ -846,7 +846,7 @@ next:
break;
qdisc_warn_nonwc("htb", cl->un.leaf.q);
- htb_next_rb_node(level ? &cl->parent->un.inner.clprio[prio].ptr:
+ htb_next_rb_node(level ? &cl->parent->un.inner.clprio[prio].ptr :
&q->hlevel[0].hprio[prio].ptr);
cl = htb_lookup_leaf(hprio, prio);
@@ -1276,9 +1276,10 @@ static int htb_delete(struct Qdisc *sch, unsigned long arg)
struct Qdisc *new_q = NULL;
int last_child = 0;
- // TODO: why don't allow to delete subtree ? references ? does
- // tc subsys quarantee us that in htb_destroy it holds no class
- // refs so that we can remove children safely there ?
+ /* TODO: why don't allow to delete subtree ? references ? does
+ * tc subsys quarantee us that in htb_destroy it holds no class
+ * refs so that we can remove children safely there ?
+ */
if (cl->children || cl->filter_cnt)
return -EBUSY;
diff --git a/net/sched/sch_netem.c b/net/sched/sch_netem.c
index 75c94e5..9765c3f 100644
--- a/net/sched/sch_netem.c
+++ b/net/sched/sch_netem.c
@@ -728,7 +728,7 @@ static int get_loss_clg(struct Qdisc *sch, const struct nlattr *attr)
nla_for_each_nested(la, attr, rem) {
u16 type = nla_type(la);
- switch(type) {
+ switch (type) {
case NETEM_LOSS_GI: {
const struct tc_netem_gimodel *gi = nla_data(la);
diff --git a/net/sched/sch_sfq.c b/net/sched/sch_sfq.c
index d3a1bc2..76f01e0 100644
--- a/net/sched/sch_sfq.c
+++ b/net/sched/sch_sfq.c
@@ -237,10 +237,12 @@ static inline void sfq_link(struct sfq_sched_data *q, sfq_index x)
}
#define sfq_unlink(q, x, n, p) \
- n = q->slots[x].dep.next; \
- p = q->slots[x].dep.prev; \
- sfq_dep_head(q, p)->next = n; \
- sfq_dep_head(q, n)->prev = p
+ do { \
+ n = q->slots[x].dep.next; \
+ p = q->slots[x].dep.prev; \
+ sfq_dep_head(q, p)->next = n; \
+ sfq_dep_head(q, n)->prev = p; \
+ } while (0)
static inline void sfq_dec(struct sfq_sched_data *q, sfq_index x)
--
1.7.12
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox