network: Allow to configure VLan egress qos maps
authorSusant Sahani <ssahani@vmware.com>
Tue, 12 Jan 2021 13:30:56 +0000 (14:30 +0100)
committerSusant Sahani <ssahani@vmware.com>
Tue, 12 Jan 2021 13:30:56 +0000 (14:30 +0100)
man/systemd.netdev.xml
src/network/netdev/netdev-gperf.gperf
src/network/netdev/vlan.c
src/network/netdev/vlan.h
test/fuzz/fuzz-netdev-parser/directives.netdev

index 7a5d5cc48d2c61ebb4c216f6c557edf0a374486a..7add69ca8dac3676fdaabc6f509560a51233a26b 100644 (file)
           like physical interfaces. When unset, the kernel's default will be used.</para>
         </listitem>
       </varlistentry>
+      <varlistentry>
+        <term><varname>EgressQOSMaps=</varname></term>
+        <listitem>
+          <para>Defines a mapping of Linux internal packet priority (<constant>SO_PRIORITY</constant>) to VLAN header
+          PCP field for outgoing frames. Takes a whitespace-separated list of unsigned integer pairs in the format
+          <literal>from</literal>-<literal>to</literal>, e.g., <literal>21-7 45-5</literal> ranges 1–4294967294.
+          Note that <literal>from</literal> must be greater than or equal to <literal>to</literal>. When unset,
+          the kernel's default will be used.
+          </para>
+        </listitem>
+      </varlistentry>
     </variablelist>
   </refsect1>
 
index fc577f493c6eef10c189ef6e752ca7ddfaa330fc..2c94065bf55faa2a843a7e6ff751a0ce8de0d2e1 100644 (file)
@@ -53,6 +53,7 @@ VLAN.GVRP,                                config_parse_tristate,
 VLAN.MVRP,                                config_parse_tristate,                     0,                             offsetof(VLan, mvrp)
 VLAN.LooseBinding,                        config_parse_tristate,                     0,                             offsetof(VLan, loose_binding)
 VLAN.ReorderHeader,                       config_parse_tristate,                     0,                             offsetof(VLan, reorder_hdr)
+VLAN.EgressQOSMaps,                       config_parse_vlan_qos_maps,                0,                             offsetof(VLan, egress_qos_maps)
 MACVLAN.Mode,                             config_parse_macvlan_mode,                 0,                             offsetof(MacVlan, mode)
 MACVLAN.SourceMACAddress,                 config_parse_hwaddrs,                      0,                             offsetof(MacVlan, match_source_mac)
 MACVTAP.Mode,                             config_parse_macvlan_mode,                 0,                             offsetof(MacVlan, mode)
index 751a037c91a5b07450ef44e93ccf0f7594951fcd..f9fcea8898ab9d8fb9098ae679f85123ef89de4e 100644 (file)
@@ -4,6 +4,7 @@
 #include <net/if.h>
 #include <linux/if_vlan.h>
 
+#include "parse-util.h"
 #include "vlan-util.h"
 #include "vlan.h"
 
@@ -54,9 +55,111 @@ static int netdev_vlan_fill_message_create(NetDev *netdev, Link *link, sd_netlin
         if (r < 0)
                 return log_netdev_error_errno(netdev, r, "Could not append IFLA_VLAN_FLAGS attribute: %m");
 
+        if (!set_isempty(v->egress_qos_maps)) {
+                struct ifla_vlan_qos_mapping *m;
+
+                r = sd_netlink_message_open_container(req, IFLA_VLAN_EGRESS_QOS);
+                if (r < 0)
+                        return log_netdev_error_errno(netdev, r, "Could not open container IFLA_VLAN_EGRESS_QOS: %m");
+
+                SET_FOREACH(m, v->egress_qos_maps) {
+                        r = sd_netlink_message_append_data(req, IFLA_VLAN_QOS_MAPPING, m, sizeof(struct ifla_vlan_qos_mapping));
+                        if (r < 0)
+                                return log_netdev_error_errno(netdev, r, "Could not append IFLA_VLAN_QOS_MAPPING attribute: %m");
+                }
+
+                r = sd_netlink_message_close_container(req);
+                if (r < 0)
+                        return log_netdev_error_errno(netdev, r, "Could not close container IFLA_VLAN_EGRESS_QOS: %m");
+        }
+
         return 0;
 }
 
+static void vlan_qos_maps_hash_func(const struct ifla_vlan_qos_mapping *x, struct siphash *state) {
+        siphash24_compress(&x->from, sizeof(x->from), state);
+        siphash24_compress(&x->to, sizeof(x->to), state);
+}
+
+static int vlan_qos_maps_compare_func(const struct ifla_vlan_qos_mapping *a, const struct ifla_vlan_qos_mapping *b) {
+        int r;
+
+        r = CMP(a->from, b->from);
+        if (r != 0)
+                return r;
+
+        return CMP(a->to, b->to);
+}
+
+DEFINE_PRIVATE_HASH_OPS_WITH_KEY_DESTRUCTOR(
+                vlan_qos_maps_hash_ops,
+                struct ifla_vlan_qos_mapping,
+                vlan_qos_maps_hash_func,
+                vlan_qos_maps_compare_func,
+                free);
+
+int config_parse_vlan_qos_maps(
+                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) {
+
+        Set **s = data;
+        int r;
+
+        assert(filename);
+        assert(lvalue);
+        assert(rvalue);
+        assert(data);
+
+        if (isempty(rvalue)) {
+                *s = set_free(*s);
+                return 0;
+        }
+
+        for (const char *p = rvalue;;) {
+                _cleanup_free_ struct ifla_vlan_qos_mapping *m = NULL;
+                _cleanup_free_ char *w = NULL;
+
+                r = extract_first_word(&p, &w, NULL, EXTRACT_CUNESCAPE|EXTRACT_UNQUOTE);
+                if (r == -ENOMEM)
+                        return log_oom();
+                if (r < 0) {
+                        log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse %s, ignoring: %s", lvalue, rvalue);
+                        return 0;
+                }
+                if (r == 0)
+                        return 0;
+
+                m = new0(struct ifla_vlan_qos_mapping, 1);
+                if (!m)
+                        return log_oom();
+
+                r = parse_range(w, &m->from, &m->to);
+                if (r < 0) {
+                        log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse %s, ignoring: %s", lvalue, w);
+                        continue;
+                }
+
+                if (m->to > m->from || m->to == 0 || m->from == 0) {
+                        log_syntax(unit, LOG_WARNING, filename, line, 0, "Invalid %s, ignoring: %s", lvalue, w);
+                        continue;
+                }
+
+                r = set_ensure_consume(s, &vlan_qos_maps_hash_ops, TAKE_PTR(m));
+                if (r < 0) {
+                        log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to store %s, ignoring: %s", lvalue, w);
+                        continue;
+                }
+        }
+}
+
 static int netdev_vlan_verify(NetDev *netdev, const char *filename) {
         VLan *v;
 
@@ -75,6 +178,16 @@ static int netdev_vlan_verify(NetDev *netdev, const char *filename) {
         return 0;
 }
 
+static void vlan_done(NetDev *n) {
+        VLan *v;
+
+        v = VLAN(n);
+
+        assert(v);
+
+        set_free(v->egress_qos_maps);
+}
+
 static void vlan_init(NetDev *netdev) {
         VLan *v = VLAN(netdev);
 
@@ -96,4 +209,5 @@ const NetDevVTable vlan_vtable = {
         .fill_message_create = netdev_vlan_fill_message_create,
         .create_type = NETDEV_CREATE_STACKED,
         .config_verify = netdev_vlan_verify,
+        .done = vlan_done,
 };
index fbaad5a538c640cc7e708bcd2e1bdca4b9b801f3..376024d4fd3501bb5a0f6c00f6047cf1528466d2 100644 (file)
@@ -4,6 +4,7 @@
 typedef struct VLan VLan;
 
 #include "netdev.h"
+#include "set.h"
 
 struct VLan {
         NetDev meta;
@@ -15,7 +16,11 @@ struct VLan {
         int mvrp;
         int loose_binding;
         int reorder_hdr;
+
+        Set *egress_qos_maps;
 };
 
 DEFINE_NETDEV_CAST(VLAN, VLan);
 extern const NetDevVTable vlan_vtable;
+
+CONFIG_PARSER_PROTOTYPE(config_parse_vlan_qos_maps);
index f1813400738ef4a723ee29d98f8f7eb11f0424df..d038b21a63404f703e8a682ad56e5d4b584d9b8d 100644 (file)
@@ -5,6 +5,7 @@ ReorderHeader=
 Id=
 GVRP=
 Protocol=
+EgressQOSMaps=
 [MACVLAN]
 Mode=
 SourceMACAddress=