]> git.proxmox.com Git - mirror_iproute2.git/commitdiff
ip link: initial support for bareudp devices
authorGuillaume Nault <gnault@redhat.com>
Wed, 1 Jul 2020 19:45:04 +0000 (21:45 +0200)
committerStephen Hemminger <stephen@networkplumber.org>
Mon, 6 Jul 2020 18:11:05 +0000 (11:11 -0700)
Bareudp devices provide a generic L3 encapsulation for tunnelling
different protocols like MPLS, IP, NSH, etc. inside a UDP tunnel.

This patch is based on original work from Martin Varghese:
https://lore.kernel.org/netdev/1570532361-15163-1-git-send-email-martinvarghesenokia@gmail.com/

Examples:

  - ip link add dev bareudp0 type bareudp dstport 6635 ethertype mpls_uc

This creates a bareudp tunnel device which tunnels L3 traffic with
ethertype 0x8847 (unicast MPLS traffic). The destination port of the
UDP header will be set to 6635. The device will listen on UDP port 6635
to receive traffic.

  - ip link add dev bareudp0 type bareudp dstport 6635 ethertype ipv4 multiproto

Same as the MPLS example, but for IPv4. The "multiproto" keyword allows
the device to also tunnel IPv6 traffic.

Signed-off-by: Guillaume Nault <gnault@redhat.com>
Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
ip/Makefile
ip/iplink.c
ip/iplink_bareudp.c [new file with mode: 0644]
man/man8/ip-link.8.in

index 8735b8e4706b3bfb1e0420eab8662cf2d19b2c9a..4cad619cb3be1043d81846e7197342cb26af6686 100644 (file)
@@ -11,7 +11,7 @@ IPOBJ=ip.o ipaddress.o ipaddrlabel.o iproute.o iprule.o ipnetns.o \
     iplink_bridge.o iplink_bridge_slave.o ipfou.o iplink_ipvlan.o \
     iplink_geneve.o iplink_vrf.o iproute_lwtunnel.o ipmacsec.o ipila.o \
     ipvrf.o iplink_xstats.o ipseg6.o iplink_netdevsim.o iplink_rmnet.o \
-    ipnexthop.o ipmptcp.o
+    ipnexthop.o ipmptcp.o iplink_bareudp.o
 
 RTMONOBJ=rtmon.o
 
index 47f73988c2d58da5a7e362b2c2cc2b3afcb64186..7d4b244d1d266b34d0214ae555fd4de978f10c70 100644 (file)
@@ -124,7 +124,7 @@ void iplink_usage(void)
                        "          bridge | bond | team | ipoib | ip6tnl | ipip | sit | vxlan |\n"
                        "          gre | gretap | erspan | ip6gre | ip6gretap | ip6erspan |\n"
                        "          vti | nlmon | team_slave | bond_slave | bridge_slave |\n"
-                       "          ipvlan | ipvtap | geneve | vrf | macsec | netdevsim | rmnet |\n"
+                       "          ipvlan | ipvtap | geneve | bareudp | vrf | macsec | netdevsim | rmnet |\n"
                        "          xfrm }\n");
        }
        exit(-1);
diff --git a/ip/iplink_bareudp.c b/ip/iplink_bareudp.c
new file mode 100644 (file)
index 0000000..885e111
--- /dev/null
@@ -0,0 +1,150 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#include <stdio.h>
+
+#include "libnetlink.h"
+#include "linux/if_ether.h"
+#include "linux/if_link.h"
+#include "linux/netlink.h"
+#include "linux/rtnetlink.h"
+#include "rt_names.h"
+#include "utils.h"
+#include "ip_common.h"
+#include "json_print.h"
+
+#define BAREUDP_ATTRSET(attrs, type) (((attrs) & (1L << (type))) != 0)
+
+static void print_explain(FILE *f)
+{
+       fprintf(f,
+               "Usage: ... bareudp dstport PORT\n"
+               "               ethertype PROTO\n"
+               "               [ srcportmin PORT ]\n"
+               "               [ [no]multiproto ]\n"
+               "\n"
+               "Where: PORT       := 0-65535\n"
+               "       PROTO      := NUMBER | ip | mpls\n"
+               "       SRCPORTMIN := 0-65535\n"
+       );
+}
+
+static void explain(void)
+{
+       print_explain(stderr);
+}
+
+static void check_duparg(__u64 *attrs, int type, const char *key,
+                        const char *argv)
+{
+       if (!BAREUDP_ATTRSET(*attrs, type)) {
+               *attrs |= (1L << type);
+               return;
+       }
+       duparg2(key, argv);
+}
+
+static int bareudp_parse_opt(struct link_util *lu, int argc, char **argv,
+                            struct nlmsghdr *n)
+{
+       bool multiproto = false;
+       __u16 srcportmin = 0;
+       __be16 ethertype = 0;
+       __be16 dstport = 0;
+       __u64 attrs = 0;
+
+       while (argc > 0) {
+               if (matches(*argv, "dstport") == 0) {
+                       NEXT_ARG();
+                       check_duparg(&attrs, IFLA_BAREUDP_PORT, "dstport",
+                                    *argv);
+                       if (get_be16(&dstport, *argv, 0))
+                               invarg("dstport", *argv);
+               } else if (matches(*argv, "ethertype") == 0)  {
+                       NEXT_ARG();
+                       check_duparg(&attrs, IFLA_BAREUDP_ETHERTYPE,
+                                    "ethertype", *argv);
+                       if (ll_proto_a2n(&ethertype, *argv))
+                               invarg("ethertype", *argv);
+               } else if (matches(*argv, "srcportmin") == 0) {
+                       NEXT_ARG();
+                       check_duparg(&attrs, IFLA_BAREUDP_SRCPORT_MIN,
+                                    "srcportmin", *argv);
+                       if (get_u16(&srcportmin, *argv, 0))
+                               invarg("srcportmin", *argv);
+               } else if (matches(*argv, "multiproto") == 0) {
+                       check_duparg(&attrs, IFLA_BAREUDP_MULTIPROTO_MODE,
+                                    *argv, *argv);
+                       multiproto = true;
+               } else if (matches(*argv, "nomultiproto") == 0) {
+                       check_duparg(&attrs, IFLA_BAREUDP_MULTIPROTO_MODE,
+                                    *argv, *argv);
+                       multiproto = false;
+               } else if (matches(*argv, "help") == 0) {
+                       explain();
+                       return -1;
+               } else {
+                       fprintf(stderr, "bareudp: unknown command \"%s\"?\n",
+                               *argv);
+                       explain();
+                       return -1;
+               }
+               argc--, argv++;
+       }
+
+       if (!BAREUDP_ATTRSET(attrs, IFLA_BAREUDP_PORT))
+               missarg("dstport");
+       if (!BAREUDP_ATTRSET(attrs, IFLA_BAREUDP_ETHERTYPE))
+               missarg("ethertype");
+
+       addattr16(n, 1024, IFLA_BAREUDP_PORT, dstport);
+       addattr16(n, 1024, IFLA_BAREUDP_ETHERTYPE, ethertype);
+       if (BAREUDP_ATTRSET(attrs, IFLA_BAREUDP_SRCPORT_MIN))
+               addattr16(n, 1024, IFLA_BAREUDP_SRCPORT_MIN, srcportmin);
+       if (multiproto)
+               addattr(n, 1024, IFLA_BAREUDP_MULTIPROTO_MODE);
+
+       return 0;
+}
+
+static void bareudp_print_opt(struct link_util *lu, FILE *f,
+                             struct rtattr *tb[])
+{
+       if (!tb)
+               return;
+
+       if (tb[IFLA_BAREUDP_PORT])
+               print_uint(PRINT_ANY, "dstport", "dstport %u ",
+                          rta_getattr_be16(tb[IFLA_BAREUDP_PORT]));
+
+       if (tb[IFLA_BAREUDP_ETHERTYPE]) {
+               struct rtattr *attr = tb[IFLA_BAREUDP_ETHERTYPE];
+               SPRINT_BUF(ethertype);
+
+               print_string(PRINT_ANY, "ethertype", "ethertype %s ",
+                            ll_proto_n2a(rta_getattr_u16(attr),
+                                         ethertype, sizeof(ethertype)));
+       }
+
+       if (tb[IFLA_BAREUDP_SRCPORT_MIN])
+               print_uint(PRINT_ANY, "srcportmin", "srcportmin %u ",
+                          rta_getattr_u16(tb[IFLA_BAREUDP_SRCPORT_MIN]));
+
+       if (tb[IFLA_BAREUDP_MULTIPROTO_MODE])
+               print_bool(PRINT_ANY, "multiproto", "multiproto ", true);
+       else
+               print_bool(PRINT_ANY, "multiproto", "nomultiproto ", false);
+}
+
+static void bareudp_print_help(struct link_util *lu, int argc, char **argv,
+                              FILE *f)
+{
+       print_explain(f);
+}
+
+struct link_util bareudp_link_util = {
+       .id             = "bareudp",
+       .maxattr        = IFLA_BAREUDP_MAX,
+       .parse_opt      = bareudp_parse_opt,
+       .print_opt      = bareudp_print_opt,
+       .print_help     = bareudp_print_help,
+};
index e8a25451f7cd4a4cdbf5497992be1dcb340d5db0..c6bd2c530547477c351d41beea56d10741ebb350 100644 (file)
@@ -223,6 +223,7 @@ ip-link \- network device configuration
 .BR ipvtap " |"
 .BR lowpan " |"
 .BR geneve " |"
+.BR bareudp " |"
 .BR vrf " |"
 .BR macsec " |"
 .BR netdevsim " |"
@@ -356,6 +357,9 @@ Link types:
 .BR geneve
 - GEneric NEtwork Virtualization Encapsulation
 .sp
+.BR bareudp
+- Bare UDP L3 encapsulation support
+.sp
 .BR macsec
 - Interface for IEEE 802.1AE MAC Security (MACsec)
 .sp
@@ -1293,6 +1297,46 @@ options.
 
 .in -8
 
+.TP
+Bareudp Type Support
+For a link of type
+.I Bareudp
+the following additional arguments are supported:
+
+.BI "ip link add " DEVICE
+.BI type " bareudp " dstport " PORT " ethertype " ETHERTYPE"
+[
+.BI srcportmin " SRCPORTMIN "
+] [
+.RB [ no ] multiproto
+]
+
+.in +8
+.sp
+.BI dstport " PORT"
+- specifies the destination port for the UDP tunnel.
+
+.sp
+.BI ethertype " ETHERTYPE"
+- specifies the ethertype of the L3 protocol being tunnelled.
+
+.sp
+.BI srcportmin " SRCPORTMIN"
+- selects the lowest value of the UDP tunnel source port range.
+
+.sp
+.RB [ no ] multiproto
+- activates support for protocols similar to the one
+.RB "specified by " ethertype .
+When
+.I ETHERTYPE
+is "mpls_uc" (that is, unicast MPLS), this allows the tunnel to also handle
+multicast MPLS.
+When
+.I ETHERTYPE
+is "ipv4", this allows the tunnel to also handle IPv6. This option is disabled
+by default.
+
 .TP
 MACVLAN and MACVTAP Type Support
 For a link of type