[PATCH net-next 4/6] xfrm: Add xfrm6 address translation function
From: Tom Herbert <hidden>
Date: 2015-09-29 22:18:02
Subsystem:
networking [general], networking [ipsec], the rest · Maintainers:
"David S. Miller", Eric Dumazet, Jakub Kicinski, Paolo Abeni, Steffen Klassert, Herbert Xu, Linus Torvalds
This patch adds xfrm6_xlat_addr which is called in the data path to perform address translation (primarily for the receive path). Modules may register their own callback to perform a translation-- this registration is managed by xfrm6_xlat_addr_add and xfrm6_xlat_addr_del. xfrm6_xlat_addr allows translation of addresses for an sk_buff. Signed-off-by: Tom Herbert <redacted> --- include/net/xfrm.h | 25 ++++++++++++++++++ net/ipv6/Kconfig | 4 +++ net/ipv6/Makefile | 1 + net/ipv6/xfrm6_policy.c | 7 +++++ net/ipv6/xfrm6_xlat_addr.c | 66 ++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 103 insertions(+) create mode 100644 net/ipv6/xfrm6_xlat_addr.c
diff --git a/include/net/xfrm.h b/include/net/xfrm.h
index fd17610..ea05c4e 100644
--- a/include/net/xfrm.h
+++ b/include/net/xfrm.h@@ -607,6 +607,31 @@ struct xfrm_mgr { int xfrm_register_km(struct xfrm_mgr *km); int xfrm_unregister_km(struct xfrm_mgr *km); +struct xfrm6_xlat_addr { + int (*xlat)(struct sk_buff *skb); + struct list_head list; +}; + +#ifdef CONFIG_INET6_XFRM_XLAT_ADDR +void xfrm6_xlat_addr_add(struct xfrm6_xlat_addr *xla); +void xfrm6_xlat_addr_del(struct xfrm6_xlat_addr *xla); +int xfrm6_xlat_addr(struct sk_buff *skb); +int xfrm6_xlat_addr_init(void); +void xfrm6_xlat_addr_fini(void); +#else +static inline int xfrm6_xlat_addr(struct sk_buff *skb) +{ + return 0; +} + +static inline int xfrm6_xlat_addr_init(void) +{ + return 0; +} + +static inline void xfrm6_xlat_addr_fini(void) { } +#endif + struct xfrm_tunnel_skb_cb { union { struct inet_skb_parm h4;
diff --git a/net/ipv6/Kconfig b/net/ipv6/Kconfig
index 983bb99..6e8ca06 100644
--- a/net/ipv6/Kconfig
+++ b/net/ipv6/Kconfig@@ -153,6 +153,10 @@ config INET6_XFRM_MODE_ROUTEOPTIMIZATION ---help--- Support for MIPv6 route optimization mode. +config INET6_XFRM_XLAT_ADDR + select XFRM + bool + config IPV6_VTI tristate "Virtual (secure) IPv6: tunneling" select IPV6_TUNNEL
diff --git a/net/ipv6/Makefile b/net/ipv6/Makefile
index 2fbd90b..c719d6f 100644
--- a/net/ipv6/Makefile
+++ b/net/ipv6/Makefile@@ -33,6 +33,7 @@ obj-$(CONFIG_INET6_XFRM_MODE_TRANSPORT) += xfrm6_mode_transport.o obj-$(CONFIG_INET6_XFRM_MODE_TUNNEL) += xfrm6_mode_tunnel.o obj-$(CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION) += xfrm6_mode_ro.o obj-$(CONFIG_INET6_XFRM_MODE_BEET) += xfrm6_mode_beet.o +obj-$(CONFIG_INET6_XFRM_XLAT_ADDR) += xfrm6_xlat_addr.o obj-$(CONFIG_IPV6_MIP6) += mip6.o obj-$(CONFIG_IPV6_ILA) += ila/ obj-$(CONFIG_NETFILTER) += netfilter/
diff --git a/net/ipv6/xfrm6_policy.c b/net/ipv6/xfrm6_policy.c
index 30caa28..81b9079 100644
--- a/net/ipv6/xfrm6_policy.c
+++ b/net/ipv6/xfrm6_policy.c@@ -390,11 +390,17 @@ int __init xfrm6_init(void) if (ret) goto out_state; + ret = xfrm6_xlat_addr_init(); + if (ret) + goto out_protocol; + #ifdef CONFIG_SYSCTL register_pernet_subsys(&xfrm6_net_ops); #endif out: return ret; +out_protocol: + xfrm6_protocol_fini(); out_state: xfrm6_state_fini(); out_policy:
@@ -407,6 +413,7 @@ void xfrm6_fini(void) #ifdef CONFIG_SYSCTL unregister_pernet_subsys(&xfrm6_net_ops); #endif + xfrm6_xlat_addr_fini(); xfrm6_protocol_fini(); xfrm6_policy_fini(); xfrm6_state_fini();
diff --git a/net/ipv6/xfrm6_xlat_addr.c b/net/ipv6/xfrm6_xlat_addr.c
new file mode 100644
index 0000000..dd2199a
--- /dev/null
+++ b/net/ipv6/xfrm6_xlat_addr.c@@ -0,0 +1,66 @@ +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/skbuff.h> +#include <net/ipv6.h> +#include <net/xfrm.h> + +static struct list_head xfrm6_xlat_addr_head __read_mostly; +static DEFINE_SPINLOCK(xfrm6_xlat_addr_lock); + +void xfrm6_xlat_addr_add(struct xfrm6_xlat_addr *xla) +{ + spin_lock(&xfrm6_xlat_addr_lock); + list_add_rcu(&xla->list, &xfrm6_xlat_addr_head); + spin_unlock(&xfrm6_xlat_addr_lock); +} +EXPORT_SYMBOL(xfrm6_xlat_addr_add); + +void xfrm6_xlat_addr_del(struct xfrm6_xlat_addr *xla) +{ + struct xfrm6_xlat_addr *tmp; + + spin_lock(&xfrm6_xlat_addr_lock); + + list_for_each_entry_rcu(tmp, &xfrm6_xlat_addr_head, list) { + if (xla == tmp) { + list_del_rcu(&xla->list); + goto out; + } + } + + pr_warn("xfrm6_xlat_addr_del: %p not found\n", xla); +out: + spin_unlock(&xfrm6_xlat_addr_lock); +} +EXPORT_SYMBOL(xfrm6_xlat_addr_del); + +int xfrm6_xlat_addr(struct sk_buff *skb) +{ + struct xfrm6_xlat_addr *xla; + int err = 0; + + rcu_read_lock(); + + list_for_each_entry_rcu(xla, &xfrm6_xlat_addr_head, list) { + err = xla->xlat(skb); + if (err < 0) + break; + } + + rcu_read_unlock(); + + return err; +} +EXPORT_SYMBOL(xfrm6_xlat_addr); + +int __init xfrm6_xlat_addr_init(void) +{ + INIT_LIST_HEAD(&xfrm6_xlat_addr_head); + + return 0; +} + +void xfrm6_xlat_addr_fini(void) +{ +} +
--
2.4.6