aboutsummaryrefslogtreecommitdiff
path: root/net/xfrm
diff options
context:
space:
mode:
authorSteffen Klassert2020-07-10 07:32:03 +0200
committerSteffen Klassert2020-07-10 07:32:03 +0200
commit2d4c7986dbc6f78043df7b946b36996fca8c046f (patch)
treeaf7df4ca6064ab193dd02bde5b0aac2ab9409528 /net/xfrm
parent428d2459cceb77357b81c242ca22462a6a904817 (diff)
parentda9bbf0598c9e66b8a46ceabaa6172596795acf2 (diff)
Merge remote-tracking branch 'origin/testing'
Xin Long says: ================== Now ipip and ipv6 tunnels processing is supported by xfrm4/6_tunnel, but not in vti and xfrmi. This feature is needed by processing those uncompressed small fragments and packets when using comp protocol. It means vti and xfrmi won't be able to accept small fragments or packets when using comp protocol, which is not expected. xfrm4/6_tunnel eventually calls xfrm_input() to process ipip and ipv6 tunnels with an ipip/ipv6-proto state (a child state of comp-proto state), and vti and xfrmi should do the same. The extra things for vti to do is: - vti_input() should be called before xfrm_input() to set XFRM_TUNNEL_SKB_CB(skb)->tunnel.ip4/6 = tunnel. [A] - vti_rcv_cb() should be called after xfrm_input() to update the skb->dev. [B] And the extra things for xfrmi to do is: - The ipip/ipv6-proto state should be assigned if_id from its parent's state. [C] - xfrmi_rcv_cb() should be called after xfrm_input() to update the skb->dev. [D] Patch 4-7 does the things in [A]. To implement [B] and [D], patch 1-3 is to build a callback function for xfrm4/6_tunnel, which can be called after xfrm_input(), similar to xfrm4/6_protocol's .cb_handler. vti and xfrmi only needs to give their own callback function in patch 4-7 and 9-10, which already exists: vti_rcv_cb() and xfrmi_rcv_cb(). Patch 8 is to do the thing in [C] by assigning child tunnel's if_id from its parent tunnel. With the whole patch series, the segments or packets with any size can work with ipsec comp proto on vti and xfrmi. v1->v2: - See Patch 2-3. v2->v3: - See Patch 2-3, 4, 6, 9-10. ================== Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>
Diffstat (limited to 'net/xfrm')
-rw-r--r--net/xfrm/xfrm_input.c24
-rw-r--r--net/xfrm/xfrm_interface.c70
2 files changed, 83 insertions, 11 deletions
diff --git a/net/xfrm/xfrm_input.c b/net/xfrm/xfrm_input.c
index bd984ff17c2d..37456d022cfa 100644
--- a/net/xfrm/xfrm_input.c
+++ b/net/xfrm/xfrm_input.c
@@ -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;
diff --git a/net/xfrm/xfrm_interface.c b/net/xfrm/xfrm_interface.c
index c407ecbc5d46..a79eb49a4e0d 100644
--- a/net/xfrm/xfrm_interface.c
+++ b/net/xfrm/xfrm_interface.c
@@ -798,6 +798,26 @@ static struct xfrm6_protocol xfrmi_ipcomp6_protocol __read_mostly = {
.priority = 10,
};
+#if IS_ENABLED(CONFIG_INET6_XFRM_TUNNEL)
+static int xfrmi6_rcv_tunnel(struct sk_buff *skb)
+{
+ const xfrm_address_t *saddr;
+ __be32 spi;
+
+ saddr = (const xfrm_address_t *)&ipv6_hdr(skb)->saddr;
+ spi = xfrm6_tunnel_spi_lookup(dev_net(skb->dev), saddr);
+
+ return xfrm6_rcv_spi(skb, IPPROTO_IPV6, spi, NULL);
+}
+
+static struct xfrm6_tunnel xfrmi_ipv6_handler __read_mostly = {
+ .handler = xfrmi6_rcv_tunnel,
+ .cb_handler = xfrmi_rcv_cb,
+ .err_handler = xfrmi6_err,
+ .priority = -1,
+};
+#endif
+
static struct xfrm4_protocol xfrmi_esp4_protocol __read_mostly = {
.handler = xfrm4_rcv,
.input_handler = xfrm_input,
@@ -822,6 +842,20 @@ static struct xfrm4_protocol xfrmi_ipcomp4_protocol __read_mostly = {
.priority = 10,
};
+#if IS_ENABLED(CONFIG_INET_XFRM_TUNNEL)
+static int xfrmi4_rcv_tunnel(struct sk_buff *skb)
+{
+ return xfrm4_rcv_spi(skb, IPPROTO_IPIP, ip_hdr(skb)->saddr);
+}
+
+static struct xfrm_tunnel xfrmi_ipip_handler __read_mostly = {
+ .handler = xfrmi4_rcv_tunnel,
+ .cb_handler = xfrmi_rcv_cb,
+ .err_handler = xfrmi4_err,
+ .priority = -1,
+};
+#endif
+
static int __init xfrmi4_init(void)
{
int err;
@@ -835,9 +869,23 @@ static int __init xfrmi4_init(void)
err = xfrm4_protocol_register(&xfrmi_ipcomp4_protocol, IPPROTO_COMP);
if (err < 0)
goto xfrm_proto_comp_failed;
+#if IS_ENABLED(CONFIG_INET_XFRM_TUNNEL)
+ err = xfrm4_tunnel_register(&xfrmi_ipip_handler, AF_INET);
+ if (err < 0)
+ goto xfrm_tunnel_ipip_failed;
+ err = xfrm4_tunnel_register(&xfrmi_ipip_handler, AF_INET6);
+ if (err < 0)
+ goto xfrm_tunnel_ipip6_failed;
+#endif
return 0;
+#if IS_ENABLED(CONFIG_INET_XFRM_TUNNEL)
+xfrm_tunnel_ipip6_failed:
+ xfrm4_tunnel_deregister(&xfrmi_ipip_handler, AF_INET);
+xfrm_tunnel_ipip_failed:
+ xfrm4_protocol_deregister(&xfrmi_ipcomp4_protocol, IPPROTO_COMP);
+#endif
xfrm_proto_comp_failed:
xfrm4_protocol_deregister(&xfrmi_ah4_protocol, IPPROTO_AH);
xfrm_proto_ah_failed:
@@ -848,6 +896,10 @@ xfrm_proto_esp_failed:
static void xfrmi4_fini(void)
{
+#if IS_ENABLED(CONFIG_INET_XFRM_TUNNEL)
+ xfrm4_tunnel_deregister(&xfrmi_ipip_handler, AF_INET6);
+ xfrm4_tunnel_deregister(&xfrmi_ipip_handler, AF_INET);
+#endif
xfrm4_protocol_deregister(&xfrmi_ipcomp4_protocol, IPPROTO_COMP);
xfrm4_protocol_deregister(&xfrmi_ah4_protocol, IPPROTO_AH);
xfrm4_protocol_deregister(&xfrmi_esp4_protocol, IPPROTO_ESP);
@@ -866,9 +918,23 @@ static int __init xfrmi6_init(void)
err = xfrm6_protocol_register(&xfrmi_ipcomp6_protocol, IPPROTO_COMP);
if (err < 0)
goto xfrm_proto_comp_failed;
+#if IS_ENABLED(CONFIG_INET6_XFRM_TUNNEL)
+ err = xfrm6_tunnel_register(&xfrmi_ipv6_handler, AF_INET6);
+ if (err < 0)
+ goto xfrm_tunnel_ipv6_failed;
+ err = xfrm6_tunnel_register(&xfrmi_ipv6_handler, AF_INET);
+ if (err < 0)
+ goto xfrm_tunnel_ip6ip_failed;
+#endif
return 0;
+#if IS_ENABLED(CONFIG_INET6_XFRM_TUNNEL)
+xfrm_tunnel_ip6ip_failed:
+ xfrm6_tunnel_deregister(&xfrmi_ipv6_handler, AF_INET6);
+xfrm_tunnel_ipv6_failed:
+ xfrm6_protocol_deregister(&xfrmi_ipcomp6_protocol, IPPROTO_COMP);
+#endif
xfrm_proto_comp_failed:
xfrm6_protocol_deregister(&xfrmi_ah6_protocol, IPPROTO_AH);
xfrm_proto_ah_failed:
@@ -879,6 +945,10 @@ xfrm_proto_esp_failed:
static void xfrmi6_fini(void)
{
+#if IS_ENABLED(CONFIG_INET6_XFRM_TUNNEL)
+ xfrm6_tunnel_deregister(&xfrmi_ipv6_handler, AF_INET);
+ xfrm6_tunnel_deregister(&xfrmi_ipv6_handler, AF_INET6);
+#endif
xfrm6_protocol_deregister(&xfrmi_ipcomp6_protocol, IPPROTO_COMP);
xfrm6_protocol_deregister(&xfrmi_ah6_protocol, IPPROTO_AH);
xfrm6_protocol_deregister(&xfrmi_esp6_protocol, IPPROTO_ESP);