Line data Source code
1 : /* SPDX-License-Identifier: LGPL-2.1+ */
2 :
3 : #include <linux/netdevice.h>
4 : #include <netinet/ether.h>
5 :
6 : #include "sd-device.h"
7 : #include "sd-netlink.h"
8 :
9 : #include "alloc-util.h"
10 : #include "conf-files.h"
11 : #include "conf-parser.h"
12 : #include "def.h"
13 : #include "device-util.h"
14 : #include "ethtool-util.h"
15 : #include "fd-util.h"
16 : #include "link-config.h"
17 : #include "log.h"
18 : #include "memory-util.h"
19 : #include "naming-scheme.h"
20 : #include "netlink-util.h"
21 : #include "network-internal.h"
22 : #include "parse-util.h"
23 : #include "path-util.h"
24 : #include "proc-cmdline.h"
25 : #include "random-util.h"
26 : #include "stat-util.h"
27 : #include "string-table.h"
28 : #include "string-util.h"
29 : #include "strv.h"
30 :
31 : struct link_config_ctx {
32 : LIST_HEAD(link_config, links);
33 :
34 : int ethtool_fd;
35 :
36 : bool enable_name_policy;
37 :
38 : sd_netlink *rtnl;
39 :
40 : usec_t network_dirs_ts_usec;
41 : };
42 :
43 0 : static void link_config_free(link_config *link) {
44 0 : if (!link)
45 0 : return;
46 :
47 0 : free(link->filename);
48 :
49 0 : set_free_free(link->match_mac);
50 0 : strv_free(link->match_path);
51 0 : strv_free(link->match_driver);
52 0 : strv_free(link->match_type);
53 0 : strv_free(link->match_name);
54 0 : strv_free(link->match_property);
55 0 : condition_free_list(link->conditions);
56 :
57 0 : free(link->description);
58 0 : free(link->mac);
59 0 : free(link->name_policy);
60 0 : free(link->name);
61 0 : free(link->alias);
62 :
63 0 : free(link);
64 : }
65 :
66 0 : DEFINE_TRIVIAL_CLEANUP_FUNC(link_config*, link_config_free);
67 :
68 0 : static void link_configs_free(link_config_ctx *ctx) {
69 : link_config *link, *link_next;
70 :
71 0 : if (!ctx)
72 0 : return;
73 :
74 0 : LIST_FOREACH_SAFE(links, link, link_next, ctx->links)
75 0 : link_config_free(link);
76 : }
77 :
78 0 : void link_config_ctx_free(link_config_ctx *ctx) {
79 0 : if (!ctx)
80 0 : return;
81 :
82 0 : safe_close(ctx->ethtool_fd);
83 :
84 0 : sd_netlink_unref(ctx->rtnl);
85 :
86 0 : link_configs_free(ctx);
87 :
88 0 : free(ctx);
89 :
90 0 : return;
91 : }
92 :
93 0 : int link_config_ctx_new(link_config_ctx **ret) {
94 0 : _cleanup_(link_config_ctx_freep) link_config_ctx *ctx = NULL;
95 :
96 0 : if (!ret)
97 0 : return -EINVAL;
98 :
99 0 : ctx = new0(link_config_ctx, 1);
100 0 : if (!ctx)
101 0 : return -ENOMEM;
102 :
103 0 : LIST_HEAD_INIT(ctx->links);
104 :
105 0 : ctx->ethtool_fd = -1;
106 :
107 0 : ctx->enable_name_policy = true;
108 :
109 0 : *ret = TAKE_PTR(ctx);
110 :
111 0 : return 0;
112 : }
113 :
114 0 : int link_load_one(link_config_ctx *ctx, const char *filename) {
115 0 : _cleanup_(link_config_freep) link_config *link = NULL;
116 0 : _cleanup_fclose_ FILE *file = NULL;
117 0 : _cleanup_free_ char *name = NULL;
118 : size_t i;
119 : int r;
120 :
121 0 : assert(ctx);
122 0 : assert(filename);
123 :
124 0 : file = fopen(filename, "re");
125 0 : if (!file)
126 0 : return errno == ENOENT ? 0 : -errno;
127 :
128 0 : if (null_or_empty_fd(fileno(file))) {
129 0 : log_debug("Skipping empty file: %s", filename);
130 0 : return 0;
131 : }
132 :
133 0 : name = strdup(filename);
134 0 : if (!name)
135 0 : return -ENOMEM;
136 :
137 0 : link = new(link_config, 1);
138 0 : if (!link)
139 0 : return -ENOMEM;
140 :
141 0 : *link = (link_config) {
142 0 : .filename = TAKE_PTR(name),
143 : .mac_address_policy = _MAC_ADDRESS_POLICY_INVALID,
144 : .wol = _WOL_INVALID,
145 : .duplex = _DUP_INVALID,
146 : .port = _NET_DEV_PORT_INVALID,
147 : .autonegotiation = -1,
148 : };
149 :
150 0 : for (i = 0; i < ELEMENTSOF(link->features); i++)
151 0 : link->features[i] = -1;
152 :
153 0 : r = config_parse(NULL, filename, file,
154 : "Match\0Link\0",
155 : config_item_perf_lookup, link_config_gperf_lookup,
156 : CONFIG_PARSE_WARN, link);
157 0 : if (r < 0)
158 0 : return r;
159 :
160 0 : if (link->speed > UINT_MAX)
161 0 : return -ERANGE;
162 :
163 0 : if (set_isempty(link->match_mac) && strv_isempty(link->match_path) &&
164 0 : strv_isempty(link->match_driver) && strv_isempty(link->match_type) &&
165 0 : strv_isempty(link->match_name) && strv_isempty(link->match_property) && !link->conditions)
166 0 : log_warning("%s: No valid settings found in the [Match] section. "
167 : "The file will match all interfaces. "
168 : "If that is intended, please add OriginalName=* in the [Match] section.",
169 : filename);
170 :
171 0 : if (!condition_test_list(link->conditions, NULL, NULL, NULL)) {
172 0 : log_debug("%s: Conditions do not match the system environment, skipping.", filename);
173 0 : return 0;
174 : }
175 :
176 0 : log_debug("Parsed configuration file %s", filename);
177 :
178 0 : LIST_PREPEND(links, ctx->links, TAKE_PTR(link));
179 0 : return 0;
180 : }
181 :
182 0 : static bool enable_name_policy(void) {
183 : bool b;
184 :
185 0 : return proc_cmdline_get_bool("net.ifnames", &b) <= 0 || b;
186 : }
187 :
188 0 : static int link_unsigned_attribute(sd_device *device, const char *attr, unsigned *type) {
189 : const char *s;
190 : int r;
191 :
192 0 : r = sd_device_get_sysattr_value(device, attr, &s);
193 0 : if (r < 0)
194 0 : return log_device_debug_errno(device, r, "Failed to query %s: %m", attr);
195 :
196 0 : r = safe_atou(s, type);
197 0 : if (r < 0)
198 0 : return log_device_warning_errno(device, r, "Failed to parse %s \"%s\": %m", attr, s);
199 :
200 0 : log_device_debug(device, "Device has %s=%u", attr, *type);
201 0 : return 0;
202 : }
203 :
204 0 : int link_config_load(link_config_ctx *ctx) {
205 0 : _cleanup_strv_free_ char **files;
206 : char **f;
207 : int r;
208 :
209 0 : link_configs_free(ctx);
210 :
211 0 : if (!enable_name_policy()) {
212 0 : ctx->enable_name_policy = false;
213 0 : log_info("Network interface NamePolicy= disabled on kernel command line, ignoring.");
214 : }
215 :
216 : /* update timestamp */
217 0 : paths_check_timestamp(NETWORK_DIRS, &ctx->network_dirs_ts_usec, true);
218 :
219 0 : r = conf_files_list_strv(&files, ".link", NULL, 0, NETWORK_DIRS);
220 0 : if (r < 0)
221 0 : return log_error_errno(r, "failed to enumerate link files: %m");
222 :
223 0 : STRV_FOREACH_BACKWARDS(f, files) {
224 0 : r = link_load_one(ctx, *f);
225 0 : if (r < 0)
226 0 : log_error_errno(r, "Failed to load %s, ignoring: %m", *f);
227 : }
228 :
229 0 : return 0;
230 : }
231 :
232 0 : bool link_config_should_reload(link_config_ctx *ctx) {
233 0 : return paths_check_timestamp(NETWORK_DIRS, &ctx->network_dirs_ts_usec, false);
234 : }
235 :
236 0 : int link_config_get(link_config_ctx *ctx, sd_device *device, link_config **ret) {
237 : link_config *link;
238 :
239 0 : assert(ctx);
240 0 : assert(device);
241 0 : assert(ret);
242 :
243 0 : LIST_FOREACH(links, link, ctx->links) {
244 0 : if (net_match_config(link->match_mac, link->match_path, link->match_driver,
245 0 : link->match_type, link->match_name, link->match_property,
246 : device, NULL, NULL)) {
247 0 : if (link->match_name && !strv_contains(link->match_name, "*")) {
248 0 : unsigned name_assign_type = NET_NAME_UNKNOWN;
249 :
250 0 : (void) link_unsigned_attribute(device, "name_assign_type", &name_assign_type);
251 :
252 0 : if (name_assign_type == NET_NAME_ENUM) {
253 0 : log_device_warning(device, "Config file %s applies to device based on potentially unpredictable interface name",
254 : link->filename);
255 0 : *ret = link;
256 :
257 0 : return 0;
258 0 : } else if (name_assign_type == NET_NAME_RENAMED) {
259 0 : log_device_warning(device, "Config file %s matches device based on renamed interface name, ignoring",
260 : link->filename);
261 :
262 0 : continue;
263 : }
264 : }
265 :
266 0 : log_device_debug(device, "Config file %s is applied", link->filename);
267 :
268 0 : *ret = link;
269 0 : return 0;
270 : }
271 : }
272 :
273 0 : *ret = NULL;
274 0 : return -ENOENT;
275 : }
276 :
277 0 : static int get_mac(sd_device *device, MACAddressPolicy policy, struct ether_addr *mac) {
278 : unsigned addr_type;
279 0 : bool want_random = policy == MAC_ADDRESS_POLICY_RANDOM;
280 : int r;
281 :
282 0 : assert(IN_SET(policy, MAC_ADDRESS_POLICY_RANDOM, MAC_ADDRESS_POLICY_PERSISTENT));
283 :
284 0 : r = link_unsigned_attribute(device, "addr_assign_type", &addr_type);
285 0 : if (r < 0)
286 0 : return r;
287 0 : switch (addr_type) {
288 0 : case NET_ADDR_SET:
289 0 : return log_device_debug(device, "MAC on the device already set by userspace");
290 0 : case NET_ADDR_STOLEN:
291 0 : return log_device_debug(device, "MAC on the device already set based on another device");
292 0 : case NET_ADDR_RANDOM:
293 : case NET_ADDR_PERM:
294 0 : break;
295 0 : default:
296 0 : return log_device_warning(device, "Unknown addr_assign_type %u, ignoring", addr_type);
297 : }
298 :
299 0 : if (want_random == (addr_type == NET_ADDR_RANDOM))
300 0 : return log_device_debug(device, "MAC on the device already matches policy *%s*",
301 : mac_address_policy_to_string(policy));
302 :
303 0 : if (want_random) {
304 0 : log_device_debug(device, "Using random bytes to generate MAC");
305 0 : random_bytes(mac->ether_addr_octet, ETH_ALEN);
306 : } else {
307 : uint64_t result;
308 :
309 0 : r = net_get_unique_predictable_data(device,
310 0 : naming_scheme_has(NAMING_STABLE_VIRTUAL_MACS),
311 : &result);
312 0 : if (r < 0)
313 0 : return log_device_warning_errno(device, r, "Could not generate persistent MAC: %m");
314 :
315 0 : log_device_debug(device, "Using generated persistent MAC address");
316 : assert_cc(ETH_ALEN <= sizeof(result));
317 0 : memcpy(mac->ether_addr_octet, &result, ETH_ALEN);
318 : }
319 :
320 : /* see eth_random_addr in the kernel */
321 0 : mac->ether_addr_octet[0] &= 0xfe; /* clear multicast bit */
322 0 : mac->ether_addr_octet[0] |= 0x02; /* set local assignment bit (IEEE802) */
323 0 : return 1;
324 : }
325 :
326 0 : int link_config_apply(link_config_ctx *ctx, link_config *config,
327 : sd_device *device, const char **name) {
328 : struct ether_addr generated_mac;
329 0 : struct ether_addr *mac = NULL;
330 0 : const char *new_name = NULL;
331 : const char *old_name;
332 0 : unsigned speed, name_type = NET_NAME_UNKNOWN;
333 : NamePolicy policy;
334 : int r, ifindex;
335 :
336 0 : assert(ctx);
337 0 : assert(config);
338 0 : assert(device);
339 0 : assert(name);
340 :
341 0 : r = sd_device_get_sysname(device, &old_name);
342 0 : if (r < 0)
343 0 : return r;
344 :
345 0 : r = ethtool_set_glinksettings(&ctx->ethtool_fd, old_name,
346 0 : config->autonegotiation, config->advertise,
347 : config->speed, config->duplex, config->port);
348 0 : if (r < 0) {
349 :
350 0 : if (config->port != _NET_DEV_PORT_INVALID)
351 0 : log_warning_errno(r, "Could not set port (%s) of %s: %m", port_to_string(config->port), old_name);
352 :
353 0 : if (!eqzero(config->advertise))
354 0 : log_warning_errno(r, "Could not set advertise mode: %m"); /* TODO: include modes in the log message. */
355 :
356 0 : if (config->speed) {
357 0 : speed = DIV_ROUND_UP(config->speed, 1000000);
358 0 : if (r == -EOPNOTSUPP) {
359 0 : r = ethtool_set_speed(&ctx->ethtool_fd, old_name, speed, config->duplex);
360 0 : if (r < 0)
361 0 : log_warning_errno(r, "Could not set speed of %s to %u Mbps: %m", old_name, speed);
362 : }
363 : }
364 :
365 0 : if (config->duplex !=_DUP_INVALID)
366 0 : log_warning_errno(r, "Could not set duplex of %s to (%s): %m", old_name, duplex_to_string(config->duplex));
367 : }
368 :
369 0 : r = ethtool_set_wol(&ctx->ethtool_fd, old_name, config->wol);
370 0 : if (r < 0)
371 0 : log_warning_errno(r, "Could not set WakeOnLan of %s to %s: %m",
372 : old_name, wol_to_string(config->wol));
373 :
374 0 : r = ethtool_set_features(&ctx->ethtool_fd, old_name, config->features);
375 0 : if (r < 0)
376 0 : log_warning_errno(r, "Could not set offload features of %s: %m", old_name);
377 :
378 0 : if (config->channels.rx_count_set || config->channels.tx_count_set || config->channels.other_count_set || config->channels.combined_count_set) {
379 0 : r = ethtool_set_channels(&ctx->ethtool_fd, old_name, &config->channels);
380 0 : if (r < 0)
381 0 : log_warning_errno(r, "Could not set channels of %s: %m", old_name);
382 : }
383 :
384 0 : r = sd_device_get_ifindex(device, &ifindex);
385 0 : if (r < 0)
386 0 : return log_device_warning_errno(device, r, "Could not find ifindex: %m");
387 :
388 0 : (void) link_unsigned_attribute(device, "name_assign_type", &name_type);
389 :
390 0 : if (IN_SET(name_type, NET_NAME_USER, NET_NAME_RENAMED)
391 0 : && !naming_scheme_has(NAMING_ALLOW_RERENAMES)) {
392 0 : log_device_debug(device, "Device already has a name given by userspace, not renaming.");
393 0 : goto no_rename;
394 : }
395 :
396 0 : if (ctx->enable_name_policy && config->name_policy)
397 0 : for (NamePolicy *p = config->name_policy; !new_name && *p != _NAMEPOLICY_INVALID; p++) {
398 0 : policy = *p;
399 :
400 0 : switch (policy) {
401 0 : case NAMEPOLICY_KERNEL:
402 0 : if (name_type != NET_NAME_PREDICTABLE)
403 0 : continue;
404 :
405 : /* The kernel claims to have given a predictable name, keep it. */
406 0 : log_device_debug(device, "Policy *%s*: keeping predictable kernel name",
407 : name_policy_to_string(policy));
408 0 : goto no_rename;
409 0 : case NAMEPOLICY_KEEP:
410 0 : if (!IN_SET(name_type, NET_NAME_USER, NET_NAME_RENAMED))
411 0 : continue;
412 :
413 0 : log_device_debug(device, "Policy *%s*: keeping existing userspace name",
414 : name_policy_to_string(policy));
415 0 : goto no_rename;
416 0 : case NAMEPOLICY_DATABASE:
417 0 : (void) sd_device_get_property_value(device, "ID_NET_NAME_FROM_DATABASE", &new_name);
418 0 : break;
419 0 : case NAMEPOLICY_ONBOARD:
420 0 : (void) sd_device_get_property_value(device, "ID_NET_NAME_ONBOARD", &new_name);
421 0 : break;
422 0 : case NAMEPOLICY_SLOT:
423 0 : (void) sd_device_get_property_value(device, "ID_NET_NAME_SLOT", &new_name);
424 0 : break;
425 0 : case NAMEPOLICY_PATH:
426 0 : (void) sd_device_get_property_value(device, "ID_NET_NAME_PATH", &new_name);
427 0 : break;
428 0 : case NAMEPOLICY_MAC:
429 0 : (void) sd_device_get_property_value(device, "ID_NET_NAME_MAC", &new_name);
430 0 : break;
431 0 : default:
432 0 : assert_not_reached("invalid policy");
433 : }
434 : }
435 :
436 0 : if (new_name)
437 0 : log_device_debug(device, "Policy *%s* yields \"%s\".", name_policy_to_string(policy), new_name);
438 0 : else if (config->name) {
439 0 : new_name = config->name;
440 0 : log_device_debug(device, "Policies didn't yield a name, using specified Name=%s.", new_name);
441 : } else
442 0 : log_device_debug(device, "Policies didn't yield a name and Name= is not given, not renaming.");
443 0 : no_rename:
444 :
445 0 : if (IN_SET(config->mac_address_policy, MAC_ADDRESS_POLICY_PERSISTENT, MAC_ADDRESS_POLICY_RANDOM)) {
446 0 : if (get_mac(device, config->mac_address_policy, &generated_mac) > 0)
447 0 : mac = &generated_mac;
448 : } else
449 0 : mac = config->mac;
450 :
451 0 : r = rtnl_set_link_properties(&ctx->rtnl, ifindex, config->alias, mac, config->mtu);
452 0 : if (r < 0)
453 0 : return log_warning_errno(r, "Could not set Alias=, MACAddress= or MTU= on %s: %m", old_name);
454 :
455 0 : *name = new_name;
456 :
457 0 : return 0;
458 : }
459 :
460 0 : int link_get_driver(link_config_ctx *ctx, sd_device *device, char **ret) {
461 : const char *name;
462 0 : char *driver = NULL;
463 : int r;
464 :
465 0 : r = sd_device_get_sysname(device, &name);
466 0 : if (r < 0)
467 0 : return r;
468 :
469 0 : r = ethtool_get_driver(&ctx->ethtool_fd, name, &driver);
470 0 : if (r < 0)
471 0 : return r;
472 :
473 0 : *ret = driver;
474 0 : return 0;
475 : }
476 :
477 : static const char* const mac_address_policy_table[_MAC_ADDRESS_POLICY_MAX] = {
478 : [MAC_ADDRESS_POLICY_PERSISTENT] = "persistent",
479 : [MAC_ADDRESS_POLICY_RANDOM] = "random",
480 : [MAC_ADDRESS_POLICY_NONE] = "none",
481 : };
482 :
483 10 : DEFINE_STRING_TABLE_LOOKUP(mac_address_policy, MACAddressPolicy);
484 0 : DEFINE_CONFIG_PARSE_ENUM(config_parse_mac_address_policy, mac_address_policy, MACAddressPolicy,
485 : "Failed to parse MAC address policy");
486 :
487 : static const char* const name_policy_table[_NAMEPOLICY_MAX] = {
488 : [NAMEPOLICY_KERNEL] = "kernel",
489 : [NAMEPOLICY_KEEP] = "keep",
490 : [NAMEPOLICY_DATABASE] = "database",
491 : [NAMEPOLICY_ONBOARD] = "onboard",
492 : [NAMEPOLICY_SLOT] = "slot",
493 : [NAMEPOLICY_PATH] = "path",
494 : [NAMEPOLICY_MAC] = "mac",
495 : };
496 :
497 18 : DEFINE_STRING_TABLE_LOOKUP(name_policy, NamePolicy);
498 0 : DEFINE_CONFIG_PARSE_ENUMV(config_parse_name_policy, name_policy, NamePolicy,
499 : _NAMEPOLICY_INVALID,
500 : "Failed to parse interface name policy");
|