]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
network,udev: configure SR-IOV VF attribute one-by-one 37269/head
authorYu Watanabe <watanabe.yu+github@gmail.com>
Wed, 30 Apr 2025 06:37:28 +0000 (15:37 +0900)
committerYu Watanabe <watanabe.yu+github@gmail.com>
Wed, 30 Apr 2025 06:47:19 +0000 (15:47 +0900)
When a [SR-IOV] section has no setting, e.g.
```ini
[SR-IOV]
VirtualFunction=0
```
then the kernel previously replied -EINVAL, as we send a rtnl message
with an empty IFLA_VF_INFO container.
See See do_setvfinfo() in net/core/rtnetlink.c of the kernel.

When a [SR-IOV] section that has an unsupported settings by the
interface driver, then previously the kernel partially applied
settings and returned -EOPNOTSUPP. E.f.
```ini
[SR-IOV]
VirtualFunction=0
LinkState=auto
Trust=true
MACAddress=02:01:00:3e:61:34
```
and the interface does not support configuring the link state, then
the MAC address is assigned, but the trust is not applied:
```
enp3s0f0: Failed to configure SR-IOV virtual function 0, ignoring: Operation not supported
    vf 0     link/ether 02:01:00:3e:61:34 brd ff:ff:ff:ff:ff:ff, spoof checking on, link-state auto, trust off
```

To fix such issues, this makes networkd/udevd send each attribute
for VF one-by-one.

Fixes #37257 and #37275.

src/network/networkd-queue.c
src/network/networkd-queue.h
src/network/networkd-sriov.c
src/shared/netif-sriov.c
src/shared/netif-sriov.h
src/udev/net/link-config.c

index 7b5060a049e11aa738c6e622e25d6ced343833e6..361aa7eec2ec3ff006aab4291d37874b01e2f9ab 100644 (file)
@@ -384,7 +384,12 @@ static const char *const request_type_table[_REQUEST_TYPE_MAX] = {
         [REQUEST_TYPE_SET_LINK_MAC]                     = "MAC address",
         [REQUEST_TYPE_SET_LINK_MASTER]                  = "master interface",
         [REQUEST_TYPE_SET_LINK_MTU]                     = "MTU",
-        [REQUEST_TYPE_SRIOV]                            = "SR-IOV",
+        [REQUEST_TYPE_SRIOV_VF_MAC]                     = "SR-IOV VF MAC address",
+        [REQUEST_TYPE_SRIOV_VF_SPOOFCHK]                = "SR-IOV VF spoof check",
+        [REQUEST_TYPE_SRIOV_VF_RSS_QUERY_EN]            = "SR-IOV VF RSS query",
+        [REQUEST_TYPE_SRIOV_VF_TRUST]                   = "SR-IOV VF trust",
+        [REQUEST_TYPE_SRIOV_VF_LINK_STATE]              = "SR-IOV VF link state",
+        [REQUEST_TYPE_SRIOV_VF_VLAN_LIST]               = "SR-IOV VF vlan list",
         [REQUEST_TYPE_TC_QDISC]                         = "QDisc",
         [REQUEST_TYPE_TC_CLASS]                         = "TClass",
         [REQUEST_TYPE_UP_DOWN]                          = "bring link up or down",
index 8600ffe8697d41afded7d152e9a2427deadb963d..00a514266d9f2711fa9b190b275bd7c5427b7dcd 100644 (file)
@@ -5,6 +5,7 @@
 
 #include "alloc-util.h"
 #include "hash-funcs.h"
+#include "netif-sriov.h"
 
 typedef struct Link Link;
 typedef struct NetDev NetDev;
@@ -44,7 +45,13 @@ typedef enum RequestType {
         REQUEST_TYPE_SET_LINK_MAC,                     /* Setting MAC address. */
         REQUEST_TYPE_SET_LINK_MASTER,                  /* Setting IFLA_MASTER. */
         REQUEST_TYPE_SET_LINK_MTU,                     /* Setting MTU. */
-        REQUEST_TYPE_SRIOV,
+        _REQUEST_TYPE_SRIOV_BASE,
+        REQUEST_TYPE_SRIOV_VF_MAC          = _REQUEST_TYPE_SRIOV_BASE + SR_IOV_VF_MAC,
+        REQUEST_TYPE_SRIOV_VF_SPOOFCHK     = _REQUEST_TYPE_SRIOV_BASE + SR_IOV_VF_SPOOFCHK,
+        REQUEST_TYPE_SRIOV_VF_RSS_QUERY_EN = _REQUEST_TYPE_SRIOV_BASE + SR_IOV_VF_RSS_QUERY_EN,
+        REQUEST_TYPE_SRIOV_VF_TRUST        = _REQUEST_TYPE_SRIOV_BASE + SR_IOV_VF_TRUST,
+        REQUEST_TYPE_SRIOV_VF_LINK_STATE   = _REQUEST_TYPE_SRIOV_BASE + SR_IOV_VF_LINK_STATE,
+        REQUEST_TYPE_SRIOV_VF_VLAN_LIST    = _REQUEST_TYPE_SRIOV_BASE + SR_IOV_VF_VLAN_LIST,
         REQUEST_TYPE_TC_CLASS,
         REQUEST_TYPE_TC_QDISC,
         REQUEST_TYPE_UP_DOWN,
index 3552d213c2bc0462f44099e7091f42059bb354c4..44b5c6ecf31114e265ff77d7bad315e0455a7bb7 100644 (file)
@@ -39,13 +39,18 @@ static int sr_iov_configure(SRIOV *sr_iov, Link *link, Request *req) {
         assert(link->ifindex > 0);
         assert(req);
 
-        log_link_debug(link, "Setting up SR-IOV virtual function %"PRIu32".", sr_iov->vf);
+        SRIOVAttribute attr = req->type - _REQUEST_TYPE_SRIOV_BASE;
+        assert(attr >= 0);
+        assert(attr < _SR_IOV_ATTRIBUTE_MAX);
+
+        log_link_debug(link, "Setting up %s for SR-IOV virtual function %"PRIu32".",
+                       sr_iov_attribute_to_string(attr), sr_iov->vf);
 
         r = sd_rtnl_message_new_link(link->manager->rtnl, &m, RTM_SETLINK, link->ifindex);
         if (r < 0)
                 return r;
 
-        r = sr_iov_set_netlink_message(sr_iov, m);
+        r = sr_iov_set_netlink_message(sr_iov, attr, m);
         if (r < 0)
                 return r;
 
@@ -81,18 +86,26 @@ int link_request_sr_iov_vfs(Link *link) {
         link->sr_iov_configured = false;
 
         ORDERED_HASHMAP_FOREACH(sr_iov, link->network->sr_iov_by_section) {
-                r = link_queue_request_safe(link, REQUEST_TYPE_SRIOV,
-                                            sr_iov, NULL,
-                                            sr_iov_hash_func,
-                                            sr_iov_compare_func,
-                                            sr_iov_process_request,
-                                            &link->sr_iov_messages,
-                                            sr_iov_handler,
-                                            NULL);
-                if (r < 0)
-                        return log_link_warning_errno(link, r,
-                                                      "Failed to request to set up SR-IOV virtual function %"PRIu32": %m",
-                                                      sr_iov->vf);
+                for (SRIOVAttribute attr = 0; attr < _SR_IOV_ATTRIBUTE_MAX; attr++) {
+                        if (!sr_iov_has_config(sr_iov, attr))
+                                continue;
+
+                        r = link_queue_request_safe(
+                                        link,
+                                        _REQUEST_TYPE_SRIOV_BASE + attr,
+                                        sr_iov,
+                                        NULL,
+                                        sr_iov_hash_func,
+                                        sr_iov_compare_func,
+                                        sr_iov_process_request,
+                                        &link->sr_iov_messages,
+                                        sr_iov_handler,
+                                        NULL);
+                        if (r < 0)
+                                return log_link_warning_errno(link, r,
+                                                              "Failed to request to set up SR-IOV virtual function %"PRIu32": %m",
+                                                              sr_iov->vf);
+                }
         }
 
         if (link->sr_iov_messages == 0) {
index fc851689b092e87913f3e431f54228431128ebf7..4889422c6dbca8f04afb56bd53007ea76da69065 100644 (file)
@@ -7,6 +7,7 @@
 #include "parse-util.h"
 #include "set.h"
 #include "stdio-util.h"
+#include "string-table.h"
 #include "string-util.h"
 
 static SRIOV* sr_iov_free(SRIOV *sr_iov) {
@@ -107,7 +108,46 @@ DEFINE_PRIVATE_HASH_OPS(
         sr_iov_hash_func,
         sr_iov_compare_func);
 
-int sr_iov_set_netlink_message(SRIOV *sr_iov, sd_netlink_message *req) {
+static const char * const sr_iov_attribute_table[_SR_IOV_ATTRIBUTE_MAX] = {
+        [SR_IOV_VF_MAC]          = "MAC address",
+        [SR_IOV_VF_SPOOFCHK]     = "spoof check",
+        [SR_IOV_VF_RSS_QUERY_EN] = "RSS query",
+        [SR_IOV_VF_TRUST]        = "trust",
+        [SR_IOV_VF_LINK_STATE]   = "link state",
+        [SR_IOV_VF_VLAN_LIST]    = "vlan list",
+};
+
+DEFINE_STRING_TABLE_LOOKUP_TO_STRING(sr_iov_attribute, SRIOVAttribute);
+
+bool sr_iov_has_config(SRIOV *sr_iov, SRIOVAttribute attr) {
+        assert(sr_iov);
+
+        switch (attr) {
+        case SR_IOV_VF_MAC:
+                return !ether_addr_is_null(&sr_iov->mac);
+
+        case SR_IOV_VF_SPOOFCHK:
+                return sr_iov->vf_spoof_check_setting >= 0;
+
+        case SR_IOV_VF_RSS_QUERY_EN:
+                return sr_iov->query_rss >= 0;
+
+        case SR_IOV_VF_TRUST:
+                return sr_iov->trust >= 0;
+
+        case SR_IOV_VF_LINK_STATE:
+                return sr_iov->link_state >= 0;
+
+        case SR_IOV_VF_VLAN_LIST:
+                return sr_iov->vlan > 0;
+
+        default:
+                assert_not_reached();
+        }
+}
+
+int sr_iov_set_netlink_message(SRIOV *sr_iov, SRIOVAttribute attr, sd_netlink_message *req) {
+
         int r;
 
         assert(sr_iov);
@@ -121,62 +161,71 @@ int sr_iov_set_netlink_message(SRIOV *sr_iov, sd_netlink_message *req) {
         if (r < 0)
                 return r;
 
-        if (!ether_addr_is_null(&sr_iov->mac)) {
+        switch (attr) {
+        case SR_IOV_VF_MAC: {
+                if (ether_addr_is_null(&sr_iov->mac))
+                        return -ENODATA;
+
                 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;
+                break;
         }
+        case SR_IOV_VF_SPOOFCHK: {
+                if (sr_iov->vf_spoof_check_setting < 0)
+                        return -ENODATA;
 
-        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;
+                break;
         }
+        case SR_IOV_VF_RSS_QUERY_EN: {
+                if (sr_iov->query_rss < 0)
+                        return -ENODATA;
 
-        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;
+                break;
         }
+        case SR_IOV_VF_TRUST: {
+                if (sr_iov->trust < 0)
+                        return -ENODATA;
 
-        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;
+                break;
         }
+        case SR_IOV_VF_LINK_STATE: {
+                if (sr_iov->link_state < 0)
+                        return -ENODATA;
 
-        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;
+                break;
         }
+        case SR_IOV_VF_VLAN_LIST: {
+                if (sr_iov->vlan <= 0)
+                        return -ENODATA;
 
-        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;
@@ -193,9 +242,13 @@ int sr_iov_set_netlink_message(SRIOV *sr_iov, sd_netlink_message *req) {
                         return r;
 
                 r = sd_netlink_message_close_container(req);
-                if (r < 0)
-                        return r;
+                break;
         }
+        default:
+                assert_not_reached();
+        }
+        if (r < 0)
+                return r;
 
         r = sd_netlink_message_close_container(req);
         if (r < 0)
index a7ebb5f3cb85791a320dc83cd030ca6c26e95bec..49e05fa28585b2b6a28d4a43364454b5237b27f3 100644 (file)
 #include "ether-addr-util.h"
 #include "hashmap.h"
 
+typedef enum SRIOVAttribute {
+        SR_IOV_VF_MAC,
+        SR_IOV_VF_SPOOFCHK,
+        SR_IOV_VF_RSS_QUERY_EN,
+        SR_IOV_VF_TRUST,
+        SR_IOV_VF_LINK_STATE,
+        SR_IOV_VF_VLAN_LIST,
+        _SR_IOV_ATTRIBUTE_MAX,
+        _SR_IOV_ATTRIBUTE_INVALID = -EINVAL,
+} SRIOVAttribute;
+
 typedef enum SRIOVLinkState {
         SR_IOV_LINK_STATE_AUTO     = IFLA_VF_LINK_STATE_AUTO,
         SR_IOV_LINK_STATE_ENABLE   = IFLA_VF_LINK_STATE_ENABLE,
@@ -33,9 +44,12 @@ typedef struct SRIOV {
         struct ether_addr mac;
 } SRIOV;
 
+const char* sr_iov_attribute_to_string(SRIOVAttribute a) _const_;
+
 void sr_iov_hash_func(const SRIOV *sr_iov, struct siphash *state);
 int sr_iov_compare_func(const SRIOV *s1, const SRIOV *s2);
-int sr_iov_set_netlink_message(SRIOV *sr_iov, sd_netlink_message *req);
+bool sr_iov_has_config(SRIOV *sr_iov, SRIOVAttribute attr);
+int sr_iov_set_netlink_message(SRIOV *sr_iov, SRIOVAttribute attr, sd_netlink_message *req);
 int sr_iov_get_num_vfs(sd_device *device, uint32_t *ret);
 int sr_iov_set_num_vfs(sd_device *device, uint32_t num_vfs, OrderedHashmap *sr_iov_by_section);
 int sr_iov_drop_invalid_sections(uint32_t num_vfs, OrderedHashmap *sr_iov_by_section);
index 6c61ff743cef522d0e90bcfc9c40b75110215a28..5c67cf2dc6082f2ec3feb6a0605f052762c1954d 100644 (file)
@@ -855,30 +855,35 @@ static int link_generate_alternative_names(Link *link) {
 }
 
 static int sr_iov_configure(Link *link, sd_netlink **rtnl, SRIOV *sr_iov) {
-        _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
         int r;
 
         assert(link);
         assert(rtnl);
         assert(link->ifindex > 0);
 
-        if (!*rtnl) {
-                r = sd_netlink_open(rtnl);
+        for (SRIOVAttribute attr = 0; attr < _SR_IOV_ATTRIBUTE_MAX; attr++) {
+                if (!sr_iov_has_config(sr_iov, attr))
+                        continue;
+
+                if (!*rtnl) {
+                        r = sd_netlink_open(rtnl);
+                        if (r < 0)
+                                return r;
+                }
+
+                _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
+                r = sd_rtnl_message_new_link(*rtnl, &req, RTM_SETLINK, link->ifindex);
                 if (r < 0)
                         return r;
-        }
 
-        r = sd_rtnl_message_new_link(*rtnl, &req, RTM_SETLINK, link->ifindex);
-        if (r < 0)
-                return r;
-
-        r = sr_iov_set_netlink_message(sr_iov, req);
-        if (r < 0)
-                return r;
+                r = sr_iov_set_netlink_message(sr_iov, attr, req);
+                if (r < 0)
+                        return r;
 
-        r = sd_netlink_call(*rtnl, req, 0, NULL);
-        if (r < 0)
-                return r;
+                r = sd_netlink_call(*rtnl, req, 0, NULL);
+                if (r < 0)
+                        return r;
+        }
 
         return 0;
 }