diff --git a/man/systemd.netdev.xml b/man/systemd.netdev.xml index ff0bdee51fb..0ad0864da0f 100644 --- a/man/systemd.netdev.xml +++ b/man/systemd.netdev.xml @@ -1149,6 +1149,15 @@ the following keys: + + External= + + Takes a boolean value. When true, then the tunnel is externally controlled, which is + also known as collect metadata mode, and most settings below like Local= + or Remote= are ignored. This implies Independent=. + Defaults to false. + + Local= diff --git a/src/network/netdev/netdev-gperf.gperf b/src/network/netdev/netdev-gperf.gperf index a993e258679..eadafbddb84 100644 --- a/src/network/netdev/netdev-gperf.gperf +++ b/src/network/netdev/netdev-gperf.gperf @@ -91,6 +91,7 @@ Tunnel.IPv6RapidDeploymentPrefix, config_parse_6rd_prefix, Tunnel.ERSPANIndex, config_parse_uint32, 0, offsetof(Tunnel, erspan_index) Tunnel.SerializeTunneledPackets, config_parse_tristate, 0, offsetof(Tunnel, gre_erspan_sequence) Tunnel.ISATAP, config_parse_tristate, 0, offsetof(Tunnel, isatap) +Tunnel.External, config_parse_bool, 0, offsetof(Tunnel, external) FooOverUDP.Protocol, config_parse_ip_protocol, 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) diff --git a/src/network/netdev/tunnel.c b/src/network/netdev/tunnel.c index 336ff3c8294..bb6e4f75869 100644 --- a/src/network/netdev/tunnel.c +++ b/src/network/netdev/tunnel.c @@ -213,6 +213,15 @@ static int netdev_ipip_sit_fill_message_create(NetDev *netdev, Link *link, sd_ne assert(t); + if (t->external) { + r = sd_netlink_message_append_flag(m, IFLA_IPTUN_COLLECT_METADATA); + if (r < 0) + return r; + + /* If external mode is enabled, then the following settings should not be appended. */ + return 0; + } + if (link || t->assign_to_loopback) { r = sd_netlink_message_append_u32(m, IFLA_IPTUN_LINK, link ? link->ifindex : LOOPBACK_IFINDEX); if (r < 0) @@ -309,6 +318,15 @@ static int netdev_gre_erspan_fill_message_create(NetDev *netdev, Link *link, sd_ assert(t); + if (t->external) { + r = sd_netlink_message_append_flag(m, IFLA_GRE_COLLECT_METADATA); + if (r < 0) + return r; + + /* If external mode is enabled, then the following settings should not be appended. */ + return 0; + } + if (link || t->assign_to_loopback) { r = sd_netlink_message_append_u32(m, IFLA_GRE_LINK, link ? link->ifindex : LOOPBACK_IFINDEX); if (r < 0) @@ -421,6 +439,15 @@ static int netdev_ip6gre_fill_message_create(NetDev *netdev, Link *link, sd_netl assert(t); + if (t->external) { + r = sd_netlink_message_append_flag(m, IFLA_GRE_COLLECT_METADATA); + if (r < 0) + return r; + + /* If external mode is enabled, then the following settings should not be appended. */ + return 0; + } + if (link || t->assign_to_loopback) { r = sd_netlink_message_append_u32(m, IFLA_GRE_LINK, link ? link->ifindex : LOOPBACK_IFINDEX); if (r < 0) @@ -553,6 +580,32 @@ static int netdev_ip6tnl_fill_message_create(NetDev *netdev, Link *link, sd_netl assert(t); + switch (t->ip6tnl_mode) { + case NETDEV_IP6_TNL_MODE_IP6IP6: + proto = IPPROTO_IPV6; + break; + case NETDEV_IP6_TNL_MODE_IPIP6: + proto = IPPROTO_IPIP; + break; + case NETDEV_IP6_TNL_MODE_ANYIP6: + default: + proto = 0; + break; + } + + r = sd_netlink_message_append_u8(m, IFLA_IPTUN_PROTO, proto); + if (r < 0) + return r; + + if (t->external) { + r = sd_netlink_message_append_flag(m, IFLA_IPTUN_COLLECT_METADATA); + if (r < 0) + return r; + + /* If external mode is enabled, then the following settings should not be appended. */ + return 0; + } + if (link || t->assign_to_loopback) { r = sd_netlink_message_append_u32(m, IFLA_IPTUN_LINK, link ? link->ifindex : LOOPBACK_IFINDEX); if (r < 0) @@ -597,23 +650,6 @@ static int netdev_ip6tnl_fill_message_create(NetDev *netdev, Link *link, sd_netl return r; } - switch (t->ip6tnl_mode) { - case NETDEV_IP6_TNL_MODE_IP6IP6: - proto = IPPROTO_IPV6; - break; - case NETDEV_IP6_TNL_MODE_IPIP6: - proto = IPPROTO_IPIP; - break; - case NETDEV_IP6_TNL_MODE_ANYIP6: - default: - proto = 0; - break; - } - - r = sd_netlink_message_append_u8(m, IFLA_IPTUN_PROTO, proto); - if (r < 0) - return r; - return 0; } @@ -640,6 +676,23 @@ static int netdev_tunnel_verify(NetDev *netdev, const char *filename) { assert(t); + if (netdev->kind == NETDEV_KIND_IP6TNL && + t->ip6tnl_mode == _NETDEV_IP6_TNL_MODE_INVALID) + return log_netdev_error_errno(netdev, SYNTHETIC_ERRNO(EINVAL), + "ip6tnl without mode configured in %s. Ignoring", filename); + + if (t->external) { + if (IN_SET(netdev->kind, NETDEV_KIND_VTI, NETDEV_KIND_VTI6)) + log_netdev_debug(netdev, "vti/vti6 tunnel do not support external mode, ignoring."); + else { + /* tunnel with external mode does not require underlying interface. */ + t->independent = true; + + /* tunnel with external mode does not require any settings checked below. */ + return 0; + } + } + if (IN_SET(netdev->kind, NETDEV_KIND_VTI, NETDEV_KIND_IPIP, NETDEV_KIND_SIT, NETDEV_KIND_GRE) && !IN_SET(t->family, AF_UNSPEC, AF_INET)) return log_netdev_error_errno(netdev, SYNTHETIC_ERRNO(EINVAL), @@ -660,11 +713,6 @@ static int netdev_tunnel_verify(NetDev *netdev, const char *filename) { return log_netdev_error_errno(netdev, SYNTHETIC_ERRNO(EINVAL), "ip6gretap tunnel without a remote IPv6 address configured in %s. Ignoring", filename); - if (netdev->kind == NETDEV_KIND_IP6TNL && - t->ip6tnl_mode == _NETDEV_IP6_TNL_MODE_INVALID) - return log_netdev_error_errno(netdev, SYNTHETIC_ERRNO(EINVAL), - "ip6tnl without mode configured in %s. Ignoring", filename); - if (t->fou_tunnel && t->fou_destination_port <= 0) return log_netdev_error_errno(netdev, SYNTHETIC_ERRNO(EINVAL), "FooOverUDP missing port configured in %s. Ignoring", filename); diff --git a/src/network/netdev/tunnel.h b/src/network/netdev/tunnel.h index 4d42ff9a154..e25dfb215a0 100644 --- a/src/network/netdev/tunnel.h +++ b/src/network/netdev/tunnel.h @@ -55,6 +55,7 @@ typedef struct Tunnel { bool independent; bool fou_tunnel; bool assign_to_loopback; + bool external; /* a.k.a collect metadata mode */ uint16_t encap_src_port; uint16_t fou_destination_port; diff --git a/test/fuzz/fuzz-netdev-parser/directives.netdev b/test/fuzz/fuzz-netdev-parser/directives.netdev index f5fa2418fee..584c1c21361 100644 --- a/test/fuzz/fuzz-netdev-parser/directives.netdev +++ b/test/fuzz/fuzz-netdev-parser/directives.netdev @@ -95,6 +95,7 @@ IPv6RapidDeploymentPrefix= ERSPANIndex= SerializeTunneledPackets= ISATAP= +External= [VXLAN] UDP6ZeroChecksumRx= ARPProxy=