networkd and sd-netlink: add support for Generic netlink And FooOverUDP to IPIP tunnel
This work add support to generic netlink to sd-netlink. See https://lwn.net/Articles/208755/ networkd: add support FooOverUDP support to IPIP tunnel netdev https://lwn.net/Articles/614348/ Example conf: /lib/systemd/network/1-fou-tunnel.netdev ``` [NetDev] Name=fou-tun Kind=fou [FooOverUDP] Port=5555 Protocol=4 ``` /lib/systemd/network/ipip-tunnel.netdev ``` [NetDev] Name=ipip-tun Kind=ipip [Tunnel] Independent=true Local=10.65.208.212 Remote=10.65.208.211 FooOverUDP=true FOUDestinationPort=5555 ``` $ ip -d link show ipip-tun ``` 5: ipip-tun@NONE: <POINTOPOINT,NOARP> mtu 1472 qdisc noop state DOWN mode DEFAULT group default qlen 1000 link/ipip 10.65.208.212 peer 10.65.208.211 promiscuity 0 ipip remote 10.65.208.211 local 10.65.208.212 ttl inherit pmtudisc encap fou encap-sport auto encap-dport 5555 noencap-csum noencap-csum6 noencap-remcsum numtxqueues 1 numrxqueues 1 gso_max_size 65536 gso_max_segs 65535 ```
This commit is contained in:
committed by
Zbigniew Jędrzejewski-Szmek
parent
c07fe6d0df
commit
53cb501a13
@@ -0,0 +1,128 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1+ */
|
||||
|
||||
#include <arpa/inet.h>
|
||||
#include <net/if.h>
|
||||
#include <linux/ip.h>
|
||||
|
||||
#include "conf-parser.h"
|
||||
#include "missing.h"
|
||||
#include "netdev/fou-tunnel.h"
|
||||
#include "networkd-link.h"
|
||||
#include "networkd-manager.h"
|
||||
#include "parse-util.h"
|
||||
#include "sd-netlink.h"
|
||||
#include "string-table.h"
|
||||
#include "string-util.h"
|
||||
#include "util.h"
|
||||
|
||||
static const char* const fou_encap_type_table[_NETDEV_FOO_OVER_UDP_ENCAP_MAX] = {
|
||||
[NETDEV_FOO_OVER_UDP_ENCAP_DIRECT] = "FooOverUDP",
|
||||
[NETDEV_FOO_OVER_UDP_ENCAP_GUE] = "GenericUDPEncapsulation",
|
||||
};
|
||||
|
||||
DEFINE_STRING_TABLE_LOOKUP(fou_encap_type, FooOverUDPEncapType);
|
||||
DEFINE_CONFIG_PARSE_ENUM(config_parse_fou_encap_type, fou_encap_type, FooOverUDPEncapType, "Failed to parse Foo Over UDP Encap type");
|
||||
|
||||
static int netdev_fill_fou_tunnel_message(NetDev *netdev, sd_netlink_message **ret) {
|
||||
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
|
||||
FouTunnel *t;
|
||||
int r;
|
||||
|
||||
assert(netdev);
|
||||
|
||||
t = FOU(netdev);
|
||||
|
||||
assert(t);
|
||||
|
||||
r = sd_genl_message_new(netdev->manager->genl, SD_GENL_FOU, FOU_CMD_ADD, &m);
|
||||
if (r < 0)
|
||||
return log_netdev_error_errno(netdev, r, "Failed to allocate generic netlink message: %m");
|
||||
|
||||
r = sd_netlink_message_append_u16(m, FOU_ATTR_PORT, htobe16(t->port));
|
||||
if (r < 0)
|
||||
return log_netdev_error_errno(netdev, r, "Could not append FOU_ATTR_PORT attribute: %m");
|
||||
|
||||
r = sd_netlink_message_append_u8(m, FOU_ATTR_TYPE, FOU_ENCAP_GUE);
|
||||
if (r < 0)
|
||||
return log_netdev_error_errno(netdev, r, "Could not append FOU_ATTR_TYPE attribute: %m");
|
||||
|
||||
r = sd_netlink_message_append_u8(m, FOU_ATTR_AF, AF_INET);
|
||||
if (r < 0)
|
||||
return log_netdev_error_errno(netdev, r, "Could not append FOU_ATTR_AF attribute: %m");
|
||||
|
||||
r = sd_netlink_message_append_u8(m, FOU_ATTR_IPPROTO, t->fou_protocol);
|
||||
if (r < 0)
|
||||
return log_netdev_error_errno(netdev, r, "Could not append FOU_ATTR_IPPROTO attribute: %m");
|
||||
|
||||
*ret = m;
|
||||
m = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int netdev_fou_tunnel_create(NetDev *netdev) {
|
||||
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL, *reply = NULL;
|
||||
uint32_t serial;
|
||||
FouTunnel *t;
|
||||
int r;
|
||||
|
||||
assert(netdev);
|
||||
|
||||
t = FOU(netdev);
|
||||
|
||||
assert(t);
|
||||
|
||||
r = netdev_fill_fou_tunnel_message(netdev, &m);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_netlink_send(netdev->manager->genl, m, &serial);
|
||||
if (r < 0 && r != -EADDRINUSE)
|
||||
return log_netdev_error_errno(netdev, r, "Failed to add FooOverUDP tunnel: %m");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int netdev_fou_tunnel_verify(NetDev *netdev, const char *filename) {
|
||||
FouTunnel *t;
|
||||
|
||||
assert(netdev);
|
||||
assert(filename);
|
||||
|
||||
t = FOU(netdev);
|
||||
|
||||
assert(t);
|
||||
|
||||
if (t->fou_encap_type == NETDEV_FOO_OVER_UDP_ENCAP_DIRECT && t->fou_protocol <= 0) {
|
||||
log_netdev_error(netdev, "FooOverUDP missing protocol configured in %s. Ignoring", filename);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (t->fou_encap_type == NETDEV_FOO_OVER_UDP_ENCAP_GUE && t->fou_protocol > 0) {
|
||||
log_netdev_error(netdev, "FooOverUDP GUE can't be set with protocol configured in %s. Ignoring", filename);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void fou_tunnel_init(NetDev *netdev) {
|
||||
FouTunnel *t;
|
||||
|
||||
assert(netdev);
|
||||
|
||||
t = FOU(netdev);
|
||||
|
||||
assert(t);
|
||||
|
||||
t->fou_encap_type = NETDEV_FOO_OVER_UDP_ENCAP_DIRECT;
|
||||
}
|
||||
|
||||
const NetDevVTable foutnl_vtable = {
|
||||
.object_size = sizeof(FouTunnel),
|
||||
.init = fou_tunnel_init,
|
||||
.sections = "Match\0NetDev\0FooOverUDP\0",
|
||||
.create = netdev_fou_tunnel_create,
|
||||
.create_type = NETDEV_CREATE_INDEPENDENT,
|
||||
.config_verify = netdev_fou_tunnel_verify,
|
||||
};
|
||||
@@ -0,0 +1,39 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1+ */
|
||||
#pragma once
|
||||
|
||||
#if HAVE_FOU_CMD_GET
|
||||
#include <linux/fou.h>
|
||||
#endif
|
||||
|
||||
#include "in-addr-util.h"
|
||||
#include "netdev/netdev.h"
|
||||
|
||||
typedef enum FooOverUDPEncapType {
|
||||
NETDEV_FOO_OVER_UDP_ENCAP_UNSPEC = FOU_ENCAP_UNSPEC,
|
||||
NETDEV_FOO_OVER_UDP_ENCAP_DIRECT = FOU_ENCAP_DIRECT,
|
||||
NETDEV_FOO_OVER_UDP_ENCAP_GUE = FOU_ENCAP_GUE,
|
||||
_NETDEV_FOO_OVER_UDP_ENCAP_MAX,
|
||||
_NETDEV_FOO_OVER_UDP_ENCAP_INVALID = -1,
|
||||
} FooOverUDPEncapType;
|
||||
|
||||
typedef struct FouTunnel {
|
||||
NetDev meta;
|
||||
|
||||
uint8_t fou_protocol;
|
||||
|
||||
uint16_t port;
|
||||
|
||||
FooOverUDPEncapType fou_encap_type;
|
||||
} FouTunnel;
|
||||
|
||||
DEFINE_NETDEV_CAST(FOU, FouTunnel);
|
||||
extern const NetDevVTable foutnl_vtable;
|
||||
|
||||
const char *fou_encap_type_to_string(FooOverUDPEncapType d) _const_;
|
||||
FooOverUDPEncapType fou_encap_type_from_string(const char *d) _pure_;
|
||||
|
||||
int config_parse_fou_encap_type(const char *unit, const char *filename,
|
||||
unsigned line, const char *section,
|
||||
unsigned section_line, const char *lvalue,
|
||||
int ltype, const char *rvalue, void *data,
|
||||
void *userdata);
|
||||
@@ -19,6 +19,7 @@ _Pragma("GCC diagnostic ignored \"-Wimplicit-fallthrough\"")
|
||||
#include "netdev/netdev.h"
|
||||
#include "netdev/vxcan.h"
|
||||
#include "netdev/wireguard.h"
|
||||
#include "netdev/fou-tunnel.h"
|
||||
#include "vlan-util.h"
|
||||
%}
|
||||
struct ConfigPerfItem;
|
||||
@@ -65,6 +66,13 @@ Tunnel.CopyDSCP, config_parse_bool, 0,
|
||||
Tunnel.EncapsulationLimit, config_parse_encap_limit, 0, offsetof(Tunnel, encap_limit)
|
||||
Tunnel.Independent, config_parse_bool, 0, offsetof(Tunnel, independent)
|
||||
Tunnel.AllowLocalRemote, config_parse_tristate, 0, offsetof(Tunnel, allow_localremote)
|
||||
Tunnel.FooOverUDP, config_parse_bool, 0, offsetof(Tunnel, fou_tunnel)
|
||||
Tunnel.FOUDestinationPort, config_parse_ip_port, 0, offsetof(Tunnel, fou_destination_port)
|
||||
Tunnel.FOUSourcePort, config_parse_ip_port, 0, offsetof(Tunnel, encap_src_port)
|
||||
Tunnel.Encapsulation, config_parse_fou_encap_type, 0, offsetof(Tunnel, fou_encap_type)
|
||||
FooOverUDP.Protocol, config_parse_uint8, 0, offsetof(FouTunnel, fou_protocol)
|
||||
FooOverUDP.Encapsulation, config_parse_fou_encap_type, 0, offsetof(FouTunnel, fou_encap_type)
|
||||
FooOverUDP.Port, config_parse_ip_port, 0, offsetof(FouTunnel, port)
|
||||
Peer.Name, config_parse_ifname, 0, offsetof(Veth, ifname_peer)
|
||||
Peer.MACAddress, config_parse_hwaddr, 0, offsetof(Veth, mac_peer)
|
||||
VXCAN.Peer, config_parse_ifname, 0, offsetof(VxCan, ifname_peer)
|
||||
|
||||
@@ -34,6 +34,7 @@
|
||||
#include "netdev/vxcan.h"
|
||||
#include "netdev/wireguard.h"
|
||||
#include "netdev/netdevsim.h"
|
||||
#include "netdev/fou-tunnel.h"
|
||||
|
||||
const NetDevVTable * const netdev_vtable[_NETDEV_KIND_MAX] = {
|
||||
[NETDEV_KIND_BRIDGE] = &bridge_vtable,
|
||||
@@ -62,6 +63,7 @@ const NetDevVTable * const netdev_vtable[_NETDEV_KIND_MAX] = {
|
||||
[NETDEV_KIND_VXCAN] = &vxcan_vtable,
|
||||
[NETDEV_KIND_WIREGUARD] = &wireguard_vtable,
|
||||
[NETDEV_KIND_NETDEVSIM] = &netdevsim_vtable,
|
||||
[NETDEV_KIND_FOU] = &foutnl_vtable,
|
||||
};
|
||||
|
||||
static const char* const netdev_kind_table[_NETDEV_KIND_MAX] = {
|
||||
@@ -91,6 +93,7 @@ static const char* const netdev_kind_table[_NETDEV_KIND_MAX] = {
|
||||
[NETDEV_KIND_VXCAN] = "vxcan",
|
||||
[NETDEV_KIND_WIREGUARD] = "wireguard",
|
||||
[NETDEV_KIND_NETDEVSIM] = "netdevsim",
|
||||
[NETDEV_KIND_FOU] = "fou",
|
||||
};
|
||||
|
||||
DEFINE_STRING_TABLE_LOOKUP(netdev_kind, NetDevKind);
|
||||
|
||||
@@ -43,6 +43,7 @@ typedef enum NetDevKind {
|
||||
NETDEV_KIND_VXCAN,
|
||||
NETDEV_KIND_WIREGUARD,
|
||||
NETDEV_KIND_NETDEVSIM,
|
||||
NETDEV_KIND_FOU,
|
||||
_NETDEV_KIND_MAX,
|
||||
_NETDEV_KIND_INVALID = -1
|
||||
} NetDevKind;
|
||||
|
||||
@@ -8,6 +8,10 @@
|
||||
|
||||
#include "sd-netlink.h"
|
||||
|
||||
#if HAVE_FOU_CMD_GET
|
||||
#include <linux/fou.h>
|
||||
#endif
|
||||
|
||||
#include "conf-parser.h"
|
||||
#include "missing.h"
|
||||
#include "networkd-link.h"
|
||||
@@ -61,6 +65,21 @@ static int netdev_ipip_fill_message_create(NetDev *netdev, Link *link, sd_netlin
|
||||
if (r < 0)
|
||||
return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_PMTUDISC attribute: %m");
|
||||
|
||||
if (t->fou_tunnel) {
|
||||
|
||||
r = sd_netlink_message_append_u16(m, IFLA_IPTUN_ENCAP_TYPE, t->fou_encap_type);
|
||||
if (r < 0)
|
||||
return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_ENCAP_TYPE attribute: %m");
|
||||
|
||||
r = sd_netlink_message_append_u16(m, IFLA_IPTUN_ENCAP_SPORT, htobe16(t->encap_src_port));
|
||||
if (r < 0)
|
||||
return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_ENCAP_SPORT attribute: %m");
|
||||
|
||||
r = sd_netlink_message_append_u16(m, IFLA_IPTUN_ENCAP_DPORT, htobe16(t->fou_destination_port));
|
||||
if (r < 0)
|
||||
return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_ENCAP_DPORT attribute: %m");
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
@@ -417,6 +436,11 @@ static int netdev_tunnel_verify(NetDev *netdev, const char *filename) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (t->fou_tunnel && t->fou_destination_port <= 0) {
|
||||
log_netdev_error(netdev, "FooOverUDP missing port configured in %s. Ignoring", filename);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -600,6 +624,7 @@ static void ipip_init(NetDev *n) {
|
||||
assert(t);
|
||||
|
||||
t->pmtudisc = true;
|
||||
t->fou_encap_type = FOU_ENCAP_DIRECT;
|
||||
}
|
||||
|
||||
static void sit_init(NetDev *n) {
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include "in-addr-util.h"
|
||||
|
||||
#include "netdev/netdev.h"
|
||||
#include "netdev/fou-tunnel.h"
|
||||
|
||||
typedef enum Ip6TnlMode {
|
||||
NETDEV_IP6_TNL_MODE_IP6IP6,
|
||||
@@ -40,10 +41,15 @@ typedef struct Tunnel {
|
||||
union in_addr_union remote;
|
||||
|
||||
Ip6TnlMode ip6tnl_mode;
|
||||
FooOverUDPEncapType fou_encap_type;
|
||||
|
||||
bool pmtudisc;
|
||||
bool copy_dscp;
|
||||
bool independent;
|
||||
bool fou_tunnel;
|
||||
|
||||
uint16_t encap_src_port;
|
||||
uint16_t fou_destination_port;
|
||||
} Tunnel;
|
||||
|
||||
DEFINE_NETDEV_CAST(IPIP, Tunnel);
|
||||
@@ -96,6 +102,7 @@ int config_parse_encap_limit(const char *unit, const char *filename,
|
||||
unsigned section_line, const char *lvalue,
|
||||
int ltype, const char *rvalue, void *data,
|
||||
void *userdata);
|
||||
|
||||
int config_parse_tunnel_key(const char *unit, const char *filename,
|
||||
unsigned line, const char *section,
|
||||
unsigned section_line, const char *lvalue,
|
||||
|
||||
Reference in New Issue
Block a user