network: tunnel: support external mode

Closes #22352.
This commit is contained in:
Yu Watanabe 2022-02-02 08:56:14 +09:00
parent acd8abb7f9
commit 1ae308abb5
5 changed files with 82 additions and 22 deletions

View file

@ -1149,6 +1149,15 @@
the following keys:</para>
<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>

View file

@ -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)

View file

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

View file

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

View file

@ -95,6 +95,7 @@ IPv6RapidDeploymentPrefix=
ERSPANIndex=
SerializeTunneledPackets=
ISATAP=
External=
[VXLAN]
UDP6ZeroChecksumRx=
ARPProxy=