Discussion:
[PATCH iproute2 0/5] iproute: Add FOU and GUE configuration in ip
Tom Herbert
2014-10-03 15:55:13 UTC
Permalink
This patch set adds support in iproute2 to configure FOU and GUE ports
for receive, and using FOU or GUE with ip tunnels (IPIP, GRE, sit) on
transmit.

A new ip subcommand "fou" has been added to configure FOU/GUE ports.
For example:

ip fou add port 5555 gue
ip fou add port 9999 ipproto 4

The first command creates a GUE port, the second creates a direct FOU
port for IPIP (receive payload is a assumed to be an IP packet).

To configure an IP tunnel to use FOU or GUE encap parameters have
been added. For example:

ip link add name tun1 type ipip remote 192.168.1.1 local 192.168.1.2 \
ttl 225 encap gue encap-sport auto encap-dport 7777 encap-csum
ip link add name tun2 type gre remote 192.168.1.1 local 192.168.1.2 \
ttl 225 encap fou encap-sport auto encap-dport 8888 encap-csum

The first command configures an IPIP tunnel to use GUE on transmit. The
peer might be configured to receive GUE packets with the
"ip fou add port 7777 gue" command.

The second configures a GRE tunnel to use FOU encapsulation. The
peer might be configured to receive these packets with the
"ip fou add port 8888 ipproto 47" command.

Tom Herbert (5):
iplink: Fix setting of -1 as ifindex
ip fou: Support to configure foo-over-udp RX
ip tunnel: Kernel uapi definitions for fou and gue
ip link ipip: Add support to configure FOU and GUE
ip link gre: Add support to configure FOU and GUE

include/linux/fou.h | 41 ++++++++++++
include/linux/if_tunnel.h | 17 +++++
ip/Makefile | 3 +-
ip/ip.c | 3 +-
ip/ip_common.h | 1 +
ip/ipfou.c | 158 ++++++++++++++++++++++++++++++++++++++++++++++
ip/iplink.c | 2 +-
ip/link_gre.c | 89 ++++++++++++++++++++++++++
ip/link_iptnl.c | 89 ++++++++++++++++++++++++++
9 files changed, 400 insertions(+), 3 deletions(-)
create mode 100644 include/linux/fou.h
create mode 100644 ip/ipfou.c
--
2.1.0.rc2.206.gedb03e5
Tom Herbert
2014-10-03 15:55:14 UTC
Permalink
Commit 3c682146aeff157ec3540 ("iplink: forbid negative ifindex and
modifying ifindex") initializes index to -1 in iplink_modify. When
creating a link, req.i.ifi_index is then set to -1 if the link option is
not used. In the kernel this is then used to set dev->ifindex. For
dev->ifindex, zero is considered to be unset and -1 is treated as
a set index, so when a second tunnel is create the new device conflicts
with the old one (both have ifindex of -1) so -EBUSY is returned.

This patch set zero in req.i.ifi_index is index is unset (still -1).

Signed-off-by: Tom Herbert <***@google.com>
---
ip/iplink.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/ip/iplink.c b/ip/iplink.c
index cb9c870..1b6ffc6 100644
--- a/ip/iplink.c
+++ b/ip/iplink.c
@@ -689,7 +689,7 @@ static int iplink_modify(int cmd, unsigned int flags, int argc, char **argv)
addattr_l(&req.n, sizeof(req), IFLA_LINK, &ifindex, 4);
}

- req.i.ifi_index = index;
+ req.i.ifi_index = (index > 0) ? : 0;
}

if (name) {
--
2.1.0.rc2.206.gedb03e5
Cong Wang
2014-10-07 00:42:11 UTC
Permalink
Post by Tom Herbert
Commit 3c682146aeff157ec3540 ("iplink: forbid negative ifindex and
modifying ifindex") initializes index to -1 in iplink_modify. When
creating a link, req.i.ifi_index is then set to -1 if the link option is
not used. In the kernel this is then used to set dev->ifindex. For
dev->ifindex, zero is considered to be unset and -1 is treated as
a set index, so when a second tunnel is create the new device conflicts
with the old one (both have ifindex of -1) so -EBUSY is returned.
This patch set zero in req.i.ifi_index is index is unset (still -1).
There was a patch before yours:
https://patchwork.ozlabs.org/patch/395404/
Tom Herbert
2014-10-03 15:55:15 UTC
Permalink
Added 'ip fou...' commands to enable/disable UDP ports for doing
foo-over-udp and Generic UDP Encapsulation variant. Arguments are port
number to bind to and IP protocol to map to port (for direct FOU).

Examples:

ip fou add port 7777 gue
ip fou add port 8888 ipproto 4

The first command creates a GUE port, the second creates a direct FOU
port for IPIP (receive payload is a assumed to be an IPv4 packet).

Signed-off-by: Tom Herbert <***@google.com>
---
include/linux/fou.h | 41 ++++++++++++++
ip/Makefile | 3 +-
ip/ip.c | 3 +-
ip/ip_common.h | 1 +
ip/ipfou.c | 158 ++++++++++++++++++++++++++++++++++++++++++++++++++++
5 files changed, 204 insertions(+), 2 deletions(-)
create mode 100644 include/linux/fou.h
create mode 100644 ip/ipfou.c

diff --git a/include/linux/fou.h b/include/linux/fou.h
new file mode 100644
index 0000000..e1724ff
--- /dev/null
+++ b/include/linux/fou.h
@@ -0,0 +1,41 @@
+/* fou.h - FOU Interface */
+
+#ifndef _LINUX_FOU_H
+#define _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_TYPE, /* 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,
+};
+
+enum {
+ FOU_ENCAP_UNSPEC,
+ FOU_ENCAP_DIRECT,
+ FOU_ENCAP_GUE,
+};
+
+#define FOU_CMD_MAX (__FOU_CMD_MAX - 1)
+
+#endif /* _LINUX_FOU_H */
diff --git a/ip/Makefile b/ip/Makefile
index 36aab47..5f78e67 100644
--- a/ip/Makefile
+++ b/ip/Makefile
@@ -5,7 +5,8 @@ IPOBJ=ip.o ipaddress.o ipaddrlabel.o iproute.o iprule.o ipnetns.o \
iplink_vlan.o link_veth.o link_gre.o iplink_can.o \
iplink_macvlan.o iplink_macvtap.o ipl2tp.o link_vti.o link_vti6.o \
iplink_vxlan.o tcp_metrics.o iplink_ipoib.o ipnetconf.o link_ip6tnl.o \
- link_iptnl.o link_gre6.o iplink_bond.o iplink_bond_slave.o iplink_hsr.o
+ link_iptnl.o link_gre6.o iplink_bond.o iplink_bond_slave.o iplink_hsr.o \
+ ipfou.o

RTMONOBJ=rtmon.o

diff --git a/ip/ip.c b/ip/ip.c
index 739b88d..4fbdea3 100644
--- a/ip/ip.c
+++ b/ip/ip.c
@@ -45,7 +45,7 @@ static void usage(void)
" ip [ -force ] -batch filename\n"
"where OBJECT := { link | addr | addrlabel | route | rule | neigh | ntable |\n"
" tunnel | tuntap | maddr | mroute | mrule | monitor | xfrm |\n"
-" netns | l2tp | tcp_metrics | token | netconf }\n"
+" netns | l2tp | fou | tcp_metrics | token | netconf }\n"
" OPTIONS := { -V[ersion] | -s[tatistics] | -d[etails] | -r[esolve] |\n"
" -f[amily] { inet | inet6 | ipx | dnet | bridge | link } |\n"
" -4 | -6 | -I | -D | -B | -0 |\n"
@@ -76,6 +76,7 @@ static const struct cmd {
{ "ntbl", do_ipntable },
{ "link", do_iplink },
{ "l2tp", do_ipl2tp },
+ { "fou", do_ipfou },
{ "tunnel", do_iptunnel },
{ "tunl", do_iptunnel },
{ "tuntap", do_iptuntap },
diff --git a/ip/ip_common.h b/ip/ip_common.h
index e56d1ac..b5138d1 100644
--- a/ip/ip_common.h
+++ b/ip/ip_common.h
@@ -48,6 +48,7 @@ extern int do_multirule(int argc, char **argv);
extern int do_netns(int argc, char **argv);
extern int do_xfrm(int argc, char **argv);
extern int do_ipl2tp(int argc, char **argv);
+extern int do_ipfou(int argc, char **argv);
extern int do_tcp_metrics(int argc, char **argv);
extern int do_ipnetconf(int argc, char **argv);
extern int do_iptoken(int argc, char **argv);
diff --git a/ip/ipfou.c b/ip/ipfou.c
new file mode 100644
index 0000000..b39dfe3
--- /dev/null
+++ b/ip/ipfou.c
@@ -0,0 +1,158 @@
+/*
+ * ipfou.c FOU (foo over UDP) support
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ * Authors: Tom Herbert <***@google.com>
+ */
+
+#include <netdb.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <net/if.h>
+#include <linux/fou.h>
+#include <linux/genetlink.h>
+#include <linux/ip.h>
+#include <arpa/inet.h>
+
+#include "libgenl.h"
+#include "utils.h"
+#include "ip_common.h"
+
+static void usage(void)
+{
+ fprintf(stderr, "Usage: ip fou add port PORT { ipproto PROTO | gue }\n");
+ fprintf(stderr, " ip fou del port PORT\n");
+ fprintf(stderr, "\n");
+ fprintf(stderr, "Where: PROTO { ipproto-name | 1..255 }\n");
+ fprintf(stderr, " TYPE { 1..65535 }\n");
+
+ exit(-1);
+}
+
+/* netlink socket */
+static struct rtnl_handle genl_rth = { .fd = -1 };
+static int genl_family = -1;
+
+#define FOU_REQUEST(_req, _bufsiz, _cmd, _flags) \
+ GENL_REQUEST(_req, _bufsiz, genl_family, 0, \
+ FOU_GENL_VERSION, _cmd, _flags)
+
+static int fou_parse_opt(int argc, char **argv, struct nlmsghdr *n,
+ bool adding)
+{
+ __u16 port;
+ int port_set = 0;
+ __u8 ipproto, type;
+ bool gue_set = false;
+ int ipproto_set = 0;
+
+ while (argc > 0) {
+ if (!matches(*argv, "port")) {
+ NEXT_ARG();
+ if (get_u16(&port, *argv, 0) || port == 0)
+ invarg("invalid port", *argv);
+ port = htons(port);
+ port_set = 1;
+ } else if (!matches(*argv, "ipproto")) {
+ struct protoent *servptr;
+
+ NEXT_ARG();
+
+ servptr = getprotobyname(*argv);
+ if (servptr)
+ ipproto = servptr->p_proto;
+ else if (get_u8(&ipproto, *argv, 0) || ipproto == 0)
+ invarg("invalid ipproto", *argv);
+ ipproto_set = 1;
+ } else if (!matches(*argv, "gue")) {
+ gue_set = true;
+ } else {
+ fprintf(stderr, "fou: unknown command \"%s\"?\n", *argv);
+ usage();
+ return -1;
+ }
+ argc--, argv++;
+ }
+
+ if (!port_set) {
+ fprintf(stderr, "fou: missing port\n");
+ return -1;
+ }
+
+ if (!ipproto_set && !gue_set && adding) {
+ fprintf(stderr, "fou: must set ipproto or gue\n");
+ return -1;
+ }
+
+ if (ipproto_set && gue_set) {
+ fprintf(stderr, "fou: cannot set ipproto and gue\n");
+ return -1;
+ }
+
+ type = gue_set ? FOU_ENCAP_GUE : FOU_ENCAP_DIRECT;
+
+ addattr16(n, 1024, FOU_ATTR_PORT, port);
+ addattr8(n, 1024, FOU_ATTR_TYPE, type);
+
+ if (ipproto_set)
+ addattr8(n, 1024, FOU_ATTR_IPPROTO, ipproto);
+
+ return 0;
+}
+
+static int do_add(int argc, char **argv)
+{
+ FOU_REQUEST(req, 1024, FOU_CMD_ADD, NLM_F_REQUEST);
+
+ fou_parse_opt(argc, argv, &req.n, true);
+
+ if (rtnl_talk(&genl_rth, &req.n, 0, 0, NULL) < 0)
+ return -2;
+
+ return 0;
+}
+
+static int do_del(int argc, char **argv)
+{
+ FOU_REQUEST(req, 1024, FOU_CMD_DEL, NLM_F_REQUEST);
+
+ fou_parse_opt(argc, argv, &req.n, false);
+
+ if (rtnl_talk(&genl_rth, &req.n, 0, 0, NULL) < 0)
+ return -2;
+
+ return 0;
+}
+
+int do_ipfou(int argc, char **argv)
+{
+ if (genl_family < 0) {
+ if (rtnl_open_byproto(&genl_rth, 0, NETLINK_GENERIC) < 0) {
+ fprintf(stderr, "Cannot open generic netlink socket\n");
+ exit(1);
+ }
+
+ genl_family = genl_resolve_family(&genl_rth, FOU_GENL_NAME);
+ if (genl_family < 0)
+ exit(1);
+ }
+
+ if (argc < 1)
+ usage();
+
+ if (matches(*argv, "add") == 0)
+ return do_add(argc-1, argv+1);
+ if (matches(*argv, "delete") == 0)
+ return do_del(argc-1, argv+1);
+ if (matches(*argv, "help") == 0)
+ usage();
+
+ fprintf(stderr, "Command \"%s\" is unknown, try \"ip fou help\".\n", *argv);
+ exit(-1);
+}
+
--
2.1.0.rc2.206.gedb03e5
Tom Herbert
2014-10-03 15:55:16 UTC
Permalink
This patch adds definitions from kernel include/uapi/linux/if_tunnel.h
for FOU and GUE.

Signed-off-by: Tom Herbert <***@google.com>
---
include/linux/if_tunnel.h | 17 +++++++++++++++++
1 file changed, 17 insertions(+)

diff --git a/include/linux/if_tunnel.h b/include/linux/if_tunnel.h
index 3e425f9..8b04f32 100644
--- a/include/linux/if_tunnel.h
+++ b/include/linux/if_tunnel.h
@@ -53,10 +53,23 @@ 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,
+ TUNNEL_ENCAP_GUE,
+};
+
+#define TUNNEL_ENCAP_FLAG_CSUM (1<<0)
+#define TUNNEL_ENCAP_FLAG_CSUM6 (1<<1)
+
/* SIT-mode i_flags */
#define SIT_ISATAP 0x0001

@@ -94,6 +107,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,
};
--
2.1.0.rc2.206.gedb03e5
Tom Herbert
2014-10-03 15:55:18 UTC
Permalink
This patch adds support to configure foo-over-udp (FOU) and Generic
UDP Encapsulation for GRE tunnels. This configuration allows selection
of FOU or GUE for the tunnel, specification of the source and
destination ports for UDP tunnel, and enabling TX checksum. This
configuration only affects the transmit side of a tunnel.

Example:

ip link add name tun1 type gre remote 192.168.1.1 local 192.168.1.2 \
ttl 225 encap fou encap-sport auto encap-dport 7777 encap-csum

This would create an GRE tunnel in GUE encapsulation where the source
port is automatically selected (based on hash of inner packet) and
checksums in the encapsulating UDP header are enabled.

Signed-off-by: Tom Herbert <***@google.com>
---
ip/link_gre.c | 89 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 89 insertions(+)

diff --git a/ip/link_gre.c b/ip/link_gre.c
index fda84d8..cd80333 100644
--- a/ip/link_gre.c
+++ b/ip/link_gre.c
@@ -30,6 +30,9 @@ static void usage(void)
fprintf(stderr, " type { gre | gretap } [ remote ADDR ] [ local ADDR ]\n");
fprintf(stderr, " [ [i|o]seq ] [ [i|o]key KEY ] [ [i|o]csum ]\n");
fprintf(stderr, " [ ttl TTL ] [ tos TOS ] [ [no]pmtudisc ] [ dev PHYS_DEV ]\n");
+ fprintf(stderr, " [ noencap ] [ encap { fou | gue | none } ]\n");
+ fprintf(stderr, " [ encap-sport PORT ] [ encap-dport PORT ]\n");
+ fprintf(stderr, " [ [no]encap-csum ] [ [no]encap-csum6 ]\n");
fprintf(stderr, "\n");
fprintf(stderr, "Where: NAME := STRING\n");
fprintf(stderr, " ADDR := { IP_ADDRESS | any }\n");
@@ -62,6 +65,10 @@ static int gre_parse_opt(struct link_util *lu, int argc, char **argv,
__u8 ttl = 0;
__u8 tos = 0;
int len;
+ __u16 encaptype = 0;
+ __u16 encapflags = 0;
+ __u16 encapsport = 0;
+ __u16 encapdport = 0;

if (!(n->nlmsg_flags & NLM_F_CREATE)) {
memset(&req, 0, sizeof(req));
@@ -127,6 +134,15 @@ get_failed:

if (greinfo[IFLA_GRE_LINK])
link = rta_getattr_u8(greinfo[IFLA_GRE_LINK]);
+
+ if (greinfo[IFLA_GRE_ENCAP_TYPE])
+ encaptype = rta_getattr_u16(greinfo[IFLA_GRE_ENCAP_TYPE]);
+ if (greinfo[IFLA_GRE_ENCAP_FLAGS])
+ encapflags = rta_getattr_u16(greinfo[IFLA_GRE_ENCAP_FLAGS]);
+ if (greinfo[IFLA_GRE_ENCAP_SPORT])
+ encapsport = rta_getattr_u16(greinfo[IFLA_GRE_ENCAP_SPORT]);
+ if (greinfo[IFLA_GRE_ENCAP_DPORT])
+ encapdport = rta_getattr_u16(greinfo[IFLA_GRE_ENCAP_DPORT]);
}

while (argc > 0) {
@@ -236,6 +252,36 @@ get_failed:
tos = uval;
} else
tos = 1;
+ } else if (strcmp(*argv, "noencap") == 0) {
+ encaptype = TUNNEL_ENCAP_NONE;
+ } else if (strcmp(*argv, "encap") == 0) {
+ NEXT_ARG();
+ if (strcmp(*argv, "fou") == 0)
+ encaptype = TUNNEL_ENCAP_FOU;
+ else if (strcmp(*argv, "gue") == 0)
+ encaptype = TUNNEL_ENCAP_GUE;
+ else if (strcmp(*argv, "none") == 0)
+ encaptype = TUNNEL_ENCAP_NONE;
+ else
+ invarg("Invalid encap type.", *argv);
+ } else if (strcmp(*argv, "encap-sport") == 0) {
+ NEXT_ARG();
+ if (strcmp(*argv, "auto") == 0)
+ encapsport = 0;
+ else if (get_u16(&encapsport, *argv, 0))
+ invarg("Invalid source port.", *argv);
+ } else if (strcmp(*argv, "encap-dport") == 0) {
+ NEXT_ARG();
+ if (get_u16(&encapdport, *argv, 0))
+ invarg("Invalid destination port.", *argv);
+ } else if (strcmp(*argv, "encap-csum") == 0) {
+ encapflags |= TUNNEL_ENCAP_FLAG_CSUM;
+ } else if (strcmp(*argv, "noencap-csum") == 0) {
+ encapflags &= ~TUNNEL_ENCAP_FLAG_CSUM;
+ } else if (strcmp(*argv, "encap-udp6-csum") == 0) {
+ encapflags |= TUNNEL_ENCAP_FLAG_CSUM6;
+ } else if (strcmp(*argv, "noencap-udp6-csum") == 0) {
+ encapflags |= ~TUNNEL_ENCAP_FLAG_CSUM6;
} else
usage();
argc--; argv++;
@@ -266,6 +312,11 @@ get_failed:
addattr_l(n, 1024, IFLA_GRE_TTL, &ttl, 1);
addattr_l(n, 1024, IFLA_GRE_TOS, &tos, 1);

+ addattr16(n, 1024, IFLA_GRE_ENCAP_TYPE, encaptype);
+ addattr16(n, 1024, IFLA_GRE_ENCAP_FLAGS, encapflags);
+ addattr16(n, 1024, IFLA_GRE_ENCAP_SPORT, htons(encapsport));
+ addattr16(n, 1024, IFLA_GRE_ENCAP_DPORT, htons(encapdport));
+
return 0;
}

@@ -352,6 +403,44 @@ static void gre_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
fputs("icsum ", f);
if (oflags & GRE_CSUM)
fputs("ocsum ", f);
+
+ if (tb[IFLA_GRE_ENCAP_TYPE] &&
+ *(__u16 *)RTA_DATA(tb[IFLA_GRE_ENCAP_TYPE]) != TUNNEL_ENCAP_NONE) {
+ __u16 type = rta_getattr_u16(tb[IFLA_GRE_ENCAP_TYPE]);
+ __u16 flags = rta_getattr_u16(tb[IFLA_GRE_ENCAP_FLAGS]);
+ __u16 sport = rta_getattr_u16(tb[IFLA_GRE_ENCAP_SPORT]);
+ __u16 dport = rta_getattr_u16(tb[IFLA_GRE_ENCAP_DPORT]);
+
+ fputs("encap ", f);
+ switch (type) {
+ case TUNNEL_ENCAP_FOU:
+ fputs("fou ", f);
+ break;
+ case TUNNEL_ENCAP_GUE:
+ fputs("gue ", f);
+ break;
+ default:
+ fputs("unknown ", f);
+ break;
+ }
+
+ if (sport == 0)
+ fputs("encap-sport auto ", f);
+ else
+ fprintf(f, "encap-sport %u", sport);
+
+ fprintf(f, "encap-dport %u ", dport);
+
+ if (flags & TUNNEL_ENCAP_FLAG_CSUM)
+ fputs("encap-csum ", f);
+ else
+ fputs("noencap-csum ", f);
+
+ if (flags & TUNNEL_ENCAP_FLAG_CSUM6)
+ fputs("encap-csum6 ", f);
+ else
+ fputs("noencap-csum6 ", f);
+ }
}

struct link_util gre_link_util = {
--
2.1.0.rc2.206.gedb03e5
Tom Herbert
2014-10-03 15:55:17 UTC
Permalink
This patch adds support to configure foo-over-udp (FOU) and Generic
UDP Encapsulation for IPIP and sit tunnels. This configuration allows
selection of FOU or GUE for the tunnel, specification of the source and
destination ports for UDP tunnel, and enabling TX checksum. This
configuration only affects the transmit side of a tunnel.

Example:

ip link add name tun1 type ipip remote 192.168.1.1 local 192.168.1.2 \
ttl 225 encap gue encap-sport auto encap-dport 9999 encap-csum

This would create an IPIP tunnel in GUE encapsulation where the source
port is automatically selected (based on hash of inner packet) and
checksums in the encapsulating UDP header are enabled.

Signed-off-by: Tom Herbert <***@google.com>
---
ip/link_iptnl.c | 89 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 89 insertions(+)

diff --git a/ip/link_iptnl.c b/ip/link_iptnl.c
index d5324f8..8e6633e 100644
--- a/ip/link_iptnl.c
+++ b/ip/link_iptnl.c
@@ -30,6 +30,9 @@ static void usage(int sit)
fprintf(stderr, " type { ipip | sit } [ remote ADDR ] [ local ADDR ]\n");
fprintf(stderr, " [ ttl TTL ] [ tos TOS ] [ [no]pmtudisc ] [ dev PHYS_DEV ]\n");
fprintf(stderr, " [ 6rd-prefix ADDR ] [ 6rd-relay_prefix ADDR ] [ 6rd-reset ]\n");
+ fprintf(stderr, " [ noencap ] [ encap { fou | gue | none } ]\n");
+ fprintf(stderr, " [ encap-sport PORT ] [ encap-dport PORT ]\n");
+ fprintf(stderr, " [ [no]encap-csum ] [ [no]encap-csum6 ]\n");
if (sit) {
fprintf(stderr, " [ mode { ip6ip | ipip | any } ]\n");
fprintf(stderr, " [ isatap ]\n");
@@ -67,6 +70,10 @@ static int iptunnel_parse_opt(struct link_util *lu, int argc, char **argv,
__u16 ip6rdprefixlen = 0;
__u32 ip6rdrelayprefix = 0;
__u16 ip6rdrelayprefixlen = 0;
+ __u16 encaptype = 0;
+ __u16 encapflags = 0;
+ __u16 encapsport = 0;
+ __u16 encapdport = 0;

memset(&ip6rdprefix, 0, sizeof(ip6rdprefix));

@@ -129,6 +136,14 @@ get_failed:
if (iptuninfo[IFLA_IPTUN_PROTO])
proto = rta_getattr_u8(iptuninfo[IFLA_IPTUN_PROTO]);

+ if (iptuninfo[IFLA_IPTUN_ENCAP_TYPE])
+ encaptype = rta_getattr_u16(iptuninfo[IFLA_IPTUN_ENCAP_TYPE]);
+ if (iptuninfo[IFLA_IPTUN_ENCAP_FLAGS])
+ encapflags = rta_getattr_u16(iptuninfo[IFLA_IPTUN_ENCAP_FLAGS]);
+ if (iptuninfo[IFLA_IPTUN_ENCAP_SPORT])
+ encapsport = rta_getattr_u16(iptuninfo[IFLA_IPTUN_ENCAP_SPORT]);
+ if (iptuninfo[IFLA_IPTUN_ENCAP_DPORT])
+ encapdport = rta_getattr_u16(iptuninfo[IFLA_IPTUN_ENCAP_DPORT]);
if (iptuninfo[IFLA_IPTUN_6RD_PREFIX])
memcpy(&ip6rdprefix,
RTA_DATA(iptuninfo[IFLA_IPTUN_6RD_PREFIX]),
@@ -206,6 +221,36 @@ get_failed:
proto = 0;
else
invarg("Cannot guess tunnel mode.", *argv);
+ } else if (strcmp(*argv, "noencap") == 0) {
+ encaptype = TUNNEL_ENCAP_NONE;
+ } else if (strcmp(*argv, "encap") == 0) {
+ NEXT_ARG();
+ if (strcmp(*argv, "fou") == 0)
+ encaptype = TUNNEL_ENCAP_FOU;
+ else if (strcmp(*argv, "gue") == 0)
+ encaptype = TUNNEL_ENCAP_GUE;
+ else if (strcmp(*argv, "none") == 0)
+ encaptype = TUNNEL_ENCAP_NONE;
+ else
+ invarg("Invalid encap type.", *argv);
+ } else if (strcmp(*argv, "encap-sport") == 0) {
+ NEXT_ARG();
+ if (strcmp(*argv, "auto") == 0)
+ encapsport = 0;
+ else if (get_u16(&encapsport, *argv, 0))
+ invarg("Invalid source port.", *argv);
+ } else if (strcmp(*argv, "encap-dport") == 0) {
+ NEXT_ARG();
+ if (get_u16(&encapdport, *argv, 0))
+ invarg("Invalid destination port.", *argv);
+ } else if (strcmp(*argv, "encap-csum") == 0) {
+ encapflags |= TUNNEL_ENCAP_FLAG_CSUM;
+ } else if (strcmp(*argv, "noencap-csum") == 0) {
+ encapflags &= ~TUNNEL_ENCAP_FLAG_CSUM;
+ } else if (strcmp(*argv, "encap-udp6-csum") == 0) {
+ encapflags |= TUNNEL_ENCAP_FLAG_CSUM6;
+ } else if (strcmp(*argv, "noencap-udp6-csum") == 0) {
+ encapflags |= ~TUNNEL_ENCAP_FLAG_CSUM6;
} else if (strcmp(*argv, "6rd-prefix") == 0) {
inet_prefix prefix;
NEXT_ARG();
@@ -243,6 +288,12 @@ get_failed:
addattr8(n, 1024, IFLA_IPTUN_TTL, ttl);
addattr8(n, 1024, IFLA_IPTUN_TOS, tos);
addattr8(n, 1024, IFLA_IPTUN_PMTUDISC, pmtudisc);
+
+ addattr16(n, 1024, IFLA_IPTUN_ENCAP_TYPE, encaptype);
+ addattr16(n, 1024, IFLA_IPTUN_ENCAP_FLAGS, encapflags);
+ addattr16(n, 1024, IFLA_IPTUN_ENCAP_SPORT, htons(encapsport));
+ addattr16(n, 1024, IFLA_IPTUN_ENCAP_DPORT, htons(encapdport));
+
if (strcmp(lu->id, "sit") == 0) {
addattr16(n, 1024, IFLA_IPTUN_FLAGS, iflags);
addattr8(n, 1024, IFLA_IPTUN_PROTO, proto);
@@ -345,6 +396,44 @@ static void iptunnel_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[
relayprefixlen);
}
}
+
+ if (tb[IFLA_IPTUN_ENCAP_TYPE] &&
+ *(__u16 *)RTA_DATA(tb[IFLA_IPTUN_ENCAP_TYPE]) != TUNNEL_ENCAP_NONE) {
+ __u16 type = rta_getattr_u16(tb[IFLA_IPTUN_ENCAP_TYPE]);
+ __u16 flags = rta_getattr_u16(tb[IFLA_IPTUN_ENCAP_FLAGS]);
+ __u16 sport = rta_getattr_u16(tb[IFLA_IPTUN_ENCAP_SPORT]);
+ __u16 dport = rta_getattr_u16(tb[IFLA_IPTUN_ENCAP_DPORT]);
+
+ fputs("encap ", f);
+ switch (type) {
+ case TUNNEL_ENCAP_FOU:
+ fputs("fou ", f);
+ break;
+ case TUNNEL_ENCAP_GUE:
+ fputs("gue ", f);
+ break;
+ default:
+ fputs("unknown ", f);
+ break;
+ }
+
+ if (sport == 0)
+ fputs("encap-sport auto ", f);
+ else
+ fprintf(f, "encap-sport %u", sport);
+
+ fprintf(f, "encap-dport %u ", dport);
+
+ if (flags & TUNNEL_ENCAP_FLAG_CSUM)
+ fputs("encap-csum ", f);
+ else
+ fputs("noencap-csum ", f);
+
+ if (flags & TUNNEL_ENCAP_FLAG_CSUM6)
+ fputs("encap-csum6 ", f);
+ else
+ fputs("noencap-csum6 ", f);
+ }
}

struct link_util ipip_link_util = {
--
2.1.0.rc2.206.gedb03e5
Sabrina Dubroca
2014-10-21 16:48:24 UTC
Permalink
Hello Tom,
Post by Tom Herbert
[...]
@@ -345,6 +396,44 @@ static void iptunnel_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[
relayprefixlen);
}
}
+
+ if (tb[IFLA_IPTUN_ENCAP_TYPE] &&
+ *(__u16 *)RTA_DATA(tb[IFLA_IPTUN_ENCAP_TYPE]) != TUNNEL_ENCAP_NONE) {
+ __u16 type = rta_getattr_u16(tb[IFLA_IPTUN_ENCAP_TYPE]);
+ __u16 flags = rta_getattr_u16(tb[IFLA_IPTUN_ENCAP_FLAGS]);
+ __u16 sport = rta_getattr_u16(tb[IFLA_IPTUN_ENCAP_SPORT]);
+ __u16 dport = rta_getattr_u16(tb[IFLA_IPTUN_ENCAP_DPORT]);
+
+ fputs("encap ", f);
+ switch (type) {
+ fputs("fou ", f);
+ break;
+ fputs("gue ", f);
+ break;
+ fputs("unknown ", f);
+ break;
+ }
+
+ if (sport == 0)
+ fputs("encap-sport auto ", f);
+ else
+ fprintf(f, "encap-sport %u", sport);
^^^
missing space?
Post by Tom Herbert
+
+ fprintf(f, "encap-dport %u ", dport);
You're missing a few ntohs for source/dest ports here:

./ip link add name tun1 type ipip remote 192.168.1.1 local 192.168.1.2 ttl 225 encap gue encap-sport auto encap-dport 9999 encap-csum
./ip -d link show dev tun1
7: ***@NONE: <POINTOPOINT,NOARP> mtu 1468 qdisc noop state DOWN mode DEFAULT group default
link/ipip 192.168.1.2 peer 192.168.1.1 promiscuity 0
ipip remote 192.168.1.1 local 192.168.1.2 ttl 225 pmtudisc encap gue encap-sport auto encap-dport 3879 encap-csum noencap-csum6
^^^^

Same comments for the next patch.
--
Sabrina
Loading...