ip link: initial support for bareudp devices

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>
This commit is contained in:
Guillaume Nault 2020-07-01 21:45:04 +02:00 committed by Stephen Hemminger
parent 8f1cd119b3
commit a6c5c952ab
4 changed files with 196 additions and 2 deletions

View 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

View 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);

150
ip/iplink_bareudp.c Normal file
View File

@ -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,
};

View 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