From 0d9b8913e256cbcf1b9f2015bed52db5256900f1 Mon Sep 17 00:00:00 2001 From: Susant Sahani Date: Tue, 12 Jan 2021 14:30:56 +0100 Subject: [PATCH] network: Allow to configure VLan egress qos maps --- man/systemd.netdev.xml | 11 ++ src/network/netdev/netdev-gperf.gperf | 1 + src/network/netdev/vlan.c | 114 ++++++++++++++++++ src/network/netdev/vlan.h | 5 + .../fuzz/fuzz-netdev-parser/directives.netdev | 1 + 5 files changed, 132 insertions(+) diff --git a/man/systemd.netdev.xml b/man/systemd.netdev.xml index 7a5d5cc48d2..7add69ca8da 100644 --- a/man/systemd.netdev.xml +++ b/man/systemd.netdev.xml @@ -491,6 +491,17 @@ like physical interfaces. When unset, the kernel's default will be used. + + EgressQOSMaps= + + Defines a mapping of Linux internal packet priority (SO_PRIORITY) to VLAN header + PCP field for outgoing frames. Takes a whitespace-separated list of unsigned integer pairs in the format + from-to, e.g., 21-7 45-5 ranges 1–4294967294. + Note that from must be greater than or equal to to. When unset, + the kernel's default will be used. + + + diff --git a/src/network/netdev/netdev-gperf.gperf b/src/network/netdev/netdev-gperf.gperf index fc577f493c6..2c94065bf55 100644 --- a/src/network/netdev/netdev-gperf.gperf +++ b/src/network/netdev/netdev-gperf.gperf @@ -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) diff --git a/src/network/netdev/vlan.c b/src/network/netdev/vlan.c index 751a037c91a..f9fcea8898a 100644 --- a/src/network/netdev/vlan.c +++ b/src/network/netdev/vlan.c @@ -4,6 +4,7 @@ #include #include +#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, }; diff --git a/src/network/netdev/vlan.h b/src/network/netdev/vlan.h index fbaad5a538c..376024d4fd3 100644 --- a/src/network/netdev/vlan.h +++ b/src/network/netdev/vlan.h @@ -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); diff --git a/test/fuzz/fuzz-netdev-parser/directives.netdev b/test/fuzz/fuzz-netdev-parser/directives.netdev index f1813400738..d038b21a634 100644 --- a/test/fuzz/fuzz-netdev-parser/directives.netdev +++ b/test/fuzz/fuzz-netdev-parser/directives.netdev @@ -5,6 +5,7 @@ ReorderHeader= Id= GVRP= Protocol= +EgressQOSMaps= [MACVLAN] Mode= SourceMACAddress=