* [PATCHv4 net-next-2.6 0/5] Removal of RH2/HAO from IPsec-protected MIPv6 traffic
@ 2010-10-04 6:24 Arnaud Ebalard
2010-10-04 6:25 ` [PATCHv4 net-next-2.6 1/5] XFRM,IPv6: Remove xfrm_spi_hash() dependency on destination address Arnaud Ebalard
` (4 more replies)
0 siblings, 5 replies; 18+ messages in thread
From: Arnaud Ebalard @ 2010-10-04 6:24 UTC (permalink / raw)
To: David S. Miller, Eric Dumazet, Herbert Xu, Hideaki YOSHIFUJI; +Cc: netdev
Hi,
This is version 4 of the patches. Compared to previous version:
- symbols which need not be exported are no more exported
- s/printk(KERNINFO, ...)/pr_info()/ in net/ipv6/mip6.c (my code
and existing one)
- I also refactored some initialization code for mip6 states
(by introduced mip6_state_init_sanity_check())
After the discussion with Herbert, I decided to leave input handlers
as they are at the moment until I have some additional time to dig on
it. At least, it's safe.
Regarding reject handler() (to warn user space so that a Binding Error
can be sent), it still does nothing yet.
Herbert, if you read this, can you take a quick look at patches 1/5 and
4/5 to tell if the changes are acceptable for IPsec users.
Cheers,
a+
^ permalink raw reply [flat|nested] 18+ messages in thread
* [PATCHv4 net-next-2.6 1/5] XFRM,IPv6: Remove xfrm_spi_hash() dependency on destination address
2010-10-04 6:24 [PATCHv4 net-next-2.6 0/5] Removal of RH2/HAO from IPsec-protected MIPv6 traffic Arnaud Ebalard
@ 2010-10-04 6:25 ` Arnaud Ebalard
2010-10-04 8:33 ` Herbert Xu
2010-10-04 6:25 ` [PATCHv4 net-next-2.6 2/5] XFRM,IPv6: Introduce receive sockopts to access IRO remapped src/dst addresses Arnaud Ebalard
` (3 subsequent siblings)
4 siblings, 1 reply; 18+ messages in thread
From: Arnaud Ebalard @ 2010-10-04 6:25 UTC (permalink / raw)
To: David S. Miller, Eric Dumazet, Herbert Xu, Hideaki YOSHIFUJI; +Cc: netdev
In the new IPsec architecture [RFC4301], "for an SA used to carry
unicast traffic, the Security Parameters Index (SPI) by itself
suffices to specify an SA". Section 4.1 of [RFC4301] provides
additional guidance on the topic.
In the old IPsec architecture [RFC2401], a SA "is uniquely identified
by a triple consisting of a Security Parameter Index (SPI), an IP
Destination Address and a security protocol (AH or ESP) identifier".
If an IPsec stack only supports the behavior mandated by the old
IPsec architecture, SAD lookup on inbound packets require the use of
both the SPI and the destination address of the SA.
For inbound IPsec traffic, IRO remapping rules may exist on the MN to
remap the destination address (CoA) into the HoA. In that case, by
design, the address found in the destination address field of the
packet (CoA) does not match the one in the SA (HoA).
At the moment, Linux XFRM stack includes the address when computing
the hash to perform state lookup by SPI. This patch changes XFRM
state hash computation to prevent destination address to be
used. This will later allow finding states for packets w/ mangled
destination addresses.
Signed-off-by: Arnaud Ebalard <arno@natisbad.org>
---
net/xfrm/xfrm_hash.h | 21 +--------------------
net/xfrm/xfrm_state.c | 20 ++++++++------------
2 files changed, 9 insertions(+), 32 deletions(-)
diff --git a/net/xfrm/xfrm_hash.h b/net/xfrm/xfrm_hash.h
index 8e69533..19eeee7 100644
--- a/net/xfrm/xfrm_hash.h
+++ b/net/xfrm/xfrm_hash.h
@@ -4,16 +4,6 @@
#include <linux/xfrm.h>
#include <linux/socket.h>
-static inline unsigned int __xfrm4_addr_hash(xfrm_address_t *addr)
-{
- return ntohl(addr->a4);
-}
-
-static inline unsigned int __xfrm6_addr_hash(xfrm_address_t *addr)
-{
- return ntohl(addr->a6[2] ^ addr->a6[3]);
-}
-
static inline unsigned int __xfrm4_daddr_saddr_hash(xfrm_address_t *daddr, xfrm_address_t *saddr)
{
u32 sum = (__force u32)daddr->a4 + (__force u32)saddr->a4;
@@ -60,18 +50,9 @@ static inline unsigned __xfrm_src_hash(xfrm_address_t *daddr,
}
static inline unsigned int
-__xfrm_spi_hash(xfrm_address_t *daddr, __be32 spi, u8 proto, unsigned short family,
- unsigned int hmask)
+__xfrm_spi_hash(__be32 spi, u8 proto, unsigned int hmask)
{
unsigned int h = (__force u32)spi ^ proto;
- switch (family) {
- case AF_INET:
- h ^= __xfrm4_addr_hash(daddr);
- break;
- case AF_INET6:
- h ^= __xfrm6_addr_hash(daddr);
- break;
- }
return (h ^ (h >> 10) ^ (h >> 20)) & hmask;
}
diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c
index eb96ce5..b6a4d8d 100644
--- a/net/xfrm/xfrm_state.c
+++ b/net/xfrm/xfrm_state.c
@@ -30,7 +30,7 @@
/* Each xfrm_state may be linked to two tables:
- 1. Hash table by (spi,daddr,ah/esp) to find SA by SPI. (input,ctl)
+ 1. Hash table by (spi,ah/esp) to find SA by SPI. (input,ctl)
2. Hash table by (daddr,family,reqid) to find what SAs exist for given
destination/tunnel endpoint. (output)
*/
@@ -67,9 +67,9 @@ static inline unsigned int xfrm_src_hash(struct net *net,
}
static inline unsigned int
-xfrm_spi_hash(struct net *net, xfrm_address_t *daddr, __be32 spi, u8 proto, unsigned short family)
+xfrm_spi_hash(struct net *net, __be32 spi, u8 proto)
{
- return __xfrm_spi_hash(daddr, spi, proto, family, net->xfrm.state_hmask);
+ return __xfrm_spi_hash(spi, proto, net->xfrm.state_hmask);
}
static void xfrm_hash_transfer(struct hlist_head *list,
@@ -95,9 +95,7 @@ static void xfrm_hash_transfer(struct hlist_head *list,
hlist_add_head(&x->bysrc, nsrctable+h);
if (x->id.spi) {
- h = __xfrm_spi_hash(&x->id.daddr, x->id.spi,
- x->id.proto, x->props.family,
- nhashmask);
+ h = __xfrm_spi_hash(x->id.spi, x->id.proto, nhashmask);
hlist_add_head(&x->byspi, nspitable+h);
}
}
@@ -679,7 +677,7 @@ xfrm_init_tempstate(struct xfrm_state *x, struct flowi *fl,
static struct xfrm_state *__xfrm_state_lookup(struct net *net, u32 mark, xfrm_address_t *daddr, __be32 spi, u8 proto, unsigned short family)
{
- unsigned int h = xfrm_spi_hash(net, daddr, spi, proto, family);
+ unsigned int h = xfrm_spi_hash(net, spi, proto);
struct xfrm_state *x;
struct hlist_node *entry;
@@ -868,7 +866,7 @@ found:
h = xfrm_src_hash(net, daddr, saddr, encap_family);
hlist_add_head(&x->bysrc, net->xfrm.state_bysrc+h);
if (x->id.spi) {
- h = xfrm_spi_hash(net, &x->id.daddr, x->id.spi, x->id.proto, encap_family);
+ h = xfrm_spi_hash(net, x->id.spi, x->id.proto);
hlist_add_head(&x->byspi, net->xfrm.state_byspi+h);
}
x->lft.hard_add_expires_seconds = net->xfrm.sysctl_acq_expires;
@@ -942,9 +940,7 @@ static void __xfrm_state_insert(struct xfrm_state *x)
hlist_add_head(&x->bysrc, net->xfrm.state_bysrc+h);
if (x->id.spi) {
- h = xfrm_spi_hash(net, &x->id.daddr, x->id.spi, x->id.proto,
- x->props.family);
-
+ h = xfrm_spi_hash(net, x->id.spi, x->id.proto);
hlist_add_head(&x->byspi, net->xfrm.state_byspi+h);
}
@@ -1535,7 +1531,7 @@ int xfrm_alloc_spi(struct xfrm_state *x, u32 low, u32 high)
}
if (x->id.spi) {
spin_lock_bh(&xfrm_state_lock);
- h = xfrm_spi_hash(net, &x->id.daddr, x->id.spi, x->id.proto, x->props.family);
+ h = xfrm_spi_hash(net, x->id.spi, x->id.proto);
hlist_add_head(&x->byspi, net->xfrm.state_byspi+h);
spin_unlock_bh(&xfrm_state_lock);
--
1.7.1
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCHv4 net-next-2.6 2/5] XFRM,IPv6: Introduce receive sockopts to access IRO remapped src/dst addresses
2010-10-04 6:24 [PATCHv4 net-next-2.6 0/5] Removal of RH2/HAO from IPsec-protected MIPv6 traffic Arnaud Ebalard
2010-10-04 6:25 ` [PATCHv4 net-next-2.6 1/5] XFRM,IPv6: Remove xfrm_spi_hash() dependency on destination address Arnaud Ebalard
@ 2010-10-04 6:25 ` Arnaud Ebalard
2010-10-04 6:25 ` [PATCHv4 net-next-2.6 3/5] XFRM,IPv6: Add IRO src/dst address remapping XFRM types and i/o handlers Arnaud Ebalard
` (2 subsequent siblings)
4 siblings, 0 replies; 18+ messages in thread
From: Arnaud Ebalard @ 2010-10-04 6:25 UTC (permalink / raw)
To: David S. Miller, Eric Dumazet, Herbert Xu, Hideaki YOSHIFUJI; +Cc: netdev
This patch introduces IRO recv sockopts, in order for userland processes
(e.g. UMIP) to access on-wire source or destination addresses found in
incoming (IPsec-protected) packets as they were before remapping by IRO.
The socket options are respectively IPV6_RECVIROSRC and IPV6_RECVIRODST.
Basically, the two recv socket options are similar in their purpose to
their generic RH2/HAO counterparts defined in RFC 3542 (IPV6_RECVIROSRC
<-> IPV6_RECVDSTOPTS, IPV6_RECVIRODST <-> IPV6_RECVRTHDR). They differ
on the following aspects:
- IRO reporting sockopts only work on incoming IPsec-protected packets
Userspace will never get IRO remapped address report for common
(non protected) packets.
- The receiver gets the original source/desination address (IRO
remapping) from its IPsec stack.
- as IRO sockopts only deal with addresses, no specific structure is
defined, i.e. struct in6_addr is used to pass info.
As we only interact with IPsec protected packets, struct sec_path is
used to carry information (addresses) for incoming packets that have
undergone remapping process.
Signed-off-by: Arnaud Ebalard <arno@natisbad.org>
---
include/linux/in6.h | 7 +++++++
include/linux/ipv6.h | 4 +++-
include/net/xfrm.h | 5 +++++
net/ipv6/datagram.c | 18 ++++++++++++++++++
net/ipv6/ipv6_sockglue.c | 26 ++++++++++++++++++++++++++
5 files changed, 59 insertions(+), 1 deletions(-)
diff --git a/include/linux/in6.h b/include/linux/in6.h
index c4bf46f..52a98ab 100644
--- a/include/linux/in6.h
+++ b/include/linux/in6.h
@@ -283,4 +283,11 @@ struct in6_flowlabel_req {
* MRT6_PIM 208
* (reserved) 209
*/
+
+/* IRO (IPsec Route Optimization) sockopts */
+#define IPV6_RECVIROSRC 74
+#define IPV6_IROSRC 75
+#define IPV6_RECVIRODST 76
+#define IPV6_IRODST 77
+
#endif
diff --git a/include/linux/ipv6.h b/include/linux/ipv6.h
index e62683b..55289ee 100644
--- a/include/linux/ipv6.h
+++ b/include/linux/ipv6.h
@@ -341,7 +341,9 @@ struct ipv6_pinfo {
odstopts:1,
rxflow:1,
rxtclass:1,
- rxpmtu:1;
+ rxpmtu:1,
+ irosrc:1,
+ irodst:1;
} bits;
__u16 all;
} rxopt;
diff --git a/include/net/xfrm.h b/include/net/xfrm.h
index 4f53532..e6a753c 100644
--- a/include/net/xfrm.h
+++ b/include/net/xfrm.h
@@ -909,6 +909,11 @@ struct sec_path {
atomic_t refcnt;
int len;
struct xfrm_state *xvec[XFRM_MAX_DEPTH];
+
+#ifdef CONFIG_XFRM_SUB_POLICY
+ struct in6_addr irosrc;
+ struct in6_addr irodst;
+#endif
};
static inline struct sec_path *
diff --git a/net/ipv6/datagram.c b/net/ipv6/datagram.c
index ef371aa..2952c9e 100644
--- a/net/ipv6/datagram.c
+++ b/net/ipv6/datagram.c
@@ -29,6 +29,7 @@
#include <net/transp_v6.h>
#include <net/ip6_route.h>
#include <net/tcp_states.h>
+#include <net/xfrm.h>
#include <linux/errqueue.h>
#include <asm/uaccess.h>
@@ -504,6 +505,23 @@ int datagram_recv_ctl(struct sock *sk, struct msghdr *msg, struct sk_buff *skb)
put_cmsg(msg, SOL_IPV6, IPV6_HOPOPTS, (ptr[1]+1)<<3, ptr);
}
+#ifdef CONFIG_XFRM_SUB_POLICY
+ /* If access to IRO-remapped source or destination address has been
+ * requested and it has indeed been remapped, provide the on-wire
+ * address to userland */
+ if (skb_sec_path(skb)) {
+ struct sec_path *sp = skb_sec_path(skb);
+
+ if (np->rxopt.bits.irosrc && !ipv6_addr_any(&sp->irosrc))
+ put_cmsg(msg, SOL_IPV6, IPV6_IROSRC,
+ sizeof(sp->irosrc), &sp->irosrc);
+
+ if (np->rxopt.bits.irodst && !ipv6_addr_any(&sp->irodst))
+ put_cmsg(msg, SOL_IPV6, IPV6_IRODST,
+ sizeof(sp->irodst), &sp->irodst);
+ }
+#endif
+
if (opt->lastopt &&
(np->rxopt.bits.dstopts || np->rxopt.bits.srcrt)) {
/*
diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c
index a7f66bc..722a49f 100644
--- a/net/ipv6/ipv6_sockglue.c
+++ b/net/ipv6/ipv6_sockglue.c
@@ -302,6 +302,22 @@ static int do_ipv6_setsockopt(struct sock *sk, int level, int optname,
retv = 0;
break;
+#ifdef CONFIG_XFRM_SUB_POLICY
+ case IPV6_RECVIROSRC:
+ if (optlen < sizeof(int))
+ goto e_inval;
+ np->rxopt.bits.irosrc = valbool;
+ retv = 0;
+ break;
+
+ case IPV6_RECVIRODST:
+ if (optlen < sizeof(int))
+ goto e_inval;
+ np->rxopt.bits.irodst = valbool;
+ retv = 0;
+ break;
+#endif
+
case IPV6_2292DSTOPTS:
if (optlen < sizeof(int))
goto e_inval;
@@ -1056,6 +1072,16 @@ static int do_ipv6_getsockopt(struct sock *sk, int level, int optname,
val = np->rxopt.bits.dstopts;
break;
+#ifdef CONFIG_XFRM_SUB_POLICY
+ case IPV6_RECVIROSRC:
+ val = np->rxopt.bits.irosrc;
+ break;
+
+ case IPV6_RECVIRODST:
+ val = np->rxopt.bits.irodst;
+ break;
+#endif
+
case IPV6_2292DSTOPTS:
val = np->rxopt.bits.odstopts;
break;
--
1.7.1
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCHv4 net-next-2.6 3/5] XFRM,IPv6: Add IRO src/dst address remapping XFRM types and i/o handlers
2010-10-04 6:24 [PATCHv4 net-next-2.6 0/5] Removal of RH2/HAO from IPsec-protected MIPv6 traffic Arnaud Ebalard
2010-10-04 6:25 ` [PATCHv4 net-next-2.6 1/5] XFRM,IPv6: Remove xfrm_spi_hash() dependency on destination address Arnaud Ebalard
2010-10-04 6:25 ` [PATCHv4 net-next-2.6 2/5] XFRM,IPv6: Introduce receive sockopts to access IRO remapped src/dst addresses Arnaud Ebalard
@ 2010-10-04 6:25 ` Arnaud Ebalard
2010-10-04 6:25 ` [PATCHv4 net-next-2.6 4/5] XFRM,IPv6: Add IRO remapping hook in xfrm_input() Arnaud Ebalard
2010-10-04 6:25 ` [PATCHv4 net-next-2.6 5/5] XFRM,IPv6: Add IRO remapping capability via socket ancillary data path Arnaud Ebalard
4 siblings, 0 replies; 18+ messages in thread
From: Arnaud Ebalard @ 2010-10-04 6:25 UTC (permalink / raw)
To: David S. Miller, Eric Dumazet, Herbert Xu, Hideaki YOSHIFUJI; +Cc: netdev
Add IRO source and destination remapping XFRM types and associated
input/output handlers. This allows userland to install such states
in order to support remapping of source or destination address
of packet. They basically work like existing RH2 and HAO ones; the
main difference is that output handlers do not expand the packet by
adding an extension header: they simply change the source or
destination in place. Input handlers are almost the same as RH2/HAO
version in their behavior, but they are triggered differently. RH2
and HAO handlers are triggered based on structures found in the
packet. On input, IRO states (and associated handlers) are looked
up when processing an IPsec-protected packet, when there is an
address mismatch.
Signed-off-by: Arnaud Ebalard <arno@natisbad.org>
---
include/net/xfrm.h | 2 +
net/ipv6/mip6.c | 181 ++++++++++++++++++++++++++++++++++++++++------
net/ipv6/xfrm6_mode_ro.c | 11 +++-
net/xfrm/xfrm_user.c | 4 +
4 files changed, 176 insertions(+), 22 deletions(-)
diff --git a/include/net/xfrm.h b/include/net/xfrm.h
index e6a753c..05b2b1f 100644
--- a/include/net/xfrm.h
+++ b/include/net/xfrm.h
@@ -35,6 +35,8 @@
#define XFRM_PROTO_IPV6 41
#define XFRM_PROTO_ROUTING IPPROTO_ROUTING
#define XFRM_PROTO_DSTOPTS IPPROTO_DSTOPTS
+#define XFRM_PROTO_IRO_SRC 127
+#define XFRM_PROTO_IRO_DST 128
#define XFRM_ALIGN8(len) (((len) + 7) & ~7)
#define MODULE_ALIAS_XFRM_MODE(family, encap) \
diff --git a/net/ipv6/mip6.c b/net/ipv6/mip6.c
index d6e9599..9685599 100644
--- a/net/ipv6/mip6.c
+++ b/net/ipv6/mip6.c
@@ -302,18 +302,26 @@ static int mip6_destopt_offset(struct xfrm_state *x, struct sk_buff *skb,
return offset;
}
-static int mip6_destopt_init_state(struct xfrm_state *x)
+/* Helper performing basic sanity checks on given mip6 state
+ * during state's initialization process */
+static int mip6_state_init_sanity_check(struct xfrm_state *x)
{
if (x->id.spi) {
- printk(KERN_INFO "%s: spi is not 0: %u\n", __func__,
- x->id.spi);
+ pr_info("%s: SPI is not 0 but %u\n", __func__, x->id.spi);
return -EINVAL;
}
if (x->props.mode != XFRM_MODE_ROUTEOPTIMIZATION) {
- printk(KERN_INFO "%s: state's mode is not %u: %u\n",
- __func__, XFRM_MODE_ROUTEOPTIMIZATION, x->props.mode);
+ pr_info("%s: state's mode is not RO (%u) but %u\n", __func__,
+ XFRM_MODE_ROUTEOPTIMIZATION, x->props.mode);
return -EINVAL;
}
+ return 0;
+}
+
+static int mip6_destopt_init_state(struct xfrm_state *x)
+{
+ if (mip6_state_init_sanity_check(x))
+ return -EINVAL;
x->props.header_len = sizeof(struct ipv6_destopt_hdr) +
calc_padlen(sizeof(struct ipv6_destopt_hdr), 6) +
@@ -440,16 +448,8 @@ static int mip6_rthdr_offset(struct xfrm_state *x, struct sk_buff *skb,
static int mip6_rthdr_init_state(struct xfrm_state *x)
{
- if (x->id.spi) {
- printk(KERN_INFO "%s: spi is not 0: %u\n", __func__,
- x->id.spi);
- return -EINVAL;
- }
- if (x->props.mode != XFRM_MODE_ROUTEOPTIMIZATION) {
- printk(KERN_INFO "%s: state's mode is not %u: %u\n",
- __func__, XFRM_MODE_ROUTEOPTIMIZATION, x->props.mode);
+ if (mip6_state_init_sanity_check(x))
return -EINVAL;
- }
x->props.header_len = sizeof(struct rt2_hdr);
@@ -477,20 +477,145 @@ static const struct xfrm_type mip6_rthdr_type =
.hdr_offset = mip6_rthdr_offset,
};
+#ifdef CONFIG_XFRM_SUB_POLICY
+/* IRO equivalent of mip6_destopt_input(): handles incoming packet with a
+ * source address different from the one expected in the SA: check that
+ * received source address is indeed the CoA we expected (or any address
+ * if the state references the unspecified address '::') */
+static int mip6_iro_src_input(struct xfrm_state *x, struct sk_buff *skb)
+{
+ struct ipv6hdr *iph = ipv6_hdr(skb);
+ int err = 1;
+
+ spin_lock(&x->lock);
+ if (!ipv6_addr_equal(&iph->saddr, (struct in6_addr *)x->coaddr) &&
+ !ipv6_addr_any((struct in6_addr *)x->coaddr))
+ err = -ENOENT;
+ spin_unlock(&x->lock);
+
+ return err;
+}
+
+/* IRO equivalent of mip6_destopt_output(): replaces current source address
+ * of outgoing packet by state's CoA. */
+static int mip6_iro_src_output(struct xfrm_state *x, struct sk_buff *skb)
+{
+ struct ipv6hdr *iph = ipv6_hdr(skb);
+
+ spin_lock_bh(&x->lock);
+ memcpy(&iph->saddr, x->coaddr, sizeof(iph->saddr));
+ spin_unlock_bh(&x->lock);
+
+ return 0;
+}
+
+static int mip6_iro_src_reject(struct xfrm_state *x, struct sk_buff *skb, struct flowi *fl)
+{
+ /* XXX We may need some reject handler at some point but it is not
+ * critical yet: see xfrm_secpath_reject() in net/xfrm/xfrm_policy.c
+ * and aslo what mip6_destopt_reject() implements */
+
+ pr_debug("%s: not implemented yet.\n", __func__);
+
+ return 0;
+}
+
+/* This is the IRO equivalent of mip6_rthdr_input(): handles incoming packet
+ * with a destination address different from the one expected in the SA:
+ * check that received destination address is indeed the CoA we expected
+ * (or any address if the state references the unspecified address '::') */
+static int mip6_iro_dst_input(struct xfrm_state *x, struct sk_buff *skb)
+{
+ struct ipv6hdr *iph = ipv6_hdr(skb);
+ int err = 1;
+
+ spin_lock(&x->lock);
+ if (!ipv6_addr_equal(&iph->daddr, (struct in6_addr *)x->coaddr) &&
+ !ipv6_addr_any((struct in6_addr *)x->coaddr))
+ err = -ENOENT;
+ spin_unlock(&x->lock);
+
+ return err;
+}
+
+/* IRO equivalent of mip6_rthdr_output(): replaces current destination
+ * address of outgoing packet with state's CoA */
+static int mip6_iro_dst_output(struct xfrm_state *x, struct sk_buff *skb)
+{
+ struct ipv6hdr *iph = ipv6_hdr(skb);
+
+ spin_lock_bh(&x->lock);
+ memcpy(&iph->daddr, x->coaddr, sizeof(iph->daddr));
+ spin_unlock_bh(&x->lock);
+
+ return 0;
+}
+
+/* Common to iro src and dst remapping states. */
+static int mip6_iro_init_state(struct xfrm_state *x)
+{
+ return mip6_state_init_sanity_check(x);
+}
+
+/* Unlike common IPsec protocols, nothing to do when destroying */
+static void mip6_iro_destroy(struct xfrm_state *x)
+{
+}
+
+static const struct xfrm_type mip6_iro_src_type =
+{
+ .description = "MIP6_IRO_SRC",
+ .owner = THIS_MODULE,
+ .proto = XFRM_PROTO_IRO_SRC,
+ .flags = XFRM_TYPE_NON_FRAGMENT | XFRM_TYPE_LOCAL_COADDR,
+ .init_state = mip6_iro_init_state,
+ .destructor = mip6_iro_destroy,
+ .input = mip6_iro_src_input,
+ .output = mip6_iro_src_output,
+ .reject = mip6_iro_src_reject,
+};
+
+static const struct xfrm_type mip6_iro_dst_type =
+{
+ .description = "MIP6_IRO_DST",
+ .owner = THIS_MODULE,
+ .proto = XFRM_PROTO_IRO_DST,
+ .flags = XFRM_TYPE_NON_FRAGMENT | XFRM_TYPE_REMOTE_COADDR,
+ .init_state = mip6_iro_init_state,
+ .destructor = mip6_iro_destroy,
+ .input = mip6_iro_dst_input,
+ .output = mip6_iro_dst_output,
+};
+#endif /* CONFIG_XFRM_SUB_POLICY */
+
static int __init mip6_init(void)
{
- printk(KERN_INFO "Mobile IPv6\n");
+ pr_info("Mobile IPv6\n");
if (xfrm_register_type(&mip6_destopt_type, AF_INET6) < 0) {
- printk(KERN_INFO "%s: can't add xfrm type(destopt)\n", __func__);
+ pr_info("%s: can't add xfrm type(destopt)\n", __func__);
goto mip6_destopt_xfrm_fail;
}
if (xfrm_register_type(&mip6_rthdr_type, AF_INET6) < 0) {
- printk(KERN_INFO "%s: can't add xfrm type(rthdr)\n", __func__);
+ pr_info("%s: can't add xfrm type(rthdr)\n", __func__);
goto mip6_rthdr_xfrm_fail;
}
+
+#ifdef CONFIG_XFRM_SUB_POLICY
+ if (xfrm_register_type(&mip6_iro_src_type, AF_INET6) < 0) {
+ pr_info("%s: can't add xfrm type(IRO src remap)\n",
+ __func__);
+ goto mip6_iro_src_remap_xfrm_fail;
+ }
+ if (xfrm_register_type(&mip6_iro_dst_type, AF_INET6) < 0) {
+ pr_info("%s: can't add xfrm type(IRO dst remap)\n",
+ __func__);
+ goto mip6_iro_dst_remap_xfrm_fail;
+ }
+#endif
+
if (rawv6_mh_filter_register(mip6_mh_filter) < 0) {
- printk(KERN_INFO "%s: can't add rawv6 mh filter\n", __func__);
+ pr_info("%s: can't add rawv6 mh filter\n", __func__);
goto mip6_rawv6_mh_fail;
}
@@ -498,6 +623,12 @@ static int __init mip6_init(void)
return 0;
mip6_rawv6_mh_fail:
+#ifdef CONFIG_XFRM_SUB_POLICY
+ xfrm_unregister_type(&mip6_iro_dst_type, AF_INET6);
+ mip6_iro_dst_remap_xfrm_fail:
+ xfrm_unregister_type(&mip6_iro_src_type, AF_INET6);
+ mip6_iro_src_remap_xfrm_fail:
+#endif
xfrm_unregister_type(&mip6_rthdr_type, AF_INET6);
mip6_rthdr_xfrm_fail:
xfrm_unregister_type(&mip6_destopt_type, AF_INET6);
@@ -508,11 +639,19 @@ static int __init mip6_init(void)
static void __exit mip6_fini(void)
{
if (rawv6_mh_filter_unregister(mip6_mh_filter) < 0)
- printk(KERN_INFO "%s: can't remove rawv6 mh filter\n", __func__);
+ pr_info("%s: can't remove rawv6 mh filter\n", __func__);
+#ifdef CONFIG_XFRM_SUB_POLICY
+ if (xfrm_unregister_type(&mip6_iro_dst_type, AF_INET6) < 0)
+ pr_info("%s: can't remove xfrm type(IRO dst remap)\n",
+ __func__);
+ if (xfrm_unregister_type(&mip6_iro_src_type, AF_INET6) < 0)
+ pr_info("%s: can't remove xfrm type(IRO src remap)\n",
+ __func__);
+#endif
if (xfrm_unregister_type(&mip6_rthdr_type, AF_INET6) < 0)
- printk(KERN_INFO "%s: can't remove xfrm type(rthdr)\n", __func__);
+ pr_info("%s: can't remove xfrm type(rthdr)\n", __func__);
if (xfrm_unregister_type(&mip6_destopt_type, AF_INET6) < 0)
- printk(KERN_INFO "%s: can't remove xfrm type(destopt)\n", __func__);
+ pr_info("%s: can't remove xfrm type(destopt)\n", __func__);
}
module_init(mip6_init);
diff --git a/net/ipv6/xfrm6_mode_ro.c b/net/ipv6/xfrm6_mode_ro.c
index 63d5d49..ea33178 100644
--- a/net/ipv6/xfrm6_mode_ro.c
+++ b/net/ipv6/xfrm6_mode_ro.c
@@ -45,6 +45,15 @@ static int xfrm6_ro_output(struct xfrm_state *x, struct sk_buff *skb)
u8 *prevhdr;
int hdr_len;
+ /* Unlike RH2 (IPPROTO_ROUTING) and HAO in DstOpt
+ * (IPPROTO_DSTOPTS), IRO remapping states do not
+ * add extension header to the packet. Source
+ * and/or destination addresses are simply modified
+ * in place. */
+ if (x->id.proto == XFRM_PROTO_IRO_SRC ||
+ x->id.proto == XFRM_PROTO_IRO_DST)
+ goto out;
+
iph = ipv6_hdr(skb);
hdr_len = x->type->hdr_offset(x, skb, &prevhdr);
@@ -54,8 +63,8 @@ static int xfrm6_ro_output(struct xfrm_state *x, struct sk_buff *skb)
__skb_pull(skb, hdr_len);
memmove(ipv6_hdr(skb), iph, hdr_len);
+ out:
x->lastused = get_seconds();
-
return 0;
}
diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c
index 8bae6b2..2aecd40 100644
--- a/net/xfrm/xfrm_user.c
+++ b/net/xfrm/xfrm_user.c
@@ -179,6 +179,10 @@ static int verify_newsa_info(struct xfrm_usersa_info *p,
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
case IPPROTO_DSTOPTS:
case IPPROTO_ROUTING:
+#ifdef CONFIG_XFRM_SUB_POLICY
+ case XFRM_PROTO_IRO_SRC:
+ case XFRM_PROTO_IRO_DST:
+#endif
if (attrs[XFRMA_ALG_COMP] ||
attrs[XFRMA_ALG_AUTH] ||
attrs[XFRMA_ALG_AUTH_TRUNC] ||
--
1.7.1
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCHv4 net-next-2.6 4/5] XFRM,IPv6: Add IRO remapping hook in xfrm_input()
2010-10-04 6:24 [PATCHv4 net-next-2.6 0/5] Removal of RH2/HAO from IPsec-protected MIPv6 traffic Arnaud Ebalard
` (2 preceding siblings ...)
2010-10-04 6:25 ` [PATCHv4 net-next-2.6 3/5] XFRM,IPv6: Add IRO src/dst address remapping XFRM types and i/o handlers Arnaud Ebalard
@ 2010-10-04 6:25 ` Arnaud Ebalard
2010-10-04 8:40 ` Herbert Xu
2010-10-04 6:25 ` [PATCHv4 net-next-2.6 5/5] XFRM,IPv6: Add IRO remapping capability via socket ancillary data path Arnaud Ebalard
4 siblings, 1 reply; 18+ messages in thread
From: Arnaud Ebalard @ 2010-10-04 6:25 UTC (permalink / raw)
To: David S. Miller, Eric Dumazet, Herbert Xu, Hideaki YOSHIFUJI; +Cc: netdev
Add a hook in xfrm_input() to allow IRO remapping to occur when
an incoming packet matching an existing SA (based on SPI) with
an unexpected destination or source address is received.
Because IRO does not consume additional bits in a packet (that's
the point), there is no way to demultiplex based on something
like nh or spi. Instead, IRO input handlers (for source and
destination address remapping) are called upon address mismatch
during IPsec processing.
For that to work, we rely on the fact that SPI values generated
locally are no more linked to destination address (first patch
of the set) and we postpone a bit the expected address check in
xfrm_input() (inside xfrm_state_lookup() against daddr param) by
introducing a call to the input_addr_check() handler from the
struct xfrm_state_afinfo associated with the address family.
Signed-off-by: Arnaud Ebalard <arno@natisbad.org>
---
include/net/xfrm.h | 5 +++
net/ipv4/xfrm4_input.c | 11 +++++++
net/ipv4/xfrm4_state.c | 1 +
net/ipv6/xfrm6_input.c | 69 +++++++++++++++++++++++++++++++++++++++++++++++-
net/ipv6/xfrm6_state.c | 1 +
net/xfrm/xfrm_input.c | 5 ++-
net/xfrm/xfrm_state.c | 2 +-
7 files changed, 90 insertions(+), 4 deletions(-)
diff --git a/include/net/xfrm.h b/include/net/xfrm.h
index 05b2b1f..5b84c19 100644
--- a/include/net/xfrm.h
+++ b/include/net/xfrm.h
@@ -312,6 +312,8 @@ struct xfrm_state_afinfo {
struct sk_buff *skb);
int (*transport_finish)(struct sk_buff *skb,
int async);
+ int (*input_addr_check)(struct sk_buff *skb,
+ struct xfrm_state *x);
};
extern int xfrm_state_register_afinfo(struct xfrm_state_afinfo *afinfo);
@@ -623,6 +625,7 @@ struct xfrm_spi_skb_cb {
struct inet6_skb_parm h6;
} header;
+ unsigned int saddroff;
unsigned int daddroff;
unsigned int family;
};
@@ -1405,6 +1408,7 @@ extern int xfrm4_rcv_encap(struct sk_buff *skb, int nexthdr, __be32 spi,
int encap_type);
extern int xfrm4_transport_finish(struct sk_buff *skb, int async);
extern int xfrm4_rcv(struct sk_buff *skb);
+extern int xfrm4_input_addr_check(struct sk_buff *skb, struct xfrm_state *x);
static inline int xfrm4_rcv_spi(struct sk_buff *skb, int nexthdr, __be32 spi)
{
@@ -1423,6 +1427,7 @@ extern int xfrm6_transport_finish(struct sk_buff *skb, int async);
extern int xfrm6_rcv(struct sk_buff *skb);
extern int xfrm6_input_addr(struct sk_buff *skb, xfrm_address_t *daddr,
xfrm_address_t *saddr, u8 proto);
+extern int xfrm6_input_addr_check(struct sk_buff *skb, struct xfrm_state *x);
extern int xfrm6_tunnel_register(struct xfrm6_tunnel *handler, unsigned short family);
extern int xfrm6_tunnel_deregister(struct xfrm6_tunnel *handler, unsigned short family);
extern __be32 xfrm6_tunnel_alloc_spi(struct net *net, xfrm_address_t *saddr);
diff --git a/net/ipv4/xfrm4_input.c b/net/ipv4/xfrm4_input.c
index 06814b6..8d414ca 100644
--- a/net/ipv4/xfrm4_input.c
+++ b/net/ipv4/xfrm4_input.c
@@ -41,6 +41,7 @@ int xfrm4_rcv_encap(struct sk_buff *skb, int nexthdr, __be32 spi,
int encap_type)
{
XFRM_SPI_SKB_CB(skb)->family = AF_INET;
+ XFRM_SPI_SKB_CB(skb)->saddroff = offsetof(struct iphdr, saddr);
XFRM_SPI_SKB_CB(skb)->daddroff = offsetof(struct iphdr, daddr);
return xfrm_input(skb, nexthdr, spi, encap_type);
}
@@ -164,3 +165,13 @@ int xfrm4_rcv(struct sk_buff *skb)
return xfrm4_rcv_spi(skb, ip_hdr(skb)->protocol, 0);
}
EXPORT_SYMBOL(xfrm4_rcv);
+
+int xfrm4_input_addr_check(struct sk_buff *skb, struct xfrm_state *x)
+{
+ xfrm_address_t *daddr;
+
+ daddr = (xfrm_address_t *)(skb_network_header(skb) +
+ XFRM_SPI_SKB_CB(skb)->daddroff);
+
+ return xfrm_addr_cmp(&x->id.daddr, daddr, AF_INET);
+}
diff --git a/net/ipv4/xfrm4_state.c b/net/ipv4/xfrm4_state.c
index 4794762..c6b038a 100644
--- a/net/ipv4/xfrm4_state.c
+++ b/net/ipv4/xfrm4_state.c
@@ -79,6 +79,7 @@ static struct xfrm_state_afinfo xfrm4_state_afinfo = {
.extract_input = xfrm4_extract_input,
.extract_output = xfrm4_extract_output,
.transport_finish = xfrm4_transport_finish,
+ .input_addr_check = xfrm4_input_addr_check,
};
void __init xfrm4_state_init(void)
diff --git a/net/ipv6/xfrm6_input.c b/net/ipv6/xfrm6_input.c
index f8c3cf8..aeb7fc6 100644
--- a/net/ipv6/xfrm6_input.c
+++ b/net/ipv6/xfrm6_input.c
@@ -15,6 +15,7 @@
#include <linux/netfilter_ipv6.h>
#include <net/ipv6.h>
#include <net/xfrm.h>
+#include <net/ip6_route.h> /* XXX for ip6_route_input() */
int xfrm6_extract_input(struct xfrm_state *x, struct sk_buff *skb)
{
@@ -24,6 +25,7 @@ int xfrm6_extract_input(struct xfrm_state *x, struct sk_buff *skb)
int xfrm6_rcv_spi(struct sk_buff *skb, int nexthdr, __be32 spi)
{
XFRM_SPI_SKB_CB(skb)->family = AF_INET6;
+ XFRM_SPI_SKB_CB(skb)->saddroff = offsetof(struct ipv6hdr, saddr);
XFRM_SPI_SKB_CB(skb)->daddroff = offsetof(struct ipv6hdr, daddr);
return xfrm_input(skb, nexthdr, spi, 0);
}
@@ -142,5 +144,70 @@ int xfrm6_input_addr(struct sk_buff *skb, xfrm_address_t *daddr,
drop:
return -1;
}
-
EXPORT_SYMBOL(xfrm6_input_addr);
+
+#if defined(CONFIG_XFRM_SUB_POLICY)
+/* Perform check on source and destination addresses and possibly IRO
+ * address remapping upon mismatch and if matching IRO state exists. */
+int xfrm6_input_addr_check(struct sk_buff *skb, struct xfrm_state *x)
+{
+ xfrm_address_t *saddr, *exp_saddr, *daddr, *exp_daddr;
+
+ saddr = (xfrm_address_t *)(skb_network_header(skb) +
+ XFRM_SPI_SKB_CB(skb)->saddroff);
+ daddr = (xfrm_address_t *)(skb_network_header(skb) +
+ XFRM_SPI_SKB_CB(skb)->daddroff);
+
+ exp_daddr = &x->id.daddr;
+ if (xfrm_addr_cmp(exp_daddr, daddr, AF_INET6)) {
+ /* Destination address mismatch: check if we have an IRO
+ * destination remapping state to explain that.
+ *
+ * Note: saddr is provided as a hint. If source address
+ * is also a remapped one, xfrm6_input_addr() will manage
+ * to find IRO destination remapping state */
+ if (xfrm6_input_addr(skb, exp_daddr, saddr,
+ XFRM_PROTO_IRO_DST) < 0)
+ return -1;
+
+ /* Copy destination address to sec_path for sock opts and
+ * replace packet destination address with expected HoA */
+ ipv6_addr_copy(&skb->sp->irodst, (struct in6_addr *)daddr);
+ ipv6_addr_copy((struct in6_addr *)daddr,
+ (struct in6_addr *)exp_daddr);
+
+ skb_dst_drop(skb);
+ ip6_route_input(skb);
+ if (skb_dst(skb)->error)
+ return -1;
+ }
+
+ exp_saddr = &x->props.saddr;
+ if (xfrm_addr_cmp(exp_saddr, saddr, AF_INET6)) {
+ /* Source address mismatch: check if we have an IRO
+ * source remapping state to explain that.
+ *
+ * Note: unlike for destination addresses above, a
+ * source mismatch is not considered fatal */
+ if (xfrm6_input_addr(skb, daddr, exp_saddr,
+ XFRM_PROTO_IRO_SRC) < 0)
+ return 0;
+
+ /* Copy destination address to sec_path for sock opts and
+ * then replace source address with expected peer's HoA */
+ ipv6_addr_copy(&skb->sp->irosrc, (struct in6_addr *)saddr);
+ ipv6_addr_copy((struct in6_addr *)saddr,
+ (struct in6_addr *)exp_saddr);
+ }
+
+ return 0;
+}
+#else
+int xfrm6_input_addr_check(struct sk_buff *skb, struct xfrm_state *x)
+{
+ xfrm_address_t *daddr;
+ daddr = (xfrm_address_t *)(skb_network_header(skb) +
+ XFRM_SPI_SKB_CB(skb)->daddroff);
+ return xfrm_addr_cmp(&x->id.daddr, daddr, AF_INET6);
+}
+#endif
diff --git a/net/ipv6/xfrm6_state.c b/net/ipv6/xfrm6_state.c
index a67575d..aeb4688 100644
--- a/net/ipv6/xfrm6_state.c
+++ b/net/ipv6/xfrm6_state.c
@@ -179,6 +179,7 @@ static struct xfrm_state_afinfo xfrm6_state_afinfo = {
.extract_input = xfrm6_extract_input,
.extract_output = xfrm6_extract_output,
.transport_finish = xfrm6_transport_finish,
+ .input_addr_check = xfrm6_input_addr_check,
};
int __init xfrm6_state_init(void)
diff --git a/net/xfrm/xfrm_input.c b/net/xfrm/xfrm_input.c
index 45f1c98..9ff65f6 100644
--- a/net/xfrm/xfrm_input.c
+++ b/net/xfrm/xfrm_input.c
@@ -152,8 +152,9 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type)
goto drop;
}
- x = xfrm_state_lookup(net, skb->mark, daddr, spi, nexthdr, family);
- if (x == NULL) {
+ x = xfrm_state_lookup(net, skb->mark, NULL, spi, nexthdr, family);
+ if (x == NULL ||
+ x->outer_mode->afinfo->input_addr_check(skb, x)) {
XFRM_INC_STATS(net, LINUX_MIB_XFRMINNOSTATES);
xfrm_audit_state_notfound(skb, family, spi, seq);
goto drop;
diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c
index b6a4d8d..b8f7c08 100644
--- a/net/xfrm/xfrm_state.c
+++ b/net/xfrm/xfrm_state.c
@@ -685,7 +685,7 @@ static struct xfrm_state *__xfrm_state_lookup(struct net *net, u32 mark, xfrm_ad
if (x->props.family != family ||
x->id.spi != spi ||
x->id.proto != proto ||
- xfrm_addr_cmp(&x->id.daddr, daddr, family))
+ (daddr && xfrm_addr_cmp(&x->id.daddr, daddr, family)))
continue;
if ((mark & x->mark.m) != x->mark.v)
--
1.7.1
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCHv4 net-next-2.6 5/5] XFRM,IPv6: Add IRO remapping capability via socket ancillary data path
2010-10-04 6:24 [PATCHv4 net-next-2.6 0/5] Removal of RH2/HAO from IPsec-protected MIPv6 traffic Arnaud Ebalard
` (3 preceding siblings ...)
2010-10-04 6:25 ` [PATCHv4 net-next-2.6 4/5] XFRM,IPv6: Add IRO remapping hook in xfrm_input() Arnaud Ebalard
@ 2010-10-04 6:25 ` Arnaud Ebalard
4 siblings, 0 replies; 18+ messages in thread
From: Arnaud Ebalard @ 2010-10-04 6:25 UTC (permalink / raw)
To: David S. Miller, Eric Dumazet, Herbert Xu, Hideaki YOSHIFUJI; +Cc: netdev
This provides the ability to remap src/dst address using IRO
via ancillary data passed to sockets. This is the IRO equivalent
of what is done for RH2/HAO (i.e. IPV6_RTHDR/IPV6_DSTOPTS).
This is used by UMIP during BA emission when acting as a Home
Agent.
Signed-off-by: Arnaud Ebalard <arno@natisbad.org>
---
include/net/ipv6.h | 4 ++++
net/ipv6/datagram.c | 20 ++++++++++++++++++++
net/ipv6/exthdrs.c | 19 +++++++++++++------
net/ipv6/ip6_flowlabel.c | 7 +++++++
net/ipv6/ip6_output.c | 22 ++++++++++++++++++++++
net/ipv6/raw.c | 3 ++-
6 files changed, 68 insertions(+), 7 deletions(-)
diff --git a/include/net/ipv6.h b/include/net/ipv6.h
index 4a3cd2c..2ba96d8 100644
--- a/include/net/ipv6.h
+++ b/include/net/ipv6.h
@@ -188,6 +188,10 @@ struct ipv6_txoptions {
struct ipv6_rt_hdr *srcrt; /* Routing Header */
struct ipv6_opt_hdr *dst1opt;
+ /* XXX protect those via some ifdef e.g. CONFIG_XFRM_SUB_POLICY ? */
+ struct in6_addr *iro_src;
+ struct in6_addr *iro_dst;
+
/* Option buffer, as read by IPV6_PKTOPTIONS, starts here. */
};
diff --git a/net/ipv6/datagram.c b/net/ipv6/datagram.c
index 2952c9e..0ac7adf 100644
--- a/net/ipv6/datagram.c
+++ b/net/ipv6/datagram.c
@@ -757,6 +757,26 @@ int datagram_send_ctl(struct net *net,
}
break;
+#ifdef CONFIG_XFRM_SUB_POLICY
+ case IPV6_IROSRC:
+ case IPV6_IRODST:
+ if (cmsg->cmsg_len < CMSG_LEN(sizeof(struct in6_addr))) {
+ err = -EINVAL;
+ goto exit_f;
+ }
+
+ if (!capable(CAP_NET_RAW)) {
+ err = -EPERM;
+ goto exit_f;
+ }
+
+ if (cmsg->cmsg_type == IPV6_IROSRC)
+ opt->iro_src = (struct in6_addr *)CMSG_DATA(cmsg);
+ else
+ opt->iro_dst = (struct in6_addr *)CMSG_DATA(cmsg);
+ break;
+#endif
+
case IPV6_2292RTHDR:
case IPV6_RTHDR:
if (cmsg->cmsg_len < CMSG_LEN(sizeof(struct ipv6_rt_hdr))) {
diff --git a/net/ipv6/exthdrs.c b/net/ipv6/exthdrs.c
index 262f105..e480b06 100644
--- a/net/ipv6/exthdrs.c
+++ b/net/ipv6/exthdrs.c
@@ -750,6 +750,10 @@ ipv6_dup_options(struct sock *sk, struct ipv6_txoptions *opt)
*((char**)&opt2->dst1opt) += dif;
if (opt2->srcrt)
*((char**)&opt2->srcrt) += dif;
+ if (opt2->iro_src)
+ *((char**)&opt2->iro_src) += dif;
+ if (opt2->iro_dst)
+ *((char**)&opt2->iro_dst) += dif;
}
return opt2;
}
@@ -874,24 +878,27 @@ struct ipv6_txoptions *ipv6_fixup_options(struct ipv6_txoptions *opt_space,
/**
* fl6_update_dst - update flowi destination address with info given
- * by srcrt option, if any.
+ * by srcrt/iro_dst option, if any.
*
* @fl: flowi for which fl6_dst is to be updated
- * @opt: struct ipv6_txoptions in which to look for srcrt opt
+ * @opt: struct ipv6_txoptions in which to look for srcrt/iro_dst opt
* @orig: copy of original fl6_dst address if modified
*
- * Returns NULL if no txoptions or no srcrt, otherwise returns orig
- * and initial value of fl->fl6_dst set in orig
+ * Returns NULL if no txoptions or no options to change flowi destination
+ * (srcrt or IRO destination remapping rule), otherwise returns orig and
+ * initial value of fl->fl6_dst set in orig
*/
struct in6_addr *fl6_update_dst(struct flowi *fl,
const struct ipv6_txoptions *opt,
struct in6_addr *orig)
{
- if (!opt || !opt->srcrt)
+ if (!opt || (!opt->srcrt && !opt->iro_dst))
return NULL;
ipv6_addr_copy(orig, &fl->fl6_dst);
- ipv6_addr_copy(&fl->fl6_dst, ((struct rt0_hdr *)opt->srcrt)->addr);
+ ipv6_addr_copy(&fl->fl6_dst,
+ opt->iro_dst ?: ((struct rt0_hdr *)opt->srcrt)->addr);
+
return orig;
}
diff --git a/net/ipv6/ip6_flowlabel.c b/net/ipv6/ip6_flowlabel.c
index 1365468..dbf9c29 100644
--- a/net/ipv6/ip6_flowlabel.c
+++ b/net/ipv6/ip6_flowlabel.c
@@ -280,6 +280,9 @@ struct ipv6_txoptions *fl6_merge_options(struct ipv6_txoptions * opt_space,
opt_space->hopopt = fl_opt->hopopt;
opt_space->dst0opt = fl_opt->dst0opt;
opt_space->srcrt = fl_opt->srcrt;
+ /* XXX protect those via some ifdef - see net/ipv6.h */
+ opt_space->iro_src = fl_opt->iro_src;
+ opt_space->iro_dst = fl_opt->iro_dst;
opt_space->opt_nflen = fl_opt->opt_nflen;
} else {
if (fopt->opt_nflen == 0)
@@ -287,6 +290,9 @@ struct ipv6_txoptions *fl6_merge_options(struct ipv6_txoptions * opt_space,
opt_space->hopopt = NULL;
opt_space->dst0opt = NULL;
opt_space->srcrt = NULL;
+ /* XXX protect those via some ifdef - see net/ipv6.h */
+ opt_space->iro_src = NULL;
+ opt_space->iro_dst = NULL;
opt_space->opt_nflen = 0;
}
opt_space->dst1opt = fopt->dst1opt;
@@ -456,6 +462,7 @@ static int ipv6_opt_cmp(struct ipv6_txoptions *o1, struct ipv6_txoptions *o2)
return 1;
if (ipv6_hdr_cmp((struct ipv6_opt_hdr *)o1->srcrt, (struct ipv6_opt_hdr *)o2->srcrt))
return 1;
+
return 0;
}
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
index 99157b4..210f269 100644
--- a/net/ipv6/ip6_output.c
+++ b/net/ipv6/ip6_output.c
@@ -222,6 +222,8 @@ int ip6_xmit(struct sock *sk, struct sk_buff *skb, struct flowi *fl,
ipv6_push_frag_opts(skb, opt, &proto);
if (opt->opt_nflen)
ipv6_push_nfrag_opts(skb, opt, &proto, &first_hop);
+ if (opt->iro_dst)
+ first_hop = opt->iro_dst;
}
skb_push(skb, sizeof(struct ipv6hdr));
@@ -1106,6 +1108,12 @@ static inline struct ipv6_rt_hdr *ip6_rthdr_dup(struct ipv6_rt_hdr *src,
return src ? kmemdup(src, (src->hdrlen + 1) * 8, gfp) : NULL;
}
+static inline struct in6_addr *ip6_iro_addr_dup(struct in6_addr *addr,
+ gfp_t gfp)
+{
+ return addr ? kmemdup(addr, sizeof(struct in6_addr), gfp) : NULL;
+}
+
int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to,
int offset, int len, int odd, struct sk_buff *skb),
void *from, int length, int transhdrlen,
@@ -1162,6 +1170,16 @@ int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to,
if (opt->srcrt && !np->cork.opt->srcrt)
return -ENOBUFS;
+ np->cork.opt->iro_src = ip6_iro_addr_dup(opt->iro_src,
+ sk->sk_allocation);
+ if (opt->iro_src && !np->cork.opt->iro_src)
+ return -ENOBUFS;
+
+ np->cork.opt->iro_dst = ip6_iro_addr_dup(opt->iro_dst,
+ sk->sk_allocation);
+ if (opt->iro_dst && !np->cork.opt->iro_dst)
+ return -ENOBUFS;
+
/* need source address above miyazawa*/
}
dst_hold(&rt->dst);
@@ -1440,6 +1458,8 @@ static void ip6_cork_release(struct inet_sock *inet, struct ipv6_pinfo *np)
kfree(np->cork.opt->dst1opt);
kfree(np->cork.opt->hopopt);
kfree(np->cork.opt->srcrt);
+ kfree(np->cork.opt->iro_src);
+ kfree(np->cork.opt->iro_dst);
kfree(np->cork.opt);
np->cork.opt = NULL;
}
@@ -1495,6 +1515,8 @@ int ip6_push_pending_frames(struct sock *sk)
ipv6_push_frag_opts(skb, opt, &proto);
if (opt && opt->opt_nflen)
ipv6_push_nfrag_opts(skb, opt, &proto, &final_dst);
+ if (opt && opt->iro_dst)
+ final_dst = opt->iro_dst;
skb_push(skb, sizeof(struct ipv6hdr));
skb_reset_network_header(skb);
diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c
index 45e6efb..1a11bd5 100644
--- a/net/ipv6/raw.c
+++ b/net/ipv6/raw.c
@@ -828,7 +828,8 @@ static int rawv6_sendmsg(struct kiocb *iocb, struct sock *sk,
if (flowlabel == NULL)
return -EINVAL;
}
- if (!(opt->opt_nflen|opt->opt_flen))
+ if (!(opt->opt_nflen|opt->opt_flen) &&
+ (!opt->iro_src && !opt->iro_dst))
opt = NULL;
}
if (opt == NULL)
--
1.7.1
^ permalink raw reply related [flat|nested] 18+ messages in thread
* Re: [PATCHv4 net-next-2.6 1/5] XFRM,IPv6: Remove xfrm_spi_hash() dependency on destination address
2010-10-04 6:25 ` [PATCHv4 net-next-2.6 1/5] XFRM,IPv6: Remove xfrm_spi_hash() dependency on destination address Arnaud Ebalard
@ 2010-10-04 8:33 ` Herbert Xu
2010-10-04 20:51 ` Arnaud Ebalard
0 siblings, 1 reply; 18+ messages in thread
From: Herbert Xu @ 2010-10-04 8:33 UTC (permalink / raw)
To: Arnaud Ebalard; +Cc: David S. Miller, Eric Dumazet, Hideaki YOSHIFUJI, netdev
On Mon, Oct 04, 2010 at 08:25:07AM +0200, Arnaud Ebalard wrote:
>
> At the moment, Linux XFRM stack includes the address when computing
> the hash to perform state lookup by SPI. This patch changes XFRM
> state hash computation to prevent destination address to be
> used. This will later allow finding states for packets w/ mangled
> destination addresses.
I'm fine with doing this for inbound SAs. However, I can't see
how we can do this for outbound SAs where the SPI is chosen by
the remote end.
Incidentally, it appears that our hash could do with some
strengthening.
Cheers,
--
Email: Herbert Xu <herbert@gondor.apana.org.au>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCHv4 net-next-2.6 4/5] XFRM,IPv6: Add IRO remapping hook in xfrm_input()
2010-10-04 6:25 ` [PATCHv4 net-next-2.6 4/5] XFRM,IPv6: Add IRO remapping hook in xfrm_input() Arnaud Ebalard
@ 2010-10-04 8:40 ` Herbert Xu
2010-10-04 20:51 ` Arnaud Ebalard
0 siblings, 1 reply; 18+ messages in thread
From: Herbert Xu @ 2010-10-04 8:40 UTC (permalink / raw)
To: Arnaud Ebalard; +Cc: David S. Miller, Eric Dumazet, Hideaki YOSHIFUJI, netdev
On Mon, Oct 04, 2010 at 08:25:23AM +0200, Arnaud Ebalard wrote:
> Add a hook in xfrm_input() to allow IRO remapping to occur when
> an incoming packet matching an existing SA (based on SPI) with
> an unexpected destination or source address is received.
> Because IRO does not consume additional bits in a packet (that's
> the point), there is no way to demultiplex based on something
> like nh or spi. Instead, IRO input handlers (for source and
> destination address remapping) are called upon address mismatch
> during IPsec processing.
> For that to work, we rely on the fact that SPI values generated
> locally are no more linked to destination address (first patch
> of the set) and we postpone a bit the expected address check in
> xfrm_input() (inside xfrm_state_lookup() against daddr param) by
> introducing a call to the input_addr_check() handler from the
> struct xfrm_state_afinfo associated with the address family.
>
> Signed-off-by: Arnaud Ebalard <arno@natisbad.org>
I would prefer for this check to go into x->type->input since
it does not apply to IPsec.
Just because the SPI is unique for inbound SAs, it doesn't mean
that we should ignore the destination IP address in the packet for
IPsec.
I think another way of getting what you want is to simply add
inbound SAs with a zero destination address in your case which
can then be made to match any destination IP address. You can
then follow that up with additional checks in x->type->input.
Cheers,
--
Email: Herbert Xu <herbert@gondor.apana.org.au>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCHv4 net-next-2.6 1/5] XFRM,IPv6: Remove xfrm_spi_hash() dependency on destination address
2010-10-04 8:33 ` Herbert Xu
@ 2010-10-04 20:51 ` Arnaud Ebalard
2010-10-05 2:11 ` Herbert Xu
0 siblings, 1 reply; 18+ messages in thread
From: Arnaud Ebalard @ 2010-10-04 20:51 UTC (permalink / raw)
To: Herbert Xu; +Cc: David S. Miller, Eric Dumazet, Hideaki YOSHIFUJI, netdev
Hi,
Herbert Xu <herbert@gondor.apana.org.au> writes:
> On Mon, Oct 04, 2010 at 08:25:07AM +0200, Arnaud Ebalard wrote:
>>
>> At the moment, Linux XFRM stack includes the address when computing
>> the hash to perform state lookup by SPI. This patch changes XFRM
>> state hash computation to prevent destination address to be
>> used. This will later allow finding states for packets w/ mangled
>> destination addresses.
>
> I'm fine with doing this for inbound SAs. However, I can't see
> how we can do this for outbound SAs where the SPI is chosen by
> the remote end.
The change *does not* make the lookup in the hash table rely only on the
spi, i.e. __xfrm_state_lookup() is still passed the address. It only
removes the destination address from the computation of the hash. This
allows passing NULL to __xfrm_state_lookup() specifically for input path
and make the lookup only based on the SPI. The destination address check
is done later (possibly after IRO remapping).
Except if I really missed something, this has no impact on outbound SA
(other hashtables are used in that case).
> Incidentally, it appears that our hash could do with some
> strengthening.
After the change, xfrm_spi_hash() would contain:
unsigned int h = (__force u32)spi ^ proto;
return ((h ^ (h >> 10) ^ (h >> 20)) & hmask)
which seems to spread the bits h correctly into hmask bits (I mean for
the effort ;-) ). Are you thinking about something like changing the
shifts based on the length of the mask?
Cheers,
a+
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCHv4 net-next-2.6 4/5] XFRM,IPv6: Add IRO remapping hook in xfrm_input()
2010-10-04 8:40 ` Herbert Xu
@ 2010-10-04 20:51 ` Arnaud Ebalard
2010-10-05 6:27 ` Herbert Xu
0 siblings, 1 reply; 18+ messages in thread
From: Arnaud Ebalard @ 2010-10-04 20:51 UTC (permalink / raw)
To: Herbert Xu; +Cc: David S. Miller, Eric Dumazet, Hideaki YOSHIFUJI, netdev
Hi,
Herbert Xu <herbert@gondor.apana.org.au> writes:
> On Mon, Oct 04, 2010 at 08:25:23AM +0200, Arnaud Ebalard wrote:
>> Add a hook in xfrm_input() to allow IRO remapping to occur when
>> an incoming packet matching an existing SA (based on SPI) with
>> an unexpected destination or source address is received.
>> Because IRO does not consume additional bits in a packet (that's
>> the point), there is no way to demultiplex based on something
>> like nh or spi. Instead, IRO input handlers (for source and
>> destination address remapping) are called upon address mismatch
>> during IPsec processing.
>> For that to work, we rely on the fact that SPI values generated
>> locally are no more linked to destination address (first patch
>> of the set) and we postpone a bit the expected address check in
>> xfrm_input() (inside xfrm_state_lookup() against daddr param) by
>> introducing a call to the input_addr_check() handler from the
>> struct xfrm_state_afinfo associated with the address family.
>>
>> Signed-off-by: Arnaud Ebalard <arno@natisbad.org>
>
> I would prefer for this check to go into x->type->input since
> it does not apply to IPsec.
Either I don't understand the sentence or this is not feasible: the
thing is there is nothing in the packet to demultiplex like nh for
RH2/HAO. Here, we only lookup for a remapping state when there is a
mismatch in the source/destination addresses expected for the SA.
That's the reason IRO remapping states only apply to IPsec traffic.
> Just because the SPI is unique for inbound SAs, it doesn't mean
> that we should ignore the destination IP address in the packet for
> IPsec.
I don't ignore it. Before the change, for input IPsec traffic, the SA
lookup is done as follows:
- SA lookup based mostly on SPI
- Destination address check (done simultaneously during lookup)
fatal if mismatch
After the change, there are three steps for IPv6:
- SA lookup based on SPI
- Destination Address check
mismatch => lookup for destination remapping state
call for associated input handler
fatal if mismatch
- Source Address check
mismatch => lookup for source remapping state
call for associated input handler
Explanation makes it looks more complex than it is:
- IPv4 IPsec is basically untouched
- IPv6 IPsec is basically untouched when CONFIG_XFRM_SUB_POLICY is not
enabled,
- when CONFIG_XFRM_SUB_POLICY is enabled additional work is done only
for IPv6 upon address mismatch.
> I think another way of getting what you want is to simply add
> inbound SAs with a zero destination address in your case which
> can then be made to match any destination IP address. You can
> then follow that up with additional checks in x->type->input.
The idea is to allow the optimization for unmodified IPsec SA
(between stable addresses, i.e. HoA). Updating IRO src/dst remapping
states allow changing the src/dst on-wire address for unmodifed SA w/o
the need to explicitly add RH2 and/or HAO. Additionally, because source
and destination remapping are not linked, your proposal would not solve
the source remapping case, would it?
Thanks for your feedback and patience, Herbert!
Cheers,
a+
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCHv4 net-next-2.6 1/5] XFRM,IPv6: Remove xfrm_spi_hash() dependency on destination address
2010-10-04 20:51 ` Arnaud Ebalard
@ 2010-10-05 2:11 ` Herbert Xu
2010-10-05 4:17 ` Herbert Xu
0 siblings, 1 reply; 18+ messages in thread
From: Herbert Xu @ 2010-10-05 2:11 UTC (permalink / raw)
To: Arnaud Ebalard; +Cc: David S. Miller, Eric Dumazet, Hideaki YOSHIFUJI, netdev
On Mon, Oct 04, 2010 at 10:51:38PM +0200, Arnaud Ebalard wrote:
>
> Herbert Xu <herbert@gondor.apana.org.au> writes:
>
> > I'm fine with doing this for inbound SAs. However, I can't see
> > how we can do this for outbound SAs where the SPI is chosen by
> > the remote end.
>
> The change *does not* make the lookup in the hash table rely only on the
> spi, i.e. __xfrm_state_lookup() is still passed the address. It only
> removes the destination address from the computation of the hash. This
> allows passing NULL to __xfrm_state_lookup() specifically for input path
> and make the lookup only based on the SPI. The destination address check
> is done later (possibly after IRO remapping).
>
> Except if I really missed something, this has no impact on outbound SA
> (other hashtables are used in that case).
I'm thinking about the case where each remote end (or one remote
end with many IP addresses) chooses to use a single SPI which then
all gets hashed to the same bucket.
Outbound SAs are hashed into the same SPI hash table as inbound SAs.
> > Incidentally, it appears that our hash could do with some
> > strengthening.
>
> After the change, xfrm_spi_hash() would contain:
>
> unsigned int h = (__force u32)spi ^ proto;
> return ((h ^ (h >> 10) ^ (h >> 20)) & hmask)
>
> which seems to spread the bits h correctly into hmask bits (I mean for
> the effort ;-) ). Are you thinking about something like changing the
> shifts based on the length of the mask?
What I meant here is that even without your change, it is relatively
easy to cause many SAs to be hashed to the same bucket.
Cheers,
--
Email: Herbert Xu <herbert@gondor.apana.org.au>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCHv4 net-next-2.6 1/5] XFRM,IPv6: Remove xfrm_spi_hash() dependency on destination address
2010-10-05 2:11 ` Herbert Xu
@ 2010-10-05 4:17 ` Herbert Xu
2010-10-07 20:13 ` Arnaud Ebalard
0 siblings, 1 reply; 18+ messages in thread
From: Herbert Xu @ 2010-10-05 4:17 UTC (permalink / raw)
To: Arnaud Ebalard; +Cc: David S. Miller, Eric Dumazet, Hideaki YOSHIFUJI, netdev
On Tue, Oct 05, 2010 at 10:11:14AM +0800, Herbert Xu wrote:
>
> I'm thinking about the case where each remote end (or one remote
> end with many IP addresses) chooses to use a single SPI which then
> all gets hashed to the same bucket.
>
> Outbound SAs are hashed into the same SPI hash table as inbound SAs.
Another solution would be to create a hash table for inbound SAs
only. Unfortunately I don't think we have anything in our current
user-interface to indicate whether an SA is inbound or outbound.
So to do this you'll need to use a heuristic such as doing a
lookup on the source/destination address at insertion time.
Cheers,
--
Email: Herbert Xu <herbert@gondor.apana.org.au>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCHv4 net-next-2.6 4/5] XFRM,IPv6: Add IRO remapping hook in xfrm_input()
2010-10-04 20:51 ` Arnaud Ebalard
@ 2010-10-05 6:27 ` Herbert Xu
2010-10-05 23:28 ` Arnaud Ebalard
0 siblings, 1 reply; 18+ messages in thread
From: Herbert Xu @ 2010-10-05 6:27 UTC (permalink / raw)
To: Arnaud Ebalard; +Cc: David S. Miller, Eric Dumazet, Hideaki YOSHIFUJI, netdev
On Mon, Oct 04, 2010 at 10:51:46PM +0200, Arnaud Ebalard wrote:
>
> Either I don't understand the sentence or this is not feasible: the
> thing is there is nothing in the packet to demultiplex like nh for
> RH2/HAO. Here, we only lookup for a remapping state when there is a
> mismatch in the source/destination addresses expected for the SA.
>
> That's the reason IRO remapping states only apply to IPsec traffic.
I see.
The thing that bugs me is that you've added an indirect call for
all IPsec traffic when only MIPv6 users would ever need this.
With your remapping, would it be possible to add dummy xfrm_state
objects with the remapped destination address that could then call
xfrm6_input_addr?
That way normal IPsec users would not be affected at all while
preserving your new functionality.
Cheers,
--
Email: Herbert Xu <herbert@gondor.apana.org.au>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCHv4 net-next-2.6 4/5] XFRM,IPv6: Add IRO remapping hook in xfrm_input()
2010-10-05 6:27 ` Herbert Xu
@ 2010-10-05 23:28 ` Arnaud Ebalard
2010-10-06 1:25 ` Herbert Xu
0 siblings, 1 reply; 18+ messages in thread
From: Arnaud Ebalard @ 2010-10-05 23:28 UTC (permalink / raw)
To: Herbert Xu; +Cc: David S. Miller, Eric Dumazet, Hideaki YOSHIFUJI, netdev
Hi,
Herbert Xu <herbert@gondor.apana.org.au> writes:
> On Mon, Oct 04, 2010 at 10:51:46PM +0200, Arnaud Ebalard wrote:
>>
>> Either I don't understand the sentence or this is not feasible: the
>> thing is there is nothing in the packet to demultiplex like nh for
>> RH2/HAO. Here, we only lookup for a remapping state when there is a
>> mismatch in the source/destination addresses expected for the SA.
>>
>> That's the reason IRO remapping states only apply to IPsec traffic.
>
> I see.
>
> The thing that bugs me is that you've added an indirect call for
> all IPsec traffic when only MIPv6 users would ever need this.
The destination address check is always done by the IPsec stack and
usually results in a direct drop if/when it fails. I just replace the
direct drop by some a possible recovery (a state lookup and a possible
remapping). The change does not impact standard IPsec users.
Regarding the source address check, I indeed add an additional memcmp()
with some additional work when there is an address mismatch. From a
performance standpoint, I *think* it does not change much: removing the
address from the hash computation for the lookup should balance the
comparison.
I made some pretty lame performance test with ... dd and nc. Two boxes,
both w/ gigabit intel cards connected via a Gigabit switch. The receiver
runs current net-next-2.6, and has static IPv6/IPv4 SA/SP (transport
mode ESP using AES):
1) First, current net-next-2.6 (no patches applied)
2) then, with my patches applied and CONFIG_XFRM_SUB_POLICY enabled
3) then, with my patches applied and CONFIG_XFRM_SUB_POLICY disabled
I use dd and netcat6 on the source to send 1GB of data to the receiver
over TCP (over IPv4 and then IPv6) for the various flavours of kernel
above (on the receiver):
dd if=/dev/zero bs=1024 count=1048576 | nc -x <receiverip> 1234
receiver has
nc -x -l -p 1234 > /dev/null
The (lack of) results are (reported by dd, 3 runs each time):
1) IPv4: 33.5760s (32.0 MB/s) IPv6 29.0952s (36.9 MB/s)
28.1210s (38.2 MB/s) 31.7187s (33.9 MB/s)
29.6547s (36.2 MB/s) 30.6551s (35.0 MB/s)
2) IPv4: 29.4168s (36.5 MB/s) IPv6: 30.8944s (34.8 MB/s)
28.6593s (37.5 MB/s) 30.0922s (35.7 MB/s)
30.1222s (35.6 MB/s) 30.1781s (35.6 MB/s)
3) IPv4: 31.0125s (34.6 MB/s) IPv6: 31.6964s (33.9 MB/s)
28.8677s (37.2 MB/s) 30.1182s (35.7 MB/s)
30.4820s (35.2 MB/s) 30.4874s (35.2 MB/s)
I expected (hoped) additional processing time to somewhat add up and
appear in the final result but I think I will need to decrease the
rest of processing to prove you right :-) I'd be happy to do some
tests if you point me better tools or good parameters to do that
(use UDP?, change MTU?, NULL enc?, more runs? ...).
> With your remapping, would it be possible to add dummy xfrm_state
> objects with the remapped destination address that could then call
> xfrm6_input_addr?
>
> That way normal IPsec users would not be affected at all while
> preserving your new functionality.
I don't think I can do that easily (at all?) with what XFRM provides,
can I? Or at least I don't see how it is possible because I would need
some kind of policy for the state to be applied and the only trigger I
see is the src/dst address mismatch when processing the IPsec packet.
Ideally, one could think the perfect solution would be to use the SPI
and associate a remapping state to it but I already dropped that one
because SPI tracking is simply a broken idea. Among the problems: you
need to update on rekeying, you can only install the remapping state
after SA is installed, ... The problem is that it is not stable, unlike
the addresses of the SA I use in current proposal.
Cheers,
a+
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCHv4 net-next-2.6 4/5] XFRM,IPv6: Add IRO remapping hook in xfrm_input()
2010-10-05 23:28 ` Arnaud Ebalard
@ 2010-10-06 1:25 ` Herbert Xu
2010-10-06 21:42 ` Arnaud Ebalard
0 siblings, 1 reply; 18+ messages in thread
From: Herbert Xu @ 2010-10-06 1:25 UTC (permalink / raw)
To: Arnaud Ebalard; +Cc: David S. Miller, Eric Dumazet, Hideaki YOSHIFUJI, netdev
On Wed, Oct 06, 2010 at 01:28:42AM +0200, Arnaud Ebalard wrote:
>
> 1) First, current net-next-2.6 (no patches applied)
> 2) then, with my patches applied and CONFIG_XFRM_SUB_POLICY enabled
> 3) then, with my patches applied and CONFIG_XFRM_SUB_POLICY disabled
To measure the effect of this properly you should use null
encryption/hashing and look at the CPU utilisation with minimum
packet sizes.
> > With your remapping, would it be possible to add dummy xfrm_state
> > objects with the remapped destination address that could then call
> > xfrm6_input_addr?
> >
> > That way normal IPsec users would not be affected at all while
> > preserving your new functionality.
>
> I don't think I can do that easily (at all?) with what XFRM provides,
> can I? Or at least I don't see how it is possible because I would need
> some kind of policy for the state to be applied and the only trigger I
> see is the src/dst address mismatch when processing the IPsec packet.
So do you know the remapped destination addresses a priori?
If not then then other possibility would be to add the code hook
in case of xfrm_state_lookup failure.
But more importantly you need to solve the hash collission issue
that I mentioned earlier. Without that it won't work at all.
Cheers,
--
Email: Herbert Xu <herbert@gondor.apana.org.au>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCHv4 net-next-2.6 4/5] XFRM,IPv6: Add IRO remapping hook in xfrm_input()
2010-10-06 1:25 ` Herbert Xu
@ 2010-10-06 21:42 ` Arnaud Ebalard
0 siblings, 0 replies; 18+ messages in thread
From: Arnaud Ebalard @ 2010-10-06 21:42 UTC (permalink / raw)
To: Herbert Xu; +Cc: David S. Miller, Eric Dumazet, Hideaki YOSHIFUJI, netdev
Hi Herbert,
Herbert Xu <herbert@gondor.apana.org.au> writes:
> On Wed, Oct 06, 2010 at 01:28:42AM +0200, Arnaud Ebalard wrote:
>>
>> 1) First, current net-next-2.6 (no patches applied)
>> 2) then, with my patches applied and CONFIG_XFRM_SUB_POLICY enabled
>> 3) then, with my patches applied and CONFIG_XFRM_SUB_POLICY disabled
>
> To measure the effect of this properly you should use null
> encryption/hashing and look at the CPU utilisation with minimum
> packet sizes.
I did that w/ the following kernels on the receiver (same as before):
- kernel 1: w/o patches (net-next-2.6)
- kernel 2: patches applied w/ CONFIG_XFRM_SUB_POLICY
- kernel 3: patches applied w/o CONFIG_XFRM_SUB_POLICY
5 runs of sending 1073741824 bytes over TCP protected using ESP (null
enc and null auth) in transport mode, forcing small packets:
dd if=/dev/zero bs=1024 count=1048576 | nc --mtu=100 -x <v4orv6dst> 1234
5 runs for each kernel for IPv4 and IPv6. I keep only the 3 central
values provided by dd indicating the completion of the emission (remove
highest and smallest) and do an average w/ those 3 values:
IPv4 IPv6
kernel 1 70.0815s 72.4843s
kernel 2 69.8335s 72.3462s
kernel 3 69.9758s 72.3588s
I used the exact same method for the tests for the 3 cases (reboot,
started the test, nothing else running). I am unable to explain why it's
longer for the test to complete with an unpatched kernel but this is
what I get. Maybe it is just an artefact and the impact is just simply
too small to be mesured. Anyway, the whole set of results are at the end
of the email.
>> > With your remapping, would it be possible to add dummy xfrm_state
>> > objects with the remapped destination address that could then call
>> > xfrm6_input_addr?
>> >
>> > That way normal IPsec users would not be affected at all while
>> > preserving your new functionality.
>>
>> I don't think I can do that easily (at all?) with what XFRM provides,
>> can I? Or at least I don't see how it is possible because I would need
>> some kind of policy for the state to be applied and the only trigger I
>> see is the src/dst address mismatch when processing the IPsec packet.
>
> So do you know the remapped destination addresses a priori?
I have both the HoA and the CoA (this is x->coaddr in my state. '::' is
allowed if I want to allow anything), but the appplication of the state
needs to be done for traffic meant for the HoA and not blindly for all
the IPsec traffic received with the CoA (as source or destination).
it's not possible to just blindly remap things based on the on-wire
address and the fact it is IPsec traffic. For instance, if some tunnel
mode IPsec traffic between a MN and its HA is used in parallel, I cannot
remap the CoA from received packets on the MN to the HoA.
That's the reason why the lookup is done via something stable (i.e. the
HoA) which is derived from the SPI during SA lookup.
> If not then then other possibility would be to add the code hook
> in case of xfrm_state_lookup failure.
This would work for destination address. But it has the drawback of
requiring a first lookup (guaranteed to fail if destination remapping
for the feature) and then a second (somehow w/o using the destination
address). Source check would still be done in all cases.
> But more importantly you need to solve the hash collission issue
> that I mentioned earlier. Without that it won't work at all.
You are correct. The fact that the byspi hash table contains all states
(for in and out traffic) and that the state lookup does not involve the
direction but only the destination address (damn, the one I remove ;-))
is a real issue. It just makes the state lookup unreliable when I pass
NULL as daddr for incoming traffic. Thanks for pointing that.
I don't see any good solution yet (state have no direction) but I will
definitely focus on that issue and spend some time on it tomorrow.
Cheers,
a+
The full set of results for the tests:
* kernel 1
$ dd if=/dev/zero bs=1024 count=1048576 | nc --mtu=100 -x 192.168.0.14 1234
1073741824 bytes (1.1 GB) copied, 70.0393 s, 15.3 MB/s
1073741824 bytes (1.1 GB) copied, 70.2442 s, 15.3 MB/s
1073741824 bytes (1.1 GB) copied, 70.1995 s, 15.3 MB/s
1073741824 bytes (1.1 GB) copied, 70.0057 s, 15.3 MB/s
1073741824 bytes (1.1 GB) copied, 69.9887 s, 15.3 MB/s
$ dd if=/dev/zero bs=1024 count=1048576 | nc --mtu=100 -x fdff::1 1234
1073741824 bytes (1.1 GB) copied, 72.5605 s, 14.8 MB/s
1073741824 bytes (1.1 GB) copied, 72.9725 s, 14.7 MB/s
1073741824 bytes (1.1 GB) copied, 72.3099 s, 14.8 MB/s
1073741824 bytes (1.1 GB) copied, 72.435 s, 14.8 MB/s
1073741824 bytes (1.1 GB) copied, 72.4573 s, 14.8 MB/s
* kernel 2
$ dd if=/dev/zero bs=1024 count=1048576 | nc --mtu=100 -x 192.168.0.14 1234
1073741824 bytes (1.1 GB) copied, 69.6845 s, 15.4 MB/s
1073741824 bytes (1.1 GB) copied, 69.9419 s, 15.4 MB/s
1073741824 bytes (1.1 GB) copied, 69.8615 s, 15.4 MB/s
1073741824 bytes (1.1 GB) copied, 70.0142 s, 15.3 MB/s
1073741824 bytes (1.1 GB) copied, 69.6970 s, 15.4 MB/s
$ dd if=/dev/zero bs=1024 count=1048576 | nc --mtu=100 -x fdff::1 1234
1073741824 bytes (1.1 GB) copied, 72.4252 s, 14.8 MB/s
1073741824 bytes (1.1 GB) copied, 71.5411 s, 15.0 MB/s
1073741824 bytes (1.1 GB) copied, 72.2388 s, 14.9 MB/s
1073741824 bytes (1.1 GB) copied, 72.3745 s, 14.8 MB/s
1073741824 bytes (1.1 GB) copied, 72.6553 s, 14.8 MB/s
* kernel 3
$ dd if=/dev/zero bs=1024 count=1048576 | nc --mtu=100 -x 192.168.0.14 1234
1073741824 bytes (1.1 GB) copied, 69.8569 s, 15.4 MB/s
1073741824 bytes (1.1 GB) copied, 70.4445 s, 15.2 MB/s
1073741824 bytes (1.1 GB) copied, 69.8989 s, 15.4 MB/s
1073741824 bytes (1.1 GB) copied, 70.0238 s, 15.3 MB/s
1073741824 bytes (1.1 GB) copied, 70.0047 s, 15.3 MB/s
$ dd if=/dev/zero bs=1024 count=1048576 | nc --mtu=100 -x fdff::1 1234
1073741824 bytes (1.1 GB) copied, 72.4677 s, 14.8 MB/s
1073741824 bytes (1.1 GB) copied, 72.2757 s, 14.9 MB/s
1073741824 bytes (1.1 GB) copied, 72.2261 s, 14.9 MB/s
1073741824 bytes (1.1 GB) copied, 72.3331 s, 14.8 MB/s
1073741824 bytes (1.1 GB) copied, 72.8262 s, 14.7 MB/s
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCHv4 net-next-2.6 1/5] XFRM,IPv6: Remove xfrm_spi_hash() dependency on destination address
2010-10-05 4:17 ` Herbert Xu
@ 2010-10-07 20:13 ` Arnaud Ebalard
2010-10-08 0:42 ` Herbert Xu
0 siblings, 1 reply; 18+ messages in thread
From: Arnaud Ebalard @ 2010-10-07 20:13 UTC (permalink / raw)
To: Herbert Xu; +Cc: David S. Miller, Eric Dumazet, Hideaki YOSHIFUJI, netdev
Hi,
Herbert Xu <herbert@gondor.apana.org.au> writes:
> On Tue, Oct 05, 2010 at 10:11:14AM +0800, Herbert Xu wrote:
>>
>> I'm thinking about the case where each remote end (or one remote
>> end with many IP addresses) chooses to use a single SPI which then
>> all gets hashed to the same bucket.
>>
>> Outbound SAs are hashed into the same SPI hash table as inbound SAs.
>
> Another solution would be to create a hash table for inbound SAs
> only. Unfortunately I don't think we have anything in our current
> user-interface to indicate whether an SA is inbound or outbound.
>
> So to do this you'll need to use a heuristic such as doing a
> lookup on the source/destination address at insertion time.
I spent some time scratching my head trying to find a good solution. It
would indeed be perfect to have a specific hash table for inbound
SA. But as you point, this would only be via a heuristic at insertion
time and there are various cases which would not work: a SA can be
installed w/o any of the addresses being configured on the system.
I think I will try the following alternative approach based on your
comments and proposals:
- drop my patch to change spi hash computation
- handle destination address remapping during input upon failure of
xfrm_state_lookup()
- handle source address remapping as it is currently done in the patch,
i.e. by comparing received one against x->props.saddr once the
state found and do
To support the destination address remapping, I will have to reverse the
logic I currently have for destination remapping states, to allow the
lookup to be done based on the on-wire address (CoA) instead of the
address in the SA (HoA). If a remapping state is found for the on-wire
address, then a new lookup is done using the associated HoA this time.
I think it would make the feature easier less intrusive for the IPsec
stack.
Thanks for your support and patience, Herbert.
a+
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCHv4 net-next-2.6 1/5] XFRM,IPv6: Remove xfrm_spi_hash() dependency on destination address
2010-10-07 20:13 ` Arnaud Ebalard
@ 2010-10-08 0:42 ` Herbert Xu
0 siblings, 0 replies; 18+ messages in thread
From: Herbert Xu @ 2010-10-08 0:42 UTC (permalink / raw)
To: Arnaud Ebalard; +Cc: David S. Miller, Eric Dumazet, Hideaki YOSHIFUJI, netdev
On Thu, Oct 07, 2010 at 10:13:04PM +0200, Arnaud Ebalard wrote:
>
> I think I will try the following alternative approach based on your
> comments and proposals:
>
> - drop my patch to change spi hash computation
> - handle destination address remapping during input upon failure of
> xfrm_state_lookup()
> - handle source address remapping as it is currently done in the patch,
> i.e. by comparing received one against x->props.saddr once the
> state found and do
I'm fine with this from IPsec's point-of-view.
On the other hand, if it is at all possible to setup these remapping
entries in the SADB beforehand, that would definitely be my
preferred solution.
Cheers,
--
Email: Herbert Xu <herbert@gondor.apana.org.au>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt
^ permalink raw reply [flat|nested] 18+ messages in thread
end of thread, other threads:[~2010-10-08 0:42 UTC | newest]
Thread overview: 18+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2010-10-04 6:24 [PATCHv4 net-next-2.6 0/5] Removal of RH2/HAO from IPsec-protected MIPv6 traffic Arnaud Ebalard
2010-10-04 6:25 ` [PATCHv4 net-next-2.6 1/5] XFRM,IPv6: Remove xfrm_spi_hash() dependency on destination address Arnaud Ebalard
2010-10-04 8:33 ` Herbert Xu
2010-10-04 20:51 ` Arnaud Ebalard
2010-10-05 2:11 ` Herbert Xu
2010-10-05 4:17 ` Herbert Xu
2010-10-07 20:13 ` Arnaud Ebalard
2010-10-08 0:42 ` Herbert Xu
2010-10-04 6:25 ` [PATCHv4 net-next-2.6 2/5] XFRM,IPv6: Introduce receive sockopts to access IRO remapped src/dst addresses Arnaud Ebalard
2010-10-04 6:25 ` [PATCHv4 net-next-2.6 3/5] XFRM,IPv6: Add IRO src/dst address remapping XFRM types and i/o handlers Arnaud Ebalard
2010-10-04 6:25 ` [PATCHv4 net-next-2.6 4/5] XFRM,IPv6: Add IRO remapping hook in xfrm_input() Arnaud Ebalard
2010-10-04 8:40 ` Herbert Xu
2010-10-04 20:51 ` Arnaud Ebalard
2010-10-05 6:27 ` Herbert Xu
2010-10-05 23:28 ` Arnaud Ebalard
2010-10-06 1:25 ` Herbert Xu
2010-10-06 21:42 ` Arnaud Ebalard
2010-10-04 6:25 ` [PATCHv4 net-next-2.6 5/5] XFRM,IPv6: Add IRO remapping capability via socket ancillary data path Arnaud Ebalard
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).