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