xfrm: add is_ipip to struct xfrm_input_afinfo
authorXin Long <lucien.xin@gmail.com>
Mon, 6 Jul 2020 12:01:29 +0000 (20:01 +0800)
committerSteffen Klassert <steffen.klassert@secunet.com>
Thu, 9 Jul 2020 10:50:12 +0000 (12:50 +0200)
This patch is to add a new member is_ipip to struct xfrm_input_afinfo,
to allow another group family of callback functions to be registered
with is_ipip set.

This will be used for doing a callback for struct xfrm(6)_tunnel of
ipip/ipv6 tunnels in xfrm_input() by calling xfrm_rcv_cb(), which is
needed by ipip/ipv6 tunnels' support in ip(6)_vti and xfrm interface
in the next patches.

Signed-off-by: Xin Long <lucien.xin@gmail.com>
Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>
include/net/xfrm.h
net/xfrm/xfrm_input.c

index e20b2b2..4666bc9 100644 (file)
@@ -373,7 +373,8 @@ struct xfrm_state_afinfo *xfrm_state_get_afinfo(unsigned int family);
 struct xfrm_state_afinfo *xfrm_state_afinfo_get_rcu(unsigned int family);
 
 struct xfrm_input_afinfo {
-       unsigned int            family;
+       u8                      family;
+       bool                    is_ipip;
        int                     (*callback)(struct sk_buff *skb, u8 protocol,
                                            int err);
 };
index bd984ff..37456d0 100644 (file)
@@ -42,7 +42,7 @@ struct xfrm_trans_cb {
 #define XFRM_TRANS_SKB_CB(__skb) ((struct xfrm_trans_cb *)&((__skb)->cb[0]))
 
 static DEFINE_SPINLOCK(xfrm_input_afinfo_lock);
-static struct xfrm_input_afinfo const __rcu *xfrm_input_afinfo[AF_INET6 + 1];
+static struct xfrm_input_afinfo const __rcu *xfrm_input_afinfo[2][AF_INET6 + 1];
 
 static struct gro_cells gro_cells;
 static struct net_device xfrm_napi_dev;
@@ -53,14 +53,14 @@ int xfrm_input_register_afinfo(const struct xfrm_input_afinfo *afinfo)
 {
        int err = 0;
 
-       if (WARN_ON(afinfo->family >= ARRAY_SIZE(xfrm_input_afinfo)))
+       if (WARN_ON(afinfo->family > AF_INET6))
                return -EAFNOSUPPORT;
 
        spin_lock_bh(&xfrm_input_afinfo_lock);
-       if (unlikely(xfrm_input_afinfo[afinfo->family] != NULL))
+       if (unlikely(xfrm_input_afinfo[afinfo->is_ipip][afinfo->family]))
                err = -EEXIST;
        else
-               rcu_assign_pointer(xfrm_input_afinfo[afinfo->family], afinfo);
+               rcu_assign_pointer(xfrm_input_afinfo[afinfo->is_ipip][afinfo->family], afinfo);
        spin_unlock_bh(&xfrm_input_afinfo_lock);
        return err;
 }
@@ -71,11 +71,11 @@ int xfrm_input_unregister_afinfo(const struct xfrm_input_afinfo *afinfo)
        int err = 0;
 
        spin_lock_bh(&xfrm_input_afinfo_lock);
-       if (likely(xfrm_input_afinfo[afinfo->family] != NULL)) {
-               if (unlikely(xfrm_input_afinfo[afinfo->family] != afinfo))
+       if (likely(xfrm_input_afinfo[afinfo->is_ipip][afinfo->family])) {
+               if (unlikely(xfrm_input_afinfo[afinfo->is_ipip][afinfo->family] != afinfo))
                        err = -EINVAL;
                else
-                       RCU_INIT_POINTER(xfrm_input_afinfo[afinfo->family], NULL);
+                       RCU_INIT_POINTER(xfrm_input_afinfo[afinfo->is_ipip][afinfo->family], NULL);
        }
        spin_unlock_bh(&xfrm_input_afinfo_lock);
        synchronize_rcu();
@@ -83,15 +83,15 @@ int xfrm_input_unregister_afinfo(const struct xfrm_input_afinfo *afinfo)
 }
 EXPORT_SYMBOL(xfrm_input_unregister_afinfo);
 
-static const struct xfrm_input_afinfo *xfrm_input_get_afinfo(unsigned int family)
+static const struct xfrm_input_afinfo *xfrm_input_get_afinfo(u8 family, bool is_ipip)
 {
        const struct xfrm_input_afinfo *afinfo;
 
-       if (WARN_ON_ONCE(family >= ARRAY_SIZE(xfrm_input_afinfo)))
+       if (WARN_ON_ONCE(family > AF_INET6))
                return NULL;
 
        rcu_read_lock();
-       afinfo = rcu_dereference(xfrm_input_afinfo[family]);
+       afinfo = rcu_dereference(xfrm_input_afinfo[is_ipip][family]);
        if (unlikely(!afinfo))
                rcu_read_unlock();
        return afinfo;
@@ -100,9 +100,11 @@ static const struct xfrm_input_afinfo *xfrm_input_get_afinfo(unsigned int family
 static int xfrm_rcv_cb(struct sk_buff *skb, unsigned int family, u8 protocol,
                       int err)
 {
+       bool is_ipip = (protocol == IPPROTO_IPIP || protocol == IPPROTO_IPV6);
+       const struct xfrm_input_afinfo *afinfo;
        int ret;
-       const struct xfrm_input_afinfo *afinfo = xfrm_input_get_afinfo(family);
 
+       afinfo = xfrm_input_get_afinfo(family, is_ipip);
        if (!afinfo)
                return -EAFNOSUPPORT;