1
1
mirror of https://github.com/systemd/systemd-stable.git synced 2024-12-23 17:34:00 +03:00

network/erspan: support erspan version 0 and 2

This also makes networkd accepts erspan index 0.

Closes #23570.
This commit is contained in:
Yu Watanabe 2022-05-31 23:08:28 +09:00
parent 1c1cb8ec6f
commit 98406eda8a
5 changed files with 207 additions and 9 deletions

View File

@ -1369,12 +1369,34 @@
</para> </para>
</listitem> </listitem>
</varlistentry> </varlistentry>
<varlistentry>
<term><varname>ERSPANVersion=</varname></term>
<listitem>
<para>Specifies the ERSPAN version number. Takes 0 for version 0 (a.k.a. type I), 1 for version 1
(a.k.a. type II), or 2 for version 2 (a.k.a. type III). Defaults to 1.</para>
</listitem>
</varlistentry>
<varlistentry> <varlistentry>
<term><varname>ERSPANIndex=</varname></term> <term><varname>ERSPANIndex=</varname></term>
<listitem> <listitem>
<para>Specifies the ERSPAN index field for the interface, an integer in the range 1…1048575 associated with <para>Specifies the ERSPAN v1 index field for the interface. Takes an integer in the range
the ERSPAN traffic's source port and direction. This field is mandatory. 0…1048575, which is associated with the ERSPAN traffic's source port and direction. Only used when
</para> <varname>ERSPANVersion=1</varname>. Defaults to 0.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><varname>ERSPANDirection=</varname></term>
<listitem>
<para>Specifies the ERSPAN v2 mirrored traffic's direction. Takes <literal>ingress</literal> or
<literal>egress</literal>. Only used when <varname>ERSPANVersion=2</varname>. Defaults to
<literal>ingress</literal>.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><varname>ERSPANHardwareId=</varname></term>
<listitem>
<para>Specifies an unique identifier of the ERSPAN v2 engine. Takes an integer in the range 0…63.
Only used when <varname>ERSPANVersion=2</varname>. Defaults to 0.</para>
</listitem> </listitem>
</varlistentry> </varlistentry>
</variablelist> </variablelist>

View File

@ -89,7 +89,10 @@ Tunnel.FOUDestinationPort, config_parse_ip_port,
Tunnel.FOUSourcePort, config_parse_ip_port, 0, offsetof(Tunnel, encap_src_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) Tunnel.Encapsulation, config_parse_fou_encap_type, 0, offsetof(Tunnel, fou_encap_type)
Tunnel.IPv6RapidDeploymentPrefix, config_parse_6rd_prefix, 0, 0 Tunnel.IPv6RapidDeploymentPrefix, config_parse_6rd_prefix, 0, 0
Tunnel.ERSPANIndex, config_parse_uint32, 0, offsetof(Tunnel, erspan_index) Tunnel.ERSPANVersion, config_parse_erspan_version, 0, offsetof(Tunnel, erspan_version)
Tunnel.ERSPANIndex, config_parse_erspan_index, 0, offsetof(Tunnel, erspan_index)
Tunnel.ERSPANDirection, config_parse_erspan_direction, 0, offsetof(Tunnel, erspan_direction)
Tunnel.ERSPANHardwareId, config_parse_erspan_hwid, 0, offsetof(Tunnel, erspan_hwid)
Tunnel.SerializeTunneledPackets, config_parse_tristate, 0, offsetof(Tunnel, gre_erspan_sequence) Tunnel.SerializeTunneledPackets, config_parse_tristate, 0, offsetof(Tunnel, gre_erspan_sequence)
Tunnel.ISATAP, config_parse_tristate, 0, offsetof(Tunnel, isatap) Tunnel.ISATAP, config_parse_tristate, 0, offsetof(Tunnel, isatap)
Tunnel.External, config_parse_bool, 0, offsetof(Tunnel, external) Tunnel.External, config_parse_bool, 0, offsetof(Tunnel, external)

View File

@ -335,9 +335,24 @@ static int netdev_gre_erspan_fill_message_create(NetDev *netdev, Link *link, sd_
} }
if (netdev->kind == NETDEV_KIND_ERSPAN) { if (netdev->kind == NETDEV_KIND_ERSPAN) {
r = sd_netlink_message_append_u8(m, IFLA_GRE_ERSPAN_VER, t->erspan_version);
if (r < 0)
return r;
if (t->erspan_version == 1) {
r = sd_netlink_message_append_u32(m, IFLA_GRE_ERSPAN_INDEX, t->erspan_index); r = sd_netlink_message_append_u32(m, IFLA_GRE_ERSPAN_INDEX, t->erspan_index);
if (r < 0) if (r < 0)
return r; return r;
} else if (t->erspan_version == 2) {
r = sd_netlink_message_append_u8(m, IFLA_GRE_ERSPAN_DIR, t->erspan_direction);
if (r < 0)
return r;
r = sd_netlink_message_append_u16(m, IFLA_GRE_ERSPAN_HWID, t->erspan_hwid);
if (r < 0)
return r;
}
} }
r = tunnel_get_local_address(t, link, &local); r = tunnel_get_local_address(t, link, &local);
@ -720,9 +735,6 @@ static int netdev_tunnel_verify(NetDev *netdev, const char *filename) {
return log_netdev_error_errno(netdev, SYNTHETIC_ERRNO(EINVAL), return log_netdev_error_errno(netdev, SYNTHETIC_ERRNO(EINVAL),
"FooOverUDP missing port configured in %s. Ignoring", filename); "FooOverUDP missing port configured in %s. Ignoring", filename);
if (netdev->kind == NETDEV_KIND_ERSPAN && (t->erspan_index >= (1 << 20) || t->erspan_index == 0))
return log_netdev_error_errno(netdev, SYNTHETIC_ERRNO(EINVAL), "Invalid erspan index %d. Ignoring", t->erspan_index);
/* netlink_message_append_in_addr_union() is used for vti/vti6. So, t->family cannot be AF_UNSPEC. */ /* netlink_message_append_in_addr_union() is used for vti/vti6. So, t->family cannot be AF_UNSPEC. */
if (netdev->kind == NETDEV_KIND_VTI) if (netdev->kind == NETDEV_KIND_VTI)
t->family = AF_INET; t->family = AF_INET;
@ -1021,6 +1033,155 @@ int config_parse_6rd_prefix(
return 0; return 0;
} }
int config_parse_erspan_version(
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) {
uint8_t n, *v = ASSERT_PTR(data);
int r;
assert(filename);
assert(lvalue);
assert(rvalue);
if (isempty(rvalue)) {
*v = 1; /* defaults to 1 */
return 0;
}
r = safe_atou8(rvalue, &n);
if (r < 0) {
log_syntax(unit, LOG_WARNING, filename, line, r,
"Failed to parse erspan version \"%s\", ignoring: %m", rvalue);
return 0;
}
if (!IN_SET(n, 0, 1, 2)) {
log_syntax(unit, LOG_WARNING, filename, line, 0,
"Invalid erspan version \"%s\", which must be 0, 1 or 2, ignoring.", rvalue);
return 0;
}
*v = n;
return 0;
}
int config_parse_erspan_index(
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) {
uint32_t n, *v = ASSERT_PTR(data);
int r;
assert(filename);
assert(lvalue);
assert(rvalue);
if (isempty(rvalue)) {
*v = 0; /* defaults to 0 */
return 0;
}
r = safe_atou32(rvalue, &n);
if (r < 0) {
log_syntax(unit, LOG_WARNING, filename, line, r,
"Failed to parse erspan index \"%s\", ignoring: %m", rvalue);
return 0;
}
if (n >= 0x100000) {
log_syntax(unit, LOG_WARNING, filename, line, 0,
"Invalid erspan index \"%s\", which must be less than 0x100000, ignoring.", rvalue);
return 0;
}
*v = n;
return 0;
}
int config_parse_erspan_direction(
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) {
uint8_t *v = ASSERT_PTR(data);
assert(filename);
assert(lvalue);
assert(rvalue);
if (isempty(rvalue) || streq(rvalue, "ingress"))
*v = 0; /* defaults to ingress */
else if (streq(rvalue, "egress"))
*v = 1;
else
log_syntax(unit, LOG_WARNING, filename, line, 0,
"Invalid erspan direction \"%s\", which must be \"ingress\" or \"egress\", ignoring.", rvalue);
return 0;
}
int config_parse_erspan_hwid(
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) {
uint16_t n, *v = ASSERT_PTR(data);
int r;
assert(filename);
assert(lvalue);
assert(rvalue);
if (isempty(rvalue)) {
*v = 0; /* defaults to 0 */
return 0;
}
r = safe_atou16(rvalue, &n);
if (r < 0) {
log_syntax(unit, LOG_WARNING, filename, line, r,
"Failed to parse erspan hwid \"%s\", ignoring: %m", rvalue);
return 0;
}
if (n >= 64) {
log_syntax(unit, LOG_WARNING, filename, line, 0,
"Invalid erspan index \"%s\", which must be less than 64, ignoring.", rvalue);
return 0;
}
*v = n;
return 0;
}
static void netdev_tunnel_init(NetDev *netdev) { static void netdev_tunnel_init(NetDev *netdev) {
Tunnel *t; Tunnel *t;
@ -1039,6 +1200,7 @@ static void netdev_tunnel_init(NetDev *netdev) {
t->ip6tnl_mode = _NETDEV_IP6_TNL_MODE_INVALID; t->ip6tnl_mode = _NETDEV_IP6_TNL_MODE_INVALID;
t->ipv6_flowlabel = _NETDEV_IPV6_FLOWLABEL_INVALID; t->ipv6_flowlabel = _NETDEV_IPV6_FLOWLABEL_INVALID;
t->allow_localremote = -1; t->allow_localremote = -1;
t->erspan_version = 1;
if (IN_SET(netdev->kind, NETDEV_KIND_IP6GRE, NETDEV_KIND_IP6GRETAP, NETDEV_KIND_IP6TNL)) if (IN_SET(netdev->kind, NETDEV_KIND_IP6GRE, NETDEV_KIND_IP6GRETAP, NETDEV_KIND_IP6TNL))
t->ttl = DEFAULT_IPV6_TTL; t->ttl = DEFAULT_IPV6_TTL;

View File

@ -41,7 +41,11 @@ typedef struct Tunnel {
uint32_t key; uint32_t key;
uint32_t ikey; uint32_t ikey;
uint32_t okey; uint32_t okey;
uint32_t erspan_index;
uint8_t erspan_version;
uint32_t erspan_index; /* version 1 */
uint8_t erspan_direction; /* version 2 */
uint16_t erspan_hwid; /* version 2 */
NetDevLocalAddressType local_type; NetDevLocalAddressType local_type;
union in_addr_union local; union in_addr_union local;
@ -128,3 +132,7 @@ CONFIG_PARSER_PROTOTYPE(config_parse_ipv6_flowlabel);
CONFIG_PARSER_PROTOTYPE(config_parse_encap_limit); CONFIG_PARSER_PROTOTYPE(config_parse_encap_limit);
CONFIG_PARSER_PROTOTYPE(config_parse_tunnel_key); CONFIG_PARSER_PROTOTYPE(config_parse_tunnel_key);
CONFIG_PARSER_PROTOTYPE(config_parse_6rd_prefix); CONFIG_PARSER_PROTOTYPE(config_parse_6rd_prefix);
CONFIG_PARSER_PROTOTYPE(config_parse_erspan_version);
CONFIG_PARSER_PROTOTYPE(config_parse_erspan_index);
CONFIG_PARSER_PROTOTYPE(config_parse_erspan_direction);
CONFIG_PARSER_PROTOTYPE(config_parse_erspan_hwid);

View File

@ -92,7 +92,10 @@ EncapsulationLimit=
TTL= TTL=
FOUSourcePort= FOUSourcePort=
IPv6RapidDeploymentPrefix= IPv6RapidDeploymentPrefix=
ERSPANVersion=
ERSPANIndex= ERSPANIndex=
ERSPANDirection=
ERSPANHardwareId=
SerializeTunneledPackets= SerializeTunneledPackets=
ISATAP= ISATAP=
External= External=