summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAnita Zhang <the.anitazha@gmail.com>2022-02-03 14:20:43 -0800
committerGitHub <noreply@github.com>2022-02-03 14:20:43 -0800
commitd83923bdb7e8bfb1e8682a4146d28b5bf86bbf65 (patch)
tree83d8fe31e6137b1750ff4cfc3499b0d53656d04b
parentce5e7872f89c2167abb8e6b6b822c2a2db1b4a7b (diff)
parent7809cab71738aa582ac30e7dbc8d1e76c303ff9e (diff)
downloadsystemd-d83923bdb7e8bfb1e8682a4146d28b5bf86bbf65.tar.gz
Merge pull request #22355 from yuwata/network-tunnel-external
network: tunnel: support external mode
-rw-r--r--man/systemd.netdev.xml9
-rw-r--r--src/network/netdev/netdev-gperf.gperf5
-rw-r--r--src/network/netdev/tunnel.c184
-rw-r--r--src/network/netdev/tunnel.h1
-rw-r--r--test/fuzz/fuzz-netdev-parser/directives.netdev1
-rw-r--r--test/test-network/conf/25-ip6tnl-external.netdev8
-rw-r--r--test/test-network/conf/netdev-link-local-addressing-yes.network1
-rwxr-xr-xtest/test-network/systemd-networkd-tests.py13
8 files changed, 146 insertions, 76 deletions
diff --git a/man/systemd.netdev.xml b/man/systemd.netdev.xml
index ff0bdee51f..0ad0864da0 100644
--- a/man/systemd.netdev.xml
+++ b/man/systemd.netdev.xml
@@ -1150,6 +1150,15 @@
<variablelist class='network-directives'>
<varlistentry>
+ <term><varname>External=</varname></term>
+ <listitem>
+ <para>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 <varname>Local=</varname>
+ or <varname>Remote=</varname> are ignored. This implies <varname>Independent=</varname>.
+ Defaults to false.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
<term><varname>Local=</varname></term>
<listitem>
<para>A static local address for tunneled packets. It must be an address on another interface
diff --git a/src/network/netdev/netdev-gperf.gperf b/src/network/netdev/netdev-gperf.gperf
index 9cb5db9366..eadafbddb8 100644
--- a/src/network/netdev/netdev-gperf.gperf
+++ b/src/network/netdev/netdev-gperf.gperf
@@ -77,9 +77,9 @@ Tunnel.InputKey, config_parse_tunnel_key,
Tunnel.OutputKey, config_parse_tunnel_key, 0, offsetof(Tunnel, okey)
Tunnel.DiscoverPathMTU, config_parse_bool, 0, offsetof(Tunnel, pmtudisc)
Tunnel.Mode, config_parse_ip6tnl_mode, 0, offsetof(Tunnel, ip6tnl_mode)
-Tunnel.IPv6FlowLabel, config_parse_ipv6_flowlabel, 0, offsetof(Tunnel, ipv6_flowlabel)
+Tunnel.IPv6FlowLabel, config_parse_ipv6_flowlabel, 0, 0
Tunnel.CopyDSCP, config_parse_bool, 0, offsetof(Tunnel, copy_dscp)
-Tunnel.EncapsulationLimit, config_parse_encap_limit, 0, offsetof(Tunnel, encap_limit)
+Tunnel.EncapsulationLimit, config_parse_encap_limit, 0, 0
Tunnel.Independent, config_parse_bool, 0, offsetof(Tunnel, independent)
Tunnel.AssignToLoopback, config_parse_bool, 0, offsetof(Tunnel, assign_to_loopback)
Tunnel.AllowLocalRemote, config_parse_tristate, 0, offsetof(Tunnel, allow_localremote)
@@ -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 389403f42c..bb6e4f7586 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)
@@ -587,33 +640,16 @@ static int netdev_ip6tnl_fill_message_create(NetDev *netdev, Link *link, sd_netl
if (t->allow_localremote >= 0)
SET_FLAG(t->flags, IP6_TNL_F_ALLOW_LOCAL_REMOTE, t->allow_localremote);
- if (t->encap_limit != 0) {
- r = sd_netlink_message_append_u8(m, IFLA_IPTUN_ENCAP_LIMIT, t->encap_limit);
- if (r < 0)
- return r;
- }
-
r = sd_netlink_message_append_u32(m, IFLA_IPTUN_FLAGS, t->flags);
if (r < 0)
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;
+ if (t->encap_limit != 0) {
+ r = sd_netlink_message_append_u8(m, IFLA_IPTUN_ENCAP_LIMIT, t->encap_limit);
+ if (r < 0)
+ return r;
}
- 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);
@@ -809,15 +857,12 @@ int config_parse_tunnel_key(
void *data,
void *userdata) {
+ uint32_t *dest = ASSERT_PTR(data), k;
union in_addr_union buffer;
- Tunnel *t = userdata;
- uint32_t k;
int r;
assert(filename);
- assert(lvalue);
assert(rvalue);
- assert(data);
r = in_addr_from_string(AF_INET, rvalue, &buffer);
if (r < 0) {
@@ -830,13 +875,7 @@ int config_parse_tunnel_key(
} else
k = be32toh(buffer.in.s_addr);
- if (streq(lvalue, "Key"))
- t->key = k;
- else if (streq(lvalue, "InputKey"))
- t->ikey = k;
- else
- t->okey = k;
-
+ *dest = k;
return 0;
}
@@ -852,32 +891,33 @@ int config_parse_ipv6_flowlabel(
void *data,
void *userdata) {
- IPv6FlowLabel *ipv6_flowlabel = data;
- Tunnel *t = userdata;
- int k = 0;
- int r;
+ Tunnel *t = ASSERT_PTR(userdata);
+ int k, r;
assert(filename);
- assert(lvalue);
assert(rvalue);
- assert(ipv6_flowlabel);
if (streq(rvalue, "inherit")) {
- *ipv6_flowlabel = IP6_FLOWINFO_FLOWLABEL;
+ t->ipv6_flowlabel = IP6_FLOWINFO_FLOWLABEL;
t->flags |= IP6_TNL_F_USE_ORIG_FLOWLABEL;
- } else {
- r = config_parse_int(unit, filename, line, section, section_line, lvalue, ltype, rvalue, &k, userdata);
- if (r < 0)
- return r;
+ return 0;
+ }
- if (k > 0xFFFFF)
- log_syntax(unit, LOG_WARNING, filename, line, 0, "Failed to parse IPv6 flowlabel option, ignoring: %s", rvalue);
- else {
- *ipv6_flowlabel = htobe32(k) & IP6_FLOWINFO_FLOWLABEL;
- t->flags &= ~IP6_TNL_F_USE_ORIG_FLOWLABEL;
- }
+ r = safe_atoi(rvalue, &k);
+ if (r < 0) {
+ log_syntax(unit, LOG_WARNING, filename, line, r,
+ "Failed to parse tunnel IPv6 flowlabel, ignoring assignment: %s", rvalue);
+ return 0;
}
+ if (k > 0xFFFFF) {
+ log_syntax(unit, LOG_WARNING, filename, line, 0,
+ "Invalid tunnel IPv6 flowlabel, ignoring assignment: %s", rvalue);
+ return 0;
+ }
+
+ t->ipv6_flowlabel = htobe32(k) & IP6_FLOWINFO_FLOWLABEL;
+ t->flags &= ~IP6_TNL_F_USE_ORIG_FLOWLABEL;
return 0;
}
@@ -893,31 +933,33 @@ int config_parse_encap_limit(
void *data,
void *userdata) {
- Tunnel *t = userdata;
- int k = 0;
- int r;
+ Tunnel *t = ASSERT_PTR(userdata);
+ int k, r;
assert(filename);
- assert(lvalue);
assert(rvalue);
- if (streq(rvalue, "none"))
+ if (streq(rvalue, "none")) {
t->flags |= IP6_TNL_F_IGN_ENCAP_LIMIT;
- else {
- r = safe_atoi(rvalue, &k);
- if (r < 0) {
- log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse Tunnel Encapsulation Limit option, ignoring: %s", rvalue);
- return 0;
- }
+ t->encap_limit = 0;
+ return 0;
+ }
- if (k > 255 || k < 0)
- log_syntax(unit, LOG_WARNING, filename, line, 0, "Invalid Tunnel Encapsulation value, ignoring: %d", k);
- else {
- t->encap_limit = k;
- t->flags &= ~IP6_TNL_F_IGN_ENCAP_LIMIT;
- }
+ r = safe_atoi(rvalue, &k);
+ if (r < 0) {
+ log_syntax(unit, LOG_WARNING, filename, line, r,
+ "Failed to parse Tunnel Encapsulation Limit option, ignoring assignment: %s", rvalue);
+ return 0;
+ }
+
+ if (k > 255 || k < 0) {
+ log_syntax(unit, LOG_WARNING, filename, line, 0,
+ "Invalid Tunnel Encapsulation value, ignoring assignment: %d", k);
+ return 0;
}
+ t->encap_limit = k;
+ t->flags &= ~IP6_TNL_F_IGN_ENCAP_LIMIT;
return 0;
}
diff --git a/src/network/netdev/tunnel.h b/src/network/netdev/tunnel.h
index 4d42ff9a15..e25dfb215a 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 f5fa2418fe..584c1c2136 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=
diff --git a/test/test-network/conf/25-ip6tnl-external.netdev b/test/test-network/conf/25-ip6tnl-external.netdev
new file mode 100644
index 0000000000..68926cdd1e
--- /dev/null
+++ b/test/test-network/conf/25-ip6tnl-external.netdev
@@ -0,0 +1,8 @@
+# SPDX-License-Identifier: LGPL-2.1-or-later
+[NetDev]
+Name=ip6tnl-external
+Kind=ip6tnl
+
+[Tunnel]
+Mode=ip6ip6
+External=yes
diff --git a/test/test-network/conf/netdev-link-local-addressing-yes.network b/test/test-network/conf/netdev-link-local-addressing-yes.network
index ea1811bbfd..8ec0190bcb 100644
--- a/test/test-network/conf/netdev-link-local-addressing-yes.network
+++ b/test/test-network/conf/netdev-link-local-addressing-yes.network
@@ -2,6 +2,7 @@
[Match]
Name=bareudp99
Name=batadv99
+Name=ip6tnl-external
Name=ipvlan99
Name=ipvtap99
Name=macvlan99
diff --git a/test/test-network/systemd-networkd-tests.py b/test/test-network/systemd-networkd-tests.py
index 7013f73851..ff6d18cd20 100755
--- a/test/test-network/systemd-networkd-tests.py
+++ b/test/test-network/systemd-networkd-tests.py
@@ -916,6 +916,7 @@ class NetworkdNetDevTests(unittest.TestCase, Utilities):
'ip6gretun97',
'ip6gretun98',
'ip6gretun99',
+ 'ip6tnl-external',
'ip6tnl-slaac',
'ip6tnl97',
'ip6tnl98',
@@ -1002,7 +1003,7 @@ class NetworkdNetDevTests(unittest.TestCase, Utilities):
'25-ip6gre-tunnel-local-any.netdev',
'25-ip6gre-tunnel-remote-any.netdev',
'25-ip6gre-tunnel.netdev',
- '25-ip6tnl-tunnel-any-any.netdev',
+ '25-ip6tnl-tunnel-external.netdev',
'25-ip6tnl-tunnel-local-any.netdev',
'25-ip6tnl-tunnel-local-slaac.netdev',
'25-ip6tnl-tunnel-local-slaac.network',
@@ -1691,9 +1692,11 @@ class NetworkdNetDevTests(unittest.TestCase, Utilities):
'25-ip6tnl-tunnel-local-any.netdev', '25-tunnel-local-any.network',
'25-ip6tnl-tunnel-remote-any.netdev', '25-tunnel-remote-any.network',
'25-veth.netdev', 'ip6tnl-slaac.network', 'ipv6-prefix.network',
- '25-ip6tnl-tunnel-local-slaac.netdev', '25-ip6tnl-tunnel-local-slaac.network')
+ '25-ip6tnl-tunnel-local-slaac.netdev', '25-ip6tnl-tunnel-local-slaac.network',
+ '25-ip6tnl-external.netdev', 'netdev-link-local-addressing-yes.network')
start_networkd()
- self.wait_online(['ip6tnl99:routable', 'ip6tnl98:routable', 'ip6tnl97:routable', 'ip6tnl-slaac:degraded',
+ self.wait_online(['ip6tnl99:routable', 'ip6tnl98:routable', 'ip6tnl97:routable',
+ 'ip6tnl-slaac:degraded', 'ip6tnl-external:degraded',
'dummy98:degraded', 'veth99:routable', 'veth-peer:degraded'])
output = check_output('ip -d link show ip6tnl99')
@@ -1705,6 +1708,10 @@ class NetworkdNetDevTests(unittest.TestCase, Utilities):
output = check_output('ip -d link show ip6tnl97')
print(output)
self.assertRegex(output, 'ip6tnl ip6ip6 remote (any|::) local 2a00:ffde:4567:edde::4987 dev dummy98')
+ output = check_output('ip -d link show ip6tnl-external')
+ print(output)
+ self.assertIn('ip6tnl-external@NONE:', output)
+ self.assertIn('ip6tnl external ', output)
output = check_output('ip -d link show ip6tnl-slaac')
print(output)
self.assertIn('ip6tnl ip6ip6 remote 2001:473:fece:cafe::5179 local 2002:da8:1:0:1034:56ff:fe78:9abc dev veth99', output)