1 /* SPDX-License-Identifier: LGPL-2.1-or-later
2 * Copyright © 2020 VMware, Inc. */
4 #include "device-enumerator-private.h"
5 #include "device-util.h"
7 #include "networkd-link.h"
8 #include "networkd-manager.h"
9 #include "networkd-queue.h"
10 #include "networkd-sriov.h"
12 static int sr_iov_handler(sd_netlink
*rtnl
, sd_netlink_message
*m
, Request
*req
, Link
*link
, SRIOV
*sr_iov
) {
18 r
= sd_netlink_message_get_errno(m
);
19 if (r
< 0 && r
!= -EEXIST
) {
20 log_link_message_error_errno(link
, m
, r
, "Could not set up SR-IOV");
21 link_enter_failed(link
);
25 if (link
->sr_iov_messages
== 0) {
26 log_link_debug(link
, "SR-IOV configured");
27 link
->sr_iov_configured
= true;
28 link_check_ready(link
);
34 static int sr_iov_configure(SRIOV
*sr_iov
, Link
*link
, Request
*req
) {
35 _cleanup_(sd_netlink_message_unrefp
) sd_netlink_message
*m
= NULL
;
40 assert(link
->manager
);
41 assert(link
->manager
->rtnl
);
42 assert(link
->ifindex
> 0);
45 log_link_debug(link
, "Setting SR-IOV virtual function %"PRIu32
".", sr_iov
->vf
);
47 r
= sd_rtnl_message_new_link(link
->manager
->rtnl
, &m
, RTM_SETLINK
, link
->ifindex
);
51 r
= sr_iov_set_netlink_message(sr_iov
, m
);
55 return request_call_netlink_async(link
->manager
->rtnl
, m
, req
);
58 static int sr_iov_process_request(Request
*req
, Link
*link
, SRIOV
*sr_iov
) {
65 if (!IN_SET(link
->state
, LINK_STATE_CONFIGURING
, LINK_STATE_CONFIGURED
))
68 r
= sr_iov_configure(sr_iov
, link
, req
);
70 return log_link_warning_errno(link
, r
,
71 "Failed to configure SR-IOV virtual function %"PRIu32
": %m",
77 int link_request_sr_iov_vfs(Link
*link
) {
82 assert(link
->network
);
84 link
->sr_iov_configured
= false;
86 ORDERED_HASHMAP_FOREACH(sr_iov
, link
->network
->sr_iov_by_section
) {
87 r
= link_queue_request_safe(link
, REQUEST_TYPE_SRIOV
,
91 sr_iov_process_request
,
92 &link
->sr_iov_messages
,
96 return log_link_warning_errno(link
, r
,
97 "Failed to request SR-IOV virtual function %"PRIu32
": %m",
101 if (link
->sr_iov_messages
== 0) {
102 link
->sr_iov_configured
= true;
103 link_check_ready(link
);
105 log_link_debug(link
, "Configuring SR-IOV");
110 static int find_ifindex_from_pci_dev_port(sd_device
*pci_dev
, const char *dev_port
) {
111 _cleanup_(sd_device_enumerator_unrefp
) sd_device_enumerator
*e
= NULL
;
118 r
= sd_device_enumerator_new(&e
);
122 r
= sd_device_enumerator_allow_uninitialized(e
);
126 r
= sd_device_enumerator_add_match_parent(e
, pci_dev
);
130 r
= sd_device_enumerator_add_match_subsystem(e
, "net", true);
134 r
= sd_device_enumerator_add_match_sysattr(e
, "dev_port", dev_port
, true);
138 dev
= sd_device_enumerator_get_device_first(e
);
140 return -ENODEV
; /* no device found */
142 if (sd_device_enumerator_get_device_next(e
))
143 return -ENXIO
; /* multiple devices found */
145 r
= sd_device_get_ifindex(dev
, &ifindex
);
153 static int manager_update_sr_iov_ifindices(Manager
*manager
, int phys_port_ifindex
, int virt_port_ifindex
) {
154 Link
*phys_link
= NULL
, *virt_link
= NULL
;
158 assert(phys_port_ifindex
> 0);
159 assert(virt_port_ifindex
> 0);
161 /* This sets ifindices only when both interfaces are already managed by us. */
163 r
= link_get_by_index(manager
, phys_port_ifindex
, &phys_link
);
167 r
= link_get_by_index(manager
, virt_port_ifindex
, &virt_link
);
171 /* update VF ifindex in PF */
172 r
= set_ensure_put(&phys_link
->sr_iov_virt_port_ifindices
, NULL
, INT_TO_PTR(virt_port_ifindex
));
176 log_link_debug(phys_link
,
177 "Found SR-IOV VF port %s(%i).",
178 virt_link
? virt_link
->ifname
: "n/a", virt_port_ifindex
);
180 /* update PF ifindex in VF */
181 if (virt_link
->sr_iov_phys_port_ifindex
> 0 && virt_link
->sr_iov_phys_port_ifindex
!= phys_port_ifindex
) {
184 if (link_get_by_index(manager
, virt_link
->sr_iov_phys_port_ifindex
, &old_phys_link
) >= 0)
185 set_remove(old_phys_link
->sr_iov_virt_port_ifindices
, INT_TO_PTR(virt_port_ifindex
));
188 virt_link
->sr_iov_phys_port_ifindex
= phys_port_ifindex
;
190 log_link_debug(virt_link
,
191 "Found SR-IOV PF port %s(%i).",
192 phys_link
? phys_link
->ifname
: "n/a", phys_port_ifindex
);
197 static int link_set_sr_iov_phys_port(Link
*link
) {
198 _cleanup_(sd_device_unrefp
) sd_device
*pci_physfn_dev
= NULL
;
199 const char *dev_port
;
204 assert(link
->manager
);
206 if (link
->sr_iov_phys_port_ifindex
> 0)
212 r
= sd_device_get_sysattr_value(link
->dev
, "dev_port", &dev_port
);
216 r
= sd_device_get_parent_with_subsystem_devtype(link
->dev
, "pci", NULL
, &pci_dev
);
220 r
= sd_device_new_child(&pci_physfn_dev
, pci_dev
, "physfn");
224 r
= find_ifindex_from_pci_dev_port(pci_physfn_dev
, dev_port
);
228 return manager_update_sr_iov_ifindices(link
->manager
, r
, link
->ifindex
);
231 static int link_set_sr_iov_virt_ports(Link
*link
) {
232 const char *dev_port
, *name
;
233 sd_device
*pci_dev
, *child
;
237 assert(link
->manager
);
239 set_clear(link
->sr_iov_virt_port_ifindices
);
244 r
= sd_device_get_sysattr_value(link
->dev
, "dev_port", &dev_port
);
248 r
= sd_device_get_parent_with_subsystem_devtype(link
->dev
, "pci", NULL
, &pci_dev
);
252 FOREACH_DEVICE_CHILD_WITH_SUFFIX(pci_dev
, child
, name
) {
255 /* Accept name prefixed with "virtfn", but refuse "virtfn" itself. */
256 n
= startswith(name
, "virtfn");
257 if (isempty(n
) || !in_charset(n
, DIGITS
))
260 r
= find_ifindex_from_pci_dev_port(child
, dev_port
);
264 if (manager_update_sr_iov_ifindices(link
->manager
, link
->ifindex
, r
) < 0)
271 int link_set_sr_iov_ifindices(Link
*link
) {
276 r
= link_set_sr_iov_phys_port(link
);
277 if (r
< 0 && !ERRNO_IS_DEVICE_ABSENT(r
))
280 r
= link_set_sr_iov_virt_ports(link
);
281 if (r
< 0 && !ERRNO_IS_DEVICE_ABSENT(r
))
287 void link_clear_sr_iov_ifindices(Link
*link
) {
291 assert(link
->manager
);
293 if (link
->sr_iov_phys_port_ifindex
> 0) {
296 if (link_get_by_index(link
->manager
, link
->sr_iov_phys_port_ifindex
, &phys_link
) >= 0)
297 set_remove(phys_link
->sr_iov_virt_port_ifindices
, INT_TO_PTR(link
->ifindex
));
299 link
->sr_iov_phys_port_ifindex
= 0;
302 while ((v
= set_steal_first(link
->sr_iov_virt_port_ifindices
))) {
305 if (link_get_by_index(link
->manager
, PTR_TO_INT(v
), &virt_link
) >= 0)
306 virt_link
->sr_iov_phys_port_ifindex
= 0;
310 bool check_ready_for_all_sr_iov_ports(
312 bool allow_unmanaged
, /* for the main target */
313 bool (check_one
)(Link
*link
, bool allow_unmanaged
)) {
319 assert(link
->manager
);
322 /* Some drivers make VF ports become down when their PF port becomes down, and may fail to configure
323 * VF ports. Also, when a VF port becomes up/down, its PF port and other VF ports may become down.
324 * See issue #23315. */
326 /* First, check the main target. */
327 if (!check_one(link
, allow_unmanaged
))
330 /* If this is a VF port, then also check the PF port. */
331 if (link
->sr_iov_phys_port_ifindex
> 0) {
332 if (link_get_by_index(link
->manager
, link
->sr_iov_phys_port_ifindex
, &phys_link
) < 0 ||
333 !check_one(phys_link
, /* allow_unmanaged = */ true))
338 /* Also check all VF ports. */
339 SET_FOREACH(v
, phys_link
->sr_iov_virt_port_ifindices
) {
340 int ifindex
= PTR_TO_INT(v
);
343 if (ifindex
== link
->ifindex
)
344 continue; /* The main target link is a VF port, and its state is already checked. */
346 if (link_get_by_index(link
->manager
, ifindex
, &virt_link
) < 0)
349 if (!check_one(virt_link
, /* allow_unmanaged = */ true))