]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
network: move SR-IOV related functions to src/shared/netif-sriov.[ch]
authorYu Watanabe <watanabe.yu+github@gmail.com>
Mon, 27 Dec 2021 02:09:02 +0000 (11:09 +0900)
committerYu Watanabe <watanabe.yu+github@gmail.com>
Wed, 19 Jan 2022 05:57:59 +0000 (14:57 +0900)
src/network/networkd-network-gperf.gperf
src/network/networkd-network.c
src/network/networkd-sriov.c
src/network/networkd-sriov.h
src/shared/meson.build
src/shared/netif-sriov.c [new file with mode: 0644]
src/shared/netif-sriov.h [new file with mode: 0644]

index 4c3bf97311d44979033e55c0ed9de021e498a8fd..08e3f13f5a5d10958cbc9ac058ce4c9e4cc85bad 100644 (file)
@@ -73,15 +73,15 @@ Link.Unmanaged,                              config_parse_bool,
 Link.ActivationPolicy,                       config_parse_activation_policy,                           0,                             offsetof(Network, activation_policy)
 Link.RequiredForOnline,                      config_parse_required_for_online,                         0,                             0
 Link.RequiredFamilyForOnline,                config_parse_required_family_for_online,                  0,                             offsetof(Network, required_family_for_online)
-SR-IOV.VirtualFunction,                      config_parse_sr_iov_uint32,                               0,                             0
-SR-IOV.VLANId,                               config_parse_sr_iov_uint32,                               0,                             0
-SR-IOV.QualityOfService,                     config_parse_sr_iov_uint32,                               0,                             0
-SR-IOV.VLANProtocol,                         config_parse_sr_iov_vlan_proto,                           0,                             0
-SR-IOV.MACSpoofCheck,                        config_parse_sr_iov_boolean,                              0,                             0
-SR-IOV.QueryReceiveSideScaling,              config_parse_sr_iov_boolean,                              0,                             0
-SR-IOV.Trust,                                config_parse_sr_iov_boolean,                              0,                             0
-SR-IOV.LinkState,                            config_parse_sr_iov_link_state,                           0,                             0
-SR-IOV.MACAddress,                           config_parse_sr_iov_mac,                                  0,                             0
+SR-IOV.VirtualFunction,                      config_parse_sr_iov_uint32,                               0,                             offsetof(Network, sr_iov_by_section)
+SR-IOV.VLANId,                               config_parse_sr_iov_uint32,                               0,                             offsetof(Network, sr_iov_by_section)
+SR-IOV.QualityOfService,                     config_parse_sr_iov_uint32,                               0,                             offsetof(Network, sr_iov_by_section)
+SR-IOV.VLANProtocol,                         config_parse_sr_iov_vlan_proto,                           0,                             offsetof(Network, sr_iov_by_section)
+SR-IOV.MACSpoofCheck,                        config_parse_sr_iov_boolean,                              0,                             offsetof(Network, sr_iov_by_section)
+SR-IOV.QueryReceiveSideScaling,              config_parse_sr_iov_boolean,                              0,                             offsetof(Network, sr_iov_by_section)
+SR-IOV.Trust,                                config_parse_sr_iov_boolean,                              0,                             offsetof(Network, sr_iov_by_section)
+SR-IOV.LinkState,                            config_parse_sr_iov_link_state,                           0,                             offsetof(Network, sr_iov_by_section)
+SR-IOV.MACAddress,                           config_parse_sr_iov_mac,                                  0,                             offsetof(Network, sr_iov_by_section)
 Network.Description,                         config_parse_string,                                      0,                             offsetof(Network, description)
 Network.KeepMaster,                          config_parse_bool,                                        0,                             offsetof(Network, keep_master)
 Network.BatmanAdvanced,                      config_parse_ifname,                                      0,                             offsetof(Network, batadv_name)
index 70e8af5bd498bf30a322150ea8de0e20ee220049..df4b6f23ad5a8f89685516e8017d227e76093dd9 100644 (file)
@@ -321,7 +321,7 @@ int network_verify(Network *network) {
         network_drop_invalid_route_prefixes(network);
         network_drop_invalid_routing_policy_rules(network);
         network_drop_invalid_traffic_control(network);
-        r = network_drop_invalid_sr_iov(network);
+        r = sr_iov_drop_invalid_sections(network->sr_iov_by_section);
         if (r < 0)
                 return r;
         network_drop_invalid_static_leases(network);
index 79e607b3dab4618edd0f8b51dceee4c9709b65c3..cf138c737021b3825dbfdfe20daec14b2f6ec8aa 100644 (file)
@@ -1,84 +1,10 @@
 /* SPDX-License-Identifier: LGPL-2.1-or-later
  * Copyright © 2020 VMware, Inc. */
 
-#include "alloc-util.h"
 #include "netlink-util.h"
+#include "networkd-link.h"
 #include "networkd-manager.h"
 #include "networkd-sriov.h"
-#include "parse-util.h"
-#include "set.h"
-#include "string-util.h"
-
-static int sr_iov_new(SRIOV **ret) {
-        SRIOV *sr_iov;
-
-        assert(ret);
-
-        sr_iov = new(SRIOV, 1);
-        if (!sr_iov)
-                return -ENOMEM;
-
-        *sr_iov = (SRIOV) {
-                  .vf = UINT32_MAX,
-                  .vlan_proto = ETH_P_8021Q,
-                  .vf_spoof_check_setting = -1,
-                  .trust = -1,
-                  .query_rss = -1,
-                  .link_state = _SR_IOV_LINK_STATE_INVALID,
-        };
-
-        *ret = TAKE_PTR(sr_iov);
-
-        return 0;
-}
-
-static int sr_iov_new_static(Network *network, const char *filename, unsigned section_line, SRIOV **ret) {
-        _cleanup_(config_section_freep) ConfigSection *n = NULL;
-        _cleanup_(sr_iov_freep) SRIOV *sr_iov = NULL;
-        SRIOV *existing = NULL;
-        int r;
-
-        assert(network);
-        assert(ret);
-        assert(filename);
-        assert(section_line > 0);
-
-        r = config_section_new(filename, section_line, &n);
-        if (r < 0)
-                return r;
-
-        existing = ordered_hashmap_get(network->sr_iov_by_section, n);
-        if (existing) {
-                *ret = existing;
-                return 0;
-        }
-
-        r = sr_iov_new(&sr_iov);
-        if (r < 0)
-                return r;
-
-        sr_iov->network = network;
-        sr_iov->section = TAKE_PTR(n);
-
-        r = ordered_hashmap_ensure_put(&network->sr_iov_by_section, &config_section_hash_ops, sr_iov->section, sr_iov);
-        if (r < 0)
-                return r;
-
-        *ret = TAKE_PTR(sr_iov);
-        return 0;
-}
-
-SRIOV *sr_iov_free(SRIOV *sr_iov) {
-        if (!sr_iov)
-                return NULL;
-
-        if (sr_iov->network && sr_iov->section)
-                ordered_hashmap_remove(sr_iov->network->sr_iov_by_section, sr_iov->section);
-
-        config_section_free(sr_iov->section);
-
-        return mfree(sr_iov);
-}
 
 static int sr_iov_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
         int r;
@@ -119,104 +45,16 @@ static int sr_iov_configure(Link *link, SRIOV *sr_iov) {
 
         r = sd_rtnl_message_new_link(link->manager->rtnl, &req, RTM_SETLINK, link->ifindex);
         if (r < 0)
-                return log_link_error_errno(link, r, "Could not allocate RTM_SETLINK message: %m");
-
-        r = sd_netlink_message_open_container(req, IFLA_VFINFO_LIST);
-        if (r < 0)
-                return log_link_error_errno(link, r, "Could not open IFLA_VFINFO_LIST container: %m");
-
-        r = sd_netlink_message_open_container(req, IFLA_VF_INFO);
-        if (r < 0)
-                return log_link_error_errno(link, r, "Could not open IFLA_VF_INFO container: %m");
-
-        if (!ether_addr_is_null(&sr_iov->mac)) {
-                struct ifla_vf_mac ivm = {
-                        .vf = sr_iov->vf,
-                };
-
-                memcpy(ivm.mac, &sr_iov->mac, ETH_ALEN);
-                r = sd_netlink_message_append_data(req, IFLA_VF_MAC, &ivm, sizeof(struct ifla_vf_mac));
-                if (r < 0)
-                        return log_link_error_errno(link, r, "Could not append IFLA_VF_MAC: %m");
-        }
-
-        if (sr_iov->vf_spoof_check_setting >= 0) {
-                struct ifla_vf_spoofchk ivs = {
-                        .vf = sr_iov->vf,
-                        .setting = sr_iov->vf_spoof_check_setting,
-                };
-
-                r = sd_netlink_message_append_data(req, IFLA_VF_SPOOFCHK, &ivs, sizeof(struct ifla_vf_spoofchk));
-                if (r < 0)
-                        return log_link_error_errno(link, r, "Could not append IFLA_VF_SPOOFCHK: %m");
-        }
-
-        if (sr_iov->query_rss >= 0) {
-                struct ifla_vf_rss_query_en ivs = {
-                        .vf = sr_iov->vf,
-                        .setting = sr_iov->query_rss,
-                };
-
-                r = sd_netlink_message_append_data(req, IFLA_VF_RSS_QUERY_EN, &ivs, sizeof(struct ifla_vf_rss_query_en));
-                if (r < 0)
-                        return log_link_error_errno(link, r, "Could not append IFLA_VF_RSS_QUERY_EN: %m");
-        }
-
-        if (sr_iov->trust >= 0) {
-                struct ifla_vf_trust ivt = {
-                        .vf = sr_iov->vf,
-                        .setting = sr_iov->trust,
-                };
-
-                r = sd_netlink_message_append_data(req, IFLA_VF_TRUST, &ivt, sizeof(struct ifla_vf_trust));
-                if (r < 0)
-                        return log_link_error_errno(link, r, "Could not append IFLA_VF_TRUST: %m");
-        }
-
-        if (sr_iov->link_state >= 0) {
-                struct ifla_vf_link_state ivl = {
-                        .vf = sr_iov->vf,
-                        .link_state = sr_iov->link_state,
-                };
-
-                r = sd_netlink_message_append_data(req, IFLA_VF_LINK_STATE, &ivl, sizeof(struct ifla_vf_link_state));
-                if (r < 0)
-                        return log_link_error_errno(link, r, "Could not append IFLA_VF_LINK_STATE: %m");
-        }
-
-        if (sr_iov->vlan > 0) {
-                /* Because of padding, first the buffer must be initialized with 0. */
-                struct ifla_vf_vlan_info ivvi = {};
-                ivvi.vf = sr_iov->vf;
-                ivvi.vlan = sr_iov->vlan;
-                ivvi.qos = sr_iov->qos;
-                ivvi.vlan_proto = htobe16(sr_iov->vlan_proto);
-
-                r = sd_netlink_message_open_container(req, IFLA_VF_VLAN_LIST);
-                if (r < 0)
-                        return log_link_error_errno(link, r, "Could not open IFLA_VF_VLAN_LIST container: %m");
-
-                r = sd_netlink_message_append_data(req, IFLA_VF_VLAN_INFO, &ivvi, sizeof(struct ifla_vf_vlan_info));
-                if (r < 0)
-                        return log_link_error_errno(link, r, "Could not append IFLA_VF_VLAN_INFO: %m");
-
-                r = sd_netlink_message_close_container(req);
-                if (r < 0)
-                        return log_link_error_errno(link, r, "Could not close IFLA_VF_VLAN_LIST container: %m");
-        }
-
-        r = sd_netlink_message_close_container(req);
-        if (r < 0)
-                return log_link_error_errno(link, r, "Could not close IFLA_VF_INFO container: %m");
+                return r;
 
-        r = sd_netlink_message_close_container(req);
+        r = sr_iov_set_netlink_message(sr_iov, req);
         if (r < 0)
-                return log_link_error_errno(link, r, "Could not close IFLA_VFINFO_LIST container: %m");
+                return r;
 
         r = netlink_call_async(link->manager->rtnl, NULL, req, sr_iov_handler,
                                link_netlink_destroy_callback, link);
         if (r < 0)
-                return log_link_error_errno(link, r, "Could not send rtnetlink message: %m");
+                return r;
 
         link_ref(link);
         link->sr_iov_messages++;
@@ -241,7 +79,9 @@ int link_configure_sr_iov(Link *link) {
         ORDERED_HASHMAP_FOREACH(sr_iov, link->network->sr_iov_by_section) {
                 r = sr_iov_configure(link, sr_iov);
                 if (r < 0)
-                        return r;
+                        return log_link_warning_errno(link, r,
+                                                      "Failed to configure SR-IOV virtual function %"PRIu32": %m",
+                                                      sr_iov->vf);
         }
 
         if (link->sr_iov_messages == 0)
@@ -251,312 +91,3 @@ int link_configure_sr_iov(Link *link) {
 
         return 0;
 }
-
-static int sr_iov_section_verify(SRIOV *sr_iov) {
-        assert(sr_iov);
-
-        if (section_is_invalid(sr_iov->section))
-                return -EINVAL;
-
-        if (sr_iov->vf == UINT32_MAX)
-                return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
-                                         "%s: [SR-IOV] section without VirtualFunction= field configured. "
-                                         "Ignoring [SR-IOV] section from line %u.",
-                                         sr_iov->section->filename, sr_iov->section->line);
-
-        return 0;
-}
-
-int network_drop_invalid_sr_iov(Network *network) {
-        _cleanup_hashmap_free_ Hashmap *hashmap = NULL;
-        SRIOV *sr_iov;
-        int r;
-
-        assert(network);
-
-        ORDERED_HASHMAP_FOREACH(sr_iov, network->sr_iov_by_section) {
-                SRIOV *dup;
-
-                if (sr_iov_section_verify(sr_iov) < 0) {
-                        sr_iov_free(sr_iov);
-                        continue;
-                }
-
-                assert(sr_iov->vf < INT_MAX);
-
-                dup = hashmap_remove(hashmap, UINT32_TO_PTR(sr_iov->vf + 1));
-                if (dup) {
-                        log_warning("%s: Conflicting [SR-IOV] section is specified at line %u and %u, "
-                                    "dropping the [SR-IOV] section specified at line %u.",
-                                    dup->section->filename, sr_iov->section->line,
-                                    dup->section->line, dup->section->line);
-                        sr_iov_free(dup);
-                }
-
-                r = hashmap_ensure_put(&hashmap, NULL, UINT32_TO_PTR(sr_iov->vf + 1), sr_iov);
-                if (r < 0)
-                        return log_oom();
-                assert(r > 0);
-        }
-
-        return 0;
-}
-
-int config_parse_sr_iov_uint32(
-                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) {
-
-        _cleanup_(sr_iov_free_or_set_invalidp) SRIOV *sr_iov = NULL;
-        Network *network = data;
-        uint32_t k;
-        int r;
-
-        assert(filename);
-        assert(lvalue);
-        assert(rvalue);
-        assert(data);
-
-        r = sr_iov_new_static(network, filename, section_line, &sr_iov);
-        if (r < 0)
-                return r;
-
-        if (isempty(rvalue)) {
-                if (streq(lvalue, "VirtualFunction"))
-                        sr_iov->vf = UINT32_MAX;
-                else if (streq(lvalue, "VLANId"))
-                        sr_iov->vlan = 0;
-                else if (streq(lvalue, "QualityOfService"))
-                        sr_iov->qos = 0;
-                else
-                        assert_not_reached();
-
-                TAKE_PTR(sr_iov);
-                return 0;
-        }
-
-        r = safe_atou32(rvalue, &k);
-        if (r < 0) {
-                log_syntax(unit, LOG_WARNING, filename, line, r,
-                           "Failed to parse SR-IOV '%s=', ignoring assignment: %s", lvalue, rvalue);
-                return 0;
-        }
-
-        if (streq(lvalue, "VLANId")) {
-                if (k == 0 || k > 4095) {
-                        log_syntax(unit, LOG_WARNING, filename, line, 0, "Invalid SR-IOV VLANId: %d", k);
-                        return 0;
-                }
-                sr_iov->vlan = k;
-        } else if (streq(lvalue, "VirtualFunction")) {
-                if (k >= INT_MAX) {
-                        log_syntax(unit, LOG_WARNING, filename, line, 0, "Invalid SR-IOV virtual function: %d", k);
-                        return 0;
-                }
-                sr_iov->vf = k;
-        } else if (streq(lvalue, "QualityOfService"))
-                sr_iov->qos = k;
-        else
-                assert_not_reached();
-
-        TAKE_PTR(sr_iov);
-        return 0;
-}
-
-int config_parse_sr_iov_vlan_proto(
-                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) {
-
-        _cleanup_(sr_iov_free_or_set_invalidp) SRIOV *sr_iov = NULL;
-        Network *network = data;
-        int r;
-
-        assert(filename);
-        assert(lvalue);
-        assert(rvalue);
-        assert(data);
-
-        r = sr_iov_new_static(network, filename, section_line, &sr_iov);
-        if (r < 0)
-                return r;
-
-        if (isempty(rvalue) || streq(rvalue, "802.1Q"))
-                sr_iov->vlan_proto = ETH_P_8021Q;
-        else if (streq(rvalue, "802.1ad"))
-                sr_iov->vlan_proto = ETH_P_8021AD;
-        else {
-                log_syntax(unit, LOG_WARNING, filename, line, 0,
-                           "Invalid SR-IOV '%s=', ignoring assignment: %s", lvalue, rvalue);
-                return 0;
-        }
-
-        TAKE_PTR(sr_iov);
-        return 0;
-}
-
-int config_parse_sr_iov_link_state(
-                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) {
-
-        _cleanup_(sr_iov_free_or_set_invalidp) SRIOV *sr_iov = NULL;
-        Network *network = data;
-        int r;
-
-        assert(filename);
-        assert(lvalue);
-        assert(rvalue);
-        assert(data);
-
-        r = sr_iov_new_static(network, filename, section_line, &sr_iov);
-        if (r < 0)
-                return r;
-
-        /* Unfortunately, SR_IOV_LINK_STATE_DISABLE is 2, not 0. So, we cannot use
-         * DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN() macro. */
-
-        if (isempty(rvalue)) {
-                sr_iov->link_state = _SR_IOV_LINK_STATE_INVALID;
-                TAKE_PTR(sr_iov);
-                return 0;
-        }
-
-        if (streq(rvalue, "auto")) {
-                sr_iov->link_state = SR_IOV_LINK_STATE_AUTO;
-                TAKE_PTR(sr_iov);
-                return 0;
-        }
-
-        r = parse_boolean(rvalue);
-        if (r < 0) {
-                log_syntax(unit, LOG_WARNING, filename, line, r,
-                           "Failed to parse SR-IOV '%s=', ignoring assignment: %s", lvalue, rvalue);
-                return 0;
-        }
-
-        sr_iov->link_state = r ? SR_IOV_LINK_STATE_ENABLE : SR_IOV_LINK_STATE_DISABLE;
-        TAKE_PTR(sr_iov);
-        return 0;
-}
-
-int config_parse_sr_iov_boolean(
-                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) {
-
-        _cleanup_(sr_iov_free_or_set_invalidp) SRIOV *sr_iov = NULL;
-        Network *network = data;
-        int r;
-
-        assert(filename);
-        assert(lvalue);
-        assert(rvalue);
-        assert(data);
-
-        r = sr_iov_new_static(network, filename, section_line, &sr_iov);
-        if (r < 0)
-                return r;
-
-        if (isempty(rvalue)) {
-                if (streq(lvalue, "MACSpoofCheck"))
-                        sr_iov->vf_spoof_check_setting = -1;
-                else if (streq(lvalue, "QueryReceiveSideScaling"))
-                        sr_iov->query_rss = -1;
-                else if (streq(lvalue, "Trust"))
-                        sr_iov->trust = -1;
-                else
-                        assert_not_reached();
-
-                TAKE_PTR(sr_iov);
-                return 0;
-        }
-
-        r = parse_boolean(rvalue);
-        if (r < 0) {
-                log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse '%s=', ignoring: %s", lvalue, rvalue);
-                return 0;
-        }
-
-        if (streq(lvalue, "MACSpoofCheck"))
-                sr_iov->vf_spoof_check_setting = r;
-        else if (streq(lvalue, "QueryReceiveSideScaling"))
-                sr_iov->query_rss = r;
-        else if (streq(lvalue, "Trust"))
-                sr_iov->trust = r;
-        else
-                assert_not_reached();
-
-        TAKE_PTR(sr_iov);
-        return 0;
-}
-
-int config_parse_sr_iov_mac(
-                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) {
-
-        _cleanup_(sr_iov_free_or_set_invalidp) SRIOV *sr_iov = NULL;
-        Network *network = data;
-        int r;
-
-        assert(filename);
-        assert(lvalue);
-        assert(rvalue);
-        assert(data);
-
-        r = sr_iov_new_static(network, filename, section_line, &sr_iov);
-        if (r < 0)
-                return r;
-
-        if (isempty(rvalue)) {
-                sr_iov->mac = ETHER_ADDR_NULL;
-                TAKE_PTR(sr_iov);
-                return 0;
-        }
-
-        r = parse_ether_addr(rvalue, &sr_iov->mac);
-        if (r < 0) {
-                log_syntax(unit, LOG_WARNING, filename, line, r,
-                           "Failed to parse SR-IOV '%s=', ignoring assignment: %s", lvalue, rvalue);
-                return 0;
-        }
-
-        TAKE_PTR(sr_iov);
-        return 0;
-}
index 270a82b233d9347043b529d7df8cabd3b1368191..4251fddf88b69914be3c810f5d4850a1e0cf1727 100644 (file)
@@ -2,45 +2,8 @@
  * Copyright © 2020 VMware, Inc. */
 #pragma once
 
-#include <linux/if_link.h>
+#include "netif-sriov.h"
 
-#include "conf-parser.h"
-#include "ether-addr-util.h"
-#include "networkd-link.h"
-#include "networkd-network.h"
-#include "networkd-util.h"
+typedef struct Link Link;
 
-typedef enum SRIOVLinkState {
-        SR_IOV_LINK_STATE_AUTO = IFLA_VF_LINK_STATE_AUTO,
-        SR_IOV_LINK_STATE_ENABLE = IFLA_VF_LINK_STATE_ENABLE,
-        SR_IOV_LINK_STATE_DISABLE = IFLA_VF_LINK_STATE_DISABLE,
-        _SR_IOV_LINK_STATE_MAX,
-        _SR_IOV_LINK_STATE_INVALID = -EINVAL,
-} SRIOVLinkState;
-
-typedef struct SRIOV {
-        ConfigSection *section;
-        Network *network;
-
-        uint32_t vf;   /* 0 - 2147483646 */
-        uint32_t vlan; /* 0 - 4095, 0 disables VLAN filter */
-        uint32_t qos;
-        uint16_t vlan_proto; /* ETH_P_8021Q or ETH_P_8021AD */
-        int vf_spoof_check_setting;
-        int query_rss;
-        int trust;
-        SRIOVLinkState link_state;
-        struct ether_addr mac;
-} SRIOV;
-
-SRIOV *sr_iov_free(SRIOV *sr_iov);
 int link_configure_sr_iov(Link *link);
-int network_drop_invalid_sr_iov(Network *network);
-
-DEFINE_SECTION_CLEANUP_FUNCTIONS(SRIOV, sr_iov_free);
-
-CONFIG_PARSER_PROTOTYPE(config_parse_sr_iov_uint32);
-CONFIG_PARSER_PROTOTYPE(config_parse_sr_iov_boolean);
-CONFIG_PARSER_PROTOTYPE(config_parse_sr_iov_link_state);
-CONFIG_PARSER_PROTOTYPE(config_parse_sr_iov_vlan_proto);
-CONFIG_PARSER_PROTOTYPE(config_parse_sr_iov_mac);
index f58d623f4a11184bd11088a4dcb083ee0157f12a..66715e00c3cc3df714ef923b08f5531f6e62531d 100644 (file)
@@ -224,6 +224,8 @@ shared_sources = files('''
         net-condition.h
         netif-naming-scheme.c
         netif-naming-scheme.h
+        netif-sriov.c
+        netif-sriov.h
         netif-util.c
         netif-util.h
         nscd-flush.h
diff --git a/src/shared/netif-sriov.c b/src/shared/netif-sriov.c
new file mode 100644 (file)
index 0000000..fc40ccb
--- /dev/null
@@ -0,0 +1,487 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+
+#include "alloc-util.h"
+#include "netlink-util.h"
+#include "netif-sriov.h"
+#include "parse-util.h"
+#include "set.h"
+#include "string-util.h"
+
+static int sr_iov_new(SRIOV **ret) {
+        SRIOV *sr_iov;
+
+        assert(ret);
+
+        sr_iov = new(SRIOV, 1);
+        if (!sr_iov)
+                return -ENOMEM;
+
+        *sr_iov = (SRIOV) {
+                  .vf = UINT32_MAX,
+                  .vlan_proto = ETH_P_8021Q,
+                  .vf_spoof_check_setting = -1,
+                  .trust = -1,
+                  .query_rss = -1,
+                  .link_state = _SR_IOV_LINK_STATE_INVALID,
+        };
+
+        *ret = TAKE_PTR(sr_iov);
+
+        return 0;
+}
+
+static int sr_iov_new_static(OrderedHashmap **sr_iov_by_section, const char *filename, unsigned section_line, SRIOV **ret) {
+        _cleanup_(config_section_freep) ConfigSection *n = NULL;
+        _cleanup_(sr_iov_freep) SRIOV *sr_iov = NULL;
+        SRIOV *existing = NULL;
+        int r;
+
+        assert(sr_iov_by_section);
+        assert(filename);
+        assert(section_line > 0);
+        assert(ret);
+
+        r = config_section_new(filename, section_line, &n);
+        if (r < 0)
+                return r;
+
+        existing = ordered_hashmap_get(*sr_iov_by_section, n);
+        if (existing) {
+                *ret = existing;
+                return 0;
+        }
+
+        r = sr_iov_new(&sr_iov);
+        if (r < 0)
+                return r;
+
+        r = ordered_hashmap_ensure_put(sr_iov_by_section, &config_section_hash_ops, n, sr_iov);
+        if (r < 0)
+                return r;
+
+        sr_iov->section = TAKE_PTR(n);
+        sr_iov->sr_iov_by_section = *sr_iov_by_section;
+
+        *ret = TAKE_PTR(sr_iov);
+        return 0;
+}
+
+SRIOV *sr_iov_free(SRIOV *sr_iov) {
+        if (!sr_iov)
+                return NULL;
+
+        if (sr_iov->sr_iov_by_section && sr_iov->section)
+                ordered_hashmap_remove(sr_iov->sr_iov_by_section, sr_iov->section);
+
+        config_section_free(sr_iov->section);
+
+        return mfree(sr_iov);
+}
+
+int sr_iov_set_netlink_message(SRIOV *sr_iov, sd_netlink_message *req) {
+        int r;
+
+        assert(sr_iov);
+        assert(req);
+
+        r = sd_netlink_message_open_container(req, IFLA_VFINFO_LIST);
+        if (r < 0)
+                return r;
+
+        r = sd_netlink_message_open_container(req, IFLA_VF_INFO);
+        if (r < 0)
+                return r;
+
+        if (!ether_addr_is_null(&sr_iov->mac)) {
+                struct ifla_vf_mac ivm = {
+                        .vf = sr_iov->vf,
+                };
+
+                memcpy(ivm.mac, &sr_iov->mac, ETH_ALEN);
+                r = sd_netlink_message_append_data(req, IFLA_VF_MAC, &ivm, sizeof(struct ifla_vf_mac));
+                if (r < 0)
+                        return r;
+        }
+
+        if (sr_iov->vf_spoof_check_setting >= 0) {
+                struct ifla_vf_spoofchk ivs = {
+                        .vf = sr_iov->vf,
+                        .setting = sr_iov->vf_spoof_check_setting,
+                };
+
+                r = sd_netlink_message_append_data(req, IFLA_VF_SPOOFCHK, &ivs, sizeof(struct ifla_vf_spoofchk));
+                if (r < 0)
+                        return r;
+        }
+
+        if (sr_iov->query_rss >= 0) {
+                struct ifla_vf_rss_query_en ivs = {
+                        .vf = sr_iov->vf,
+                        .setting = sr_iov->query_rss,
+                };
+
+                r = sd_netlink_message_append_data(req, IFLA_VF_RSS_QUERY_EN, &ivs, sizeof(struct ifla_vf_rss_query_en));
+                if (r < 0)
+                        return r;
+        }
+
+        if (sr_iov->trust >= 0) {
+                struct ifla_vf_trust ivt = {
+                        .vf = sr_iov->vf,
+                        .setting = sr_iov->trust,
+                };
+
+                r = sd_netlink_message_append_data(req, IFLA_VF_TRUST, &ivt, sizeof(struct ifla_vf_trust));
+                if (r < 0)
+                        return r;
+        }
+
+        if (sr_iov->link_state >= 0) {
+                struct ifla_vf_link_state ivl = {
+                        .vf = sr_iov->vf,
+                        .link_state = sr_iov->link_state,
+                };
+
+                r = sd_netlink_message_append_data(req, IFLA_VF_LINK_STATE, &ivl, sizeof(struct ifla_vf_link_state));
+                if (r < 0)
+                        return r;
+        }
+
+        if (sr_iov->vlan > 0) {
+                /* Because of padding, first the buffer must be initialized with 0. */
+                struct ifla_vf_vlan_info ivvi = {};
+                ivvi.vf = sr_iov->vf;
+                ivvi.vlan = sr_iov->vlan;
+                ivvi.qos = sr_iov->qos;
+                ivvi.vlan_proto = htobe16(sr_iov->vlan_proto);
+
+                r = sd_netlink_message_open_container(req, IFLA_VF_VLAN_LIST);
+                if (r < 0)
+                        return r;
+
+                r = sd_netlink_message_append_data(req, IFLA_VF_VLAN_INFO, &ivvi, sizeof(struct ifla_vf_vlan_info));
+                if (r < 0)
+                        return r;
+
+                r = sd_netlink_message_close_container(req);
+                if (r < 0)
+                        return r;
+        }
+
+        r = sd_netlink_message_close_container(req);
+        if (r < 0)
+                return r;
+
+        r = sd_netlink_message_close_container(req);
+        if (r < 0)
+                return r;
+
+        return 0;
+}
+
+static int sr_iov_section_verify(SRIOV *sr_iov) {
+        assert(sr_iov);
+
+        if (section_is_invalid(sr_iov->section))
+                return -EINVAL;
+
+        if (sr_iov->vf == UINT32_MAX)
+                return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
+                                         "%s: [SR-IOV] section without VirtualFunction= field configured. "
+                                         "Ignoring [SR-IOV] section from line %u.",
+                                         sr_iov->section->filename, sr_iov->section->line);
+
+        return 0;
+}
+
+int sr_iov_drop_invalid_sections(OrderedHashmap *sr_iov_by_section) {
+        _cleanup_hashmap_free_ Hashmap *hashmap = NULL;
+        SRIOV *sr_iov;
+        int r;
+
+        ORDERED_HASHMAP_FOREACH(sr_iov, sr_iov_by_section) {
+                SRIOV *dup;
+
+                if (sr_iov_section_verify(sr_iov) < 0) {
+                        sr_iov_free(sr_iov);
+                        continue;
+                }
+
+                assert(sr_iov->vf < INT_MAX);
+
+                dup = hashmap_remove(hashmap, UINT32_TO_PTR(sr_iov->vf + 1));
+                if (dup) {
+                        log_warning("%s: Conflicting [SR-IOV] section is specified at line %u and %u, "
+                                    "dropping the [SR-IOV] section specified at line %u.",
+                                    dup->section->filename, sr_iov->section->line,
+                                    dup->section->line, dup->section->line);
+                        sr_iov_free(dup);
+                }
+
+                r = hashmap_ensure_put(&hashmap, NULL, UINT32_TO_PTR(sr_iov->vf + 1), sr_iov);
+                if (r < 0)
+                        return log_oom();
+                assert(r > 0);
+        }
+
+        return 0;
+}
+
+int config_parse_sr_iov_uint32(
+                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) {
+
+        _cleanup_(sr_iov_free_or_set_invalidp) SRIOV *sr_iov = NULL;
+        OrderedHashmap **sr_iov_by_section = data;
+        uint32_t k;
+        int r;
+
+        assert(filename);
+        assert(lvalue);
+        assert(rvalue);
+        assert(data);
+
+        r = sr_iov_new_static(sr_iov_by_section, filename, section_line, &sr_iov);
+        if (r < 0)
+                return r;
+
+        if (isempty(rvalue)) {
+                if (streq(lvalue, "VirtualFunction"))
+                        sr_iov->vf = UINT32_MAX;
+                else if (streq(lvalue, "VLANId"))
+                        sr_iov->vlan = 0;
+                else if (streq(lvalue, "QualityOfService"))
+                        sr_iov->qos = 0;
+                else
+                        assert_not_reached();
+
+                TAKE_PTR(sr_iov);
+                return 0;
+        }
+
+        r = safe_atou32(rvalue, &k);
+        if (r < 0) {
+                log_syntax(unit, LOG_WARNING, filename, line, r,
+                           "Failed to parse SR-IOV '%s=', ignoring assignment: %s", lvalue, rvalue);
+                return 0;
+        }
+
+        if (streq(lvalue, "VLANId")) {
+                if (k == 0 || k > 4095) {
+                        log_syntax(unit, LOG_WARNING, filename, line, 0, "Invalid SR-IOV VLANId: %d", k);
+                        return 0;
+                }
+                sr_iov->vlan = k;
+        } else if (streq(lvalue, "VirtualFunction")) {
+                if (k >= INT_MAX) {
+                        log_syntax(unit, LOG_WARNING, filename, line, 0, "Invalid SR-IOV virtual function: %d", k);
+                        return 0;
+                }
+                sr_iov->vf = k;
+        } else if (streq(lvalue, "QualityOfService"))
+                sr_iov->qos = k;
+        else
+                assert_not_reached();
+
+        TAKE_PTR(sr_iov);
+        return 0;
+}
+
+int config_parse_sr_iov_vlan_proto(
+                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) {
+
+        _cleanup_(sr_iov_free_or_set_invalidp) SRIOV *sr_iov = NULL;
+        OrderedHashmap **sr_iov_by_section = data;
+        int r;
+
+        assert(filename);
+        assert(lvalue);
+        assert(rvalue);
+        assert(data);
+
+        r = sr_iov_new_static(sr_iov_by_section, filename, section_line, &sr_iov);
+        if (r < 0)
+                return r;
+
+        if (isempty(rvalue) || streq(rvalue, "802.1Q"))
+                sr_iov->vlan_proto = ETH_P_8021Q;
+        else if (streq(rvalue, "802.1ad"))
+                sr_iov->vlan_proto = ETH_P_8021AD;
+        else {
+                log_syntax(unit, LOG_WARNING, filename, line, 0,
+                           "Invalid SR-IOV '%s=', ignoring assignment: %s", lvalue, rvalue);
+                return 0;
+        }
+
+        TAKE_PTR(sr_iov);
+        return 0;
+}
+
+int config_parse_sr_iov_link_state(
+                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) {
+
+        _cleanup_(sr_iov_free_or_set_invalidp) SRIOV *sr_iov = NULL;
+        OrderedHashmap **sr_iov_by_section = data;
+        int r;
+
+        assert(filename);
+        assert(lvalue);
+        assert(rvalue);
+        assert(data);
+
+        r = sr_iov_new_static(sr_iov_by_section, filename, section_line, &sr_iov);
+        if (r < 0)
+                return r;
+
+        /* Unfortunately, SR_IOV_LINK_STATE_DISABLE is 2, not 0. So, we cannot use
+         * DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN() macro. */
+
+        if (isempty(rvalue)) {
+                sr_iov->link_state = _SR_IOV_LINK_STATE_INVALID;
+                TAKE_PTR(sr_iov);
+                return 0;
+        }
+
+        if (streq(rvalue, "auto")) {
+                sr_iov->link_state = SR_IOV_LINK_STATE_AUTO;
+                TAKE_PTR(sr_iov);
+                return 0;
+        }
+
+        r = parse_boolean(rvalue);
+        if (r < 0) {
+                log_syntax(unit, LOG_WARNING, filename, line, r,
+                           "Failed to parse SR-IOV '%s=', ignoring assignment: %s", lvalue, rvalue);
+                return 0;
+        }
+
+        sr_iov->link_state = r ? SR_IOV_LINK_STATE_ENABLE : SR_IOV_LINK_STATE_DISABLE;
+        TAKE_PTR(sr_iov);
+        return 0;
+}
+
+int config_parse_sr_iov_boolean(
+                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) {
+
+        _cleanup_(sr_iov_free_or_set_invalidp) SRIOV *sr_iov = NULL;
+        OrderedHashmap **sr_iov_by_section = data;
+        int r;
+
+        assert(filename);
+        assert(lvalue);
+        assert(rvalue);
+        assert(data);
+
+        r = sr_iov_new_static(sr_iov_by_section, filename, section_line, &sr_iov);
+        if (r < 0)
+                return r;
+
+        if (isempty(rvalue)) {
+                if (streq(lvalue, "MACSpoofCheck"))
+                        sr_iov->vf_spoof_check_setting = -1;
+                else if (streq(lvalue, "QueryReceiveSideScaling"))
+                        sr_iov->query_rss = -1;
+                else if (streq(lvalue, "Trust"))
+                        sr_iov->trust = -1;
+                else
+                        assert_not_reached();
+
+                TAKE_PTR(sr_iov);
+                return 0;
+        }
+
+        r = parse_boolean(rvalue);
+        if (r < 0) {
+                log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse '%s=', ignoring: %s", lvalue, rvalue);
+                return 0;
+        }
+
+        if (streq(lvalue, "MACSpoofCheck"))
+                sr_iov->vf_spoof_check_setting = r;
+        else if (streq(lvalue, "QueryReceiveSideScaling"))
+                sr_iov->query_rss = r;
+        else if (streq(lvalue, "Trust"))
+                sr_iov->trust = r;
+        else
+                assert_not_reached();
+
+        TAKE_PTR(sr_iov);
+        return 0;
+}
+
+int config_parse_sr_iov_mac(
+                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) {
+
+        _cleanup_(sr_iov_free_or_set_invalidp) SRIOV *sr_iov = NULL;
+        OrderedHashmap **sr_iov_by_section = data;
+        int r;
+
+        assert(filename);
+        assert(lvalue);
+        assert(rvalue);
+        assert(data);
+
+        r = sr_iov_new_static(sr_iov_by_section, filename, section_line, &sr_iov);
+        if (r < 0)
+                return r;
+
+        if (isempty(rvalue)) {
+                sr_iov->mac = ETHER_ADDR_NULL;
+                TAKE_PTR(sr_iov);
+                return 0;
+        }
+
+        r = parse_ether_addr(rvalue, &sr_iov->mac);
+        if (r < 0) {
+                log_syntax(unit, LOG_WARNING, filename, line, r,
+                           "Failed to parse SR-IOV '%s=', ignoring assignment: %s", lvalue, rvalue);
+                return 0;
+        }
+
+        TAKE_PTR(sr_iov);
+        return 0;
+}
diff --git a/src/shared/netif-sriov.h b/src/shared/netif-sriov.h
new file mode 100644 (file)
index 0000000..8714962
--- /dev/null
@@ -0,0 +1,43 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+#pragma once
+
+#include <linux/if_link.h>
+
+#include "conf-parser.h"
+#include "ether-addr-util.h"
+#include "hashmap.h"
+
+typedef enum SRIOVLinkState {
+        SR_IOV_LINK_STATE_AUTO = IFLA_VF_LINK_STATE_AUTO,
+        SR_IOV_LINK_STATE_ENABLE = IFLA_VF_LINK_STATE_ENABLE,
+        SR_IOV_LINK_STATE_DISABLE = IFLA_VF_LINK_STATE_DISABLE,
+        _SR_IOV_LINK_STATE_MAX,
+        _SR_IOV_LINK_STATE_INVALID = -EINVAL,
+} SRIOVLinkState;
+
+typedef struct SRIOV {
+        ConfigSection *section;
+        OrderedHashmap *sr_iov_by_section;
+
+        uint32_t vf;   /* 0 - 2147483646 */
+        uint32_t vlan; /* 0 - 4095, 0 disables VLAN filter */
+        uint32_t qos;
+        uint16_t vlan_proto; /* ETH_P_8021Q or ETH_P_8021AD */
+        int vf_spoof_check_setting;
+        int query_rss;
+        int trust;
+        SRIOVLinkState link_state;
+        struct ether_addr mac;
+} SRIOV;
+
+SRIOV *sr_iov_free(SRIOV *sr_iov);
+int sr_iov_set_netlink_message(SRIOV *sr_iov, sd_netlink_message *req);
+int sr_iov_drop_invalid_sections(OrderedHashmap *sr_iov_by_section);
+
+DEFINE_SECTION_CLEANUP_FUNCTIONS(SRIOV, sr_iov_free);
+
+CONFIG_PARSER_PROTOTYPE(config_parse_sr_iov_uint32);
+CONFIG_PARSER_PROTOTYPE(config_parse_sr_iov_boolean);
+CONFIG_PARSER_PROTOTYPE(config_parse_sr_iov_link_state);
+CONFIG_PARSER_PROTOTYPE(config_parse_sr_iov_vlan_proto);
+CONFIG_PARSER_PROTOTYPE(config_parse_sr_iov_mac);