]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
network/erspan: support erspan version 0 and 2
authorYu Watanabe <watanabe.yu+github@gmail.com>
Tue, 31 May 2022 14:08:28 +0000 (23:08 +0900)
committerYu Watanabe <watanabe.yu+github@gmail.com>
Tue, 31 May 2022 19:02:48 +0000 (04:02 +0900)
This also makes networkd accepts erspan index 0.

Closes #23570.

man/systemd.netdev.xml
src/network/netdev/netdev-gperf.gperf
src/network/netdev/tunnel.c
src/network/netdev/tunnel.h
test/fuzz/fuzz-netdev-parser/directives.netdev

index 3a776b3f42190702e6cecf6b7401415bedb5e424..0855cf17a820459cd00443287682cb9a342e9a5b 100644 (file)
           </para>
         </listitem>
       </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>
         <term><varname>ERSPANIndex=</varname></term>
         <listitem>
-          <para>Specifies the ERSPAN index field for the interface, an integer in the range 1…1048575 associated with
-          the ERSPAN traffic's source port and direction. This field is mandatory.
-          </para>
+          <para>Specifies the ERSPAN v1 index field for the interface. Takes an integer in the range
+          0…1048575, which is associated with the ERSPAN traffic's source port and direction. Only used when
+          <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>
       </varlistentry>
     </variablelist>
index 77140be400c3b77fb443b6ae0a5599882dbb34d0..55ad60ddc8b8661eb4ba8b23e71e1abb3af79805 100644 (file)
@@ -89,7 +89,10 @@ Tunnel.FOUDestinationPort,                config_parse_ip_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.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.ISATAP,                            config_parse_tristate,                     0,                             offsetof(Tunnel, isatap)
 Tunnel.External,                          config_parse_bool,                         0,                             offsetof(Tunnel, external)
index 747acb1e80961ee9f9b181a290106b4c50f57f70..78a8708b212cc0d6f54f58ae91c79042f9f9c35a 100644 (file)
@@ -335,9 +335,24 @@ static int netdev_gre_erspan_fill_message_create(NetDev *netdev, Link *link, sd_
         }
 
         if (netdev->kind == NETDEV_KIND_ERSPAN) {
-                r = sd_netlink_message_append_u32(m, IFLA_GRE_ERSPAN_INDEX, t->erspan_index);
+                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);
+                        if (r < 0)
+                                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);
@@ -720,9 +735,6 @@ static int netdev_tunnel_verify(NetDev *netdev, const char *filename) {
                 return log_netdev_error_errno(netdev, SYNTHETIC_ERRNO(EINVAL),
                                               "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. */
         if (netdev->kind == NETDEV_KIND_VTI)
                 t->family = AF_INET;
@@ -1021,6 +1033,155 @@ int config_parse_6rd_prefix(
         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) {
         Tunnel *t;
 
@@ -1039,6 +1200,7 @@ static void netdev_tunnel_init(NetDev *netdev) {
         t->ip6tnl_mode = _NETDEV_IP6_TNL_MODE_INVALID;
         t->ipv6_flowlabel = _NETDEV_IPV6_FLOWLABEL_INVALID;
         t->allow_localremote = -1;
+        t->erspan_version = 1;
 
         if (IN_SET(netdev->kind, NETDEV_KIND_IP6GRE, NETDEV_KIND_IP6GRETAP, NETDEV_KIND_IP6TNL))
                 t->ttl = DEFAULT_IPV6_TTL;
index e25dfb215a0ffde9aaa7ffaaca11885b8569fa29..7c81f2239162c376c2e8abddded48bcf70894fe8 100644 (file)
@@ -41,7 +41,11 @@ typedef struct Tunnel {
         uint32_t key;
         uint32_t ikey;
         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;
         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_tunnel_key);
 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);
index d6c2e18464e203327c0c3a5f359576c5585a3f56..d97f81512bb335e75bf2537167dd54a2badc7cd5 100644 (file)
@@ -92,7 +92,10 @@ EncapsulationLimit=
 TTL=
 FOUSourcePort=
 IPv6RapidDeploymentPrefix=
+ERSPANVersion=
 ERSPANIndex=
+ERSPANDirection=
+ERSPANHardwareId=
 SerializeTunneledPackets=
 ISATAP=
 External=