netdev.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH RFC v3 0/12] vti4: prepare namespace and interfamily support.
@ 2014-01-27 10:29 Steffen Klassert
  2014-01-27 10:29 ` [PATCH RFC v3 01/12] xfrm4: Add IPsec protocol multiplexer Steffen Klassert
                   ` (13 more replies)
  0 siblings, 14 replies; 18+ messages in thread
From: Steffen Klassert @ 2014-01-27 10:29 UTC (permalink / raw)
  To: netdev; +Cc: Steffen Klassert, Christophe Gouault, Saurabh Mohan

This patchset prepares vti4 for proper namespace and interfamily support.

Currently the receive hook is in the middle of the decapsulation
process, some of the header pointers point still into the IPsec packet
others point already into the decapsulated packet. This makes it
very unflexible and proper namespace and interfamily support can't
be done as it is.

The patchset that implements an IPsec protocol multiplexer, so that vti
can register it's own receive path hooks. Further it makes the i_key
usable for vti and changes the vti code to do the following:

vti uses the IPsec protocol multiplexer to register it's
own receive side hooks for ESP, AH and IPCOMP.

Vti does the following on receive side:

1. Do an input policy check for the IPsec packet we received.
   This is required because this packet could be already
   processed by IPsec (tunnel in tunnel or a block policy
   is present), so an inbound policy check is needed.

2. Mark the packet with the i_key. The policy and the state
   must match this key now. Policy and state belong to the vti
   namespace and policy enforcement is done at the further layers.

3. Call the generic xfrm layer to do decryption and decapsulation.

4. Wait for a callback from the xfrm layer to properly clean the skb to
   not leak informations on namespace transitions and to update the device
   statistics.

On transmit side:

1. Mark the packet with the o_key. The policy and the state
   must match this key now.

2. Do a xfrm_lookup on the original packet with the mark applied.

3. Check if we got an IPsec route.

4. Clean the skb to not leak informations on namespace
   transitions.

5. Attach the dst_enty we got from the xfrm_lookup to the skb.

6. Call dst_output to do the IPsec processing.

7. Do the device statistics.


Changes from v1:

- Rebased to current net-next.
- Fix a rcu lockdep complaint in xfrm protocol registration/deregistration.
- Fix usage of a ipv4 specific callback handler in generic code.
- Use skb_scrub_packet() to clear the skb in vti_rcv(), suggested by
  Nicolas Dichtel.
- Add support for IPCOMP.
- Support inter address family tunneling.

Changes from v2:

- Rebased to current net-next.
- Check for matching tunnel endpoints of the xfrm state and
  the vti interface.
- Use a own error handler to not create dependencies to the
  generic IPsec protocol handlers.
- Change the receive path to do the namespace transition after
  decapsulation. With this the xfrm lookups are done in the outer
  namespace for xmit and receive, thanks to Christophe Gouault
  for pointing this out.
- Enable namespace changing of vti devices.

I'd take this into the ipsec-next tree after the merge window closes
if noone has further suggestions or objections.

^ permalink raw reply	[flat|nested] 18+ messages in thread

* [PATCH RFC v3 01/12] xfrm4: Add IPsec protocol multiplexer
  2014-01-27 10:29 [PATCH RFC v3 0/12] vti4: prepare namespace and interfamily support Steffen Klassert
@ 2014-01-27 10:29 ` Steffen Klassert
  2014-01-27 10:29 ` [PATCH RFC v3 02/12] esp4: Use the IPsec protocol multiplexer API Steffen Klassert
                   ` (12 subsequent siblings)
  13 siblings, 0 replies; 18+ messages in thread
From: Steffen Klassert @ 2014-01-27 10:29 UTC (permalink / raw)
  To: netdev; +Cc: Steffen Klassert, Christophe Gouault, Saurabh Mohan

This patch add an IPsec protocol multiplexer. With this
it is possible to add alternative protocol handlers as
needed for IPsec virtual tunnel interfaces.

Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>
---
 include/net/xfrm.h        |   24 +++++
 net/ipv4/Makefile         |    2 +-
 net/ipv4/xfrm4_protocol.c |  242 +++++++++++++++++++++++++++++++++++++++++++++
 net/xfrm/xfrm_input.c     |   18 ++--
 4 files changed, 279 insertions(+), 7 deletions(-)
 create mode 100644 net/ipv4/xfrm4_protocol.c

diff --git a/include/net/xfrm.h b/include/net/xfrm.h
index afa5730..34aef6f 100644
--- a/include/net/xfrm.h
+++ b/include/net/xfrm.h
@@ -1347,6 +1347,17 @@ struct xfrm_algo_desc {
 	struct sadb_alg desc;
 };
 
+
+/* XFRM protocol handlers.  */
+struct xfrm4_protocol {
+	int (*handler)(struct sk_buff *skb);
+	int (*cb_handler)(struct sk_buff *skb, int err);
+	int (*err_handler)(struct sk_buff *skb, u32 info);
+
+	struct xfrm4_protocol __rcu *next;
+	int priority;
+};
+
 /* XFRM tunnel handlers.  */
 struct xfrm_tunnel {
 	int (*handler)(struct sk_buff *skb);
@@ -1504,6 +1515,9 @@ int xfrm4_extract_output(struct xfrm_state *x, struct sk_buff *skb);
 int xfrm4_prepare_output(struct xfrm_state *x, struct sk_buff *skb);
 int xfrm4_output(struct sk_buff *skb);
 int xfrm4_output_finish(struct sk_buff *skb);
+void xfrm4_rcv_cb(struct sk_buff *skb, u8 protocol, int err);
+int xfrm4_protocol_register(struct xfrm4_protocol *handler, unsigned char protocol);
+int xfrm4_protocol_deregister(struct xfrm4_protocol *handler, unsigned char protocol);
 int xfrm4_tunnel_register(struct xfrm_tunnel *handler, unsigned short family);
 int xfrm4_tunnel_deregister(struct xfrm_tunnel *handler, unsigned short family);
 void xfrm4_local_error(struct sk_buff *skb, u32 mtu);
@@ -1737,4 +1751,14 @@ static inline int xfrm_mark_put(struct sk_buff *skb, const struct xfrm_mark *m)
 	return ret;
 }
 
+static inline void xfrm_rcv_cb(struct sk_buff *skb, unsigned int family,
+			       u8 protocol, int err)
+{
+	switch(family) {
+	case AF_INET:
+		xfrm4_rcv_cb(skb, protocol, err);
+		break;
+	}
+}
+
 #endif	/* _NET_XFRM_H */
diff --git a/net/ipv4/Makefile b/net/ipv4/Makefile
index f8c49ce..f032688 100644
--- a/net/ipv4/Makefile
+++ b/net/ipv4/Makefile
@@ -55,4 +55,4 @@ obj-$(CONFIG_MEMCG_KMEM) += tcp_memcontrol.o
 obj-$(CONFIG_NETLABEL) += cipso_ipv4.o
 
 obj-$(CONFIG_XFRM) += xfrm4_policy.o xfrm4_state.o xfrm4_input.o \
-		      xfrm4_output.o
+		      xfrm4_output.o xfrm4_protocol.o
diff --git a/net/ipv4/xfrm4_protocol.c b/net/ipv4/xfrm4_protocol.c
new file mode 100644
index 0000000..993ab39
--- /dev/null
+++ b/net/ipv4/xfrm4_protocol.c
@@ -0,0 +1,242 @@
+/* xfrm4_protocol.c - Generic xfrm protocol multiplexer.
+ *
+ * Copyright (C) 2013 secunet Security Networks AG
+ *
+ * Author:
+ * Steffen Klassert <steffen.klassert@secunet.com>
+ *
+ * Based on:
+ * net/ipv4/tunnel4.c
+ *
+ *	This program is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU General Public License
+ *	as published by the Free Software Foundation; either version
+ *	2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/init.h>
+#include <linux/mutex.h>
+#include <linux/skbuff.h>
+#include <net/icmp.h>
+#include <net/ip.h>
+#include <net/protocol.h>
+#include <net/xfrm.h>
+
+static struct xfrm4_protocol __rcu *esp4_handlers __read_mostly;
+static struct xfrm4_protocol __rcu *ah4_handlers __read_mostly;
+static struct xfrm4_protocol __rcu *ipcomp4_handlers __read_mostly;
+static DEFINE_MUTEX(xfrm4_protocol_mutex);
+
+static inline struct xfrm4_protocol __rcu **proto_handlers(u8 protocol)
+{
+	switch (protocol) {
+	case IPPROTO_ESP:
+		return &esp4_handlers;
+	case IPPROTO_AH:
+		return &ah4_handlers;
+	case IPPROTO_COMP:
+		return &ipcomp4_handlers;
+	}
+
+	return NULL;
+}
+
+#define for_each_protocol_rcu(head, handler)		\
+	for (handler = rcu_dereference(head);		\
+	     handler != NULL;				\
+	     handler = rcu_dereference(handler->next))	\
+
+void xfrm4_rcv_cb(struct sk_buff *skb, u8 protocol, int err)
+{
+	struct xfrm4_protocol *handler;
+
+	for_each_protocol_rcu(*proto_handlers(protocol), handler)
+		if (!handler->cb_handler(skb, err))
+			return;
+}
+EXPORT_SYMBOL(xfrm4_rcv_cb);
+
+static int xfrm4_esp_rcv(struct sk_buff *skb)
+{
+	struct xfrm4_protocol *handler;
+
+	for_each_protocol_rcu(esp4_handlers, handler)
+		if (!handler->handler(skb))
+			return 0;
+
+	icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0);
+
+	kfree_skb(skb);
+	return 0;
+}
+
+static void xfrm4_esp_err(struct sk_buff *skb, u32 info)
+{
+	struct xfrm4_protocol *handler;
+
+	for_each_protocol_rcu(esp4_handlers, handler)
+		if (!handler->err_handler(skb, info))
+			break;
+}
+
+static int xfrm4_ah_rcv(struct sk_buff *skb)
+{
+	struct xfrm4_protocol *handler;
+
+	for_each_protocol_rcu(ah4_handlers, handler)
+		if (!handler->handler(skb))
+			return 0;
+
+	icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0);
+
+	kfree_skb(skb);
+	return 0;
+}
+
+static void xfrm4_ah_err(struct sk_buff *skb, u32 info)
+{
+	struct xfrm4_protocol *handler;
+
+	for_each_protocol_rcu(ah4_handlers, handler)
+		if (!handler->err_handler(skb, info))
+			break;
+}
+
+static int xfrm4_ipcomp_rcv(struct sk_buff *skb)
+{
+	struct xfrm4_protocol *handler;
+
+	for_each_protocol_rcu(ipcomp4_handlers, handler)
+		if (!handler->handler(skb))
+			return 0;
+
+	icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0);
+
+	kfree_skb(skb);
+	return 0;
+}
+
+static void xfrm4_ipcomp_err(struct sk_buff *skb, u32 info)
+{
+	struct xfrm4_protocol *handler;
+
+	for_each_protocol_rcu(ipcomp4_handlers, handler)
+		if (!handler->err_handler(skb, info))
+			break;
+}
+
+static const struct net_protocol esp4_protocol = {
+	.handler	=	xfrm4_esp_rcv,
+	.err_handler	=	xfrm4_esp_err,
+	.no_policy	=	1,
+	.netns_ok	=	1,
+};
+
+static const struct net_protocol ah4_protocol = {
+	.handler	=	xfrm4_ah_rcv,
+	.err_handler	=	xfrm4_ah_err,
+	.no_policy	=	1,
+	.netns_ok	=	1,
+};
+
+static const struct net_protocol ipcomp4_protocol = {
+	.handler	=	xfrm4_ipcomp_rcv,
+	.err_handler	=	xfrm4_ipcomp_err,
+	.no_policy	=	1,
+	.netns_ok	=	1,
+};
+
+static inline const struct net_protocol *netproto(unsigned char protocol)
+{
+	switch (protocol) {
+	case IPPROTO_ESP:
+		return &esp4_protocol;
+	case IPPROTO_AH:
+		return &ah4_protocol;
+	case IPPROTO_COMP:
+		return &ipcomp4_protocol;
+	}
+
+	return NULL;
+}
+
+int xfrm4_protocol_register(struct xfrm4_protocol *handler,
+			    unsigned char protocol)
+{
+	struct xfrm4_protocol __rcu **pprev;
+	struct xfrm4_protocol *t;
+	bool add_netproto = false;
+
+	int ret = -EEXIST;
+	int priority = handler->priority;
+
+	mutex_lock(&xfrm4_protocol_mutex);
+
+	if (!rcu_dereference_protected(*proto_handlers(protocol),
+				       lockdep_is_held(&xfrm4_protocol_mutex)))
+		add_netproto = true;
+
+	for (pprev = proto_handlers(protocol);
+	     (t = rcu_dereference_protected(*pprev,
+			lockdep_is_held(&xfrm4_protocol_mutex))) != NULL;
+	     pprev = &t->next) {
+		if (t->priority < priority)
+			break;
+		if (t->priority == priority)
+			goto err;
+	}
+
+	handler->next = *pprev;
+	rcu_assign_pointer(*pprev, handler);
+
+	ret = 0;
+
+err:
+	mutex_unlock(&xfrm4_protocol_mutex);
+
+	if (add_netproto) {
+		if (inet_add_protocol(netproto(protocol), protocol)) {
+			pr_err("%s: can't add protocol\n", __func__);
+			ret = -EAGAIN;
+		}
+	}
+
+	return ret;
+}
+EXPORT_SYMBOL(xfrm4_protocol_register);
+
+int xfrm4_protocol_deregister(struct xfrm4_protocol *handler,
+			      unsigned char protocol)
+{
+	struct xfrm4_protocol __rcu **pprev;
+	struct xfrm4_protocol *t;
+	int ret = -ENOENT;
+
+	mutex_lock(&xfrm4_protocol_mutex);
+
+	for (pprev = proto_handlers(protocol);
+	     (t = rcu_dereference_protected(*pprev,
+			lockdep_is_held(&xfrm4_protocol_mutex))) != NULL;
+	     pprev = &t->next) {
+		if (t == handler) {
+			*pprev = handler->next;
+			ret = 0;
+			break;
+		}
+	}
+
+	if (!rcu_dereference_protected(*proto_handlers(protocol),
+				       lockdep_is_held(&xfrm4_protocol_mutex))) {
+		if (inet_del_protocol(netproto(protocol), protocol) < 0) {
+			pr_err("%s: can't remove protocol\n", __func__);
+			ret = -EAGAIN;
+		}
+	}
+
+	mutex_unlock(&xfrm4_protocol_mutex);
+
+	synchronize_net();
+
+	return ret;
+}
+EXPORT_SYMBOL(xfrm4_protocol_deregister);
diff --git a/net/xfrm/xfrm_input.c b/net/xfrm/xfrm_input.c
index 6c7ac01..9bf7559 100644
--- a/net/xfrm/xfrm_input.c
+++ b/net/xfrm/xfrm_input.c
@@ -108,7 +108,7 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type)
 	int err;
 	__be32 seq;
 	__be32 seq_hi;
-	struct xfrm_state *x;
+	struct xfrm_state *x = NULL;
 	xfrm_address_t *daddr;
 	struct xfrm_mode *inner_mode;
 	unsigned int family;
@@ -120,9 +120,14 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type)
 		async = 1;
 		x = xfrm_input_state(skb);
 		seq = XFRM_SKB_CB(skb)->seq.input.low;
+		family = x->outer_mode->afinfo->family;
 		goto resume;
 	}
 
+	daddr = (xfrm_address_t *)(skb_network_header(skb) +
+				   XFRM_SPI_SKB_CB(skb)->daddroff);
+	family = XFRM_SPI_SKB_CB(skb)->family;
+
 	/* Allocate new secpath or COW existing one. */
 	if (!skb->sp || atomic_read(&skb->sp->refcnt) != 1) {
 		struct sec_path *sp;
@@ -137,10 +142,6 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type)
 		skb->sp = sp;
 	}
 
-	daddr = (xfrm_address_t *)(skb_network_header(skb) +
-				   XFRM_SPI_SKB_CB(skb)->daddroff);
-	family = XFRM_SPI_SKB_CB(skb)->family;
-
 	seq = 0;
 	if (!spi && (err = xfrm_parse_spi(skb, nexthdr, &spi, &seq)) != 0) {
 		XFRM_INC_STATS(net, LINUX_MIB_XFRMINHDRERROR);
@@ -199,8 +200,10 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type)
 
 		nexthdr = x->type->input(x, skb);
 
-		if (nexthdr == -EINPROGRESS)
+		if (nexthdr == -EINPROGRESS) {
+			xfrm_rcv_cb(skb, family, x->type->proto, nexthdr);
 			return 0;
+		}
 
 resume:
 		spin_lock(&x->lock);
@@ -263,6 +266,8 @@ resume:
 		}
 	} while (!err);
 
+	xfrm_rcv_cb(skb, family, x->type->proto, 0);
+
 	nf_reset(skb);
 
 	if (decaps) {
@@ -276,6 +281,7 @@ resume:
 drop_unlock:
 	spin_unlock(&x->lock);
 drop:
+	xfrm_rcv_cb(skb, family, x ? x->type->proto : nexthdr, -1);
 	kfree_skb(skb);
 	return 0;
 }
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [PATCH RFC v3 02/12] esp4: Use the IPsec protocol multiplexer API
  2014-01-27 10:29 [PATCH RFC v3 0/12] vti4: prepare namespace and interfamily support Steffen Klassert
  2014-01-27 10:29 ` [PATCH RFC v3 01/12] xfrm4: Add IPsec protocol multiplexer Steffen Klassert
@ 2014-01-27 10:29 ` Steffen Klassert
  2014-01-27 10:29 ` [PATCH RFC v3 03/12] ah4: " Steffen Klassert
                   ` (11 subsequent siblings)
  13 siblings, 0 replies; 18+ messages in thread
From: Steffen Klassert @ 2014-01-27 10:29 UTC (permalink / raw)
  To: netdev; +Cc: Steffen Klassert, Christophe Gouault, Saurabh Mohan

Switch esp4 to use the new IPsec protocol multiplexer.

Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>
---
 net/ipv4/esp4.c |   25 ++++++++++++++++---------
 1 file changed, 16 insertions(+), 9 deletions(-)

diff --git a/net/ipv4/esp4.c b/net/ipv4/esp4.c
index 7785b28..d1a4ccd 100644
--- a/net/ipv4/esp4.c
+++ b/net/ipv4/esp4.c
@@ -473,7 +473,7 @@ static u32 esp4_get_mtu(struct xfrm_state *x, int mtu)
 		 net_adj) & ~(blksize - 1)) + net_adj - 2;
 }
 
-static void esp4_err(struct sk_buff *skb, u32 info)
+static int esp4_err(struct sk_buff *skb, u32 info)
 {
 	struct net *net = dev_net(skb->dev);
 	const struct iphdr *iph = (const struct iphdr *)skb->data;
@@ -483,23 +483,25 @@ static void esp4_err(struct sk_buff *skb, u32 info)
 	switch (icmp_hdr(skb)->type) {
 	case ICMP_DEST_UNREACH:
 		if (icmp_hdr(skb)->code != ICMP_FRAG_NEEDED)
-			return;
+			return 0;
 	case ICMP_REDIRECT:
 		break;
 	default:
-		return;
+		return 0;
 	}
 
 	x = xfrm_state_lookup(net, skb->mark, (const xfrm_address_t *)&iph->daddr,
 			      esph->spi, IPPROTO_ESP, AF_INET);
 	if (!x)
-		return;
+		return 0;
 
 	if (icmp_hdr(skb)->type == ICMP_DEST_UNREACH)
 		ipv4_update_pmtu(skb, net, info, 0, 0, IPPROTO_ESP, 0);
 	else
 		ipv4_redirect(skb, net, 0, 0, IPPROTO_ESP, 0);
 	xfrm_state_put(x);
+
+	return 0;
 }
 
 static void esp_destroy(struct xfrm_state *x)
@@ -672,6 +674,11 @@ error:
 	return err;
 }
 
+static int esp4_rcv_cb(struct sk_buff *skb, int err)
+{
+	return 0;
+}
+
 static const struct xfrm_type esp_type =
 {
 	.description	= "ESP4",
@@ -685,11 +692,11 @@ static const struct xfrm_type esp_type =
 	.output		= esp_output
 };
 
-static const struct net_protocol esp4_protocol = {
+static struct xfrm4_protocol esp4_protocol = {
 	.handler	=	xfrm4_rcv,
+	.cb_handler	=	esp4_rcv_cb,
 	.err_handler	=	esp4_err,
-	.no_policy	=	1,
-	.netns_ok	=	1,
+	.priority	=	0,
 };
 
 static int __init esp4_init(void)
@@ -698,7 +705,7 @@ static int __init esp4_init(void)
 		pr_info("%s: can't add xfrm type\n", __func__);
 		return -EAGAIN;
 	}
-	if (inet_add_protocol(&esp4_protocol, IPPROTO_ESP) < 0) {
+	if (xfrm4_protocol_register(&esp4_protocol, IPPROTO_ESP) < 0) {
 		pr_info("%s: can't add protocol\n", __func__);
 		xfrm_unregister_type(&esp_type, AF_INET);
 		return -EAGAIN;
@@ -708,7 +715,7 @@ static int __init esp4_init(void)
 
 static void __exit esp4_fini(void)
 {
-	if (inet_del_protocol(&esp4_protocol, IPPROTO_ESP) < 0)
+	if (xfrm4_protocol_deregister(&esp4_protocol, IPPROTO_ESP) < 0)
 		pr_info("%s: can't remove protocol\n", __func__);
 	if (xfrm_unregister_type(&esp_type, AF_INET) < 0)
 		pr_info("%s: can't remove xfrm type\n", __func__);
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [PATCH RFC v3 03/12] ah4: Use the IPsec protocol multiplexer API
  2014-01-27 10:29 [PATCH RFC v3 0/12] vti4: prepare namespace and interfamily support Steffen Klassert
  2014-01-27 10:29 ` [PATCH RFC v3 01/12] xfrm4: Add IPsec protocol multiplexer Steffen Klassert
  2014-01-27 10:29 ` [PATCH RFC v3 02/12] esp4: Use the IPsec protocol multiplexer API Steffen Klassert
@ 2014-01-27 10:29 ` Steffen Klassert
  2014-01-27 10:29 ` [PATCH RFC v3 04/12] ipcomp4: " Steffen Klassert
                   ` (10 subsequent siblings)
  13 siblings, 0 replies; 18+ messages in thread
From: Steffen Klassert @ 2014-01-27 10:29 UTC (permalink / raw)
  To: netdev; +Cc: Steffen Klassert, Christophe Gouault, Saurabh Mohan

Switch ah4 to use the new IPsec protocol multiplexer.

Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>
---
 net/ipv4/ah4.c |   24 +++++++++++++++---------
 1 file changed, 15 insertions(+), 9 deletions(-)

diff --git a/net/ipv4/ah4.c b/net/ipv4/ah4.c
index 7179026..ea30e4e 100644
--- a/net/ipv4/ah4.c
+++ b/net/ipv4/ah4.c
@@ -397,7 +397,7 @@ out:
 	return err;
 }
 
-static void ah4_err(struct sk_buff *skb, u32 info)
+static int ah4_err(struct sk_buff *skb, u32 info)
 {
 	struct net *net = dev_net(skb->dev);
 	const struct iphdr *iph = (const struct iphdr *)skb->data;
@@ -407,23 +407,25 @@ static void ah4_err(struct sk_buff *skb, u32 info)
 	switch (icmp_hdr(skb)->type) {
 	case ICMP_DEST_UNREACH:
 		if (icmp_hdr(skb)->code != ICMP_FRAG_NEEDED)
-			return;
+			return 0;
 	case ICMP_REDIRECT:
 		break;
 	default:
-		return;
+		return 0;
 	}
 
 	x = xfrm_state_lookup(net, skb->mark, (const xfrm_address_t *)&iph->daddr,
 			      ah->spi, IPPROTO_AH, AF_INET);
 	if (!x)
-		return;
+		return 0;
 
 	if (icmp_hdr(skb)->type == ICMP_DEST_UNREACH)
 		ipv4_update_pmtu(skb, net, info, 0, 0, IPPROTO_AH, 0);
 	else
 		ipv4_redirect(skb, net, 0, 0, IPPROTO_AH, 0);
 	xfrm_state_put(x);
+
+	return 0;
 }
 
 static int ah_init_state(struct xfrm_state *x)
@@ -505,6 +507,10 @@ static void ah_destroy(struct xfrm_state *x)
 	kfree(ahp);
 }
 
+static int ah4_rcv_cb(struct sk_buff *skb, int err)
+{
+	return 0;
+}
 
 static const struct xfrm_type ah_type =
 {
@@ -518,11 +524,11 @@ static const struct xfrm_type ah_type =
 	.output		= ah_output
 };
 
-static const struct net_protocol ah4_protocol = {
+static struct xfrm4_protocol ah4_protocol = {
 	.handler	=	xfrm4_rcv,
+	.cb_handler	=	ah4_rcv_cb,
 	.err_handler	=	ah4_err,
-	.no_policy	=	1,
-	.netns_ok	=	1,
+	.priority	=	0,
 };
 
 static int __init ah4_init(void)
@@ -531,7 +537,7 @@ static int __init ah4_init(void)
 		pr_info("%s: can't add xfrm type\n", __func__);
 		return -EAGAIN;
 	}
-	if (inet_add_protocol(&ah4_protocol, IPPROTO_AH) < 0) {
+	if (xfrm4_protocol_register(&ah4_protocol, IPPROTO_AH) < 0) {
 		pr_info("%s: can't add protocol\n", __func__);
 		xfrm_unregister_type(&ah_type, AF_INET);
 		return -EAGAIN;
@@ -541,7 +547,7 @@ static int __init ah4_init(void)
 
 static void __exit ah4_fini(void)
 {
-	if (inet_del_protocol(&ah4_protocol, IPPROTO_AH) < 0)
+	if (xfrm4_protocol_deregister(&ah4_protocol, IPPROTO_AH) < 0)
 		pr_info("%s: can't remove protocol\n", __func__);
 	if (xfrm_unregister_type(&ah_type, AF_INET) < 0)
 		pr_info("%s: can't remove xfrm type\n", __func__);
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [PATCH RFC v3 04/12] ipcomp4: Use the IPsec protocol multiplexer API
  2014-01-27 10:29 [PATCH RFC v3 0/12] vti4: prepare namespace and interfamily support Steffen Klassert
                   ` (2 preceding siblings ...)
  2014-01-27 10:29 ` [PATCH RFC v3 03/12] ah4: " Steffen Klassert
@ 2014-01-27 10:29 ` Steffen Klassert
  2014-01-27 10:29 ` [PATCH RFC v3 05/12] xfrm: Add xfrm_tunnel_skb_cb to the skb common buffer Steffen Klassert
                   ` (9 subsequent siblings)
  13 siblings, 0 replies; 18+ messages in thread
From: Steffen Klassert @ 2014-01-27 10:29 UTC (permalink / raw)
  To: netdev; +Cc: Steffen Klassert, Christophe Gouault, Saurabh Mohan

Switch ipcomp4 to use the new IPsec protocol multiplexer.

Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>
---
 net/ipv4/ipcomp.c |   25 ++++++++++++++++---------
 1 file changed, 16 insertions(+), 9 deletions(-)

diff --git a/net/ipv4/ipcomp.c b/net/ipv4/ipcomp.c
index 826be4c..6135ff8 100644
--- a/net/ipv4/ipcomp.c
+++ b/net/ipv4/ipcomp.c
@@ -23,7 +23,7 @@
 #include <net/protocol.h>
 #include <net/sock.h>
 
-static void ipcomp4_err(struct sk_buff *skb, u32 info)
+static int ipcomp4_err(struct sk_buff *skb, u32 info)
 {
 	struct net *net = dev_net(skb->dev);
 	__be32 spi;
@@ -34,24 +34,26 @@ static void ipcomp4_err(struct sk_buff *skb, u32 info)
 	switch (icmp_hdr(skb)->type) {
 	case ICMP_DEST_UNREACH:
 		if (icmp_hdr(skb)->code != ICMP_FRAG_NEEDED)
-			return;
+			return 0;
 	case ICMP_REDIRECT:
 		break;
 	default:
-		return;
+		return 0;
 	}
 
 	spi = htonl(ntohs(ipch->cpi));
 	x = xfrm_state_lookup(net, skb->mark, (const xfrm_address_t *)&iph->daddr,
 			      spi, IPPROTO_COMP, AF_INET);
 	if (!x)
-		return;
+		return 0;
 
 	if (icmp_hdr(skb)->type == ICMP_DEST_UNREACH)
 		ipv4_update_pmtu(skb, net, info, 0, 0, IPPROTO_COMP, 0);
 	else
 		ipv4_redirect(skb, net, 0, 0, IPPROTO_COMP, 0);
 	xfrm_state_put(x);
+
+	return 0;
 }
 
 /* We always hold one tunnel user reference to indicate a tunnel */
@@ -147,6 +149,11 @@ out:
 	return err;
 }
 
+static int ipcomp4_rcv_cb(struct sk_buff *skb, int err)
+{
+	return 0;
+}
+
 static const struct xfrm_type ipcomp_type = {
 	.description	= "IPCOMP4",
 	.owner		= THIS_MODULE,
@@ -157,11 +164,11 @@ static const struct xfrm_type ipcomp_type = {
 	.output		= ipcomp_output
 };
 
-static const struct net_protocol ipcomp4_protocol = {
+static struct xfrm4_protocol ipcomp4_protocol = {
 	.handler	=	xfrm4_rcv,
+	.cb_handler	=	ipcomp4_rcv_cb,
 	.err_handler	=	ipcomp4_err,
-	.no_policy	=	1,
-	.netns_ok	=	1,
+	.priority	=	0,
 };
 
 static int __init ipcomp4_init(void)
@@ -170,7 +177,7 @@ static int __init ipcomp4_init(void)
 		pr_info("%s: can't add xfrm type\n", __func__);
 		return -EAGAIN;
 	}
-	if (inet_add_protocol(&ipcomp4_protocol, IPPROTO_COMP) < 0) {
+	if (xfrm4_protocol_register(&ipcomp4_protocol, IPPROTO_COMP) < 0) {
 		pr_info("%s: can't add protocol\n", __func__);
 		xfrm_unregister_type(&ipcomp_type, AF_INET);
 		return -EAGAIN;
@@ -180,7 +187,7 @@ static int __init ipcomp4_init(void)
 
 static void __exit ipcomp4_fini(void)
 {
-	if (inet_del_protocol(&ipcomp4_protocol, IPPROTO_COMP) < 0)
+	if (xfrm4_protocol_deregister(&ipcomp4_protocol, IPPROTO_COMP) < 0)
 		pr_info("%s: can't remove protocol\n", __func__);
 	if (xfrm_unregister_type(&ipcomp_type, AF_INET) < 0)
 		pr_info("%s: can't remove xfrm type\n", __func__);
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [PATCH RFC v3 05/12] xfrm: Add xfrm_tunnel_skb_cb to the skb common buffer
  2014-01-27 10:29 [PATCH RFC v3 0/12] vti4: prepare namespace and interfamily support Steffen Klassert
                   ` (3 preceding siblings ...)
  2014-01-27 10:29 ` [PATCH RFC v3 04/12] ipcomp4: " Steffen Klassert
@ 2014-01-27 10:29 ` Steffen Klassert
  2014-01-27 10:29 ` [PATCH RFC v3 06/12] ip_tunnel: Make vti work with i_key set Steffen Klassert
                   ` (8 subsequent siblings)
  13 siblings, 0 replies; 18+ messages in thread
From: Steffen Klassert @ 2014-01-27 10:29 UTC (permalink / raw)
  To: netdev; +Cc: Steffen Klassert, Christophe Gouault, Saurabh Mohan

IPsec vti_rcv needs to remind the tunnel pointer to
check it later at the vti_rcv_cb callback. So add
this pointer to the IPsec common buffer.

Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>
---
 include/net/xfrm.h    |   29 +++++++++++++++++------------
 net/xfrm/xfrm_input.c |    6 ++----
 2 files changed, 19 insertions(+), 16 deletions(-)

diff --git a/include/net/xfrm.h b/include/net/xfrm.h
index 34aef6f..c8f84171 100644
--- a/include/net/xfrm.h
+++ b/include/net/xfrm.h
@@ -599,16 +599,27 @@ struct xfrm_mgr {
 int xfrm_register_km(struct xfrm_mgr *km);
 int xfrm_unregister_km(struct xfrm_mgr *km);
 
+struct xfrm_tunnel_skb_cb {
+	union {
+		struct inet_skb_parm h4;
+		struct inet6_skb_parm h6;
+	} header;
+
+	union {
+		struct ip_tunnel *ip4;
+		struct ip6_tnl *ip6;
+	} tunnel;
+};
+
+#define XFRM_TUNNEL_SKB_CB(__skb) ((struct xfrm_tunnel_skb_cb *)&((__skb)->cb[0]))
+
 /*
  * This structure is used for the duration where packets are being
  * transformed by IPsec.  As soon as the packet leaves IPsec the
  * area beyond the generic IP part may be overwritten.
  */
 struct xfrm_skb_cb {
-	union {
-		struct inet_skb_parm h4;
-		struct inet6_skb_parm h6;
-        } header;
+	struct xfrm_tunnel_skb_cb header;
 
         /* Sequence number for replay protection. */
 	union {
@@ -630,10 +641,7 @@ struct xfrm_skb_cb {
  * to transmit header information to the mode input/output functions.
  */
 struct xfrm_mode_skb_cb {
-	union {
-		struct inet_skb_parm h4;
-		struct inet6_skb_parm h6;
-	} header;
+	struct xfrm_tunnel_skb_cb header;
 
 	/* Copied from header for IPv4, always set to zero and DF for IPv6. */
 	__be16 id;
@@ -665,10 +673,7 @@ struct xfrm_mode_skb_cb {
  * related information.
  */
 struct xfrm_spi_skb_cb {
-	union {
-		struct inet_skb_parm h4;
-		struct inet6_skb_parm h6;
-	} header;
+	struct xfrm_tunnel_skb_cb header;
 
 	unsigned int daddroff;
 	unsigned int family;
diff --git a/net/xfrm/xfrm_input.c b/net/xfrm/xfrm_input.c
index 9bf7559..aea3a90 100644
--- a/net/xfrm/xfrm_input.c
+++ b/net/xfrm/xfrm_input.c
@@ -200,10 +200,8 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type)
 
 		nexthdr = x->type->input(x, skb);
 
-		if (nexthdr == -EINPROGRESS) {
-			xfrm_rcv_cb(skb, family, x->type->proto, nexthdr);
+		if (nexthdr == -EINPROGRESS) 
 			return 0;
-		}
 
 resume:
 		spin_lock(&x->lock);
@@ -281,7 +279,7 @@ resume:
 drop_unlock:
 	spin_unlock(&x->lock);
 drop:
-	xfrm_rcv_cb(skb, family, x ? x->type->proto : nexthdr, -1);
+	xfrm_rcv_cb(skb, family, x && x->type ? x->type->proto : nexthdr, -1);
 	kfree_skb(skb);
 	return 0;
 }
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [PATCH RFC v3 06/12] ip_tunnel: Make vti work with i_key set
  2014-01-27 10:29 [PATCH RFC v3 0/12] vti4: prepare namespace and interfamily support Steffen Klassert
                   ` (4 preceding siblings ...)
  2014-01-27 10:29 ` [PATCH RFC v3 05/12] xfrm: Add xfrm_tunnel_skb_cb to the skb common buffer Steffen Klassert
@ 2014-01-27 10:29 ` Steffen Klassert
  2014-01-27 10:29 ` [PATCH RFC v3 07/12] vti: Update the ipv4 side to use it's own receive hook Steffen Klassert
                   ` (7 subsequent siblings)
  13 siblings, 0 replies; 18+ messages in thread
From: Steffen Klassert @ 2014-01-27 10:29 UTC (permalink / raw)
  To: netdev; +Cc: Steffen Klassert, Christophe Gouault, Saurabh Mohan

Vti uses the o_key to mark packets that were transmitted or received
by a vti interface. Unfortunately we can't apply different marks
to in and outbound packets with only one key availabe. Vti interfaces
typically use wildcard selectors for vti IPsec policies. On forwarding,
the same output policy will match for both directions. This generates
a loop between the IPsec gateways until the ttl of the packet is
exceeded.

The gre i_key/o_key are usually there to find the right gre tunnel
during a lookup. When vti uses the i_key to mark packets, the tunnel
lookup does not work any more because vti does not use the gre keys
as a hash key for the lookup.

This patch workarounds this my not including the i_key when comupting
the hash for the tunnel lookup in case of vti tunnels.

With this we have separate keys available for the transmitting and
receiving side of the vti interface.

Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>
---
 net/ipv4/ip_tunnel.c |    6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/net/ipv4/ip_tunnel.c b/net/ipv4/ip_tunnel.c
index c0e3cb7..239c10c 100644
--- a/net/ipv4/ip_tunnel.c
+++ b/net/ipv4/ip_tunnel.c
@@ -285,13 +285,17 @@ static struct hlist_head *ip_bucket(struct ip_tunnel_net *itn,
 {
 	unsigned int h;
 	__be32 remote;
+	__be32 i_key = parms->i_key;
 
 	if (parms->iph.daddr && !ipv4_is_multicast(parms->iph.daddr))
 		remote = parms->iph.daddr;
 	else
 		remote = 0;
 
-	h = ip_tunnel_hash(parms->i_key, remote);
+	if (!(parms->i_flags & TUNNEL_KEY) && (parms->i_flags & VTI_ISVTI))
+		i_key = 0;
+
+	h = ip_tunnel_hash(i_key, remote);
 	return &itn->tunnels[h];
 }
 
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [PATCH RFC v3 07/12] vti: Update the ipv4 side to use it's own receive hook.
  2014-01-27 10:29 [PATCH RFC v3 0/12] vti4: prepare namespace and interfamily support Steffen Klassert
                   ` (5 preceding siblings ...)
  2014-01-27 10:29 ` [PATCH RFC v3 06/12] ip_tunnel: Make vti work with i_key set Steffen Klassert
@ 2014-01-27 10:29 ` Steffen Klassert
  2014-01-27 10:29 ` [PATCH RFC v3 08/12] xfrm4: Remove xfrm_tunnel_notifier Steffen Klassert
                   ` (6 subsequent siblings)
  13 siblings, 0 replies; 18+ messages in thread
From: Steffen Klassert @ 2014-01-27 10:29 UTC (permalink / raw)
  To: netdev; +Cc: Steffen Klassert, Christophe Gouault, Saurabh Mohan

With this patch, vti uses the IPsec protocol multiplexer to
register it's own receive side hooks for ESP, AH and IPCOMP.

Vti now does the following on receive side:

1. Do an input policy check for the IPsec packet we received.
   This is required because this packet could be already
   prosecces by IPsec, so an inbuond policy check is needed.

2. Mark the packet with the i_key. The policy and the state
   must match this key now. Policy and state belong to the outer
   namespace and policy enforcement is done at the further layers.

3. Call the generic xfrm layer to do decryption and decapsulation.

4. Wait for a callback from the xfrm layer to properly clean the
   skb to not leak informations on namespace and to update the
   device statistics.

On transmit side:

1. Mark the packet with the o_key. The policy and the state
   must match this key now.

2. Do a xfrm_lookup on the original packet with the mark applied.

3. Check if we got an IPsec route.

4. Clean the skb to not leak informations on namespace
   transitions.

5. Attach the dst_enty we got from the xfrm_lookup to the skb.

6. Call dst_output to do the IPsec processing.

7. Do the device statistics.

Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>
---
 net/ipv4/ip_vti.c |  212 +++++++++++++++++++++++++++++++++++++++++------------
 1 file changed, 166 insertions(+), 46 deletions(-)

diff --git a/net/ipv4/ip_vti.c b/net/ipv4/ip_vti.c
index 48eafae..1432bec 100644
--- a/net/ipv4/ip_vti.c
+++ b/net/ipv4/ip_vti.c
@@ -49,7 +49,6 @@ static struct rtnl_link_ops vti_link_ops __read_mostly;
 static int vti_net_id __read_mostly;
 static int vti_tunnel_init(struct net_device *dev);
 
-/* We dont digest the packet therefore let the packet pass */
 static int vti_rcv(struct sk_buff *skb)
 {
 	struct ip_tunnel *tunnel;
@@ -60,66 +59,82 @@ static int vti_rcv(struct sk_buff *skb)
 	tunnel = ip_tunnel_lookup(itn, skb->dev->ifindex, TUNNEL_NO_KEY,
 				  iph->saddr, iph->daddr, 0);
 	if (tunnel != NULL) {
-		struct pcpu_sw_netstats *tstats;
-		u32 oldmark = skb->mark;
-		int ret;
-
-
-		/* temporarily mark the skb with the tunnel o_key, to
-		 * only match policies with this mark.
-		 */
-		skb->mark = be32_to_cpu(tunnel->parms.o_key);
-		ret = xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb);
-		skb->mark = oldmark;
-		if (!ret)
-			return -1;
-
-		tstats = this_cpu_ptr(tunnel->dev->tstats);
-		u64_stats_update_begin(&tstats->syncp);
-		tstats->rx_packets++;
-		tstats->rx_bytes += skb->len;
-		u64_stats_update_end(&tstats->syncp);
-
-		secpath_reset(skb);
-		skb->dev = tunnel->dev;
-		return 1;
+		if (!xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb))
+			goto drop;
+
+		XFRM_TUNNEL_SKB_CB(skb)->tunnel.ip4 = tunnel;
+		skb->mark = be32_to_cpu(tunnel->parms.i_key);
+
+		return xfrm4_rcv(skb);
 	}
 
 	return -1;
+drop:
+	kfree_skb(skb);
+	return 0;
+}
+
+static int vti_rcv_cb(struct sk_buff *skb, int err)
+{
+	struct net_device *dev;
+	struct pcpu_sw_netstats *tstats;
+	struct ip_tunnel *tunnel = XFRM_TUNNEL_SKB_CB(skb)->tunnel.ip4;
+
+	if (!tunnel)
+		return -1;
+
+	dev = tunnel->dev;
+
+	if (err) {
+		dev->stats.rx_errors++;
+		dev->stats.rx_dropped++;
+
+		return 0;
+	}
+
+	skb_scrub_packet(skb, !net_eq(tunnel->net, dev_net(skb->dev)));
+	skb->dev = dev;
+
+	tstats = this_cpu_ptr(dev->tstats);
+
+	u64_stats_update_begin(&tstats->syncp);
+	tstats->rx_packets++;
+	tstats->rx_bytes += skb->len;
+	u64_stats_update_end(&tstats->syncp);
+
+	return 0;
 }
 
 /* This function assumes it is being called from dev_queue_xmit()
  * and that skb is filled properly by that function.
  */
-
 static netdev_tx_t vti_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
 {
 	struct ip_tunnel *tunnel = netdev_priv(dev);
-	struct iphdr  *tiph = &tunnel->parms.iph;
-	u8     tos;
 	struct rtable *rt;		/* Route to the other host */
 	struct net_device *tdev;	/* Device to other host */
-	struct iphdr  *old_iph = ip_hdr(skb);
-	__be32 dst = tiph->daddr;
-	struct flowi4 fl4;
+	struct flowi fl;
 	int err;
 
 	if (skb->protocol != htons(ETH_P_IP))
 		goto tx_error;
 
-	tos = old_iph->tos;
+	memset(&fl, 0, sizeof(fl));
+	skb->mark = be32_to_cpu(tunnel->parms.o_key);
+	xfrm_decode_session(skb, &fl, AF_INET);
+
+	if (!skb_dst(skb)) {
+		dev->stats.tx_carrier_errors++;
+		goto tx_error_icmp;
+	}
 
-	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);
+	dst_hold(skb_dst(skb));
+	rt = (struct rtable *)xfrm_lookup(tunnel->net, skb_dst(skb), &fl, NULL, 0);
 	if (IS_ERR(rt)) {
 		dev->stats.tx_carrier_errors++;
 		goto tx_error_icmp;
 	}
+
 	/* if there is no transform then this tunnel is not functional.
 	 * Or if the xfrm is not mode tunnel.
 	 */
@@ -147,9 +162,8 @@ static netdev_tx_t vti_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
 	}
 
 	memset(IPCB(skb), 0, sizeof(*IPCB(skb)));
-	skb_dst_drop(skb);
+	skb_scrub_packet(skb, !net_eq(tunnel->net, dev_net(dev)));
 	skb_dst_set(skb, &rt->dst);
-	nf_reset(skb);
 	skb->dev = skb_dst(skb)->dev;
 
 	err = dst_output(skb);
@@ -166,6 +180,65 @@ tx_error:
 	return NETDEV_TX_OK;
 }
 
+static int vti4_err(struct sk_buff *skb, u32 info)
+{
+	__be32 spi;
+	struct xfrm_state *x;
+	struct ip_tunnel *tunnel;
+	struct ip_esp_hdr *esph;
+	struct ip_auth_hdr *ah ;
+	struct ip_comp_hdr *ipch;
+	struct net *net = dev_net(skb->dev);
+	const struct iphdr *iph = (const struct iphdr *)skb->data;
+	int protocol = iph->protocol;
+	struct ip_tunnel_net *itn = net_generic(net, vti_net_id);
+
+	tunnel = ip_tunnel_lookup(itn, skb->dev->ifindex, TUNNEL_NO_KEY,
+				  iph->daddr, iph->saddr, 0);
+	if (!tunnel)
+		return -1;
+
+	switch (protocol) {
+	case IPPROTO_ESP:
+		esph = (struct ip_esp_hdr *)(skb->data+(iph->ihl<<2));
+		spi = esph->spi;
+		break;
+	case IPPROTO_AH:
+		ah = (struct ip_auth_hdr *)(skb->data+(iph->ihl<<2));
+		spi = ah->spi;
+		break;
+	case IPPROTO_COMP:
+		ipch = (struct ip_comp_hdr *)(skb->data+(iph->ihl<<2));
+		spi = htonl(ntohs(ipch->cpi));
+		break;
+	default:
+		return 0;
+	}
+
+	switch (icmp_hdr(skb)->type) {
+	case ICMP_DEST_UNREACH:
+		if (icmp_hdr(skb)->code != ICMP_FRAG_NEEDED)
+			return 0;
+	case ICMP_REDIRECT:
+		break;
+	default:
+		return 0;
+	}
+
+	x = xfrm_state_lookup(net, skb->mark, (const xfrm_address_t *)&iph->daddr,
+			      spi, protocol, AF_INET);
+	if (!x)
+		return 0;
+
+	if (icmp_hdr(skb)->type == ICMP_DEST_UNREACH)
+		ipv4_update_pmtu(skb, net, info, 0, 0, protocol, 0);
+	else
+		ipv4_redirect(skb, net, 0, 0, protocol, 0);
+	xfrm_state_put(x);
+
+	return 0;
+}
+
 static int
 vti_tunnel_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
 {
@@ -181,12 +254,13 @@ vti_tunnel_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
 			return -EINVAL;
 	}
 
+	p.i_flags |= VTI_ISVTI;
 	err = ip_tunnel_ioctl(dev, &p, cmd);
 	if (err)
 		return err;
 
 	if (cmd != SIOCDELTUNNEL) {
-		p.i_flags |= GRE_KEY | VTI_ISVTI;
+		p.i_flags |= GRE_KEY;
 		p.o_flags |= GRE_KEY;
 	}
 
@@ -241,9 +315,25 @@ static void __net_init vti_fb_tunnel_init(struct net_device *dev)
 	iph->ihl		= 5;
 }
 
-static struct xfrm_tunnel_notifier vti_handler __read_mostly = {
+static struct xfrm4_protocol vti_esp4_protocol __read_mostly = {
+	.handler	=	vti_rcv,
+	.cb_handler	=	vti_rcv_cb,
+	.err_handler	=	vti4_err,
+	.priority	=	100,
+};
+
+static struct xfrm4_protocol vti_ah4_protocol __read_mostly = {
+	.handler	=	vti_rcv,
+	.cb_handler	=	vti_rcv_cb,
+	.err_handler	=	vti4_err,
+	.priority	=	100,
+};
+
+static struct xfrm4_protocol vti_ipcomp4_protocol __read_mostly = {
 	.handler	=	vti_rcv,
-	.priority	=	1,
+	.cb_handler	=	vti_rcv_cb,
+	.err_handler	=	vti4_err,
+	.priority	=	100,
 };
 
 static int __net_init vti_init_net(struct net *net)
@@ -287,6 +377,8 @@ static void vti_netlink_parms(struct nlattr *data[],
 	if (!data)
 		return;
 
+	parms->i_flags = VTI_ISVTI;
+
 	if (data[IFLA_VTI_LINK])
 		parms->link = nla_get_u32(data[IFLA_VTI_LINK]);
 
@@ -382,10 +474,31 @@ static int __init vti_init(void)
 	err = register_pernet_device(&vti_net_ops);
 	if (err < 0)
 		return err;
-	err = xfrm4_mode_tunnel_input_register(&vti_handler);
+	err = xfrm4_protocol_register(&vti_esp4_protocol, IPPROTO_ESP);
+	if (err < 0) {
+		unregister_pernet_device(&vti_net_ops);
+		pr_info("vti init: can't register tunnel\n");
+
+		return err;
+	}
+
+	err = xfrm4_protocol_register(&vti_ah4_protocol, IPPROTO_AH);
+	if (err < 0) {
+		xfrm4_protocol_deregister(&vti_esp4_protocol, IPPROTO_ESP);
+		unregister_pernet_device(&vti_net_ops);
+		pr_info("vti init: can't register tunnel\n");
+
+		return err;
+	}
+
+	err = xfrm4_protocol_register(&vti_ipcomp4_protocol, IPPROTO_COMP);
 	if (err < 0) {
+		xfrm4_protocol_deregister(&vti_ah4_protocol, IPPROTO_AH);
+		xfrm4_protocol_deregister(&vti_esp4_protocol, IPPROTO_ESP);
 		unregister_pernet_device(&vti_net_ops);
 		pr_info("vti init: can't register tunnel\n");
+
+		return err;
 	}
 
 	err = rtnl_link_register(&vti_link_ops);
@@ -395,7 +508,9 @@ static int __init vti_init(void)
 	return err;
 
 rtnl_link_failed:
-	xfrm4_mode_tunnel_input_deregister(&vti_handler);
+	xfrm4_protocol_deregister(&vti_ipcomp4_protocol, IPPROTO_COMP);
+	xfrm4_protocol_deregister(&vti_ah4_protocol, IPPROTO_AH);
+	xfrm4_protocol_deregister(&vti_esp4_protocol, IPPROTO_ESP);
 	unregister_pernet_device(&vti_net_ops);
 	return err;
 }
@@ -403,8 +518,13 @@ rtnl_link_failed:
 static void __exit vti_fini(void)
 {
 	rtnl_link_unregister(&vti_link_ops);
-	if (xfrm4_mode_tunnel_input_deregister(&vti_handler))
+	if (xfrm4_protocol_deregister(&vti_ipcomp4_protocol, IPPROTO_COMP))
+		pr_info("vti close: can't deregister tunnel\n");
+	if (xfrm4_protocol_deregister(&vti_ah4_protocol, IPPROTO_AH))
 		pr_info("vti close: can't deregister tunnel\n");
+	if (xfrm4_protocol_deregister(&vti_esp4_protocol, IPPROTO_ESP))
+		pr_info("vti close: can't deregister tunnel\n");
+
 
 	unregister_pernet_device(&vti_net_ops);
 }
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [PATCH RFC v3 08/12] xfrm4: Remove xfrm_tunnel_notifier
  2014-01-27 10:29 [PATCH RFC v3 0/12] vti4: prepare namespace and interfamily support Steffen Klassert
                   ` (6 preceding siblings ...)
  2014-01-27 10:29 ` [PATCH RFC v3 07/12] vti: Update the ipv4 side to use it's own receive hook Steffen Klassert
@ 2014-01-27 10:29 ` Steffen Klassert
  2014-01-27 10:29 ` [PATCH RFC v3 09/12] vti4: Use the on xfrm_lookup returned dst_entry directly Steffen Klassert
                   ` (5 subsequent siblings)
  13 siblings, 0 replies; 18+ messages in thread
From: Steffen Klassert @ 2014-01-27 10:29 UTC (permalink / raw)
  To: netdev; +Cc: Steffen Klassert, Christophe Gouault, Saurabh Mohan

This was used from vti and is replaced by the IPsec protocol
multiplexer hooks. It is now unused, so remove it.

Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>
---
 include/net/xfrm.h           |    2 --
 net/ipv4/xfrm4_mode_tunnel.c |   68 ------------------------------------------
 2 files changed, 70 deletions(-)

diff --git a/include/net/xfrm.h b/include/net/xfrm.h
index c8f84171..8f28b9e 100644
--- a/include/net/xfrm.h
+++ b/include/net/xfrm.h
@@ -1526,8 +1526,6 @@ int xfrm4_protocol_deregister(struct xfrm4_protocol *handler, unsigned char prot
 int xfrm4_tunnel_register(struct xfrm_tunnel *handler, unsigned short family);
 int xfrm4_tunnel_deregister(struct xfrm_tunnel *handler, unsigned short family);
 void xfrm4_local_error(struct sk_buff *skb, u32 mtu);
-int xfrm4_mode_tunnel_input_register(struct xfrm_tunnel_notifier *handler);
-int xfrm4_mode_tunnel_input_deregister(struct xfrm_tunnel_notifier *handler);
 int xfrm6_mode_tunnel_input_register(struct xfrm_tunnel_notifier *handler);
 int xfrm6_mode_tunnel_input_deregister(struct xfrm_tunnel_notifier *handler);
 int xfrm6_extract_header(struct sk_buff *skb);
diff --git a/net/ipv4/xfrm4_mode_tunnel.c b/net/ipv4/xfrm4_mode_tunnel.c
index 31b1815..05f2b48 100644
--- a/net/ipv4/xfrm4_mode_tunnel.c
+++ b/net/ipv4/xfrm4_mode_tunnel.c
@@ -15,65 +15,6 @@
 #include <net/ip.h>
 #include <net/xfrm.h>
 
-/* Informational hook. The decap is still done here. */
-static struct xfrm_tunnel_notifier __rcu *rcv_notify_handlers __read_mostly;
-static DEFINE_MUTEX(xfrm4_mode_tunnel_input_mutex);
-
-int xfrm4_mode_tunnel_input_register(struct xfrm_tunnel_notifier *handler)
-{
-	struct xfrm_tunnel_notifier __rcu **pprev;
-	struct xfrm_tunnel_notifier *t;
-	int ret = -EEXIST;
-	int priority = handler->priority;
-
-	mutex_lock(&xfrm4_mode_tunnel_input_mutex);
-
-	for (pprev = &rcv_notify_handlers;
-	     (t = rcu_dereference_protected(*pprev,
-	     lockdep_is_held(&xfrm4_mode_tunnel_input_mutex))) != NULL;
-	     pprev = &t->next) {
-		if (t->priority > priority)
-			break;
-		if (t->priority == priority)
-			goto err;
-
-	}
-
-	handler->next = *pprev;
-	rcu_assign_pointer(*pprev, handler);
-
-	ret = 0;
-
-err:
-	mutex_unlock(&xfrm4_mode_tunnel_input_mutex);
-	return ret;
-}
-EXPORT_SYMBOL_GPL(xfrm4_mode_tunnel_input_register);
-
-int xfrm4_mode_tunnel_input_deregister(struct xfrm_tunnel_notifier *handler)
-{
-	struct xfrm_tunnel_notifier __rcu **pprev;
-	struct xfrm_tunnel_notifier *t;
-	int ret = -ENOENT;
-
-	mutex_lock(&xfrm4_mode_tunnel_input_mutex);
-	for (pprev = &rcv_notify_handlers;
-	     (t = rcu_dereference_protected(*pprev,
-	     lockdep_is_held(&xfrm4_mode_tunnel_input_mutex))) != NULL;
-	     pprev = &t->next) {
-		if (t == handler) {
-			*pprev = handler->next;
-			ret = 0;
-			break;
-		}
-	}
-	mutex_unlock(&xfrm4_mode_tunnel_input_mutex);
-	synchronize_net();
-
-	return ret;
-}
-EXPORT_SYMBOL_GPL(xfrm4_mode_tunnel_input_deregister);
-
 static inline void ipip_ecn_decapsulate(struct sk_buff *skb)
 {
 	struct iphdr *inner_iph = ipip_hdr(skb);
@@ -127,14 +68,8 @@ static int xfrm4_mode_tunnel_output(struct xfrm_state *x, struct sk_buff *skb)
 	return 0;
 }
 
-#define for_each_input_rcu(head, handler)	\
-	for (handler = rcu_dereference(head);	\
-	     handler != NULL;			\
-	     handler = rcu_dereference(handler->next))
-
 static int xfrm4_mode_tunnel_input(struct xfrm_state *x, struct sk_buff *skb)
 {
-	struct xfrm_tunnel_notifier *handler;
 	int err = -EINVAL;
 
 	if (XFRM_MODE_SKB_CB(skb)->protocol != IPPROTO_IPIP)
@@ -143,9 +78,6 @@ static int xfrm4_mode_tunnel_input(struct xfrm_state *x, struct sk_buff *skb)
 	if (!pskb_may_pull(skb, sizeof(struct iphdr)))
 		goto out;
 
-	for_each_input_rcu(rcv_notify_handlers, handler)
-		handler->handler(skb);
-
 	err = skb_unclone(skb, GFP_ATOMIC);
 	if (err)
 		goto out;
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [PATCH RFC v3 09/12] vti4: Use the on xfrm_lookup returned dst_entry directly
  2014-01-27 10:29 [PATCH RFC v3 0/12] vti4: prepare namespace and interfamily support Steffen Klassert
                   ` (7 preceding siblings ...)
  2014-01-27 10:29 ` [PATCH RFC v3 08/12] xfrm4: Remove xfrm_tunnel_notifier Steffen Klassert
@ 2014-01-27 10:29 ` Steffen Klassert
  2014-01-27 10:29 ` [PATCH RFC v3 10/12] vti4: Support inter address family tunneling Steffen Klassert
                   ` (4 subsequent siblings)
  13 siblings, 0 replies; 18+ messages in thread
From: Steffen Klassert @ 2014-01-27 10:29 UTC (permalink / raw)
  To: netdev; +Cc: Steffen Klassert, Christophe Gouault, Saurabh Mohan

We need to be protocol family indepenent to support
inter addresss family tunneling with vti. So use a
dst_entry instead of the ipv4 rtable in vti_tunnel_xmit.

Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>
---
 net/ipv4/ip_vti.c |   22 +++++++++++-----------
 1 file changed, 11 insertions(+), 11 deletions(-)

diff --git a/net/ipv4/ip_vti.c b/net/ipv4/ip_vti.c
index 1432bec..b8d6184 100644
--- a/net/ipv4/ip_vti.c
+++ b/net/ipv4/ip_vti.c
@@ -111,7 +111,7 @@ static int vti_rcv_cb(struct sk_buff *skb, int err)
 static netdev_tx_t vti_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
 {
 	struct ip_tunnel *tunnel = netdev_priv(dev);
-	struct rtable *rt;		/* Route to the other host */
+	struct dst_entry *dst = skb_dst(skb);
 	struct net_device *tdev;	/* Device to other host */
 	struct flowi fl;
 	int err;
@@ -123,14 +123,14 @@ static netdev_tx_t vti_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
 	skb->mark = be32_to_cpu(tunnel->parms.o_key);
 	xfrm_decode_session(skb, &fl, AF_INET);
 
-	if (!skb_dst(skb)) {
+	if (!dst) {
 		dev->stats.tx_carrier_errors++;
 		goto tx_error_icmp;
 	}
 
-	dst_hold(skb_dst(skb));
-	rt = (struct rtable *)xfrm_lookup(tunnel->net, skb_dst(skb), &fl, NULL, 0);
-	if (IS_ERR(rt)) {
+	dst_hold(dst);
+	dst = xfrm_lookup(tunnel->net, dst, &fl, NULL, 0);
+	if (IS_ERR(dst)) {
 		dev->stats.tx_carrier_errors++;
 		goto tx_error_icmp;
 	}
@@ -138,16 +138,16 @@ static netdev_tx_t vti_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
 	/* if there is no transform then this tunnel is not functional.
 	 * Or if the xfrm is not mode tunnel.
 	 */
-	if (!rt->dst.xfrm ||
-	    rt->dst.xfrm->props.mode != XFRM_MODE_TUNNEL) {
+	if (!dst->xfrm ||
+	    dst->xfrm->props.mode != XFRM_MODE_TUNNEL) {
 		dev->stats.tx_carrier_errors++;
-		ip_rt_put(rt);
+		dst_release(dst);
 		goto tx_error_icmp;
 	}
-	tdev = rt->dst.dev;
+	tdev = dst->dev;
 
 	if (tdev == dev) {
-		ip_rt_put(rt);
+		dst_release(dst);
 		dev->stats.collisions++;
 		goto tx_error;
 	}
@@ -163,7 +163,7 @@ static netdev_tx_t vti_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
 
 	memset(IPCB(skb), 0, sizeof(*IPCB(skb)));
 	skb_scrub_packet(skb, !net_eq(tunnel->net, dev_net(dev)));
-	skb_dst_set(skb, &rt->dst);
+	skb_dst_set(skb, dst);
 	skb->dev = skb_dst(skb)->dev;
 
 	err = dst_output(skb);
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [PATCH RFC v3 10/12] vti4: Support inter address family tunneling.
  2014-01-27 10:29 [PATCH RFC v3 0/12] vti4: prepare namespace and interfamily support Steffen Klassert
                   ` (8 preceding siblings ...)
  2014-01-27 10:29 ` [PATCH RFC v3 09/12] vti4: Use the on xfrm_lookup returned dst_entry directly Steffen Klassert
@ 2014-01-27 10:29 ` Steffen Klassert
  2014-01-27 10:29 ` [PATCH RFC v3 11/12] vti4: Check the tunnel endpoints of the xfrm state and the vti interface Steffen Klassert
                   ` (3 subsequent siblings)
  13 siblings, 0 replies; 18+ messages in thread
From: Steffen Klassert @ 2014-01-27 10:29 UTC (permalink / raw)
  To: netdev; +Cc: Steffen Klassert, Christophe Gouault, Saurabh Mohan

With this patch we can tunnel ipv6 traffic via a vti4
interface. A vti4 interface can now have an ipv6 address
and ipv6 traffic can be routed via a vti4 interface.
The resulting traffic is xfrm transformed and tunneled
throuhg ipv4 if matching IPsec policies and states are
present.

Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>
---
 net/ipv4/ip_vti.c |   48 ++++++++++++++++++++++++++++++++++--------------
 1 file changed, 34 insertions(+), 14 deletions(-)

diff --git a/net/ipv4/ip_vti.c b/net/ipv4/ip_vti.c
index b8d6184..1708fc1 100644
--- a/net/ipv4/ip_vti.c
+++ b/net/ipv4/ip_vti.c
@@ -34,6 +34,7 @@
 #include <linux/init.h>
 #include <linux/netfilter_ipv4.h>
 #include <linux/if_ether.h>
+#include <linux/icmpv6.h>
 
 #include <net/sock.h>
 #include <net/ip.h>
@@ -105,31 +106,21 @@ static int vti_rcv_cb(struct sk_buff *skb, int err)
 	return 0;
 }
 
-/* This function assumes it is being called from dev_queue_xmit()
- * and that skb is filled properly by that function.
- */
-static netdev_tx_t vti_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
+static netdev_tx_t vti_xmit(struct sk_buff *skb, struct net_device *dev,
+			    struct flowi *fl)
 {
 	struct ip_tunnel *tunnel = netdev_priv(dev);
 	struct dst_entry *dst = skb_dst(skb);
 	struct net_device *tdev;	/* Device to other host */
-	struct flowi fl;
 	int err;
 
-	if (skb->protocol != htons(ETH_P_IP))
-		goto tx_error;
-
-	memset(&fl, 0, sizeof(fl));
-	skb->mark = be32_to_cpu(tunnel->parms.o_key);
-	xfrm_decode_session(skb, &fl, AF_INET);
-
 	if (!dst) {
 		dev->stats.tx_carrier_errors++;
 		goto tx_error_icmp;
 	}
 
 	dst_hold(dst);
-	dst = xfrm_lookup(tunnel->net, dst, &fl, NULL, 0);
+	dst = xfrm_lookup(tunnel->net, dst, fl, NULL, 0);
 	if (IS_ERR(dst)) {
 		dev->stats.tx_carrier_errors++;
 		goto tx_error_icmp;
@@ -161,7 +152,6 @@ static netdev_tx_t vti_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
 			tunnel->err_count = 0;
 	}
 
-	memset(IPCB(skb), 0, sizeof(*IPCB(skb)));
 	skb_scrub_packet(skb, !net_eq(tunnel->net, dev_net(dev)));
 	skb_dst_set(skb, dst);
 	skb->dev = skb_dst(skb)->dev;
@@ -180,6 +170,36 @@ tx_error:
 	return NETDEV_TX_OK;
 }
 
+/* This function assumes it is being called from dev_queue_xmit()
+ * and that skb is filled properly by that function.
+ */
+static netdev_tx_t vti_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+	struct ip_tunnel *tunnel = netdev_priv(dev);
+	struct flowi fl;
+
+	memset(&fl, 0, sizeof(fl));
+
+	skb->mark = be32_to_cpu(tunnel->parms.o_key);
+
+	switch (skb->protocol) {
+	case htons(ETH_P_IP):
+		xfrm_decode_session(skb, &fl, AF_INET);
+		memset(IPCB(skb), 0, sizeof(*IPCB(skb)));
+		break;
+	case htons(ETH_P_IPV6):
+		xfrm_decode_session(skb, &fl, AF_INET6);
+		memset(IP6CB(skb), 0, sizeof(*IP6CB(skb)));
+		break;
+	default:
+		dev->stats.tx_errors++;
+		dev_kfree_skb(skb);
+		return NETDEV_TX_OK;
+	}
+
+	return vti_xmit(skb, dev, &fl);
+}
+
 static int vti4_err(struct sk_buff *skb, u32 info)
 {
 	__be32 spi;
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [PATCH RFC v3 11/12] vti4: Check the tunnel endpoints of the xfrm state and the vti interface
  2014-01-27 10:29 [PATCH RFC v3 0/12] vti4: prepare namespace and interfamily support Steffen Klassert
                   ` (9 preceding siblings ...)
  2014-01-27 10:29 ` [PATCH RFC v3 10/12] vti4: Support inter address family tunneling Steffen Klassert
@ 2014-01-27 10:29 ` Steffen Klassert
  2014-01-27 10:29 ` [PATCH RFC v3 12/12] vti4: Enable namespace changing Steffen Klassert
                   ` (2 subsequent siblings)
  13 siblings, 0 replies; 18+ messages in thread
From: Steffen Klassert @ 2014-01-27 10:29 UTC (permalink / raw)
  To: netdev; +Cc: Steffen Klassert, Christophe Gouault, Saurabh Mohan

The tunnel endpoints of the xfrm_state we got from the xfrm_lookup
must match the tunnel endpoints of the vti interface. This patch
ensures this matching.

Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>
---
 net/ipv4/ip_vti.c |   29 ++++++++++++++++++++++++-----
 1 file changed, 24 insertions(+), 5 deletions(-)

diff --git a/net/ipv4/ip_vti.c b/net/ipv4/ip_vti.c
index 1708fc1..1415c4a 100644
--- a/net/ipv4/ip_vti.c
+++ b/net/ipv4/ip_vti.c
@@ -106,10 +106,32 @@ static int vti_rcv_cb(struct sk_buff *skb, int err)
 	return 0;
 }
 
+static bool vti_state_check(const struct xfrm_state *x, __be32 dst, __be32 src)
+{
+	xfrm_address_t *daddr = (xfrm_address_t *)&dst;
+	xfrm_address_t *saddr = (xfrm_address_t *)&src;
+
+	/* if there is no transform then this tunnel is not functional.
+	 * Or if the xfrm is not mode tunnel.
+	 */
+	if (!x || x->props.mode != XFRM_MODE_TUNNEL ||
+	    x->props.family != AF_INET)
+		return false;
+
+	if (!dst)
+		return xfrm_addr_equal(saddr, &x->props.saddr, AF_INET);
+
+	if (!xfrm_state_addr_check(x, daddr, saddr, AF_INET))
+		return false;
+
+	return true;
+}
+
 static netdev_tx_t vti_xmit(struct sk_buff *skb, struct net_device *dev,
 			    struct flowi *fl)
 {
 	struct ip_tunnel *tunnel = netdev_priv(dev);
+	struct ip_tunnel_parm *parms = &tunnel->parms;
 	struct dst_entry *dst = skb_dst(skb);
 	struct net_device *tdev;	/* Device to other host */
 	int err;
@@ -126,15 +148,12 @@ static netdev_tx_t vti_xmit(struct sk_buff *skb, struct net_device *dev,
 		goto tx_error_icmp;
 	}
 
-	/* if there is no transform then this tunnel is not functional.
-	 * Or if the xfrm is not mode tunnel.
-	 */
-	if (!dst->xfrm ||
-	    dst->xfrm->props.mode != XFRM_MODE_TUNNEL) {
+	if (!vti_state_check(dst->xfrm, parms->iph.daddr, parms->iph.saddr)) {
 		dev->stats.tx_carrier_errors++;
 		dst_release(dst);
 		goto tx_error_icmp;
 	}
+
 	tdev = dst->dev;
 
 	if (tdev == dev) {
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [PATCH RFC v3 12/12] vti4: Enable namespace changing
  2014-01-27 10:29 [PATCH RFC v3 0/12] vti4: prepare namespace and interfamily support Steffen Klassert
                   ` (10 preceding siblings ...)
  2014-01-27 10:29 ` [PATCH RFC v3 11/12] vti4: Check the tunnel endpoints of the xfrm state and the vti interface Steffen Klassert
@ 2014-01-27 10:29 ` Steffen Klassert
  2014-01-28  0:35 ` [PATCH RFC v3 0/12] vti4: prepare namespace and interfamily support David Miller
  2014-01-29 10:55 ` Christophe Gouault
  13 siblings, 0 replies; 18+ messages in thread
From: Steffen Klassert @ 2014-01-27 10:29 UTC (permalink / raw)
  To: netdev; +Cc: Steffen Klassert, Christophe Gouault, Saurabh Mohan

vti4 is now fully namespace aware, so allow namespace changing
for vti devices

Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>
---
 net/ipv4/ip_vti.c |    1 -
 1 file changed, 1 deletion(-)

diff --git a/net/ipv4/ip_vti.c b/net/ipv4/ip_vti.c
index 1415c4a..7b1542c 100644
--- a/net/ipv4/ip_vti.c
+++ b/net/ipv4/ip_vti.c
@@ -337,7 +337,6 @@ static int vti_tunnel_init(struct net_device *dev)
 	dev->flags		= IFF_NOARP;
 	dev->iflink		= 0;
 	dev->addr_len		= 4;
-	dev->features		|= NETIF_F_NETNS_LOCAL;
 	dev->features		|= NETIF_F_LLTX;
 	dev->priv_flags		&= ~IFF_XMIT_DST_RELEASE;
 
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 18+ messages in thread

* Re: [PATCH RFC v3 0/12] vti4: prepare namespace and interfamily support.
  2014-01-27 10:29 [PATCH RFC v3 0/12] vti4: prepare namespace and interfamily support Steffen Klassert
                   ` (11 preceding siblings ...)
  2014-01-27 10:29 ` [PATCH RFC v3 12/12] vti4: Enable namespace changing Steffen Klassert
@ 2014-01-28  0:35 ` David Miller
  2014-01-29 10:55 ` Christophe Gouault
  13 siblings, 0 replies; 18+ messages in thread
From: David Miller @ 2014-01-28  0:35 UTC (permalink / raw)
  To: steffen.klassert; +Cc: netdev, christophe.gouault, saurabh.mohan

From: Steffen Klassert <steffen.klassert@secunet.com>
Date: Mon, 27 Jan 2014 11:29:25 +0100

> This patchset prepares vti4 for proper namespace and interfamily
> support.

No major objections from me, this looks good.

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH RFC v3 0/12] vti4: prepare namespace and interfamily support.
  2014-01-27 10:29 [PATCH RFC v3 0/12] vti4: prepare namespace and interfamily support Steffen Klassert
                   ` (12 preceding siblings ...)
  2014-01-28  0:35 ` [PATCH RFC v3 0/12] vti4: prepare namespace and interfamily support David Miller
@ 2014-01-29 10:55 ` Christophe Gouault
  2014-01-30  9:56   ` Steffen Klassert
  13 siblings, 1 reply; 18+ messages in thread
From: Christophe Gouault @ 2014-01-29 10:55 UTC (permalink / raw)
  To: Steffen Klassert, netdev; +Cc: Saurabh Mohan

On 01/27/2014 11:29 AM, Steffen Klassert wrote:
> This patchset prepares vti4 for proper namespace and interfamily support.
>
> Currently the receive hook is in the middle of the decapsulation
> process, some of the header pointers point still into the IPsec packet
> others point already into the decapsulated packet. This makes it
> very unflexible and proper namespace and interfamily support can't
> be done as it is.
>
> The patchset that implements an IPsec protocol multiplexer, so that vti
> can register it's own receive path hooks. Further it makes the i_key
> usable for vti and changes the vti code to do the following:
>
> vti uses the IPsec protocol multiplexer to register it's
> own receive side hooks for ESP, AH and IPCOMP.
>
> Vti does the following on receive side:
>
> 1. Do an input policy check for the IPsec packet we received.
>     This is required because this packet could be already
>     processed by IPsec (tunnel in tunnel or a block policy
>     is present), so an inbound policy check is needed.
>
> 2. Mark the packet with the i_key. The policy and the state
>     must match this key now. Policy and state belong to the vti
>     namespace and policy enforcement is done at the further layers.

Hi Steffen,

I did some tests, and it seems there is no inbound policy check against
a vti SP after the ipsec decryption:

To confirm the problem, I added some logs in the kernel to track the
outbound SPD lookup and inbound policy check.

I tested a ping from HostL(10.22.1.1) to HostR(10.24.1.201), that must
be encapsulated via a vti interface (vti1, mark 1, ifindex 8) between
IPsecVTI(10.23.1.101) and HostR(10.23.1.201).

. 10.22.1.0/24 10.23.1.0/24 10.24.1.0/24
. (HostL) ------------(IPsecVTI)============(HostR)------------
. .1 .101 .201

Here is the trace:

(1) xfrm_lookup: oif=8 mark=0 saddr=10.22.1.1 daddr=10.24.1.201
(2) xfrm_lookup: oif=8 mark=1 saddr=10.22.1.1 daddr=10.24.1.201
(3) vti_rcv: found tunnel vti1
(4) __xfrm_policy_check: dir=0 iif=0 mark=0 saddr=10.23.1.201
daddr=10.23.1.101 skb->sp->len=0
(5) __xfrm_policy_check: dir=2 iif=0 mark=0 saddr=10.24.1.201
daddr=10.22.1.1 skb->sp->len=0

And the analysis:

- A first SPD lookup is done before entering vti1 in (1), seeking for
a "global SP".
- A second SPD lookup is done after entering vti1 in (2), with mark 1,
seeking for a "vti SP"
- the icmp request is encapsulated and sent to HostR
- the esp-encrypted icmp reply is received, the packet enters vti1
and an inbound policy check is performed on the ESP packet itself in
(4), with mark 0, seeking for a "global SP".
- the packet is decrypted and its mark set to 1, but no vti inbound
policy check is done. Then the skb mark and secpath are reset by
skb_scrub_params (called by vti_rcv_cb).
- Then only an inbound policy check is performed on the icmp
reply in (5), seeking for a "global SP". It is considered a plaintext
packet, with no mark or secpath.

=> there is no check that the forward vti security policy was
enforced.

Best Regards,
Christophe.

>
> 3. Call the generic xfrm layer to do decryption and decapsulation.
>
> 4. Wait for a callback from the xfrm layer to properly clean the skb to
>     not leak informations on namespace transitions and to update the device
>     statistics.
>
> On transmit side:
>
> 1. Mark the packet with the o_key. The policy and the state
>     must match this key now.
>
> 2. Do a xfrm_lookup on the original packet with the mark applied.
>
> 3. Check if we got an IPsec route.
>
> 4. Clean the skb to not leak informations on namespace
>     transitions.
>
> 5. Attach the dst_enty we got from the xfrm_lookup to the skb.
>
> 6. Call dst_output to do the IPsec processing.
>
> 7. Do the device statistics.
>
>
> Changes from v1:
>
> - Rebased to current net-next.
> - Fix a rcu lockdep complaint in xfrm protocol registration/deregistration.
> - Fix usage of a ipv4 specific callback handler in generic code.
> - Use skb_scrub_packet() to clear the skb in vti_rcv(), suggested by
>    Nicolas Dichtel.
> - Add support for IPCOMP.
> - Support inter address family tunneling.
>
> Changes from v2:
>
> - Rebased to current net-next.
> - Check for matching tunnel endpoints of the xfrm state and
>    the vti interface.
> - Use a own error handler to not create dependencies to the
>    generic IPsec protocol handlers.
> - Change the receive path to do the namespace transition after
>    decapsulation. With this the xfrm lookups are done in the outer
>    namespace for xmit and receive, thanks to Christophe Gouault
>    for pointing this out.
> - Enable namespace changing of vti devices.
>
> I'd take this into the ipsec-next tree after the merge window closes
> if noone has further suggestions or objections.
>

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH RFC v3 0/12] vti4: prepare namespace and interfamily support.
  2014-01-29 10:55 ` Christophe Gouault
@ 2014-01-30  9:56   ` Steffen Klassert
  2014-02-04 11:05     ` Christophe Gouault
  0 siblings, 1 reply; 18+ messages in thread
From: Steffen Klassert @ 2014-01-30  9:56 UTC (permalink / raw)
  To: Christophe Gouault; +Cc: netdev, Saurabh Mohan

On Wed, Jan 29, 2014 at 11:55:40AM +0100, Christophe Gouault wrote:
> 
> Hi Steffen,
> 
> I did some tests, and it seems there is no inbound policy check against
> a vti SP after the ipsec decryption:

Thanks for testing!

> 
> To confirm the problem, I added some logs in the kernel to track the
> outbound SPD lookup and inbound policy check.
> 
> I tested a ping from HostL(10.22.1.1) to HostR(10.24.1.201), that must
> be encapsulated via a vti interface (vti1, mark 1, ifindex 8) between
> IPsecVTI(10.23.1.101) and HostR(10.23.1.201).
> 
> . 10.22.1.0/24 10.23.1.0/24 10.24.1.0/24
> . (HostL) ------------(IPsecVTI)============(HostR)------------
> . .1 .101 .201
> 
> Here is the trace:
> 
> (1) xfrm_lookup: oif=8 mark=0 saddr=10.22.1.1 daddr=10.24.1.201
> (2) xfrm_lookup: oif=8 mark=1 saddr=10.22.1.1 daddr=10.24.1.201
> (3) vti_rcv: found tunnel vti1
> (4) __xfrm_policy_check: dir=0 iif=0 mark=0 saddr=10.23.1.201
> daddr=10.23.1.101 skb->sp->len=0
> (5) __xfrm_policy_check: dir=2 iif=0 mark=0 saddr=10.24.1.201
> daddr=10.22.1.1 skb->sp->len=0
> 
> And the analysis:
> 
> - A first SPD lookup is done before entering vti1 in (1), seeking for
> a "global SP".
> - A second SPD lookup is done after entering vti1 in (2), with mark 1,
> seeking for a "vti SP"
> - the icmp request is encapsulated and sent to HostR
> - the esp-encrypted icmp reply is received, the packet enters vti1
> and an inbound policy check is performed on the ESP packet itself in
> (4), with mark 0, seeking for a "global SP".
> - the packet is decrypted and its mark set to 1, but no vti inbound
> policy check is done. Then the skb mark and secpath are reset by
> skb_scrub_params (called by vti_rcv_cb).
> - Then only an inbound policy check is performed on the icmp
> reply in (5), seeking for a "global SP". It is considered a plaintext
> packet, with no mark or secpath.
> 
> => there is no check that the forward vti security policy was
> enforced.
> 

Yes, that's true and this is a real problem. If we want to support
namespace transitions with vti, we can't know if a packet is going
to be forwarded or locally received in the other namespace. This means
that we don't know if we should enforce a input or a forward policy.

All we can do here, is to enforce a input policy before we do the
namespace transition in the receive path. The patch below (on top
of the vti patchset) should do this.

But this has the implication that forward policies do not make
much sense in combination with vti. This is a bit contrary to
traditional xfrm processing. But on the other hand, we receive
plaintext packets from the vti device so we should not check
for any IPsec processing that happened before we received the
packets via the vti device.


---
 include/net/xfrm.h        |   10 +++++-----
 net/ipv4/ip_vti.c         |    5 ++++-
 net/ipv4/xfrm4_protocol.c |    9 ++++++---
 net/xfrm/xfrm_input.c     |    4 +++-
 4 files changed, 18 insertions(+), 10 deletions(-)

diff --git a/include/net/xfrm.h b/include/net/xfrm.h
index b7740ce..cac9c46 100644
--- a/include/net/xfrm.h
+++ b/include/net/xfrm.h
@@ -1519,7 +1519,7 @@ int xfrm4_extract_output(struct xfrm_state *x, struct sk_buff *skb);
 int xfrm4_prepare_output(struct xfrm_state *x, struct sk_buff *skb);
 int xfrm4_output(struct sk_buff *skb);
 int xfrm4_output_finish(struct sk_buff *skb);
-void xfrm4_rcv_cb(struct sk_buff *skb, u8 protocol, int err);
+int xfrm4_rcv_cb(struct sk_buff *skb, u8 protocol, int err);
 int xfrm4_protocol_register(struct xfrm4_protocol *handler, unsigned char protocol);
 int xfrm4_protocol_deregister(struct xfrm4_protocol *handler, unsigned char protocol);
 int xfrm4_tunnel_register(struct xfrm_tunnel *handler, unsigned short family);
@@ -1753,14 +1753,14 @@ static inline int xfrm_mark_put(struct sk_buff *skb, const struct xfrm_mark *m)
 	return ret;
 }
 
-static inline void xfrm_rcv_cb(struct sk_buff *skb, unsigned int family,
-			       u8 protocol, int err)
+static inline int xfrm_rcv_cb(struct sk_buff *skb, unsigned int family,
+			      u8 protocol, int err)
 {
 	switch(family) {
 	case AF_INET:
-		xfrm4_rcv_cb(skb, protocol, err);
-		break;
+		return xfrm4_rcv_cb(skb, protocol, err);
 	}
+	return 0;
 }
 
 #endif	/* _NET_XFRM_H */
diff --git a/net/ipv4/ip_vti.c b/net/ipv4/ip_vti.c
index 7b1542c..5beb260 100644
--- a/net/ipv4/ip_vti.c
+++ b/net/ipv4/ip_vti.c
@@ -82,7 +82,7 @@ static int vti_rcv_cb(struct sk_buff *skb, int err)
 	struct ip_tunnel *tunnel = XFRM_TUNNEL_SKB_CB(skb)->tunnel.ip4;
 
 	if (!tunnel)
-		return -1;
+		return 1;
 
 	dev = tunnel->dev;
 
@@ -93,6 +93,9 @@ static int vti_rcv_cb(struct sk_buff *skb, int err)
 		return 0;
 	}
 
+	if (!xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb))
+		return -EPERM;
+
 	skb_scrub_packet(skb, !net_eq(tunnel->net, dev_net(skb->dev)));
 	skb->dev = dev;
 
diff --git a/net/ipv4/xfrm4_protocol.c b/net/ipv4/xfrm4_protocol.c
index 993ab39..5ab5527 100644
--- a/net/ipv4/xfrm4_protocol.c
+++ b/net/ipv4/xfrm4_protocol.c
@@ -46,13 +46,16 @@ static inline struct xfrm4_protocol __rcu **proto_handlers(u8 protocol)
 	     handler != NULL;				\
 	     handler = rcu_dereference(handler->next))	\
 
-void xfrm4_rcv_cb(struct sk_buff *skb, u8 protocol, int err)
+int xfrm4_rcv_cb(struct sk_buff *skb, u8 protocol, int err)
 {
+	int ret;
 	struct xfrm4_protocol *handler;
 
 	for_each_protocol_rcu(*proto_handlers(protocol), handler)
-		if (!handler->cb_handler(skb, err))
-			return;
+		if ((ret = handler->cb_handler(skb, err)) <= 0)
+			return ret;
+
+	return 0;
 }
 EXPORT_SYMBOL(xfrm4_rcv_cb);
 
diff --git a/net/xfrm/xfrm_input.c b/net/xfrm/xfrm_input.c
index fb64b4a..99e3a9e 100644
--- a/net/xfrm/xfrm_input.c
+++ b/net/xfrm/xfrm_input.c
@@ -263,7 +263,9 @@ resume:
 		}
 	} while (!err);
 
-	xfrm_rcv_cb(skb, family, x->type->proto, 0);
+	err = xfrm_rcv_cb(skb, family, x->type->proto, 0);
+	if (err)
+		goto drop;
 
 	nf_reset(skb);
 
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 18+ messages in thread

* Re: [PATCH RFC v3 0/12] vti4: prepare namespace and interfamily support.
  2014-01-30  9:56   ` Steffen Klassert
@ 2014-02-04 11:05     ` Christophe Gouault
  2014-02-14  7:48       ` Steffen Klassert
  0 siblings, 1 reply; 18+ messages in thread
From: Christophe Gouault @ 2014-02-04 11:05 UTC (permalink / raw)
  To: Steffen Klassert; +Cc: netdev, Saurabh Mohan

On 01/30/2014 10:56 AM, Steffen Klassert wrote:
> On Wed, Jan 29, 2014 at 11:55:40AM +0100, Christophe Gouault wrote:
> [...]
>> => there is no check that the forward vti security policy was
>> enforced.
>>
>
> Yes, that's true and this is a real problem. If we want to support
> namespace transitions with vti, we can't know if a packet is going
> to be forwarded or locally received in the other namespace. This means
> that we don't know if we should enforce a input or a forward policy.
>
> All we can do here, is to enforce a input policy before we do the
> namespace transition in the receive path. The patch below (on top
> of the vti patchset) should do this.

Hi Steffen, and thank you for the patch.

I tested it within a single netns, then with cross-netns. Both work as
follows:

- all the vti SPs and SAs must be created in the "outer" netns.
- only outbound and inbound vti policies are taken into account, not
   forward vti policies.

in output:

- a global SPD lookup is performed before entering the vti
   interface (in the inner netns). It can be bypassed by adding a policy
   such as:

    ip xfrm policy add dir out mark 0 dev vti1

- then a vti SPD lookup is performed with the vti interface (in the
   outer netns).

in input:

- a global inbound policy check is done (in the outer netns)
   on the IPsec packet by the vti interface.
- then the packet is decrypted.
- then a vti inbound policy check is done on the decrypted packet
   (in the outer netns).
- then the packet device is set to the vti interface and its netns
   is changed to the inner netns.
- finally, a global inbound/forward policy check is done on the
   plaintext packet (without security context), as if it has just arrived
   in plaintext from the network.

> But this has the implication that forward policies do not make
> much sense in combination with vti. This is a bit contrary to
> traditional xfrm processing. But on the other hand, we receive
> plaintext packets from the vti device so we should not check
> for any IPsec processing that happened before we received the
> packets via the vti device.

Unfortunately, the inbound/forward policy checks do not take the inbound
interface into account (__xfrm_decode_session does not properly fill in
the iif field of the flowi), so in the last global policy check, there
is no way of differentiating a plaintext packet directly received from
the network from a plaintext packet that was processed by a vti interface.

Intuitively, I would like to do the same as in output: add a policy that
accepts packets received via a vti interface, and only check more
closely other packets directly received from the network.

Best Regards,
Christophe.

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH RFC v3 0/12] vti4: prepare namespace and interfamily support.
  2014-02-04 11:05     ` Christophe Gouault
@ 2014-02-14  7:48       ` Steffen Klassert
  0 siblings, 0 replies; 18+ messages in thread
From: Steffen Klassert @ 2014-02-14  7:48 UTC (permalink / raw)
  To: Christophe Gouault; +Cc: netdev, Saurabh Mohan

On Tue, Feb 04, 2014 at 12:05:06PM +0100, Christophe Gouault wrote:
> 
> Hi Steffen, and thank you for the patch.
> 
> I tested it within a single netns, then with cross-netns.

Thaks a lot for testing!

> 
> Unfortunately, the inbound/forward policy checks do not take the inbound
> interface into account (__xfrm_decode_session does not properly fill in
> the iif field of the flowi), so in the last global policy check, there
> is no way of differentiating a plaintext packet directly received from
> the network from a plaintext packet that was processed by a vti interface.

Input interface maching is not implemented, the xfrm_selector has
one ifindex field and this is interpreted as the output interface.
But I would not mind if someone would implement input interface maching.

I'll do another, hopefully final, RFC version of the vti4 paches today.

^ permalink raw reply	[flat|nested] 18+ messages in thread

end of thread, other threads:[~2014-02-14  7:48 UTC | newest]

Thread overview: 18+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-01-27 10:29 [PATCH RFC v3 0/12] vti4: prepare namespace and interfamily support Steffen Klassert
2014-01-27 10:29 ` [PATCH RFC v3 01/12] xfrm4: Add IPsec protocol multiplexer Steffen Klassert
2014-01-27 10:29 ` [PATCH RFC v3 02/12] esp4: Use the IPsec protocol multiplexer API Steffen Klassert
2014-01-27 10:29 ` [PATCH RFC v3 03/12] ah4: " Steffen Klassert
2014-01-27 10:29 ` [PATCH RFC v3 04/12] ipcomp4: " Steffen Klassert
2014-01-27 10:29 ` [PATCH RFC v3 05/12] xfrm: Add xfrm_tunnel_skb_cb to the skb common buffer Steffen Klassert
2014-01-27 10:29 ` [PATCH RFC v3 06/12] ip_tunnel: Make vti work with i_key set Steffen Klassert
2014-01-27 10:29 ` [PATCH RFC v3 07/12] vti: Update the ipv4 side to use it's own receive hook Steffen Klassert
2014-01-27 10:29 ` [PATCH RFC v3 08/12] xfrm4: Remove xfrm_tunnel_notifier Steffen Klassert
2014-01-27 10:29 ` [PATCH RFC v3 09/12] vti4: Use the on xfrm_lookup returned dst_entry directly Steffen Klassert
2014-01-27 10:29 ` [PATCH RFC v3 10/12] vti4: Support inter address family tunneling Steffen Klassert
2014-01-27 10:29 ` [PATCH RFC v3 11/12] vti4: Check the tunnel endpoints of the xfrm state and the vti interface Steffen Klassert
2014-01-27 10:29 ` [PATCH RFC v3 12/12] vti4: Enable namespace changing Steffen Klassert
2014-01-28  0:35 ` [PATCH RFC v3 0/12] vti4: prepare namespace and interfamily support David Miller
2014-01-29 10:55 ` Christophe Gouault
2014-01-30  9:56   ` Steffen Klassert
2014-02-04 11:05     ` Christophe Gouault
2014-02-14  7:48       ` Steffen Klassert

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).