|
@@ -55,6 +55,7 @@ static int stale_bundle(struct dst_entry *dst);
|
|
|
static int xfrm_bundle_ok(struct xfrm_dst *xdst);
|
|
|
static void xfrm_policy_queue_process(unsigned long arg);
|
|
|
|
|
|
+static void __xfrm_policy_link(struct xfrm_policy *pol, int dir);
|
|
|
static struct xfrm_policy *__xfrm_policy_unlink(struct xfrm_policy *pol,
|
|
|
int dir);
|
|
|
|
|
@@ -561,7 +562,7 @@ static void xfrm_hash_resize(struct work_struct *work)
|
|
|
mutex_lock(&hash_resize_mutex);
|
|
|
|
|
|
total = 0;
|
|
|
- for (dir = 0; dir < XFRM_POLICY_MAX * 2; dir++) {
|
|
|
+ for (dir = 0; dir < XFRM_POLICY_MAX; dir++) {
|
|
|
if (xfrm_bydst_should_resize(net, dir, &total))
|
|
|
xfrm_bydst_resize(net, dir);
|
|
|
}
|
|
@@ -601,7 +602,7 @@ static void xfrm_hash_rebuild(struct work_struct *work)
|
|
|
write_lock_bh(&net->xfrm.xfrm_policy_lock);
|
|
|
|
|
|
/* reset the bydst and inexact table in all directions */
|
|
|
- for (dir = 0; dir < XFRM_POLICY_MAX * 2; dir++) {
|
|
|
+ for (dir = 0; dir < XFRM_POLICY_MAX; dir++) {
|
|
|
INIT_HLIST_HEAD(&net->xfrm.policy_inexact[dir]);
|
|
|
hmask = net->xfrm.policy_bydst[dir].hmask;
|
|
|
odst = net->xfrm.policy_bydst[dir].table;
|
|
@@ -779,8 +780,7 @@ int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl)
|
|
|
hlist_add_behind(&policy->bydst, newpos);
|
|
|
else
|
|
|
hlist_add_head(&policy->bydst, chain);
|
|
|
- xfrm_pol_hold(policy);
|
|
|
- net->xfrm.policy_count[dir]++;
|
|
|
+ __xfrm_policy_link(policy, dir);
|
|
|
atomic_inc(&net->xfrm.flow_cache_genid);
|
|
|
|
|
|
/* After previous checking, family can either be AF_INET or AF_INET6 */
|
|
@@ -799,7 +799,6 @@ int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl)
|
|
|
policy->curlft.use_time = 0;
|
|
|
if (!mod_timer(&policy->timer, jiffies + HZ))
|
|
|
xfrm_pol_hold(policy);
|
|
|
- list_add(&policy->walk.all, &net->xfrm.policy_all);
|
|
|
write_unlock_bh(&net->xfrm.xfrm_policy_lock);
|
|
|
|
|
|
if (delpol)
|
|
@@ -1247,17 +1246,10 @@ out:
|
|
|
static void __xfrm_policy_link(struct xfrm_policy *pol, int dir)
|
|
|
{
|
|
|
struct net *net = xp_net(pol);
|
|
|
- struct hlist_head *chain = policy_hash_bysel(net, &pol->selector,
|
|
|
- pol->family, dir);
|
|
|
|
|
|
list_add(&pol->walk.all, &net->xfrm.policy_all);
|
|
|
- hlist_add_head(&pol->bydst, chain);
|
|
|
- hlist_add_head(&pol->byidx, net->xfrm.policy_byidx+idx_hash(net, pol->index));
|
|
|
net->xfrm.policy_count[dir]++;
|
|
|
xfrm_pol_hold(pol);
|
|
|
-
|
|
|
- if (xfrm_bydst_should_resize(net, dir, NULL))
|
|
|
- schedule_work(&net->xfrm.policy_hash_work);
|
|
|
}
|
|
|
|
|
|
static struct xfrm_policy *__xfrm_policy_unlink(struct xfrm_policy *pol,
|
|
@@ -1265,17 +1257,31 @@ static struct xfrm_policy *__xfrm_policy_unlink(struct xfrm_policy *pol,
|
|
|
{
|
|
|
struct net *net = xp_net(pol);
|
|
|
|
|
|
- if (hlist_unhashed(&pol->bydst))
|
|
|
+ if (list_empty(&pol->walk.all))
|
|
|
return NULL;
|
|
|
|
|
|
- hlist_del_init(&pol->bydst);
|
|
|
- hlist_del(&pol->byidx);
|
|
|
- list_del(&pol->walk.all);
|
|
|
+ /* Socket policies are not hashed. */
|
|
|
+ if (!hlist_unhashed(&pol->bydst)) {
|
|
|
+ hlist_del(&pol->bydst);
|
|
|
+ hlist_del(&pol->byidx);
|
|
|
+ }
|
|
|
+
|
|
|
+ list_del_init(&pol->walk.all);
|
|
|
net->xfrm.policy_count[dir]--;
|
|
|
|
|
|
return pol;
|
|
|
}
|
|
|
|
|
|
+static void xfrm_sk_policy_link(struct xfrm_policy *pol, int dir)
|
|
|
+{
|
|
|
+ __xfrm_policy_link(pol, XFRM_POLICY_MAX + dir);
|
|
|
+}
|
|
|
+
|
|
|
+static void xfrm_sk_policy_unlink(struct xfrm_policy *pol, int dir)
|
|
|
+{
|
|
|
+ __xfrm_policy_unlink(pol, XFRM_POLICY_MAX + dir);
|
|
|
+}
|
|
|
+
|
|
|
int xfrm_policy_delete(struct xfrm_policy *pol, int dir)
|
|
|
{
|
|
|
struct net *net = xp_net(pol);
|
|
@@ -1307,7 +1313,7 @@ int xfrm_sk_policy_insert(struct sock *sk, int dir, struct xfrm_policy *pol)
|
|
|
if (pol) {
|
|
|
pol->curlft.add_time = get_seconds();
|
|
|
pol->index = xfrm_gen_index(net, XFRM_POLICY_MAX+dir, 0);
|
|
|
- __xfrm_policy_link(pol, XFRM_POLICY_MAX+dir);
|
|
|
+ xfrm_sk_policy_link(pol, dir);
|
|
|
}
|
|
|
if (old_pol) {
|
|
|
if (pol)
|
|
@@ -1316,7 +1322,7 @@ int xfrm_sk_policy_insert(struct sock *sk, int dir, struct xfrm_policy *pol)
|
|
|
/* Unlinking succeeds always. This is the only function
|
|
|
* allowed to delete or replace socket policy.
|
|
|
*/
|
|
|
- __xfrm_policy_unlink(old_pol, XFRM_POLICY_MAX+dir);
|
|
|
+ xfrm_sk_policy_unlink(old_pol, dir);
|
|
|
}
|
|
|
write_unlock_bh(&net->xfrm.xfrm_policy_lock);
|
|
|
|
|
@@ -1349,7 +1355,7 @@ static struct xfrm_policy *clone_policy(const struct xfrm_policy *old, int dir)
|
|
|
memcpy(newp->xfrm_vec, old->xfrm_vec,
|
|
|
newp->xfrm_nr*sizeof(struct xfrm_tmpl));
|
|
|
write_lock_bh(&net->xfrm.xfrm_policy_lock);
|
|
|
- __xfrm_policy_link(newp, XFRM_POLICY_MAX+dir);
|
|
|
+ xfrm_sk_policy_link(newp, dir);
|
|
|
write_unlock_bh(&net->xfrm.xfrm_policy_lock);
|
|
|
xfrm_pol_put(newp);
|
|
|
}
|
|
@@ -1878,7 +1884,6 @@ xfrm_resolve_and_create_bundle(struct xfrm_policy **pols, int num_pols,
|
|
|
|
|
|
static void xfrm_policy_queue_process(unsigned long arg)
|
|
|
{
|
|
|
- int err = 0;
|
|
|
struct sk_buff *skb;
|
|
|
struct sock *sk;
|
|
|
struct dst_entry *dst;
|
|
@@ -1941,7 +1946,7 @@ static void xfrm_policy_queue_process(unsigned long arg)
|
|
|
skb_dst_drop(skb);
|
|
|
skb_dst_set(skb, dst);
|
|
|
|
|
|
- err = dst_output(skb);
|
|
|
+ dst_output(skb);
|
|
|
}
|
|
|
|
|
|
out:
|
|
@@ -2966,10 +2971,11 @@ static int __net_init xfrm_policy_init(struct net *net)
|
|
|
goto out_byidx;
|
|
|
net->xfrm.policy_idx_hmask = hmask;
|
|
|
|
|
|
- for (dir = 0; dir < XFRM_POLICY_MAX * 2; dir++) {
|
|
|
+ for (dir = 0; dir < XFRM_POLICY_MAX; dir++) {
|
|
|
struct xfrm_policy_hash *htab;
|
|
|
|
|
|
net->xfrm.policy_count[dir] = 0;
|
|
|
+ net->xfrm.policy_count[XFRM_POLICY_MAX + dir] = 0;
|
|
|
INIT_HLIST_HEAD(&net->xfrm.policy_inexact[dir]);
|
|
|
|
|
|
htab = &net->xfrm.policy_bydst[dir];
|
|
@@ -3021,7 +3027,7 @@ static void xfrm_policy_fini(struct net *net)
|
|
|
|
|
|
WARN_ON(!list_empty(&net->xfrm.policy_all));
|
|
|
|
|
|
- for (dir = 0; dir < XFRM_POLICY_MAX * 2; dir++) {
|
|
|
+ for (dir = 0; dir < XFRM_POLICY_MAX; dir++) {
|
|
|
struct xfrm_policy_hash *htab;
|
|
|
|
|
|
WARN_ON(!hlist_empty(&net->xfrm.policy_inexact[dir]));
|