1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
3 #include "alloc-util.h"
4 #include "device-util.h"
5 #include "netlink-util.h"
6 #include "netif-sriov.h"
7 #include "parse-util.h"
9 #include "stdio-util.h"
10 #include "string-util.h"
12 static int sr_iov_new(SRIOV
**ret
) {
17 sr_iov
= new(SRIOV
, 1);
23 .vlan_proto
= ETH_P_8021Q
,
24 .vf_spoof_check_setting
= -1,
27 .link_state
= _SR_IOV_LINK_STATE_INVALID
,
30 *ret
= TAKE_PTR(sr_iov
);
35 static int sr_iov_new_static(OrderedHashmap
**sr_iov_by_section
, const char *filename
, unsigned section_line
, SRIOV
**ret
) {
36 _cleanup_(config_section_freep
) ConfigSection
*n
= NULL
;
37 _cleanup_(sr_iov_freep
) SRIOV
*sr_iov
= NULL
;
38 SRIOV
*existing
= NULL
;
41 assert(sr_iov_by_section
);
43 assert(section_line
> 0);
46 r
= config_section_new(filename
, section_line
, &n
);
50 existing
= ordered_hashmap_get(*sr_iov_by_section
, n
);
56 r
= sr_iov_new(&sr_iov
);
60 r
= ordered_hashmap_ensure_put(sr_iov_by_section
, &config_section_hash_ops
, n
, sr_iov
);
64 sr_iov
->section
= TAKE_PTR(n
);
65 sr_iov
->sr_iov_by_section
= *sr_iov_by_section
;
67 *ret
= TAKE_PTR(sr_iov
);
71 SRIOV
*sr_iov_free(SRIOV
*sr_iov
) {
75 if (sr_iov
->sr_iov_by_section
&& sr_iov
->section
)
76 ordered_hashmap_remove(sr_iov
->sr_iov_by_section
, sr_iov
->section
);
78 config_section_free(sr_iov
->section
);
83 void sr_iov_hash_func(const SRIOV
*sr_iov
, struct siphash
*state
) {
87 siphash24_compress_typesafe(sr_iov
->vf
, state
);
90 int sr_iov_compare_func(const SRIOV
*s1
, const SRIOV
*s2
) {
94 return CMP(s1
->vf
, s2
->vf
);
97 DEFINE_PRIVATE_HASH_OPS(
101 sr_iov_compare_func
);
103 int sr_iov_set_netlink_message(SRIOV
*sr_iov
, sd_netlink_message
*req
) {
109 r
= sd_netlink_message_open_container(req
, IFLA_VFINFO_LIST
);
113 r
= sd_netlink_message_open_container(req
, IFLA_VF_INFO
);
117 if (!ether_addr_is_null(&sr_iov
->mac
)) {
118 struct ifla_vf_mac ivm
= {
122 memcpy(ivm
.mac
, &sr_iov
->mac
, ETH_ALEN
);
123 r
= sd_netlink_message_append_data(req
, IFLA_VF_MAC
, &ivm
, sizeof(struct ifla_vf_mac
));
128 if (sr_iov
->vf_spoof_check_setting
>= 0) {
129 struct ifla_vf_spoofchk ivs
= {
131 .setting
= sr_iov
->vf_spoof_check_setting
,
134 r
= sd_netlink_message_append_data(req
, IFLA_VF_SPOOFCHK
, &ivs
, sizeof(struct ifla_vf_spoofchk
));
139 if (sr_iov
->query_rss
>= 0) {
140 struct ifla_vf_rss_query_en ivs
= {
142 .setting
= sr_iov
->query_rss
,
145 r
= sd_netlink_message_append_data(req
, IFLA_VF_RSS_QUERY_EN
, &ivs
, sizeof(struct ifla_vf_rss_query_en
));
150 if (sr_iov
->trust
>= 0) {
151 struct ifla_vf_trust ivt
= {
153 .setting
= sr_iov
->trust
,
156 r
= sd_netlink_message_append_data(req
, IFLA_VF_TRUST
, &ivt
, sizeof(struct ifla_vf_trust
));
161 if (sr_iov
->link_state
>= 0) {
162 struct ifla_vf_link_state ivl
= {
164 .link_state
= sr_iov
->link_state
,
167 r
= sd_netlink_message_append_data(req
, IFLA_VF_LINK_STATE
, &ivl
, sizeof(struct ifla_vf_link_state
));
172 if (sr_iov
->vlan
> 0) {
173 /* Because of padding, first the buffer must be initialized with 0. */
174 struct ifla_vf_vlan_info ivvi
= {};
175 ivvi
.vf
= sr_iov
->vf
;
176 ivvi
.vlan
= sr_iov
->vlan
;
177 ivvi
.qos
= sr_iov
->qos
;
178 ivvi
.vlan_proto
= htobe16(sr_iov
->vlan_proto
);
180 r
= sd_netlink_message_open_container(req
, IFLA_VF_VLAN_LIST
);
184 r
= sd_netlink_message_append_data(req
, IFLA_VF_VLAN_INFO
, &ivvi
, sizeof(struct ifla_vf_vlan_info
));
188 r
= sd_netlink_message_close_container(req
);
193 r
= sd_netlink_message_close_container(req
);
197 r
= sd_netlink_message_close_container(req
);
204 int sr_iov_get_num_vfs(sd_device
*device
, uint32_t *ret
) {
212 r
= sd_device_get_sysattr_value(device
, "device/sriov_numvfs", &str
);
216 r
= safe_atou32(str
, &n
);
224 int sr_iov_set_num_vfs(sd_device
*device
, uint32_t num_vfs
, OrderedHashmap
*sr_iov_by_section
) {
225 char val
[DECIMAL_STR_MAX(uint32_t)];
231 if (num_vfs
== UINT32_MAX
) {
232 uint32_t current_num_vfs
;
235 /* If the number of virtual functions is not specified, then use the maximum number of VF + 1. */
238 ORDERED_HASHMAP_FOREACH(sr_iov
, sr_iov_by_section
)
239 num_vfs
= MAX(num_vfs
, sr_iov
->vf
+ 1);
241 if (num_vfs
== 0) /* No VF is configured. */
244 r
= sr_iov_get_num_vfs(device
, ¤t_num_vfs
);
246 return log_device_debug_errno(device
, r
, "Failed to get the current number of SR-IOV virtual functions: %m");
248 /* Enough VFs already exist. */
249 if (num_vfs
<= current_num_vfs
)
252 } else if (num_vfs
== 0) {
253 r
= sd_device_set_sysattr_value(device
, "device/sriov_numvfs", "0");
255 log_device_debug_errno(device
, r
, "Failed to write device/sriov_numvfs sysfs attribute, ignoring: %m");
257 /* Gracefully handle the error in disabling VFs when the interface does not support SR-IOV. */
258 return r
== -ENOENT
? 0 : r
;
261 /* So, the interface does not have enough VFs. Before increasing the number of VFs, check the
262 * maximum allowed number of VFs from the sriov_totalvfs sysattr. Note that the sysattr
263 * currently exists only for PCI drivers. Hence, ignore -ENOENT.
264 * TODO: netdevsim provides the information in debugfs. */
265 r
= sd_device_get_sysattr_value(device
, "device/sriov_totalvfs", &str
);
267 uint32_t max_num_vfs
;
269 r
= safe_atou32(str
, &max_num_vfs
);
271 return log_device_debug_errno(device
, r
, "Failed to parse device/sriov_totalvfs sysfs attribute '%s': %m", str
);
273 if (num_vfs
> max_num_vfs
)
274 return log_device_debug_errno(device
, SYNTHETIC_ERRNO(ERANGE
),
275 "Specified number of virtual functions is out of range. "
276 "The maximum allowed value is %"PRIu32
".",
279 } else if (r
!= -ENOENT
) /* Currently, only PCI driver has the attribute. */
280 return log_device_debug_errno(device
, r
, "Failed to read device/sriov_totalvfs sysfs attribute: %m");
282 xsprintf(val
, "%"PRIu32
, num_vfs
);
283 r
= sd_device_set_sysattr_value(device
, "device/sriov_numvfs", val
);
285 /* Some devices e.g. netdevsim refuse to set sriov_numvfs if it has non-zero value. */
286 r
= sd_device_set_sysattr_value(device
, "device/sriov_numvfs", "0");
288 r
= sd_device_set_sysattr_value(device
, "device/sriov_numvfs", val
);
291 return log_device_debug_errno(device
, r
, "Failed to write device/sriov_numvfs sysfs attribute: %m");
293 log_device_debug(device
, "device/sriov_numvfs sysfs attribute set to '%s'.", val
);
297 static int sr_iov_section_verify(uint32_t num_vfs
, SRIOV
*sr_iov
) {
300 if (section_is_invalid(sr_iov
->section
))
303 if (sr_iov
->vf
== UINT32_MAX
)
304 return log_warning_errno(SYNTHETIC_ERRNO(EINVAL
),
305 "%s: [SR-IOV] section without VirtualFunction= field configured. "
306 "Ignoring [SR-IOV] section from line %u.",
307 sr_iov
->section
->filename
, sr_iov
->section
->line
);
309 if (sr_iov
->vf
>= num_vfs
)
310 return log_warning_errno(SYNTHETIC_ERRNO(EINVAL
),
311 "%s: VirtualFunction= must be smaller than the value specified in SR-IOVVirtualFunctions=. "
312 "Ignoring [SR-IOV] section from line %u.",
313 sr_iov
->section
->filename
, sr_iov
->section
->line
);
318 int sr_iov_drop_invalid_sections(uint32_t num_vfs
, OrderedHashmap
*sr_iov_by_section
) {
319 _cleanup_set_free_ Set
*set
= NULL
;
323 ORDERED_HASHMAP_FOREACH(sr_iov
, sr_iov_by_section
) {
326 if (sr_iov_section_verify(num_vfs
, sr_iov
) < 0) {
331 dup
= set_remove(set
, sr_iov
);
333 log_warning("%s: Conflicting [SR-IOV] section is specified at line %u and %u, "
334 "dropping the [SR-IOV] section specified at line %u.",
335 dup
->section
->filename
, sr_iov
->section
->line
,
336 dup
->section
->line
, dup
->section
->line
);
340 r
= set_ensure_put(&set
, &sr_iov_hash_ops
, sr_iov
);
349 int config_parse_sr_iov_uint32(
351 const char *filename
,
354 unsigned section_line
,
361 _cleanup_(sr_iov_free_or_set_invalidp
) SRIOV
*sr_iov
= NULL
;
362 OrderedHashmap
**sr_iov_by_section
= ASSERT_PTR(data
);
370 r
= sr_iov_new_static(sr_iov_by_section
, filename
, section_line
, &sr_iov
);
374 if (isempty(rvalue
)) {
375 if (streq(lvalue
, "VirtualFunction"))
376 sr_iov
->vf
= UINT32_MAX
;
377 else if (streq(lvalue
, "VLANId"))
379 else if (streq(lvalue
, "QualityOfService"))
382 assert_not_reached();
388 r
= safe_atou32(rvalue
, &k
);
390 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
391 "Failed to parse SR-IOV '%s=', ignoring assignment: %s", lvalue
, rvalue
);
395 if (streq(lvalue
, "VLANId")) {
396 if (k
== 0 || k
> 4095) {
397 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0, "Invalid SR-IOV VLANId: %u", k
);
401 } else if (streq(lvalue
, "VirtualFunction")) {
403 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0, "Invalid SR-IOV virtual function: %u", k
);
407 } else if (streq(lvalue
, "QualityOfService"))
410 assert_not_reached();
416 int config_parse_sr_iov_vlan_proto(
418 const char *filename
,
421 unsigned section_line
,
428 _cleanup_(sr_iov_free_or_set_invalidp
) SRIOV
*sr_iov
= NULL
;
429 OrderedHashmap
**sr_iov_by_section
= ASSERT_PTR(data
);
436 r
= sr_iov_new_static(sr_iov_by_section
, filename
, section_line
, &sr_iov
);
440 if (isempty(rvalue
) || streq(rvalue
, "802.1Q"))
441 sr_iov
->vlan_proto
= ETH_P_8021Q
;
442 else if (streq(rvalue
, "802.1ad"))
443 sr_iov
->vlan_proto
= ETH_P_8021AD
;
445 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
446 "Invalid SR-IOV '%s=', ignoring assignment: %s", lvalue
, rvalue
);
454 int config_parse_sr_iov_link_state(
456 const char *filename
,
459 unsigned section_line
,
466 _cleanup_(sr_iov_free_or_set_invalidp
) SRIOV
*sr_iov
= NULL
;
467 OrderedHashmap
**sr_iov_by_section
= ASSERT_PTR(data
);
474 r
= sr_iov_new_static(sr_iov_by_section
, filename
, section_line
, &sr_iov
);
478 /* Unfortunately, SR_IOV_LINK_STATE_DISABLE is 2, not 0. So, we cannot use
479 * DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN() macro. */
481 if (isempty(rvalue
)) {
482 sr_iov
->link_state
= _SR_IOV_LINK_STATE_INVALID
;
487 if (streq(rvalue
, "auto")) {
488 sr_iov
->link_state
= SR_IOV_LINK_STATE_AUTO
;
493 r
= parse_boolean(rvalue
);
495 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
496 "Failed to parse SR-IOV '%s=', ignoring assignment: %s", lvalue
, rvalue
);
500 sr_iov
->link_state
= r
? SR_IOV_LINK_STATE_ENABLE
: SR_IOV_LINK_STATE_DISABLE
;
505 int config_parse_sr_iov_boolean(
507 const char *filename
,
510 unsigned section_line
,
517 _cleanup_(sr_iov_free_or_set_invalidp
) SRIOV
*sr_iov
= NULL
;
518 OrderedHashmap
**sr_iov_by_section
= ASSERT_PTR(data
);
525 r
= sr_iov_new_static(sr_iov_by_section
, filename
, section_line
, &sr_iov
);
529 if (isempty(rvalue
)) {
530 if (streq(lvalue
, "MACSpoofCheck"))
531 sr_iov
->vf_spoof_check_setting
= -1;
532 else if (streq(lvalue
, "QueryReceiveSideScaling"))
533 sr_iov
->query_rss
= -1;
534 else if (streq(lvalue
, "Trust"))
537 assert_not_reached();
543 r
= parse_boolean(rvalue
);
545 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
, "Failed to parse '%s=', ignoring: %s", lvalue
, rvalue
);
549 if (streq(lvalue
, "MACSpoofCheck"))
550 sr_iov
->vf_spoof_check_setting
= r
;
551 else if (streq(lvalue
, "QueryReceiveSideScaling"))
552 sr_iov
->query_rss
= r
;
553 else if (streq(lvalue
, "Trust"))
556 assert_not_reached();
562 int config_parse_sr_iov_mac(
564 const char *filename
,
567 unsigned section_line
,
574 _cleanup_(sr_iov_free_or_set_invalidp
) SRIOV
*sr_iov
= NULL
;
575 OrderedHashmap
**sr_iov_by_section
= ASSERT_PTR(data
);
582 r
= sr_iov_new_static(sr_iov_by_section
, filename
, section_line
, &sr_iov
);
586 if (isempty(rvalue
)) {
587 sr_iov
->mac
= ETHER_ADDR_NULL
;
592 r
= parse_ether_addr(rvalue
, &sr_iov
->mac
);
594 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
595 "Failed to parse SR-IOV '%s=', ignoring assignment: %s", lvalue
, rvalue
);
603 int config_parse_sr_iov_num_vfs(
605 const char *filename
,
608 unsigned section_line
,
615 uint32_t n
, *num_vfs
= ASSERT_PTR(data
);
622 if (isempty(rvalue
)) {
623 *num_vfs
= UINT32_MAX
;
627 r
= safe_atou32(rvalue
, &n
);
629 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
630 "Failed to parse %s=, ignoring assignment: %s", lvalue
, rvalue
);
635 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
636 "The number of SR-IOV virtual functions is too large. It must be equal to "
637 "or smaller than 2147483647. Ignoring assignment: %"PRIu32
, n
);