1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
4 #include <linux/netdevice.h> /* Must be included after <net/if.h> */
5 #include <netinet/ether.h>
9 #include "sd-netlink.h"
11 #include "alloc-util.h"
12 #include "arphrd-util.h"
13 #include "conf-files.h"
14 #include "conf-parser.h"
15 #include "constants.h"
16 #include "creds-util.h"
17 #include "device-private.h"
18 #include "device-util.h"
19 #include "ethtool-util.h"
22 #include "link-config.h"
24 #include "memory-util.h"
25 #include "net-condition.h"
26 #include "netif-sriov.h"
27 #include "netif-util.h"
28 #include "netlink-util.h"
29 #include "parse-util.h"
30 #include "path-lookup.h"
31 #include "path-util.h"
32 #include "proc-cmdline.h"
33 #include "random-util.h"
34 #include "stat-util.h"
35 #include "string-table.h"
36 #include "string-util.h"
40 struct LinkConfigContext
{
41 LIST_HEAD(LinkConfig
, configs
);
43 Hashmap
*stats_by_path
;
46 static LinkConfig
* link_config_free(LinkConfig
*config
) {
50 free(config
->filename
);
51 strv_free(config
->dropins
);
53 net_match_clear(&config
->match
);
54 condition_free_list(config
->conditions
);
56 free(config
->description
);
57 free(config
->name_policy
);
59 strv_free(config
->alternative_names
);
60 free(config
->alternative_names_policy
);
62 free(config
->wol_password_file
);
63 erase_and_free(config
->wol_password
);
65 ordered_hashmap_free_with_destructor(config
->sr_iov_by_section
, sr_iov_free
);
70 DEFINE_TRIVIAL_CLEANUP_FUNC(LinkConfig
*, link_config_free
);
72 static void link_configs_free(LinkConfigContext
*ctx
) {
76 ctx
->stats_by_path
= hashmap_free(ctx
->stats_by_path
);
78 LIST_FOREACH(configs
, config
, ctx
->configs
)
79 link_config_free(config
);
82 LinkConfigContext
*link_config_ctx_free(LinkConfigContext
*ctx
) {
86 safe_close(ctx
->ethtool_fd
);
87 link_configs_free(ctx
);
91 int link_config_ctx_new(LinkConfigContext
**ret
) {
92 _cleanup_(link_config_ctx_freep
) LinkConfigContext
*ctx
= NULL
;
97 ctx
= new(LinkConfigContext
, 1);
101 *ctx
= (LinkConfigContext
) {
102 .ethtool_fd
= -EBADF
,
105 *ret
= TAKE_PTR(ctx
);
110 static int link_parse_wol_password(LinkConfig
*config
, const char *str
) {
111 _cleanup_(erase_and_freep
) uint8_t *p
= NULL
;
117 assert_cc(sizeof(struct ether_addr
) == SOPASS_MAX
);
119 p
= new(uint8_t, SOPASS_MAX
);
123 /* Reuse parse_ether_addr(), as their formats are equivalent. */
124 r
= parse_ether_addr(str
, (struct ether_addr
*) p
);
128 erase_and_free(config
->wol_password
);
129 config
->wol_password
= TAKE_PTR(p
);
133 static int link_read_wol_password_from_file(LinkConfig
*config
) {
134 _cleanup_(erase_and_freep
) char *password
= NULL
;
139 if (!config
->wol_password_file
)
142 r
= read_full_file_full(
143 AT_FDCWD
, config
->wol_password_file
, UINT64_MAX
, SIZE_MAX
,
144 READ_FULL_FILE_SECURE
| READ_FULL_FILE_WARN_WORLD_READABLE
| READ_FULL_FILE_CONNECT_SOCKET
,
145 NULL
, &password
, NULL
);
149 return link_parse_wol_password(config
, password
);
152 static int link_read_wol_password_from_cred(LinkConfig
*config
) {
153 _cleanup_free_
char *base
= NULL
, *cred_name
= NULL
;
154 _cleanup_(erase_and_freep
) char *password
= NULL
;
158 assert(config
->filename
);
160 if (config
->wol
== UINT32_MAX
)
161 return 0; /* WakeOnLan= is not specified. */
162 if (!FLAGS_SET(config
->wol
, WAKE_MAGICSECURE
))
163 return 0; /* secureon is not specified in WakeOnLan=. */
164 if (config
->wol_password
)
165 return 0; /* WakeOnLanPassword= is specified. */
166 if (config
->wol_password_file
)
167 return 0; /* a file name is specified in WakeOnLanPassword=, but failed to read it. */
169 r
= path_extract_filename(config
->filename
, &base
);
173 cred_name
= strjoin(base
, ".wol.password");
177 r
= read_credential(cred_name
, (void**) &password
, NULL
);
179 r
= read_credential("wol.password", (void**) &password
, NULL
);
183 return link_parse_wol_password(config
, password
);
186 static int link_adjust_wol_options(LinkConfig
*config
) {
191 r
= link_read_wol_password_from_file(config
);
195 log_warning_errno(r
, "Failed to read WakeOnLan password from %s, ignoring: %m", config
->wol_password_file
);
197 r
= link_read_wol_password_from_cred(config
);
201 log_warning_errno(r
, "Failed to read WakeOnLan password from credential, ignoring: %m");
203 if (config
->wol
!= UINT32_MAX
&& config
->wol_password
)
204 /* Enable WAKE_MAGICSECURE flag when WakeOnLanPassword=. Note that when
205 * WakeOnLanPassword= is set without WakeOnLan=, then ethtool_set_wol() enables
206 * WAKE_MAGICSECURE flag and other flags are not changed. */
207 config
->wol
|= WAKE_MAGICSECURE
;
212 int link_load_one(LinkConfigContext
*ctx
, const char *filename
) {
213 _cleanup_(link_config_freep
) LinkConfig
*config
= NULL
;
214 _cleanup_hashmap_free_ Hashmap
*stats_by_path
= NULL
;
215 _cleanup_free_
char *name
= NULL
;
216 const char *dropin_dirname
;
223 r
= null_or_empty_path(filename
);
225 return log_warning_errno(r
, "Failed to check if \"%s\" is empty: %m", filename
);
227 log_debug("Skipping empty file: %s", filename
);
231 name
= strdup(filename
);
235 config
= new(LinkConfig
, 1);
239 *config
= (LinkConfig
) {
240 .filename
= TAKE_PTR(name
),
241 .mac_address_policy
= MAC_ADDRESS_POLICY_NONE
,
242 .wol
= UINT32_MAX
, /* UINT32_MAX means do not change WOL setting. */
243 .duplex
= _DUP_INVALID
,
244 .port
= _NET_DEV_PORT_INVALID
,
245 .autonegotiation
= -1,
246 .rx_flow_control
= -1,
247 .tx_flow_control
= -1,
248 .autoneg_flow_control
= -1,
249 .txqueuelen
= UINT32_MAX
,
250 .coalesce
.use_adaptive_rx_coalesce
= -1,
251 .coalesce
.use_adaptive_tx_coalesce
= -1,
252 .mdi
= ETH_TP_MDI_INVALID
,
253 .sr_iov_num_vfs
= UINT32_MAX
,
256 for (i
= 0; i
< ELEMENTSOF(config
->features
); i
++)
257 config
->features
[i
] = -1;
259 dropin_dirname
= strjoina(basename(filename
), ".d");
260 r
= config_parse_many(
261 STRV_MAKE_CONST(filename
),
268 config_item_perf_lookup
, link_config_gperf_lookup
,
269 CONFIG_PARSE_WARN
, config
, &stats_by_path
,
272 return r
; /* config_parse_many() logs internally. */
274 if (ctx
->stats_by_path
) {
275 r
= hashmap_move(ctx
->stats_by_path
, stats_by_path
);
277 log_warning_errno(r
, "Failed to save stats of '%s' and its drop-in configs, ignoring: %m", filename
);
279 ctx
->stats_by_path
= TAKE_PTR(stats_by_path
);
281 if (net_match_is_empty(&config
->match
) && !config
->conditions
) {
282 log_warning("%s: No valid settings found in the [Match] section, ignoring file. "
283 "To match all interfaces, add OriginalName=* in the [Match] section.",
288 if (!condition_test_list(config
->conditions
, environ
, NULL
, NULL
, NULL
)) {
289 log_debug("%s: Conditions do not match the system environment, skipping.", filename
);
293 if (IN_SET(config
->mac_address_policy
, MAC_ADDRESS_POLICY_PERSISTENT
, MAC_ADDRESS_POLICY_RANDOM
) &&
294 config
->hw_addr
.length
> 0)
295 log_warning("%s: MACAddress= in [Link] section will be ignored when MACAddressPolicy= "
296 "is set to \"persistent\" or \"random\".",
299 r
= link_adjust_wol_options(config
);
301 return r
; /* link_adjust_wol_options() logs internally. */
303 r
= sr_iov_drop_invalid_sections(config
->sr_iov_num_vfs
, config
->sr_iov_by_section
);
305 return r
; /* sr_iov_drop_invalid_sections() logs internally. */
307 log_debug("Parsed configuration file \"%s\"", filename
);
309 LIST_PREPEND(configs
, ctx
->configs
, TAKE_PTR(config
));
313 static int device_unsigned_attribute(sd_device
*device
, const char *attr
, unsigned *type
) {
317 r
= sd_device_get_sysattr_value(device
, attr
, &s
);
319 return log_device_debug_errno(device
, r
, "Failed to query %s: %m", attr
);
321 r
= safe_atou(s
, type
);
323 return log_device_warning_errno(device
, r
, "Failed to parse %s \"%s\": %m", attr
, s
);
325 log_device_debug(device
, "Device has %s=%u", attr
, *type
);
329 int link_config_load(LinkConfigContext
*ctx
) {
330 _cleanup_strv_free_
char **files
= NULL
;
335 link_configs_free(ctx
);
337 r
= conf_files_list_strv(&files
, ".link", NULL
, 0, NETWORK_DIRS
);
339 return log_error_errno(r
, "failed to enumerate link files: %m");
341 STRV_FOREACH_BACKWARDS(f
, files
)
342 (void) link_load_one(ctx
, *f
);
347 bool link_config_should_reload(LinkConfigContext
*ctx
) {
348 _cleanup_hashmap_free_ Hashmap
*stats_by_path
= NULL
;
353 r
= config_get_stats_by_path(".link", NULL
, 0, NETWORK_DIRS
, /* check_dropins = */ true, &stats_by_path
);
355 log_warning_errno(r
, "Failed to get stats of .link files, ignoring: %m");
359 return !stats_by_path_equal(ctx
->stats_by_path
, stats_by_path
);
362 Link
*link_free(Link
*link
) {
366 sd_device_unref(link
->device
);
369 strv_free(link
->altnames
);
373 int link_new(LinkConfigContext
*ctx
, sd_netlink
**rtnl
, sd_device
*device
, Link
**ret
) {
374 _cleanup_(link_freep
) Link
*link
= NULL
;
387 .device
= sd_device_ref(device
),
390 r
= sd_device_get_sysname(device
, &link
->ifname
);
394 r
= sd_device_get_ifindex(device
, &link
->ifindex
);
398 r
= sd_device_get_action(device
, &link
->action
);
402 r
= device_unsigned_attribute(device
, "name_assign_type", &link
->name_assign_type
);
404 log_link_debug_errno(link
, r
, "Failed to get \"name_assign_type\" attribute, ignoring: %m");
406 r
= device_unsigned_attribute(device
, "addr_assign_type", &link
->addr_assign_type
);
408 log_link_debug_errno(link
, r
, "Failed to get \"addr_assign_type\" attribute, ignoring: %m");
410 r
= rtnl_get_link_info(rtnl
, link
->ifindex
, &link
->iftype
, &link
->flags
,
411 &link
->kind
, &link
->hw_addr
, &link
->permanent_hw_addr
);
415 if (link
->hw_addr
.length
> 0 && link
->permanent_hw_addr
.length
== 0) {
416 r
= ethtool_get_permanent_hw_addr(&ctx
->ethtool_fd
, link
->ifname
, &link
->permanent_hw_addr
);
418 log_link_debug_errno(link
, r
, "Failed to get permanent hardware address, ignoring: %m");
421 r
= ethtool_get_driver(&ctx
->ethtool_fd
, link
->ifname
, &link
->driver
);
423 log_link_debug_errno(link
, r
, "Failed to get driver, ignoring: %m");
425 *ret
= TAKE_PTR(link
);
429 int link_get_config(LinkConfigContext
*ctx
, Link
*link
) {
435 /* Do not configure loopback interfaces by .link files. */
436 if (link
->flags
& IFF_LOOPBACK
)
439 LIST_FOREACH(configs
, config
, ctx
->configs
) {
440 r
= net_match_config(
444 &link
->permanent_hw_addr
,
449 /* alternative_names = */ NULL
,
450 /* wlan_iftype = */ 0,
458 if (config
->match
.ifname
&& !strv_contains(config
->match
.ifname
, "*") && link
->name_assign_type
== NET_NAME_ENUM
)
459 log_link_warning(link
, "Config file %s is applied to device based on potentially unpredictable interface name.",
462 log_link_debug(link
, "Config file %s is applied", config
->filename
);
464 link
->config
= config
;
471 static int link_apply_ethtool_settings(Link
*link
, int *ethtool_fd
) {
477 assert(link
->config
);
480 config
= link
->config
;
483 r
= ethtool_set_glinksettings(ethtool_fd
, name
,
484 config
->autonegotiation
, config
->advertise
,
485 config
->speed
, config
->duplex
, config
->port
, config
->mdi
);
487 if (config
->autonegotiation
>= 0)
488 log_link_warning_errno(link
, r
, "Could not %s auto negotiation, ignoring: %m",
489 enable_disable(config
->autonegotiation
));
491 if (!eqzero(config
->advertise
))
492 log_link_warning_errno(link
, r
, "Could not set advertise mode, ignoring: %m");
494 if (config
->speed
> 0)
495 log_link_warning_errno(link
, r
, "Could not set speed to %"PRIu64
"Mbps, ignoring: %m",
496 DIV_ROUND_UP(config
->speed
, 1000000));
498 if (config
->duplex
>= 0)
499 log_link_warning_errno(link
, r
, "Could not set duplex to %s, ignoring: %m",
500 duplex_to_string(config
->duplex
));
502 if (config
->port
>= 0)
503 log_link_warning_errno(link
, r
, "Could not set port to '%s', ignoring: %m",
504 port_to_string(config
->port
));
506 if (config
->mdi
!= ETH_TP_MDI_INVALID
)
507 log_link_warning_errno(link
, r
, "Could not set MDI-X to '%s', ignoring: %m",
508 mdi_to_string(config
->mdi
));
511 r
= ethtool_set_wol(ethtool_fd
, name
, config
->wol
, config
->wol_password
);
513 _cleanup_free_
char *str
= NULL
;
515 (void) wol_options_to_string_alloc(config
->wol
, &str
);
516 log_link_warning_errno(link
, r
, "Could not set WakeOnLan%s%s, ignoring: %m",
517 isempty(str
) ? "" : " to ", strempty(str
));
520 r
= ethtool_set_features(ethtool_fd
, name
, config
->features
);
522 log_link_warning_errno(link
, r
, "Could not set offload features, ignoring: %m");
524 r
= ethtool_set_channels(ethtool_fd
, name
, &config
->channels
);
526 log_link_warning_errno(link
, r
, "Could not set channels, ignoring: %m");
528 r
= ethtool_set_nic_buffer_size(ethtool_fd
, name
, &config
->ring
);
530 log_link_warning_errno(link
, r
, "Could not set ring buffer, ignoring: %m");
532 r
= ethtool_set_flow_control(ethtool_fd
, name
, config
->rx_flow_control
, config
->tx_flow_control
, config
->autoneg_flow_control
);
534 log_link_warning_errno(link
, r
, "Could not set flow control, ignoring: %m");
536 r
= ethtool_set_nic_coalesce_settings(ethtool_fd
, name
, &config
->coalesce
);
538 log_link_warning_errno(link
, r
, "Could not set coalesce settings, ignoring: %m");
543 static bool hw_addr_is_valid(Link
*link
, const struct hw_addr_data
*hw_addr
) {
547 switch (link
->iftype
) {
549 /* Refuse all zero and all 0xFF. */
550 assert(hw_addr
->length
== ETH_ALEN
);
551 return !ether_addr_is_null(&hw_addr
->ether
) && !ether_addr_is_broadcast(&hw_addr
->ether
);
553 case ARPHRD_INFINIBAND
:
554 /* The last 8 bytes cannot be zero. */
555 assert(hw_addr
->length
== INFINIBAND_ALEN
);
556 return !memeqzero(hw_addr
->bytes
+ INFINIBAND_ALEN
- 8, 8);
559 assert_not_reached();
563 static int link_generate_new_hw_addr(Link
*link
, struct hw_addr_data
*ret
) {
564 struct hw_addr_data hw_addr
= HW_ADDR_NULL
;
565 bool is_static
= false;
571 assert(link
->config
);
572 assert(link
->device
);
575 if (link
->hw_addr
.length
== 0)
578 if (link
->config
->mac_address_policy
== MAC_ADDRESS_POLICY_NONE
) {
579 log_link_debug(link
, "Using static MAC address.");
580 hw_addr
= link
->config
->hw_addr
;
585 if (!IN_SET(link
->iftype
, ARPHRD_ETHER
, ARPHRD_INFINIBAND
))
588 switch (link
->addr_assign_type
) {
590 log_link_debug(link
, "MAC address on the device already set by userspace.");
592 case NET_ADDR_STOLEN
:
593 log_link_debug(link
, "MAC address on the device already set based on another device.");
595 case NET_ADDR_RANDOM
:
599 log_link_warning(link
, "Unknown addr_assign_type %u, ignoring", link
->addr_assign_type
);
603 if ((link
->config
->mac_address_policy
== MAC_ADDRESS_POLICY_RANDOM
) == (link
->addr_assign_type
== NET_ADDR_RANDOM
)) {
604 log_link_debug(link
, "MAC address on the device already matches policy \"%s\".",
605 mac_address_policy_to_string(link
->config
->mac_address_policy
));
609 hw_addr
= (struct hw_addr_data
) {
610 .length
= arphrd_to_hw_addr_len(link
->iftype
),
613 switch (link
->iftype
) {
616 len
= hw_addr
.length
;
618 case ARPHRD_INFINIBAND
:
619 p
= hw_addr
.bytes
+ INFINIBAND_ALEN
- 8;
623 assert_not_reached();
626 if (link
->config
->mac_address_policy
== MAC_ADDRESS_POLICY_RANDOM
)
627 /* We require genuine randomness here, since we want to make sure we won't collide with other
628 * systems booting up at the very same time. */
630 random_bytes(p
, len
);
631 if (hw_addr_is_valid(link
, &hw_addr
))
638 r
= net_get_unique_predictable_data(link
->device
,
639 naming_scheme_has(NAMING_STABLE_VIRTUAL_MACS
),
642 return log_link_warning_errno(link
, r
, "Could not generate persistent MAC address: %m");
644 assert(len
<= sizeof(result
));
645 memcpy(p
, &result
, len
);
646 if (!hw_addr_is_valid(link
, &hw_addr
))
647 return log_link_warning_errno(link
, SYNTHETIC_ERRNO(EINVAL
),
648 "Could not generate valid persistent MAC address: %m");
653 r
= net_verify_hardware_address(link
->ifname
, is_static
, link
->iftype
, &link
->hw_addr
, &hw_addr
);
657 if (hw_addr_equal(&link
->hw_addr
, &hw_addr
)) {
662 if (hw_addr
.length
> 0)
663 log_link_debug(link
, "Applying %s MAC address: %s",
664 link
->config
->mac_address_policy
== MAC_ADDRESS_POLICY_NONE
? "static" :
665 mac_address_policy_to_string(link
->config
->mac_address_policy
),
666 HW_ADDR_TO_STR(&hw_addr
));
672 static int link_apply_rtnl_settings(Link
*link
, sd_netlink
**rtnl
) {
673 struct hw_addr_data hw_addr
= {};
678 assert(link
->config
);
681 config
= link
->config
;
683 (void) link_generate_new_hw_addr(link
, &hw_addr
);
685 r
= rtnl_set_link_properties(rtnl
, link
->ifindex
, config
->alias
, &hw_addr
,
686 config
->txqueues
, config
->rxqueues
, config
->txqueuelen
,
687 config
->mtu
, config
->gso_max_size
, config
->gso_max_segments
);
689 log_link_warning_errno(link
, r
,
690 "Could not set Alias=, MACAddress=/MACAddressPolicy=, "
691 "TransmitQueues=, ReceiveQueues=, TransmitQueueLength=, MTUBytes=, "
692 "GenericSegmentOffloadMaxBytes= or GenericSegmentOffloadMaxSegments=, "
698 static bool enable_name_policy(void) {
699 static int cached
= -1;
706 r
= proc_cmdline_get_bool("net.ifnames", /* flags = */ 0, &b
);
708 log_warning_errno(r
, "Failed to parse net.ifnames= kernel command line option, ignoring: %m");
710 return (cached
= true);
713 log_info("Network interface NamePolicy= disabled on kernel command line.");
718 static int link_generate_new_name(Link
*link
) {
723 assert(link
->config
);
724 assert(link
->device
);
726 config
= link
->config
;
727 device
= link
->device
;
729 if (link
->action
!= SD_DEVICE_ADD
) {
730 log_link_debug(link
, "Skipping to apply Name= and NamePolicy= on '%s' uevent.",
731 device_action_to_string(link
->action
));
735 if (IN_SET(link
->name_assign_type
, NET_NAME_USER
, NET_NAME_RENAMED
) &&
736 !naming_scheme_has(NAMING_ALLOW_RERENAMES
)) {
737 log_link_debug(link
, "Device already has a name given by userspace, not renaming.");
741 if (enable_name_policy() && config
->name_policy
)
742 for (NamePolicy
*policy
= config
->name_policy
; *policy
!= _NAMEPOLICY_INVALID
; policy
++) {
743 const char *new_name
= NULL
;
746 case NAMEPOLICY_KERNEL
:
747 if (link
->name_assign_type
!= NET_NAME_PREDICTABLE
)
750 /* The kernel claims to have given a predictable name, keep it. */
751 log_link_debug(link
, "Policy *%s*: keeping predictable kernel name",
752 name_policy_to_string(*policy
));
754 case NAMEPOLICY_KEEP
:
755 if (!IN_SET(link
->name_assign_type
, NET_NAME_USER
, NET_NAME_RENAMED
))
758 log_link_debug(link
, "Policy *%s*: keeping existing userspace name",
759 name_policy_to_string(*policy
));
761 case NAMEPOLICY_DATABASE
:
762 (void) sd_device_get_property_value(device
, "ID_NET_NAME_FROM_DATABASE", &new_name
);
764 case NAMEPOLICY_ONBOARD
:
765 (void) sd_device_get_property_value(device
, "ID_NET_NAME_ONBOARD", &new_name
);
767 case NAMEPOLICY_SLOT
:
768 (void) sd_device_get_property_value(device
, "ID_NET_NAME_SLOT", &new_name
);
770 case NAMEPOLICY_PATH
:
771 (void) sd_device_get_property_value(device
, "ID_NET_NAME_PATH", &new_name
);
774 (void) sd_device_get_property_value(device
, "ID_NET_NAME_MAC", &new_name
);
777 assert_not_reached();
779 if (ifname_valid(new_name
)) {
780 log_link_debug(link
, "Policy *%s* yields \"%s\".", name_policy_to_string(*policy
), new_name
);
781 link
->new_name
= new_name
;
786 if (link
->config
->name
) {
787 log_link_debug(link
, "Policies didn't yield a name, using specified Name=%s.", link
->config
->name
);
788 link
->new_name
= link
->config
->name
;
792 log_link_debug(link
, "Policies didn't yield a name and Name= is not given, not renaming.");
794 link
->new_name
= link
->ifname
;
798 static int link_generate_alternative_names(Link
*link
) {
799 _cleanup_strv_free_
char **altnames
= NULL
;
805 config
= ASSERT_PTR(link
->config
);
806 device
= ASSERT_PTR(link
->device
);
807 assert(!link
->altnames
);
809 if (link
->action
!= SD_DEVICE_ADD
) {
810 log_link_debug(link
, "Skipping to apply AlternativeNames= and AlternativeNamesPolicy= on '%s' uevent.",
811 device_action_to_string(link
->action
));
815 if (config
->alternative_names
) {
816 altnames
= strv_copy(config
->alternative_names
);
821 if (config
->alternative_names_policy
)
822 for (NamePolicy
*p
= config
->alternative_names_policy
; *p
!= _NAMEPOLICY_INVALID
; p
++) {
823 const char *n
= NULL
;
826 case NAMEPOLICY_DATABASE
:
827 (void) sd_device_get_property_value(device
, "ID_NET_NAME_FROM_DATABASE", &n
);
829 case NAMEPOLICY_ONBOARD
:
830 (void) sd_device_get_property_value(device
, "ID_NET_NAME_ONBOARD", &n
);
832 case NAMEPOLICY_SLOT
:
833 (void) sd_device_get_property_value(device
, "ID_NET_NAME_SLOT", &n
);
835 case NAMEPOLICY_PATH
:
836 (void) sd_device_get_property_value(device
, "ID_NET_NAME_PATH", &n
);
839 (void) sd_device_get_property_value(device
, "ID_NET_NAME_MAC", &n
);
842 assert_not_reached();
844 if (ifname_valid_full(n
, IFNAME_VALID_ALTERNATIVE
)) {
845 r
= strv_extend(&altnames
, n
);
851 link
->altnames
= TAKE_PTR(altnames
);
855 static int sr_iov_configure(Link
*link
, sd_netlink
**rtnl
, SRIOV
*sr_iov
) {
856 _cleanup_(sd_netlink_message_unrefp
) sd_netlink_message
*req
= NULL
;
861 assert(link
->ifindex
> 0);
864 r
= sd_netlink_open(rtnl
);
869 r
= sd_rtnl_message_new_link(*rtnl
, &req
, RTM_SETLINK
, link
->ifindex
);
873 r
= sr_iov_set_netlink_message(sr_iov
, req
);
877 r
= sd_netlink_call(*rtnl
, req
, 0, NULL
);
884 static int link_apply_sr_iov_config(Link
*link
, sd_netlink
**rtnl
) {
890 assert(link
->config
);
891 assert(link
->device
);
893 r
= sr_iov_set_num_vfs(link
->device
, link
->config
->sr_iov_num_vfs
, link
->config
->sr_iov_by_section
);
895 log_link_warning_errno(link
, r
, "Failed to set the number of SR-IOV virtual functions, ignoring: %m");
897 if (ordered_hashmap_isempty(link
->config
->sr_iov_by_section
))
900 r
= sr_iov_get_num_vfs(link
->device
, &n
);
902 log_link_warning_errno(link
, r
, "Failed to get the number of SR-IOV virtual functions, ignoring [SR-IOV] sections: %m");
906 log_link_warning(link
, "No SR-IOV virtual function exists, ignoring [SR-IOV] sections: %m");
910 ORDERED_HASHMAP_FOREACH(sr_iov
, link
->config
->sr_iov_by_section
) {
911 if (sr_iov
->vf
>= n
) {
912 log_link_warning(link
, "SR-IOV virtual function %"PRIu32
" does not exist, ignoring.", sr_iov
->vf
);
916 r
= sr_iov_configure(link
, rtnl
, sr_iov
);
918 log_link_warning_errno(link
, r
,
919 "Failed to configure SR-IOV virtual function %"PRIu32
", ignoring: %m",
926 int link_apply_config(LinkConfigContext
*ctx
, sd_netlink
**rtnl
, Link
*link
) {
933 if (!IN_SET(link
->action
, SD_DEVICE_ADD
, SD_DEVICE_BIND
, SD_DEVICE_MOVE
)) {
934 log_link_debug(link
, "Skipping to apply .link settings on '%s' uevent.",
935 device_action_to_string(link
->action
));
937 link
->new_name
= link
->ifname
;
941 r
= link_apply_ethtool_settings(link
, &ctx
->ethtool_fd
);
945 r
= link_apply_rtnl_settings(link
, rtnl
);
949 r
= link_generate_new_name(link
);
953 r
= link_generate_alternative_names(link
);
957 r
= link_apply_sr_iov_config(link
, rtnl
);
964 int config_parse_ifalias(
966 const char *filename
,
969 unsigned section_line
,
976 char **s
= ASSERT_PTR(data
);
982 if (isempty(rvalue
)) {
987 if (!ascii_is_valid(rvalue
)) {
988 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
989 "Interface alias is not ASCII clean, ignoring assignment: %s", rvalue
);
993 if (strlen(rvalue
) >= IFALIASZ
) {
994 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
995 "Interface alias is too long, ignoring assignment: %s", rvalue
);
999 return free_and_strdup_warn(s
, rvalue
);
1002 int config_parse_rx_tx_queues(
1004 const char *filename
,
1006 const char *section
,
1007 unsigned section_line
,
1014 uint32_t k
, *v
= data
;
1017 if (isempty(rvalue
)) {
1022 r
= safe_atou32(rvalue
, &k
);
1024 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
, "Failed to parse %s=, ignoring assignment: %s.", lvalue
, rvalue
);
1027 if (k
== 0 || k
> 4096) {
1028 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0, "Invalid %s=, ignoring assignment: %s.", lvalue
, rvalue
);
1036 int config_parse_txqueuelen(
1038 const char *filename
,
1040 const char *section
,
1041 unsigned section_line
,
1048 uint32_t k
, *v
= data
;
1051 if (isempty(rvalue
)) {
1056 r
= safe_atou32(rvalue
, &k
);
1058 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
, "Failed to parse %s=, ignoring assignment: %s.", lvalue
, rvalue
);
1061 if (k
== UINT32_MAX
) {
1062 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0, "Invalid %s=, ignoring assignment: %s.", lvalue
, rvalue
);
1070 int config_parse_wol_password(
1072 const char *filename
,
1074 const char *section
,
1075 unsigned section_line
,
1082 LinkConfig
*config
= ASSERT_PTR(userdata
);
1089 if (isempty(rvalue
)) {
1090 config
->wol_password
= erase_and_free(config
->wol_password
);
1091 config
->wol_password_file
= mfree(config
->wol_password_file
);
1095 if (path_is_absolute(rvalue
) && path_is_safe(rvalue
)) {
1096 config
->wol_password
= erase_and_free(config
->wol_password
);
1097 return free_and_strdup_warn(&config
->wol_password_file
, rvalue
);
1100 warn_file_is_world_accessible(filename
, NULL
, unit
, line
);
1102 r
= link_parse_wol_password(config
, rvalue
);
1106 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
1107 "Failed to parse %s=, ignoring assignment: %s.", lvalue
, rvalue
);
1111 config
->wol_password_file
= mfree(config
->wol_password_file
);
1115 static const char* const mac_address_policy_table
[_MAC_ADDRESS_POLICY_MAX
] = {
1116 [MAC_ADDRESS_POLICY_PERSISTENT
] = "persistent",
1117 [MAC_ADDRESS_POLICY_RANDOM
] = "random",
1118 [MAC_ADDRESS_POLICY_NONE
] = "none",
1121 DEFINE_STRING_TABLE_LOOKUP(mac_address_policy
, MACAddressPolicy
);
1122 DEFINE_CONFIG_PARSE_ENUM_WITH_DEFAULT(
1123 config_parse_mac_address_policy
,
1126 MAC_ADDRESS_POLICY_NONE
,
1127 "Failed to parse MAC address policy");
1129 DEFINE_CONFIG_PARSE_ENUMV(config_parse_name_policy
, name_policy
, NamePolicy
,
1130 _NAMEPOLICY_INVALID
,
1131 "Failed to parse interface name policy");
1133 DEFINE_CONFIG_PARSE_ENUMV(config_parse_alternative_names_policy
, alternative_names_policy
, NamePolicy
,
1134 _NAMEPOLICY_INVALID
,
1135 "Failed to parse alternative names policy");