* [PATCH net-next 1/7] net: Export inet_offloads and inet6_offloads
2014-09-11 20:07 [PATCH net-next 0/7] net: foo-over-udp (fou) Tom Herbert
@ 2014-09-11 20:07 ` Tom Herbert
2014-09-11 20:07 ` [PATCH net-next 2/7] fou: Support for foo-over-udp RX path Tom Herbert
` (5 subsequent siblings)
6 siblings, 0 replies; 10+ messages in thread
From: Tom Herbert @ 2014-09-11 20:07 UTC (permalink / raw)
To: davem, netdev
Want to be able to call this in foo-over-udp offloads, etc.
Signed-off-by: Tom Herbert <therbert@google.com>
---
net/ipv4/protocol.c | 1 +
net/ipv6/protocol.c | 1 +
2 files changed, 2 insertions(+)
diff --git a/net/ipv4/protocol.c b/net/ipv4/protocol.c
index 46d6a1c..4b7c0ec 100644
--- a/net/ipv4/protocol.c
+++ b/net/ipv4/protocol.c
@@ -30,6 +30,7 @@
const struct net_protocol __rcu *inet_protos[MAX_INET_PROTOS] __read_mostly;
const struct net_offload __rcu *inet_offloads[MAX_INET_PROTOS] __read_mostly;
+EXPORT_SYMBOL(inet_offloads);
int inet_add_protocol(const struct net_protocol *prot, unsigned char protocol)
{
diff --git a/net/ipv6/protocol.c b/net/ipv6/protocol.c
index e048cf1..e3770ab 100644
--- a/net/ipv6/protocol.c
+++ b/net/ipv6/protocol.c
@@ -51,6 +51,7 @@ EXPORT_SYMBOL(inet6_del_protocol);
#endif
const struct net_offload __rcu *inet6_offloads[MAX_INET_PROTOS] __read_mostly;
+EXPORT_SYMBOL(inet6_offloads);
int inet6_add_offload(const struct net_offload *prot, unsigned char protocol)
{
--
2.1.0.rc2.206.gedb03e5
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH net-next 2/7] fou: Support for foo-over-udp RX path
2014-09-11 20:07 [PATCH net-next 0/7] net: foo-over-udp (fou) Tom Herbert
2014-09-11 20:07 ` [PATCH net-next 1/7] net: Export inet_offloads and inet6_offloads Tom Herbert
@ 2014-09-11 20:07 ` Tom Herbert
2014-09-13 17:09 ` David Miller
2014-09-11 20:07 ` [PATCH net-next 3/7] fou: Add GRO support Tom Herbert
` (4 subsequent siblings)
6 siblings, 1 reply; 10+ messages in thread
From: Tom Herbert @ 2014-09-11 20:07 UTC (permalink / raw)
To: davem, netdev
This patch provides a receive path for foo-over-udp. This allows
direct encapsulation of IP protocols over UDP. The bound destination
port is used to map to an IP protocol, and the XFRM framework
(udp_encap_rcv) is used to receive encapsulated packets. Upon
reception, the encapsulation header is logically removed (pointer
to transport header is advanced) and the packet is reinjected into
the receive path with the IP protocol indicated by the mapping.
Netlink is used to configure FOU ports. The configuration information
includes the port number to bind to and the IP protocol corresponding
to that port.
This should support GRE/UDP
(http://tools.ietf.org/html/draft-yong-tsvwg-gre-in-udp-encap-02),
as will as the other IP tunneling protocols (IPIP, SIT).
Signed-off-by: Tom Herbert <therbert@google.com>
---
include/net/fou.h | 31 ++++++
include/uapi/linux/fou.h | 34 ++++++
net/ipv4/Kconfig | 10 ++
net/ipv4/Makefile | 1 +
net/ipv4/fou.c | 274 +++++++++++++++++++++++++++++++++++++++++++++++
5 files changed, 350 insertions(+)
create mode 100644 include/net/fou.h
create mode 100644 include/uapi/linux/fou.h
create mode 100644 net/ipv4/fou.c
diff --git a/include/net/fou.h b/include/net/fou.h
new file mode 100644
index 0000000..509cd61
--- /dev/null
+++ b/include/net/fou.h
@@ -0,0 +1,31 @@
+#ifndef __NET_FOU_H
+#define __NET_FOU_H
+
+#include <net/udp_tunnel.h>
+
+struct fou_cfg {
+ u8 protocol;
+ struct udp_port_cfg udp_config;
+};
+
+#if defined(CONFIG_NET_FOU) || defined(CONFIG_NET_FOU_MODULE)
+
+int fou_create(struct net *net, struct fou_cfg *cfg,
+ struct socket **sockp);
+int fou_destroy(struct net *net, struct fou_cfg *cfg);
+
+#else
+static inline int fou_create(struct net *net, struct fou_cfg *cfg,
+ struct socket **sockp)
+{
+ return 0;
+}
+
+static inline int fou_destroy(struct net *net, struct fou_cfg *cfg)
+{
+ return 0;
+}
+
+#endif
+
+#endif /* __NET_FOU_H */
diff --git a/include/uapi/linux/fou.h b/include/uapi/linux/fou.h
new file mode 100644
index 0000000..f1a756b
--- /dev/null
+++ b/include/uapi/linux/fou.h
@@ -0,0 +1,34 @@
+/* fou.h - FOU Interface */
+
+#ifndef _UAPI_LINUX_FOU_H
+#define _UAPI_LINUX_FOU_H
+
+#include <linux/types.h>
+
+/* NETLINK_GENERIC related info
+ */
+#define FOU_GENL_NAME "fou"
+#define FOU_GENL_VERSION 0x1
+
+enum {
+ FOU_ATTR_UNSPEC,
+ FOU_ATTR_PORT, /* u16 */
+ FOU_ATTR_AF, /* u8 */
+ FOU_ATTR_IPPROTO, /* u8 */
+
+ __FOU_ATTR_MAX,
+};
+
+#define FOU_ATTR_MAX (__FOU_ATTR_MAX - 1)
+
+enum {
+ FOU_CMD_UNSPEC,
+ FOU_CMD_ADD,
+ FOU_CMD_DEL,
+
+ __FOU_CMD_MAX,
+};
+
+#define FOU_CMD_MAX (__FOU_CMD_MAX - 1)
+
+#endif /* _UAPI_LINUX_FOU_H */
diff --git a/net/ipv4/Kconfig b/net/ipv4/Kconfig
index dbc10d8..84f710b 100644
--- a/net/ipv4/Kconfig
+++ b/net/ipv4/Kconfig
@@ -311,6 +311,16 @@ config NET_UDP_TUNNEL
tristate
default n
+config NET_FOU
+ tristate "IP: Foo (IP protocols) over UDP"
+ select XFRM
+ select NET_UDP_TUNNEL
+ ---help---
+ Foo over UDP allows any IP protocol to be directly encapsulated
+ over UDP include tunnels (IPIP, GRE, SIT). By encapsulating in UDP
+ network mechanisms and optimizations for UDP (such as ECMP
+ and RSS) can be leveraged to provide better service.
+
config INET_AH
tristate "IP: AH transformation"
select XFRM_ALGO
diff --git a/net/ipv4/Makefile b/net/ipv4/Makefile
index 8ee1cd4..d78d404 100644
--- a/net/ipv4/Makefile
+++ b/net/ipv4/Makefile
@@ -20,6 +20,7 @@ obj-$(CONFIG_IP_MULTIPLE_TABLES) += fib_rules.o
obj-$(CONFIG_IP_MROUTE) += ipmr.o
obj-$(CONFIG_NET_IPIP) += ipip.o
gre-y := gre_demux.o
+obj-$(CONFIG_NET_FOU) += fou.o
obj-$(CONFIG_NET_IPGRE_DEMUX) += gre.o
obj-$(CONFIG_NET_IPGRE) += ip_gre.o
obj-$(CONFIG_NET_UDP_TUNNEL) += udp_tunnel.o
diff --git a/net/ipv4/fou.c b/net/ipv4/fou.c
new file mode 100644
index 0000000..f69df75
--- /dev/null
+++ b/net/ipv4/fou.c
@@ -0,0 +1,274 @@
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/socket.h>
+#include <linux/skbuff.h>
+#include <linux/ip.h>
+#include <linux/udp.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <net/fou.h>
+#include <net/genetlink.h>
+#include <net/ip.h>
+#include <net/udp.h>
+#include <net/xfrm.h>
+#include <uapi/linux/fou.h>
+#include <uapi/linux/genetlink.h>
+
+static DEFINE_SPINLOCK(fou_lock);
+static LIST_HEAD(fou_list);
+
+struct fou {
+ struct socket *sock;
+ u8 protocol;
+ u16 port;
+ struct list_head list;
+};
+
+static inline struct fou *fou_from_sock(struct sock *sk)
+{
+ return (struct fou *)sk->sk_user_data;
+}
+
+static int fou_udp_encap_recv_deliver(struct sk_buff *skb,
+ u8 protocol, size_t len)
+{
+ struct iphdr *iph = ip_hdr(skb);
+
+ /* Remove 'len' bytes from the packet (UDP header and
+ * FOU header if present), modify the protocol to the one
+ * we found, and then call rcv_encap.
+ */
+ iph->tot_len = htons(ntohs(iph->tot_len) - len);
+ __skb_pull(skb, len);
+ skb_postpull_rcsum(skb, udp_hdr(skb), len);
+ skb_reset_transport_header(skb);
+
+ return -protocol;
+}
+
+static int fou_udp_recv(struct sock *sk, struct sk_buff *skb)
+{
+ struct fou *fou = fou_from_sock(sk);
+
+ if (!fou)
+ return 1;
+
+ return fou_udp_encap_recv_deliver(skb, fou->protocol,
+ sizeof(struct udphdr));
+}
+
+static int fou_add_to_port_list(struct fou *fou)
+{
+ struct fou *fout;
+
+ spin_lock(&fou_lock);
+ list_for_each_entry(fout, &fou_list, list) {
+ if (fou->port == fout->port) {
+ spin_unlock(&fou_lock);
+ return -EALREADY;
+ }
+ }
+
+ list_add(&fou->list, &fou_list);
+ spin_unlock(&fou_lock);
+
+ return 0;
+}
+
+static void fou_release(struct fou *fou)
+{
+ struct socket *sock = fou->sock;
+ struct sock *sk = sock->sk;
+
+ udp_del_offload(&fou->udp_offloads);
+
+ list_del(&fou->list);
+
+ /* Remove hooks into tunnel socket */
+ sk->sk_user_data = NULL;
+
+ sock_release(sock);
+
+ kfree(fou);
+}
+
+int fou_create(struct net *net, struct fou_cfg *cfg,
+ struct socket **sockp)
+{
+ struct fou *fou = NULL;
+ int err;
+ struct socket *sock = NULL;
+ struct sock *sk;
+
+ /* Open UDP socket */
+ err = udp_sock_create(net, &cfg->udp_config, &sock);
+ if (err < 0)
+ goto error;
+
+ sk = sock->sk;
+
+ /* Allocate FOU port structure */
+ fou = kzalloc(sizeof(*fou), GFP_KERNEL);
+ if (!fou) {
+ err = -ENOMEM;
+ goto error;
+ }
+
+ /* Mark socket as an encapsulation socket. See net/ipv4/udp.c */
+ fou->protocol = cfg->protocol;
+ fou->port = cfg->udp_config.local_udp_port;
+ udp_sk(sk)->encap_rcv = fou_udp_recv;
+
+ udp_sk(sk)->encap_type = 1;
+ udp_encap_enable();
+
+ sk->sk_user_data = fou;
+ fou->sock = sock;
+
+ udp_set_convert_csum(sock->sk, true);
+
+ sk->sk_allocation = GFP_ATOMIC;
+
+ err = fou_add_to_port_list(fou);
+ if (err)
+ goto error;
+
+ if (sockp)
+ *sockp = sock;
+
+ return 0;
+
+error:
+ kfree(fou);
+ if (sock)
+ sock_release(sock);
+
+ return err;
+}
+EXPORT_SYMBOL_GPL(fou_create);
+
+int fou_destroy(struct net *net, struct fou_cfg *cfg)
+{
+ struct fou *fou;
+ u16 port = htons(cfg->udp_config.local_udp_port);
+ int err = -EINVAL;
+
+ spin_lock(&fou_lock);
+ list_for_each_entry(fou, &fou_list, list) {
+ if (fou->port == port) {
+ fou_release(fou);
+ err = 0;
+ break;
+ }
+ }
+ spin_unlock(&fou_lock);
+
+ return err;
+}
+EXPORT_SYMBOL_GPL(fou_destroy);
+
+static struct genl_family fou_nl_family = {
+ .id = GENL_ID_GENERATE,
+ .hdrsize = 0,
+ .name = FOU_GENL_NAME,
+ .version = FOU_GENL_VERSION,
+ .maxattr = FOU_ATTR_MAX,
+ .netnsok = true,
+};
+
+static struct nla_policy fou_nl_policy[FOU_ATTR_MAX + 1] = {
+ [FOU_ATTR_PORT] = { .type = NLA_U16, },
+ [FOU_ATTR_AF] = { .type = NLA_U8, },
+ [FOU_ATTR_IPPROTO] = { .type = NLA_U8, },
+};
+
+static int parse_nl_config(struct genl_info *info,
+ struct fou_cfg *cfg)
+{
+ memset(cfg, 0, sizeof(*cfg));
+
+ cfg->udp_config.family = AF_INET;
+
+ if (info->attrs[FOU_ATTR_AF]) {
+ u8 family = nla_get_u8(info->attrs[FOU_ATTR_AF]);
+
+ if (family != AF_INET && family != AF_INET6)
+ return -EINVAL;
+
+ cfg->udp_config.family = family;
+ }
+
+ if (info->attrs[FOU_ATTR_PORT]) {
+ u16 port = nla_get_u16(info->attrs[FOU_ATTR_PORT]);
+
+ cfg->udp_config.local_udp_port = port;
+ }
+
+ if (info->attrs[FOU_ATTR_IPPROTO])
+ cfg->protocol = nla_get_u8(info->attrs[FOU_ATTR_IPPROTO]);
+}
+
+static int fou_nl_cmd_add_port(struct sk_buff *skb, struct genl_info *info)
+{
+ struct fou_cfg cfg;
+ int err;
+
+ err = parse_nl_config(info, &cfg);
+ if (err)
+ return err;
+
+ return fou_create(&init_net, &cfg, NULL);
+}
+
+static int fou_nl_cmd_rm_port(struct sk_buff *skb, struct genl_info *info)
+{
+ struct fou_cfg cfg;
+
+ parse_nl_config(info, &cfg);
+
+ return fou_destroy(&init_net, &cfg);
+}
+
+static const struct genl_ops fou_nl_ops[] = {
+ {
+ .cmd = FOU_CMD_ADD,
+ .doit = fou_nl_cmd_add_port,
+ .policy = fou_nl_policy,
+ .flags = GENL_ADMIN_PERM,
+ },
+ {
+ .cmd = FOU_CMD_DEL,
+ .doit = fou_nl_cmd_rm_port,
+ .policy = fou_nl_policy,
+ .flags = GENL_ADMIN_PERM,
+ },
+};
+
+static int __init fou_init(void)
+{
+ int ret;
+
+ ret = genl_register_family_with_ops(&fou_nl_family,
+ fou_nl_ops);
+
+ return ret;
+}
+
+static void __exit fou_fini(void)
+{
+ struct fou *fou, *next;
+
+ genl_unregister_family(&fou_nl_family);
+
+ /* Close all the FOU sockets */
+
+ spin_lock(&fou_lock);
+ list_for_each_entry_safe(fou, next, &fou_list, list)
+ fou_release(fou);
+ spin_unlock(&fou_lock);
+}
+
+module_init(fou_init);
+module_exit(fou_fini);
+MODULE_AUTHOR("Tom Herbert <therbert@google.com>");
+MODULE_LICENSE("GPL");
--
2.1.0.rc2.206.gedb03e5
^ permalink raw reply related [flat|nested] 10+ messages in thread
* Re: [PATCH net-next 2/7] fou: Support for foo-over-udp RX path
2014-09-11 20:07 ` [PATCH net-next 2/7] fou: Support for foo-over-udp RX path Tom Herbert
@ 2014-09-13 17:09 ` David Miller
0 siblings, 0 replies; 10+ messages in thread
From: David Miller @ 2014-09-13 17:09 UTC (permalink / raw)
To: therbert; +Cc: netdev
From: Tom Herbert <therbert@google.com>
Date: Thu, 11 Sep 2014 13:07:31 -0700
> +#if defined(CONFIG_NET_FOU) || defined(CONFIG_NET_FOU_MODULE)
"IS_ENABLED(NET_FOU)"
> +int fou_create(struct net *net, struct fou_cfg *cfg,
> + struct socket **sockp);
> +int fou_destroy(struct net *net, struct fou_cfg *cfg);
> +
> +#else
> +static inline int fou_create(struct net *net, struct fou_cfg *cfg,
> + struct socket **sockp)
> +{
> + return 0;
> +}
> +
> +static inline int fou_destroy(struct net *net, struct fou_cfg *cfg)
> +{
> + return 0;
> +}
> +
> +#endif
I see no uses of fou_{create,destroy}() outside of net/ipv4/fou.c which
is only built when NET_FOU is enabled.
Yet you have NOP helpers (which probably should be returning an error
instead of 0) and export the symbol, both of which seem unnecessary.
^ permalink raw reply [flat|nested] 10+ messages in thread
* [PATCH net-next 3/7] fou: Add GRO support
2014-09-11 20:07 [PATCH net-next 0/7] net: foo-over-udp (fou) Tom Herbert
2014-09-11 20:07 ` [PATCH net-next 1/7] net: Export inet_offloads and inet6_offloads Tom Herbert
2014-09-11 20:07 ` [PATCH net-next 2/7] fou: Support for foo-over-udp RX path Tom Herbert
@ 2014-09-11 20:07 ` Tom Herbert
2014-09-11 20:07 ` [PATCH net-next 4/7] net: Changes to ip_tunnel to support foo-over-udp encapsulation Tom Herbert
` (3 subsequent siblings)
6 siblings, 0 replies; 10+ messages in thread
From: Tom Herbert @ 2014-09-11 20:07 UTC (permalink / raw)
To: davem, netdev
Implement fou_gro_receive and fou_gro_complete, and populate these
in the corresponding udp_offloads for the socket. Added ipproto to
udp_offloads and pass this from UDP to the fou GRO routine in proto
field of napi_gro_cb structure.
Signed-off-by: Tom Herbert <therbert@google.com>
---
include/linux/netdevice.h | 3 +-
net/ipv4/fou.c | 92 +++++++++++++++++++++++++++++++++++++++++++++++
net/ipv4/udp_offload.c | 5 ++-
3 files changed, 98 insertions(+), 2 deletions(-)
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index ba72f6b..a195e11 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -1874,7 +1874,7 @@ struct napi_gro_cb {
/* jiffies when first packet was created/queued */
unsigned long age;
- /* Used in ipv6_gro_receive() */
+ /* Used in ipv6_gro_receive() and foo-over-udp */
u16 proto;
/* Used in udp_gro_receive */
@@ -1925,6 +1925,7 @@ struct packet_offload {
struct udp_offload {
__be16 port;
+ u8 ipproto;
struct offload_callbacks callbacks;
};
diff --git a/net/ipv4/fou.c b/net/ipv4/fou.c
index f69df75..41b692c 100644
--- a/net/ipv4/fou.c
+++ b/net/ipv4/fou.c
@@ -9,6 +9,7 @@
#include <net/fou.h>
#include <net/genetlink.h>
#include <net/ip.h>
+#include <net/protocol.h>
#include <net/udp.h>
#include <net/xfrm.h>
#include <uapi/linux/fou.h>
@@ -21,6 +22,7 @@ struct fou {
struct socket *sock;
u8 protocol;
u16 port;
+ struct udp_offload udp_offloads;
struct list_head list;
};
@@ -57,6 +59,70 @@ static int fou_udp_recv(struct sock *sk, struct sk_buff *skb)
sizeof(struct udphdr));
}
+static inline struct sk_buff **fou_gro_receive(struct sk_buff **head,
+ struct sk_buff *skb,
+ const struct net_offload
+ **offloads)
+{
+ const struct net_offload *ops;
+ struct sk_buff **pp = NULL;
+ u8 proto = NAPI_GRO_CB(skb)->proto;
+
+ rcu_read_lock();
+ ops = rcu_dereference(offloads[proto]);
+ if (!ops || !ops->callbacks.gro_receive)
+ goto out_unlock;
+
+ pp = ops->callbacks.gro_receive(head, skb);
+
+out_unlock:
+ rcu_read_unlock();
+
+ return pp;
+}
+
+static inline int fou_gro_complete(struct sk_buff *skb, int nhoff,
+ const struct net_offload **offloads)
+{
+ const struct net_offload *ops;
+ u8 proto = NAPI_GRO_CB(skb)->proto;
+ int err = -ENOSYS;
+
+ rcu_read_lock();
+ ops = rcu_dereference(offloads[proto]);
+ if (WARN_ON(!ops || !ops->callbacks.gro_complete))
+ goto out_unlock;
+
+ err = ops->callbacks.gro_complete(skb, nhoff);
+
+out_unlock:
+ rcu_read_unlock();
+
+ return err;
+}
+
+static struct sk_buff **fou4_gro_receive(struct sk_buff **head,
+ struct sk_buff *skb)
+{
+ return fou_gro_receive(head, skb, inet_offloads);
+}
+
+static int fou4_gro_complete(struct sk_buff *skb, int nhoff)
+{
+ return fou_gro_complete(skb, nhoff, inet_offloads);
+}
+
+static struct sk_buff **fou6_gro_receive(struct sk_buff **head,
+ struct sk_buff *skb)
+{
+ return fou_gro_receive(head, skb, inet6_offloads);
+}
+
+static int fou6_gro_complete(struct sk_buff *skb, int nhoff)
+{
+ return fou_gro_complete(skb, nhoff, inet6_offloads);
+}
+
static int fou_add_to_port_list(struct fou *fou)
{
struct fou *fout;
@@ -129,6 +195,29 @@ int fou_create(struct net *net, struct fou_cfg *cfg,
sk->sk_allocation = GFP_ATOMIC;
+ switch (cfg->udp_config.family) {
+ case AF_INET:
+ fou->udp_offloads.callbacks.gro_receive = fou4_gro_receive;
+ fou->udp_offloads.callbacks.gro_complete = fou4_gro_complete;
+ break;
+ case AF_INET6:
+ fou->udp_offloads.callbacks.gro_receive = fou6_gro_receive;
+ fou->udp_offloads.callbacks.gro_complete = fou6_gro_complete;
+ break;
+ default:
+ err = -EPFNOSUPPORT;
+ goto error;
+ }
+
+ fou->udp_offloads.port = cfg->udp_config.local_udp_port;
+ fou->udp_offloads.ipproto = cfg->protocol;
+
+ if (cfg->udp_config.family == AF_INET) {
+ err = udp_add_offload(&fou->udp_offloads);
+ if (err)
+ goto error;
+ }
+
err = fou_add_to_port_list(fou);
if (err)
goto error;
@@ -156,6 +245,7 @@ int fou_destroy(struct net *net, struct fou_cfg *cfg)
spin_lock(&fou_lock);
list_for_each_entry(fou, &fou_list, list) {
if (fou->port == port) {
+ udp_del_offload(&fou->udp_offloads);
fou_release(fou);
err = 0;
break;
@@ -206,6 +296,8 @@ static int parse_nl_config(struct genl_info *info,
if (info->attrs[FOU_ATTR_IPPROTO])
cfg->protocol = nla_get_u8(info->attrs[FOU_ATTR_IPPROTO]);
+
+ return 0;
}
static int fou_nl_cmd_add_port(struct sk_buff *skb, struct genl_info *info)
diff --git a/net/ipv4/udp_offload.c b/net/ipv4/udp_offload.c
index 52d5f46..18b7d69 100644
--- a/net/ipv4/udp_offload.c
+++ b/net/ipv4/udp_offload.c
@@ -276,6 +276,7 @@ unflush:
skb_gro_pull(skb, sizeof(struct udphdr)); /* pull encapsulating udp header */
skb_gro_postpull_rcsum(skb, uh, sizeof(struct udphdr));
+ NAPI_GRO_CB(skb)->proto = uo_priv->offload->ipproto;
pp = uo_priv->offload->callbacks.gro_receive(head, skb);
out_unlock:
@@ -329,8 +330,10 @@ int udp_gro_complete(struct sk_buff *skb, int nhoff)
break;
}
- if (uo_priv != NULL)
+ if (uo_priv != NULL) {
+ NAPI_GRO_CB(skb)->proto = uo_priv->offload->ipproto;
err = uo_priv->offload->callbacks.gro_complete(skb, nhoff + sizeof(struct udphdr));
+ }
rcu_read_unlock();
return err;
--
2.1.0.rc2.206.gedb03e5
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH net-next 4/7] net: Changes to ip_tunnel to support foo-over-udp encapsulation
2014-09-11 20:07 [PATCH net-next 0/7] net: foo-over-udp (fou) Tom Herbert
` (2 preceding siblings ...)
2014-09-11 20:07 ` [PATCH net-next 3/7] fou: Add GRO support Tom Herbert
@ 2014-09-11 20:07 ` Tom Herbert
2014-09-13 17:09 ` David Miller
2014-09-11 20:07 ` [PATCH net-next 5/7] sit: TX path for sit/UDP " Tom Herbert
` (2 subsequent siblings)
6 siblings, 1 reply; 10+ messages in thread
From: Tom Herbert @ 2014-09-11 20:07 UTC (permalink / raw)
To: davem, netdev
This patch changes IP tunnel to support (secondary) encapsulation,
Foo-over-UDP. Changes include:
1) Adding tun_hlen as the tunnel header length, encap_hlen as the
encapsulation header length, and hlen becomes the grand total
of these.
2) Added generic function to handle IOCTLs
3) Added IOCTLs to setup or remove encapsulation. This includes
uapi to configure encapsulation on a tunnel.
4) Support to perform FOU encapsulation in ip_tunnel_xmit.
encap tunnel.
Signed-off-by: Tom Herbert <therbert@google.com>
---
include/net/ip_tunnels.h | 25 +++++-
include/uapi/linux/if_tunnel.h | 23 ++++++
net/ipv4/ip_tunnel.c | 177 ++++++++++++++++++++++++++++++++++++++++-
3 files changed, 223 insertions(+), 2 deletions(-)
diff --git a/include/net/ip_tunnels.h b/include/net/ip_tunnels.h
index 8dd8cab..34f567d 100644
--- a/include/net/ip_tunnels.h
+++ b/include/net/ip_tunnels.h
@@ -10,6 +10,7 @@
#include <net/gro_cells.h>
#include <net/inet_ecn.h>
#include <net/ip.h>
+#include <net/netns/generic.h>
#include <net/rtnetlink.h>
#if IS_ENABLED(CONFIG_IPV6)
@@ -56,13 +57,18 @@ struct ip_tunnel {
/* These four fields used only by GRE */
__u32 i_seqno; /* The last seen seqno */
__u32 o_seqno; /* The last output seqno */
- int hlen; /* Precalculated header length */
+ int tun_hlen; /* Precalculated header length */
int mlink;
struct ip_tunnel_dst __percpu *dst_cache;
struct ip_tunnel_parm parms;
+ int encap_hlen; /* Encap header length (FOU,GUE) */
+ struct ip_tunnel_encap encap;
+
+ int hlen; /* tun_hlen + encap_hlen */
+
/* for SIT */
#ifdef CONFIG_IPV6_SIT_6RD
struct ip_tunnel_6rd_parm ip6rd;
@@ -114,6 +120,21 @@ void ip_tunnel_delete_net(struct ip_tunnel_net *itn, struct rtnl_link_ops *ops);
void ip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev,
const struct iphdr *tnl_params, const u8 protocol);
int ip_tunnel_ioctl(struct net_device *dev, struct ip_tunnel_parm *p, int cmd);
+int __ip_tunnel_gen_ioctl(struct net_device *dev, struct net_device *tundev,
+ struct ifreq *ifr, int cmd);
+int ip_tunnel_encap(struct sk_buff *skb, struct ip_tunnel *t,
+ u8 *protocol, struct flowi4 *fl4);
+
+static inline int ip_tunnel_gen_ioctl(struct net_device *dev,
+ struct ifreq *ifr, int cmd)
+{
+ struct net *net = dev_net(dev);
+ struct ip_tunnel *tunnel = netdev_priv(dev);
+ struct ip_tunnel_net *itn = net_generic(net, tunnel->ip_tnl_net_id);
+
+ return __ip_tunnel_gen_ioctl(dev, itn->fb_tunnel_dev, ifr, cmd);
+}
+
int ip_tunnel_change_mtu(struct net_device *dev, int new_mtu);
struct rtnl_link_stats64 *ip_tunnel_get_stats64(struct net_device *dev,
@@ -131,6 +152,8 @@ int ip_tunnel_newlink(struct net_device *dev, struct nlattr *tb[],
struct ip_tunnel_parm *p);
void ip_tunnel_setup(struct net_device *dev, int net_id);
void ip_tunnel_dst_reset_all(struct ip_tunnel *t);
+int ip_tunnel_encap_setup(struct ip_tunnel *t,
+ struct ip_tunnel_encap *ipencap);
/* Extract dsfield from inner protocol */
static inline u8 ip_tunnel_get_dsfield(const struct iphdr *iph,
diff --git a/include/uapi/linux/if_tunnel.h b/include/uapi/linux/if_tunnel.h
index 3bce9e9..4369b62 100644
--- a/include/uapi/linux/if_tunnel.h
+++ b/include/uapi/linux/if_tunnel.h
@@ -17,6 +17,10 @@
#define SIOCADD6RD (SIOCDEVPRIVATE + 9)
#define SIOCDEL6RD (SIOCDEVPRIVATE + 10)
#define SIOCCHG6RD (SIOCDEVPRIVATE + 11)
+#define SIOCGETTUNENCAP (SIOCDEVPRIVATE + 12)
+#define SIOCADDTUNENCAP (SIOCDEVPRIVATE + 13)
+#define SIOCDELTUNENCAP (SIOCDEVPRIVATE + 14)
+#define SIOCCHGTUNENCAP (SIOCDEVPRIVATE + 15)
#define GRE_CSUM __cpu_to_be16(0x8000)
#define GRE_ROUTING __cpu_to_be16(0x4000)
@@ -53,10 +57,29 @@ enum {
IFLA_IPTUN_6RD_RELAY_PREFIX,
IFLA_IPTUN_6RD_PREFIXLEN,
IFLA_IPTUN_6RD_RELAY_PREFIXLEN,
+ IFLA_IPTUN_ENCAP_TYPE,
+ IFLA_IPTUN_ENCAP_FLAGS,
+ IFLA_IPTUN_ENCAP_SPORT,
+ IFLA_IPTUN_ENCAP_DPORT,
__IFLA_IPTUN_MAX,
};
#define IFLA_IPTUN_MAX (__IFLA_IPTUN_MAX - 1)
+enum tunnel_encap_types {
+ TUNNEL_ENCAP_NONE,
+ TUNNEL_ENCAP_FOU,
+};
+
+#define TUNNEL_ENCAP_FLAG_CSUM (1<<0)
+#define TUNNEL_ENCAP_FLAG_CSUM6 (1<<1)
+
+
+struct ip_tunnel_encap {
+ __u16 type;
+ __u16 flags;
+ __be16 sport;
+ __be16 dport;
+};
/* SIT-mode i_flags */
#define SIT_ISATAP 0x0001
diff --git a/net/ipv4/ip_tunnel.c b/net/ipv4/ip_tunnel.c
index afed1aa..c12f9d7 100644
--- a/net/ipv4/ip_tunnel.c
+++ b/net/ipv4/ip_tunnel.c
@@ -55,6 +55,7 @@
#include <net/net_namespace.h>
#include <net/netns/generic.h>
#include <net/rtnetlink.h>
+#include <net/udp.h>
#if IS_ENABLED(CONFIG_IPV6)
#include <net/ipv6.h>
@@ -487,6 +488,177 @@ drop:
}
EXPORT_SYMBOL_GPL(ip_tunnel_rcv);
+static int ip_encap_hlen(struct ip_tunnel_encap *e)
+{
+ switch (e->type) {
+ case TUNNEL_ENCAP_NONE:
+ return 0;
+ case TUNNEL_ENCAP_FOU:
+ return sizeof(struct udphdr);
+ default:
+ return -EINVAL;
+ }
+}
+
+int ip_tunnel_encap_setup(struct ip_tunnel *t,
+ struct ip_tunnel_encap *ipencap)
+{
+ int hlen;
+
+ memset(&t->encap, 0, sizeof(t->encap));
+
+ hlen = ip_encap_hlen(ipencap);
+ if (hlen < 0)
+ return hlen;
+
+ t->encap.type = ipencap->type;
+ t->encap.sport = ipencap->sport;
+ t->encap.dport = ipencap->dport;
+ t->encap.flags = ipencap->flags;
+
+ t->encap_hlen = hlen;
+ t->hlen = t->encap_hlen + t->tun_hlen;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(ip_tunnel_encap_setup);
+
+static int fou_build_header(struct sk_buff *skb, struct ip_tunnel_encap *e,
+ size_t hdr_len, u8 *protocol, struct flowi4 *fl4)
+{
+ struct udphdr *uh;
+ __be16 sport;
+ bool csum = !!(e->flags & TUNNEL_ENCAP_FLAG_CSUM);
+ int type = csum ? SKB_GSO_UDP_TUNNEL_CSUM : SKB_GSO_UDP_TUNNEL;
+
+ skb = iptunnel_handle_offloads(skb, csum, type);
+
+ if (IS_ERR(skb))
+ return PTR_ERR(skb);
+
+ /* Get length and hash before making space in skb */
+
+ sport = e->sport ? : udp_flow_src_port(dev_net(skb->dev),
+ skb, 0, 0, false);
+
+ skb_push(skb, hdr_len);
+
+ skb_reset_transport_header(skb);
+ uh = udp_hdr(skb);
+
+ uh->dest = e->dport;
+ uh->source = sport;
+ uh->len = htons(skb->len);
+ uh->check = 0;
+ udp_set_csum(!(e->flags & TUNNEL_ENCAP_FLAG_CSUM), skb,
+ fl4->saddr, fl4->daddr, skb->len);
+
+ *protocol = IPPROTO_UDP;
+
+ return 0;
+}
+
+int ip_tunnel_encap(struct sk_buff *skb, struct ip_tunnel *t,
+ u8 *protocol, struct flowi4 *fl4)
+{
+ switch (t->encap.type) {
+ case TUNNEL_ENCAP_NONE:
+ return 0;
+ case TUNNEL_ENCAP_FOU:
+ return fou_build_header(skb, &t->encap, t->encap_hlen,
+ protocol, fl4);
+ default:
+ return -EINVAL;
+ }
+}
+EXPORT_SYMBOL(ip_tunnel_encap);
+
+int __ip_tunnel_gen_ioctl(struct net_device *dev, struct net_device *tundev,
+ struct ifreq *ifr, int cmd)
+{
+ int err = 0;
+ struct ip_tunnel *t;
+ struct net *net = dev_net(dev);
+ size_t hlen;
+ struct ip_tunnel_encap e;
+
+ switch (cmd) {
+ case SIOCGETTUNENCAP:
+ if (dev == tundev)
+ return -EINVAL;
+
+ t = netdev_priv(dev);
+ if (!t)
+ return -ENOENT;
+
+ if (copy_to_user(ifr->ifr_ifru.ifru_data, &t->encap,
+ sizeof(t->encap)))
+ err = -EFAULT;
+ break;
+
+ case SIOCDELTUNENCAP:
+ if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
+ return -EPERM;
+ if (dev == tundev)
+ return -EINVAL;
+
+ t = netdev_priv(dev);
+ if (!t)
+ return -ENOENT;
+
+ memset(&t->encap, 0, sizeof(t->encap));
+ t->encap.type = TUNNEL_ENCAP_NONE;
+ t->encap_hlen = 0;
+ t->hlen = t->encap_hlen + t->tun_hlen;
+
+ dev->mtu = ip_tunnel_bind_dev(dev);
+
+ netdev_state_change(dev);
+ break;
+
+ case SIOCADDTUNENCAP:
+ case SIOCCHGTUNENCAP:
+ if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
+ return -EPERM;
+ if (dev == tundev)
+ return -EINVAL;
+
+ t = netdev_priv(dev);
+ if (!t)
+ return -ENOENT;
+
+ if (copy_from_user(&e, ifr->ifr_ifru.ifru_data, sizeof(e))) {
+ err = -EFAULT;
+ break;
+ }
+ hlen = ip_encap_hlen(&e);
+ if (hlen < 0)
+ return hlen;
+
+ t->encap.type = e.type;
+ t->encap.sport = e.sport;
+ t->encap.dport = e.dport;
+ t->encap.flags = e.flags;
+ t->encap_hlen = hlen;
+ t->hlen = t->encap_hlen + t->tun_hlen;
+
+ dev->mtu = ip_tunnel_bind_dev(dev);
+
+ netdev_state_change(dev);
+ if (copy_to_user(ifr->ifr_ifru.ifru_data, &t->encap,
+ sizeof(t->encap))) {
+ err = -EFAULT;
+ break;
+ }
+ break;
+
+ default:
+ err = -ENOIOCTLCMD;
+ }
+ return err;
+}
+EXPORT_SYMBOL_GPL(__ip_tunnel_gen_ioctl);
+
static int tnl_update_pmtu(struct net_device *dev, struct sk_buff *skb,
struct rtable *rt, __be16 df)
{
@@ -536,7 +708,7 @@ static int tnl_update_pmtu(struct net_device *dev, struct sk_buff *skb,
}
void ip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev,
- const struct iphdr *tnl_params, const u8 protocol)
+ const struct iphdr *tnl_params, u8 protocol)
{
struct ip_tunnel *tunnel = netdev_priv(dev);
const struct iphdr *inner_iph;
@@ -617,6 +789,9 @@ void ip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev,
init_tunnel_flow(&fl4, protocol, dst, tnl_params->saddr,
tunnel->parms.o_key, RT_TOS(tos), tunnel->parms.link);
+ if (ip_tunnel_encap(skb, tunnel, &protocol, &fl4) < 0)
+ goto tx_error;
+
rt = connected ? tunnel_rtable_get(tunnel, 0, &fl4.saddr) : NULL;
if (!rt) {
--
2.1.0.rc2.206.gedb03e5
^ permalink raw reply related [flat|nested] 10+ messages in thread
* Re: [PATCH net-next 4/7] net: Changes to ip_tunnel to support foo-over-udp encapsulation
2014-09-11 20:07 ` [PATCH net-next 4/7] net: Changes to ip_tunnel to support foo-over-udp encapsulation Tom Herbert
@ 2014-09-13 17:09 ` David Miller
0 siblings, 0 replies; 10+ messages in thread
From: David Miller @ 2014-09-13 17:09 UTC (permalink / raw)
To: therbert; +Cc: netdev
From: Tom Herbert <therbert@google.com>
Date: Thu, 11 Sep 2014 13:07:33 -0700
> @@ -17,6 +17,10 @@
> #define SIOCADD6RD (SIOCDEVPRIVATE + 9)
> #define SIOCDEL6RD (SIOCDEVPRIVATE + 10)
> #define SIOCCHG6RD (SIOCDEVPRIVATE + 11)
> +#define SIOCGETTUNENCAP (SIOCDEVPRIVATE + 12)
> +#define SIOCADDTUNENCAP (SIOCDEVPRIVATE + 13)
> +#define SIOCDELTUNENCAP (SIOCDEVPRIVATE + 14)
> +#define SIOCCHGTUNENCAP (SIOCDEVPRIVATE + 15)
>
> #define GRE_CSUM __cpu_to_be16(0x8000)
> #define GRE_ROUTING __cpu_to_be16(0x4000)
Let's not extend the ioctls and just add the netlink parts,
thanks.
^ permalink raw reply [flat|nested] 10+ messages in thread
* [PATCH net-next 5/7] sit: TX path for sit/UDP foo-over-udp encapsulation
2014-09-11 20:07 [PATCH net-next 0/7] net: foo-over-udp (fou) Tom Herbert
` (3 preceding siblings ...)
2014-09-11 20:07 ` [PATCH net-next 4/7] net: Changes to ip_tunnel to support foo-over-udp encapsulation Tom Herbert
@ 2014-09-11 20:07 ` Tom Herbert
2014-09-11 20:07 ` [PATCH net-next 6/7] ipip: TX path for IPIP/UDP " Tom Herbert
2014-09-11 20:07 ` [PATCH net-next 7/7] gre: TX path for GRE/UDP " Tom Herbert
6 siblings, 0 replies; 10+ messages in thread
From: Tom Herbert @ 2014-09-11 20:07 UTC (permalink / raw)
To: davem, netdev
Signed-off-by: Tom Herbert <therbert@google.com>
---
net/ipv6/sit.c | 81 +++++++++++++++++++++++++++++++++++++++++++++++++++++-----
1 file changed, 74 insertions(+), 7 deletions(-)
diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c
index 86e3fa8..fc65b60f 100644
--- a/net/ipv6/sit.c
+++ b/net/ipv6/sit.c
@@ -822,6 +822,7 @@ static netdev_tx_t ipip6_tunnel_xmit(struct sk_buff *skb,
int addr_type;
u8 ttl;
int err;
+ u8 protocol = IPPROTO_IPV6;
if (skb->protocol != htons(ETH_P_IPV6))
goto tx_error;
@@ -905,6 +906,17 @@ static netdev_tx_t ipip6_tunnel_xmit(struct sk_buff *skb,
}
tdev = rt->dst.dev;
+ skb = iptunnel_handle_offloads(skb, false, SKB_GSO_SIT);
+ if (IS_ERR(skb)) {
+ ip_rt_put(rt);
+ goto tx_error;
+ }
+
+ if (ip_tunnel_encap(skb, tunnel, &protocol, &fl4) < 0) {
+ ip_rt_put(rt);
+ goto tx_error;
+ }
+
if (tdev == dev) {
ip_rt_put(rt);
dev->stats.collisions++;
@@ -969,14 +981,8 @@ static netdev_tx_t ipip6_tunnel_xmit(struct sk_buff *skb,
ttl = iph6->hop_limit;
tos = INET_ECN_encapsulate(tos, ipv6_get_dsfield(iph6));
- skb = iptunnel_handle_offloads(skb, false, SKB_GSO_SIT);
- if (IS_ERR(skb)) {
- ip_rt_put(rt);
- goto out;
- }
-
err = iptunnel_xmit(skb->sk, rt, skb, fl4.saddr, fl4.daddr,
- IPPROTO_IPV6, tos, ttl, df,
+ protocol, tos, ttl, df,
!net_eq(tunnel->net, dev_net(dev)));
iptunnel_xmit_stats(err, &dev->stats, dev->tstats);
return NETDEV_TX_OK;
@@ -1089,6 +1095,12 @@ static void ipip6_tunnel_update(struct ip_tunnel *t, struct ip_tunnel_parm *p)
netdev_state_change(t->dev);
}
+static int ipip6_tunnel_update_encap(struct ip_tunnel *t,
+ struct ip_tunnel_encap *ipencap)
+{
+ return 0;
+}
+
#ifdef CONFIG_IPV6_SIT_6RD
static int ipip6_tunnel_update_6rd(struct ip_tunnel *t,
struct ip_tunnel_6rd *ip6rd)
@@ -1135,6 +1147,12 @@ ipip6_tunnel_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
struct ip_tunnel_6rd ip6rd;
#endif
+ /* Try generic tunnel ioctls first */
+ err = __ip_tunnel_gen_ioctl(dev, sitn->fb_tunnel_dev, ifr, cmd);
+ if (err != -ENOIOCTLCMD)
+ return err;
+
+ err = 0;
switch (cmd) {
case SIOCGETTUNNEL:
#ifdef CONFIG_IPV6_SIT_6RD
@@ -1466,6 +1484,40 @@ static void ipip6_netlink_parms(struct nlattr *data[],
}
+/* This function returns true when ENCAP attributes are present in the nl msg */
+static bool ipip6_netlink_encap_parms(struct nlattr *data[],
+ struct ip_tunnel_encap *ipencap)
+{
+ bool ret = false;
+
+ memset(ipencap, 0, sizeof(*ipencap));
+
+ if (!data)
+ return ret;
+
+ if (data[IFLA_IPTUN_ENCAP_TYPE]) {
+ ret = true;
+ ipencap->type = nla_get_u16(data[IFLA_IPTUN_ENCAP_TYPE]);
+ }
+
+ if (data[IFLA_IPTUN_ENCAP_FLAGS]) {
+ ret = true;
+ ipencap->flags = nla_get_u16(data[IFLA_IPTUN_ENCAP_FLAGS]);
+ }
+
+ if (data[IFLA_IPTUN_ENCAP_SPORT]) {
+ ret = true;
+ ipencap->sport = nla_get_u16(data[IFLA_IPTUN_ENCAP_SPORT]);
+ }
+
+ if (data[IFLA_IPTUN_ENCAP_DPORT]) {
+ ret = true;
+ ipencap->dport = nla_get_u16(data[IFLA_IPTUN_ENCAP_DPORT]);
+ }
+
+ return ret;
+}
+
#ifdef CONFIG_IPV6_SIT_6RD
/* This function returns true when 6RD attributes are present in the nl msg */
static bool ipip6_netlink_6rd_parms(struct nlattr *data[],
@@ -1509,6 +1561,7 @@ static int ipip6_newlink(struct net *src_net, struct net_device *dev,
{
struct net *net = dev_net(dev);
struct ip_tunnel *nt;
+ struct ip_tunnel_encap ipencap;
#ifdef CONFIG_IPV6_SIT_6RD
struct ip_tunnel_6rd ip6rd;
#endif
@@ -1524,6 +1577,12 @@ static int ipip6_newlink(struct net *src_net, struct net_device *dev,
if (err < 0)
return err;
+ if (ipip6_netlink_encap_parms(data, &ipencap)) {
+ err = ipip6_tunnel_update_encap(nt, &ipencap);
+ if (err < 0)
+ return err;
+ }
+
#ifdef CONFIG_IPV6_SIT_6RD
if (ipip6_netlink_6rd_parms(data, &ip6rd))
err = ipip6_tunnel_update_6rd(nt, &ip6rd);
@@ -1537,11 +1596,13 @@ static int ipip6_changelink(struct net_device *dev, struct nlattr *tb[],
{
struct ip_tunnel *t = netdev_priv(dev);
struct ip_tunnel_parm p;
+ struct ip_tunnel_encap ipencap;
struct net *net = t->net;
struct sit_net *sitn = net_generic(net, sit_net_id);
#ifdef CONFIG_IPV6_SIT_6RD
struct ip_tunnel_6rd ip6rd;
#endif
+ int err;
if (dev == sitn->fb_tunnel_dev)
return -EINVAL;
@@ -1562,6 +1623,12 @@ static int ipip6_changelink(struct net_device *dev, struct nlattr *tb[],
ipip6_tunnel_update(t, &p);
+ if (ipip6_netlink_encap_parms(data, &ipencap)) {
+ err = ipip6_tunnel_update_encap(t, &ipencap);
+ if (err < 0)
+ return err;
+ }
+
#ifdef CONFIG_IPV6_SIT_6RD
if (ipip6_netlink_6rd_parms(data, &ip6rd))
return ipip6_tunnel_update_6rd(t, &ip6rd);
--
2.1.0.rc2.206.gedb03e5
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH net-next 6/7] ipip: TX path for IPIP/UDP foo-over-udp encapsulation
2014-09-11 20:07 [PATCH net-next 0/7] net: foo-over-udp (fou) Tom Herbert
` (4 preceding siblings ...)
2014-09-11 20:07 ` [PATCH net-next 5/7] sit: TX path for sit/UDP " Tom Herbert
@ 2014-09-11 20:07 ` Tom Herbert
2014-09-11 20:07 ` [PATCH net-next 7/7] gre: TX path for GRE/UDP " Tom Herbert
6 siblings, 0 replies; 10+ messages in thread
From: Tom Herbert @ 2014-09-11 20:07 UTC (permalink / raw)
To: davem, netdev
Signed-off-by: Tom Herbert <therbert@google.com>
---
net/ipv4/ipip.c | 67 ++++++++++++++++++++++++++++++++++++++++++++++++++++++---
1 file changed, 64 insertions(+), 3 deletions(-)
diff --git a/net/ipv4/ipip.c b/net/ipv4/ipip.c
index 62eaa00..3474106 100644
--- a/net/ipv4/ipip.c
+++ b/net/ipv4/ipip.c
@@ -240,6 +240,11 @@ ipip_tunnel_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
int err = 0;
struct ip_tunnel_parm p;
+ /* Try generic tunnel ioctls first */
+ err = ip_tunnel_gen_ioctl(dev, ifr, cmd);
+ if (err != -ENOIOCTLCMD)
+ return err;
+
if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof(p)))
return -EFAULT;
@@ -301,7 +306,8 @@ static int ipip_tunnel_init(struct net_device *dev)
memcpy(dev->dev_addr, &tunnel->parms.iph.saddr, 4);
memcpy(dev->broadcast, &tunnel->parms.iph.daddr, 4);
- tunnel->hlen = 0;
+ tunnel->tun_hlen = 0;
+ tunnel->hlen = tunnel->tun_hlen + tunnel->encap_hlen;
tunnel->parms.iph.protocol = IPPROTO_IPIP;
return ip_tunnel_init(dev);
}
@@ -340,19 +346,67 @@ static void ipip_netlink_parms(struct nlattr *data[],
parms->iph.frag_off = htons(IP_DF);
}
+/* This function returns true when ENCAP attributes are present in the nl msg */
+static bool ipip_netlink_encap_parms(struct nlattr *data[],
+ struct ip_tunnel_encap *ipencap)
+{
+ bool ret = false;
+
+ memset(ipencap, 0, sizeof(*ipencap));
+
+ if (!data)
+ return ret;
+
+ if (data[IFLA_IPTUN_ENCAP_TYPE]) {
+ ret = true;
+ ipencap->type = nla_get_u16(data[IFLA_IPTUN_ENCAP_TYPE]);
+ }
+
+ if (data[IFLA_IPTUN_ENCAP_FLAGS]) {
+ ret = true;
+ ipencap->flags = nla_get_u16(data[IFLA_IPTUN_ENCAP_FLAGS]);
+ }
+
+ if (data[IFLA_IPTUN_ENCAP_SPORT]) {
+ ret = true;
+ ipencap->sport = nla_get_u16(data[IFLA_IPTUN_ENCAP_SPORT]);
+ }
+
+ if (data[IFLA_IPTUN_ENCAP_DPORT]) {
+ ret = true;
+ ipencap->dport = nla_get_u16(data[IFLA_IPTUN_ENCAP_DPORT]);
+ }
+
+ return ret;
+}
+
static int ipip_newlink(struct net *src_net, struct net_device *dev,
struct nlattr *tb[], struct nlattr *data[])
{
struct ip_tunnel_parm p;
+ struct ip_tunnel *t = netdev_priv(dev);
+ struct ip_tunnel_encap ipencap;
+ int err;
+
+ if (ipip_netlink_encap_parms(data, &ipencap)) {
+ err = ip_tunnel_encap_setup(t, &ipencap);
+ if (err < 0)
+ return err;
+ }
ipip_netlink_parms(data, &p);
- return ip_tunnel_newlink(dev, tb, &p);
+ err = ip_tunnel_newlink(dev, tb, &p);
+
+ return err;
}
static int ipip_changelink(struct net_device *dev, struct nlattr *tb[],
struct nlattr *data[])
{
+ struct ip_tunnel *t = netdev_priv(dev);
struct ip_tunnel_parm p;
+ struct ip_tunnel_encap ipencap;
+ int err;
ipip_netlink_parms(data, &p);
@@ -360,7 +414,14 @@ static int ipip_changelink(struct net_device *dev, struct nlattr *tb[],
(!(dev->flags & IFF_POINTOPOINT) && p.iph.daddr))
return -EINVAL;
- return ip_tunnel_changelink(dev, tb, &p);
+ err = ip_tunnel_changelink(dev, tb, &p);
+ if (err < 0)
+ return err;
+
+ if (ipip_netlink_encap_parms(data, &ipencap))
+ err = ip_tunnel_encap_setup(t, &ipencap);
+
+ return err;
}
static size_t ipip_get_size(const struct net_device *dev)
--
2.1.0.rc2.206.gedb03e5
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH net-next 7/7] gre: TX path for GRE/UDP foo-over-udp encapsulation
2014-09-11 20:07 [PATCH net-next 0/7] net: foo-over-udp (fou) Tom Herbert
` (5 preceding siblings ...)
2014-09-11 20:07 ` [PATCH net-next 6/7] ipip: TX path for IPIP/UDP " Tom Herbert
@ 2014-09-11 20:07 ` Tom Herbert
6 siblings, 0 replies; 10+ messages in thread
From: Tom Herbert @ 2014-09-11 20:07 UTC (permalink / raw)
To: davem, netdev
Signed-off-by: Tom Herbert <therbert@google.com>
---
include/uapi/linux/if_tunnel.h | 4 +++
net/ipv4/ip_gre.c | 77 +++++++++++++++++++++++++++++++++++++++---
2 files changed, 76 insertions(+), 5 deletions(-)
diff --git a/include/uapi/linux/if_tunnel.h b/include/uapi/linux/if_tunnel.h
index 4369b62..8aa2431 100644
--- a/include/uapi/linux/if_tunnel.h
+++ b/include/uapi/linux/if_tunnel.h
@@ -117,6 +117,10 @@ enum {
IFLA_GRE_ENCAP_LIMIT,
IFLA_GRE_FLOWINFO,
IFLA_GRE_FLAGS,
+ IFLA_GRE_ENCAP_TYPE,
+ IFLA_GRE_ENCAP_FLAGS,
+ IFLA_GRE_ENCAP_SPORT,
+ IFLA_GRE_ENCAP_DPORT,
__IFLA_GRE_MAX,
};
diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c
index 9b84254..f820481 100644
--- a/net/ipv4/ip_gre.c
+++ b/net/ipv4/ip_gre.c
@@ -239,7 +239,7 @@ static void __gre_xmit(struct sk_buff *skb, struct net_device *dev,
tpi.seq = htonl(tunnel->o_seqno);
/* Push GRE header. */
- gre_build_header(skb, &tpi, tunnel->hlen);
+ gre_build_header(skb, &tpi, tunnel->tun_hlen);
ip_tunnel_xmit(skb, dev, tnl_params, tnl_params->protocol);
}
@@ -310,9 +310,14 @@ out:
static int ipgre_tunnel_ioctl(struct net_device *dev,
struct ifreq *ifr, int cmd)
{
- int err = 0;
+ int err;
struct ip_tunnel_parm p;
+ /* Try generic tunnel ioctls first */
+ err = ip_tunnel_gen_ioctl(dev, ifr, cmd);
+ if (err != -ENOIOCTLCMD)
+ return err;
+
if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof(p)))
return -EFAULT;
if (cmd == SIOCADDTUNNEL || cmd == SIOCCHGTUNNEL) {
@@ -472,9 +477,11 @@ static void __gre_tunnel_init(struct net_device *dev)
struct ip_tunnel *tunnel;
tunnel = netdev_priv(dev);
- tunnel->hlen = ip_gre_calc_hlen(tunnel->parms.o_flags);
+ tunnel->tun_hlen = ip_gre_calc_hlen(tunnel->parms.o_flags);
tunnel->parms.iph.protocol = IPPROTO_GRE;
+ tunnel->hlen = tunnel->tun_hlen + tunnel->encap_hlen;
+
dev->needed_headroom = LL_MAX_HEADER + sizeof(struct iphdr) + 4;
dev->mtu = ETH_DATA_LEN - sizeof(struct iphdr) - 4;
@@ -628,6 +635,40 @@ static void ipgre_netlink_parms(struct nlattr *data[], struct nlattr *tb[],
parms->iph.frag_off = htons(IP_DF);
}
+/* This function returns true when ENCAP attributes are present in the nl msg */
+static bool ipgre_netlink_encap_parms(struct nlattr *data[],
+ struct ip_tunnel_encap *ipencap)
+{
+ bool ret = false;
+
+ memset(ipencap, 0, sizeof(*ipencap));
+
+ if (!data)
+ return ret;
+
+ if (data[IFLA_GRE_ENCAP_TYPE]) {
+ ret = true;
+ ipencap->type = nla_get_u16(data[IFLA_GRE_ENCAP_TYPE]);
+ }
+
+ if (data[IFLA_GRE_ENCAP_FLAGS]) {
+ ret = true;
+ ipencap->flags = nla_get_u16(data[IFLA_GRE_ENCAP_FLAGS]);
+ }
+
+ if (data[IFLA_GRE_ENCAP_SPORT]) {
+ ret = true;
+ ipencap->sport = nla_get_u16(data[IFLA_GRE_ENCAP_SPORT]);
+ }
+
+ if (data[IFLA_GRE_ENCAP_DPORT]) {
+ ret = true;
+ ipencap->dport = nla_get_u16(data[IFLA_GRE_ENCAP_DPORT]);
+ }
+
+ return ret;
+}
+
static int gre_tap_init(struct net_device *dev)
{
__gre_tunnel_init(dev);
@@ -653,22 +694,48 @@ static void ipgre_tap_setup(struct net_device *dev)
ip_tunnel_setup(dev, gre_tap_net_id);
}
+static int ipgre_tunnel_update_encap(struct ip_tunnel *t,
+ struct ip_tunnel_encap *ipencap)
+{
+ return 0;
+}
+
static int ipgre_newlink(struct net *src_net, struct net_device *dev,
struct nlattr *tb[], struct nlattr *data[])
{
struct ip_tunnel_parm p;
+ struct ip_tunnel *nt;
+ struct ip_tunnel_encap ipencap;
+ int err;
ipgre_netlink_parms(data, tb, &p);
- return ip_tunnel_newlink(dev, tb, &p);
+ err = ip_tunnel_newlink(dev, tb, &p);
+ if (err < 0)
+ return err;
+
+ if (ipgre_netlink_encap_parms(data, &ipencap))
+ err = ipgre_tunnel_update_encap(nt, &ipencap);
+
+ return err;
}
static int ipgre_changelink(struct net_device *dev, struct nlattr *tb[],
struct nlattr *data[])
{
+ struct ip_tunnel *t = netdev_priv(dev);
struct ip_tunnel_parm p;
+ struct ip_tunnel_encap ipencap;
+ int err;
ipgre_netlink_parms(data, tb, &p);
- return ip_tunnel_changelink(dev, tb, &p);
+ err = ip_tunnel_changelink(dev, tb, &p);
+ if (err < 0)
+ return err;
+
+ if (ipgre_netlink_encap_parms(data, &ipencap))
+ err = ipgre_tunnel_update_encap(t, &ipencap);
+
+ return err;
}
static size_t ipgre_get_size(const struct net_device *dev)
--
2.1.0.rc2.206.gedb03e5
^ permalink raw reply related [flat|nested] 10+ messages in thread