Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/klassert/ipsec...
authorDavid S. Miller <davem@davemloft.net>
Tue, 9 Dec 2014 02:30:21 +0000 (21:30 -0500)
committerDavid S. Miller <davem@davemloft.net>
Tue, 9 Dec 2014 02:30:21 +0000 (21:30 -0500)
Steffen Klassert says:

====================
pull request (net-next): ipsec-next 2014-12-03

1) Fix a set but not used warning. From Fabian Frederick.

2) Currently we make sequence number values available to userspace
   only if we use ESN. Make the sequence number values also available
   for non ESN states. From Zhi Ding.

3) Remove socket policy hashing. We don't need it because socket
   policies are always looked up via a linked list. From Herbert Xu.

4) After removing socket policy hashing, we can use __xfrm_policy_link
   in xfrm_policy_insert. From Herbert Xu.

5) Add a lookup method for vti6 tunnels with wildcard endpoints.
   I forgot this when I initially implemented vti6.

Please pull or let me know if there are problems.
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
include/net/netns/xfrm.h
net/ipv6/ip6_vti.c
net/xfrm/xfrm_policy.c
net/xfrm/xfrm_user.c

index 9da7982..730d82a 100644 (file)
@@ -50,8 +50,8 @@ struct netns_xfrm {
        struct list_head        policy_all;
        struct hlist_head       *policy_byidx;
        unsigned int            policy_idx_hmask;
-       struct hlist_head       policy_inexact[XFRM_POLICY_MAX * 2];
-       struct xfrm_policy_hash policy_bydst[XFRM_POLICY_MAX * 2];
+       struct hlist_head       policy_inexact[XFRM_POLICY_MAX];
+       struct xfrm_policy_hash policy_bydst[XFRM_POLICY_MAX];
        unsigned int            policy_count[XFRM_POLICY_MAX * 2];
        struct work_struct      policy_hash_work;
        struct xfrm_policy_hthresh policy_hthresh;
index 16a7e81..ace10d0 100644 (file)
@@ -95,6 +95,7 @@ vti6_tnl_lookup(struct net *net, const struct in6_addr *remote,
        unsigned int hash = HASH(remote, local);
        struct ip6_tnl *t;
        struct vti6_net *ip6n = net_generic(net, vti6_net_id);
+       struct in6_addr any;
 
        for_each_vti6_tunnel_rcu(ip6n->tnls_r_l[hash]) {
                if (ipv6_addr_equal(local, &t->parms.laddr) &&
@@ -102,6 +103,22 @@ vti6_tnl_lookup(struct net *net, const struct in6_addr *remote,
                    (t->dev->flags & IFF_UP))
                        return t;
        }
+
+       memset(&any, 0, sizeof(any));
+       hash = HASH(&any, local);
+       for_each_vti6_tunnel_rcu(ip6n->tnls_r_l[hash]) {
+               if (ipv6_addr_equal(local, &t->parms.laddr) &&
+                   (t->dev->flags & IFF_UP))
+                       return t;
+       }
+
+       hash = HASH(remote, &any);
+       for_each_vti6_tunnel_rcu(ip6n->tnls_r_l[hash]) {
+               if (ipv6_addr_equal(remote, &t->parms.raddr) &&
+                   (t->dev->flags & IFF_UP))
+                       return t;
+       }
+
        t = rcu_dereference(ip6n->tnls_wc[0]);
        if (t && (t->dev->flags & IFF_UP))
                return t;
index 88bf289..cee479b 100644 (file)
@@ -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]));
index e812e98..8128594 100644 (file)
@@ -824,13 +824,15 @@ static int copy_to_user_state_extra(struct xfrm_state *x,
        ret = xfrm_mark_put(skb, &x->mark);
        if (ret)
                goto out;
-       if (x->replay_esn) {
+       if (x->replay_esn)
                ret = nla_put(skb, XFRMA_REPLAY_ESN_VAL,
                              xfrm_replay_state_esn_len(x->replay_esn),
                              x->replay_esn);
-               if (ret)
-                       goto out;
-       }
+       else
+               ret = nla_put(skb, XFRMA_REPLAY_VAL, sizeof(x->replay),
+                             &x->replay);
+       if (ret)
+               goto out;
        if (x->security)
                ret = copy_sec_ctx(x->security, skb);
 out:
@@ -2569,6 +2571,8 @@ static inline size_t xfrm_sa_len(struct xfrm_state *x)
                l += nla_total_size(sizeof(x->tfcpad));
        if (x->replay_esn)
                l += nla_total_size(xfrm_replay_state_esn_len(x->replay_esn));
+       else
+               l += nla_total_size(sizeof(struct xfrm_replay_state));
        if (x->security)
                l += nla_total_size(sizeof(struct xfrm_user_sec_ctx) +
                                    x->security->ctx_len);