]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/udev/net/link-config.c
util-lib: split our string related calls from util.[ch] into its own file string...
[thirdparty/systemd.git] / src / udev / net / link-config.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4 This file is part of systemd.
5
6 Copyright (C) 2013 Tom Gundersen <teg@jklm.no>
7
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
12
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 #include <netinet/ether.h>
23 #include <linux/netdevice.h>
24
25 #include "sd-netlink.h"
26
27 #include "conf-files.h"
28 #include "conf-parser.h"
29 #include "ethtool-util.h"
30 #include "libudev-private.h"
31 #include "link-config.h"
32 #include "log.h"
33 #include "missing.h"
34 #include "netlink-util.h"
35 #include "network-internal.h"
36 #include "path-util.h"
37 #include "random-util.h"
38 #include "string-util.h"
39 #include "strv.h"
40 #include "util.h"
41
42 struct link_config_ctx {
43 LIST_HEAD(link_config, links);
44
45 int ethtool_fd;
46
47 bool enable_name_policy;
48
49 sd_netlink *rtnl;
50
51 usec_t link_dirs_ts_usec;
52 };
53
54 static const char* const link_dirs[] = {
55 "/etc/systemd/network",
56 "/run/systemd/network",
57 "/usr/lib/systemd/network",
58 #ifdef HAVE_SPLIT_USR
59 "/lib/systemd/network",
60 #endif
61 NULL};
62
63 static void link_config_free(link_config *link) {
64 if (!link)
65 return;
66
67 free(link->filename);
68
69 free(link->match_mac);
70 strv_free(link->match_path);
71 strv_free(link->match_driver);
72 strv_free(link->match_type);
73 free(link->match_name);
74 free(link->match_host);
75 free(link->match_virt);
76 free(link->match_kernel);
77 free(link->match_arch);
78
79 free(link->description);
80 free(link->mac);
81 free(link->name_policy);
82 free(link->name);
83 free(link->alias);
84
85 free(link);
86 }
87
88 DEFINE_TRIVIAL_CLEANUP_FUNC(link_config*, link_config_free);
89
90 static void link_configs_free(link_config_ctx *ctx) {
91 link_config *link, *link_next;
92
93 if (!ctx)
94 return;
95
96 LIST_FOREACH_SAFE(links, link, link_next, ctx->links)
97 link_config_free(link);
98 }
99
100 void link_config_ctx_free(link_config_ctx *ctx) {
101 if (!ctx)
102 return;
103
104 safe_close(ctx->ethtool_fd);
105
106 sd_netlink_unref(ctx->rtnl);
107
108 link_configs_free(ctx);
109
110 free(ctx);
111
112 return;
113 }
114
115 DEFINE_TRIVIAL_CLEANUP_FUNC(link_config_ctx*, link_config_ctx_free);
116
117 int link_config_ctx_new(link_config_ctx **ret) {
118 _cleanup_(link_config_ctx_freep) link_config_ctx *ctx = NULL;
119
120 if (!ret)
121 return -EINVAL;
122
123 ctx = new0(link_config_ctx, 1);
124 if (!ctx)
125 return -ENOMEM;
126
127 LIST_HEAD_INIT(ctx->links);
128
129 ctx->ethtool_fd = -1;
130
131 ctx->enable_name_policy = true;
132
133 *ret = ctx;
134 ctx = NULL;
135
136 return 0;
137 }
138
139 static int load_link(link_config_ctx *ctx, const char *filename) {
140 _cleanup_(link_config_freep) link_config *link = NULL;
141 _cleanup_fclose_ FILE *file = NULL;
142 int r;
143
144 assert(ctx);
145 assert(filename);
146
147 file = fopen(filename, "re");
148 if (!file) {
149 if (errno == ENOENT)
150 return 0;
151 else
152 return -errno;
153 }
154
155 if (null_or_empty_fd(fileno(file))) {
156 log_debug("Skipping empty file: %s", filename);
157 return 0;
158 }
159
160 link = new0(link_config, 1);
161 if (!link)
162 return log_oom();
163
164 link->mac_policy = _MACPOLICY_INVALID;
165 link->wol = _WOL_INVALID;
166 link->duplex = _DUP_INVALID;
167
168 r = config_parse(NULL, filename, file,
169 "Match\0Link\0Ethernet\0",
170 config_item_perf_lookup, link_config_gperf_lookup,
171 false, false, true, link);
172 if (r < 0)
173 return r;
174 else
175 log_debug("Parsed configuration file %s", filename);
176
177 if (link->mtu > UINT_MAX || link->speed > UINT_MAX)
178 return -ERANGE;
179
180 link->filename = strdup(filename);
181
182 LIST_PREPEND(links, ctx->links, link);
183 link = NULL;
184
185 return 0;
186 }
187
188 static bool enable_name_policy(void) {
189 _cleanup_free_ char *line = NULL;
190 const char *word, *state;
191 int r;
192 size_t l;
193
194 r = proc_cmdline(&line);
195 if (r < 0) {
196 log_warning_errno(r, "Failed to read /proc/cmdline, ignoring: %m");
197 return true;
198 }
199
200 FOREACH_WORD_QUOTED(word, l, line, state)
201 if (strneq(word, "net.ifnames=0", l))
202 return false;
203
204 return true;
205 }
206
207 int link_config_load(link_config_ctx *ctx) {
208 int r;
209 _cleanup_strv_free_ char **files;
210 char **f;
211
212 link_configs_free(ctx);
213
214 if (!enable_name_policy()) {
215 ctx->enable_name_policy = false;
216 log_info("Network interface NamePolicy= disabled on kernel command line, ignoring.");
217 }
218
219 /* update timestamp */
220 paths_check_timestamp(link_dirs, &ctx->link_dirs_ts_usec, true);
221
222 r = conf_files_list_strv(&files, ".link", NULL, link_dirs);
223 if (r < 0)
224 return log_error_errno(r, "failed to enumerate link files: %m");
225
226 STRV_FOREACH_BACKWARDS(f, files) {
227 r = load_link(ctx, *f);
228 if (r < 0)
229 return r;
230 }
231
232 return 0;
233 }
234
235 bool link_config_should_reload(link_config_ctx *ctx) {
236 return paths_check_timestamp(link_dirs, &ctx->link_dirs_ts_usec, false);
237 }
238
239 int link_config_get(link_config_ctx *ctx, struct udev_device *device,
240 link_config **ret) {
241 link_config *link;
242
243 assert(ctx);
244 assert(device);
245 assert(ret);
246
247 LIST_FOREACH(links, link, ctx->links) {
248 const char* attr_value;
249
250 attr_value = udev_device_get_sysattr_value(device, "address");
251
252 if (net_match_config(link->match_mac, link->match_path, link->match_driver,
253 link->match_type, link->match_name, link->match_host,
254 link->match_virt, link->match_kernel, link->match_arch,
255 attr_value ? ether_aton(attr_value) : NULL,
256 udev_device_get_property_value(device, "ID_PATH"),
257 udev_device_get_driver(udev_device_get_parent(device)),
258 udev_device_get_property_value(device, "ID_NET_DRIVER"),
259 udev_device_get_devtype(device),
260 udev_device_get_sysname(device))) {
261 if (link->match_name) {
262 unsigned char name_assign_type = NET_NAME_UNKNOWN;
263
264 attr_value = udev_device_get_sysattr_value(device, "name_assign_type");
265 if (attr_value)
266 (void) safe_atou8(attr_value, &name_assign_type);
267
268 if (name_assign_type == NET_NAME_ENUM) {
269 log_warning("Config file %s applies to device based on potentially unpredictable interface name '%s'",
270 link->filename, udev_device_get_sysname(device));
271 *ret = link;
272
273 return 0;
274 } else if (name_assign_type == NET_NAME_RENAMED) {
275 log_warning("Config file %s matches device based on renamed interface name '%s', ignoring",
276 link->filename, udev_device_get_sysname(device));
277
278 continue;
279 }
280 }
281
282 log_debug("Config file %s applies to device %s",
283 link->filename, udev_device_get_sysname(device));
284
285 *ret = link;
286
287 return 0;
288 }
289 }
290
291 *ret = NULL;
292
293 return -ENOENT;
294 }
295
296 static bool mac_is_random(struct udev_device *device) {
297 const char *s;
298 unsigned type;
299 int r;
300
301 /* if we can't get the assign type, assume it is not random */
302 s = udev_device_get_sysattr_value(device, "addr_assign_type");
303 if (!s)
304 return false;
305
306 r = safe_atou(s, &type);
307 if (r < 0)
308 return false;
309
310 return type == NET_ADDR_RANDOM;
311 }
312
313 static bool should_rename(struct udev_device *device, bool respect_predictable) {
314 const char *s;
315 unsigned type;
316 int r;
317
318 /* if we can't get the assgin type, assume we should rename */
319 s = udev_device_get_sysattr_value(device, "name_assign_type");
320 if (!s)
321 return true;
322
323 r = safe_atou(s, &type);
324 if (r < 0)
325 return true;
326
327 switch (type) {
328 case NET_NAME_USER:
329 case NET_NAME_RENAMED:
330 /* these were already named by userspace, do not touch again */
331 return false;
332 case NET_NAME_PREDICTABLE:
333 /* the kernel claims to have given a predictable name */
334 if (respect_predictable)
335 return false;
336 /* fall through */
337 case NET_NAME_ENUM:
338 default:
339 /* the name is known to be bad, or of an unknown type */
340 return true;
341 }
342 }
343
344 static int get_mac(struct udev_device *device, bool want_random,
345 struct ether_addr *mac) {
346 int r;
347
348 if (want_random)
349 random_bytes(mac->ether_addr_octet, ETH_ALEN);
350 else {
351 uint8_t result[8];
352
353 r = net_get_unique_predictable_data(device, result);
354 if (r < 0)
355 return r;
356
357 assert_cc(ETH_ALEN <= sizeof(result));
358 memcpy(mac->ether_addr_octet, result, ETH_ALEN);
359 }
360
361 /* see eth_random_addr in the kernel */
362 mac->ether_addr_octet[0] &= 0xfe; /* clear multicast bit */
363 mac->ether_addr_octet[0] |= 0x02; /* set local assignment bit (IEEE802) */
364
365 return 0;
366 }
367
368 int link_config_apply(link_config_ctx *ctx, link_config *config,
369 struct udev_device *device, const char **name) {
370 const char *old_name;
371 const char *new_name = NULL;
372 struct ether_addr generated_mac;
373 struct ether_addr *mac = NULL;
374 bool respect_predictable = false;
375 int r, ifindex;
376
377 assert(ctx);
378 assert(config);
379 assert(device);
380 assert(name);
381
382 old_name = udev_device_get_sysname(device);
383 if (!old_name)
384 return -EINVAL;
385
386 r = ethtool_set_speed(&ctx->ethtool_fd, old_name, config->speed / 1024, config->duplex);
387 if (r < 0)
388 log_warning_errno(r, "Could not set speed or duplex of %s to %zu Mbps (%s): %m",
389 old_name, config->speed / 1024,
390 duplex_to_string(config->duplex));
391
392 r = ethtool_set_wol(&ctx->ethtool_fd, old_name, config->wol);
393 if (r < 0)
394 log_warning_errno(r, "Could not set WakeOnLan of %s to %s: %m",
395 old_name, wol_to_string(config->wol));
396
397 ifindex = udev_device_get_ifindex(device);
398 if (ifindex <= 0) {
399 log_warning("Could not find ifindex");
400 return -ENODEV;
401 }
402
403 if (ctx->enable_name_policy && config->name_policy) {
404 NamePolicy *policy;
405
406 for (policy = config->name_policy;
407 !new_name && *policy != _NAMEPOLICY_INVALID; policy++) {
408 switch (*policy) {
409 case NAMEPOLICY_KERNEL:
410 respect_predictable = true;
411 break;
412 case NAMEPOLICY_DATABASE:
413 new_name = udev_device_get_property_value(device, "ID_NET_NAME_FROM_DATABASE");
414 break;
415 case NAMEPOLICY_ONBOARD:
416 new_name = udev_device_get_property_value(device, "ID_NET_NAME_ONBOARD");
417 break;
418 case NAMEPOLICY_SLOT:
419 new_name = udev_device_get_property_value(device, "ID_NET_NAME_SLOT");
420 break;
421 case NAMEPOLICY_PATH:
422 new_name = udev_device_get_property_value(device, "ID_NET_NAME_PATH");
423 break;
424 case NAMEPOLICY_MAC:
425 new_name = udev_device_get_property_value(device, "ID_NET_NAME_MAC");
426 break;
427 default:
428 break;
429 }
430 }
431 }
432
433 if (should_rename(device, respect_predictable)) {
434 /* if not set by policy, fall back manually set name */
435 if (!new_name)
436 new_name = config->name;
437 } else
438 new_name = NULL;
439
440 switch (config->mac_policy) {
441 case MACPOLICY_PERSISTENT:
442 if (mac_is_random(device)) {
443 r = get_mac(device, false, &generated_mac);
444 if (r == -ENOENT) {
445 log_warning_errno(r, "Could not generate persistent MAC address for %s: %m", old_name);
446 break;
447 } else if (r < 0)
448 return r;
449 mac = &generated_mac;
450 }
451 break;
452 case MACPOLICY_RANDOM:
453 if (!mac_is_random(device)) {
454 r = get_mac(device, true, &generated_mac);
455 if (r == -ENOENT) {
456 log_warning_errno(r, "Could not generate random MAC address for %s: %m", old_name);
457 break;
458 } else if (r < 0)
459 return r;
460 mac = &generated_mac;
461 }
462 break;
463 case MACPOLICY_NONE:
464 default:
465 mac = config->mac;
466 }
467
468 r = rtnl_set_link_properties(&ctx->rtnl, ifindex, config->alias, mac, config->mtu);
469 if (r < 0)
470 return log_warning_errno(r, "Could not set Alias, MACAddress or MTU on %s: %m", old_name);
471
472 *name = new_name;
473
474 return 0;
475 }
476
477 int link_get_driver(link_config_ctx *ctx, struct udev_device *device, char **ret) {
478 const char *name;
479 char *driver = NULL;
480 int r;
481
482 name = udev_device_get_sysname(device);
483 if (!name)
484 return -EINVAL;
485
486 r = ethtool_get_driver(&ctx->ethtool_fd, name, &driver);
487 if (r < 0)
488 return r;
489
490 *ret = driver;
491 return 0;
492 }
493
494 static const char* const mac_policy_table[_MACPOLICY_MAX] = {
495 [MACPOLICY_PERSISTENT] = "persistent",
496 [MACPOLICY_RANDOM] = "random",
497 [MACPOLICY_NONE] = "none"
498 };
499
500 DEFINE_STRING_TABLE_LOOKUP(mac_policy, MACPolicy);
501 DEFINE_CONFIG_PARSE_ENUM(config_parse_mac_policy, mac_policy, MACPolicy,
502 "Failed to parse MAC address policy");
503
504 static const char* const name_policy_table[_NAMEPOLICY_MAX] = {
505 [NAMEPOLICY_KERNEL] = "kernel",
506 [NAMEPOLICY_DATABASE] = "database",
507 [NAMEPOLICY_ONBOARD] = "onboard",
508 [NAMEPOLICY_SLOT] = "slot",
509 [NAMEPOLICY_PATH] = "path",
510 [NAMEPOLICY_MAC] = "mac"
511 };
512
513 DEFINE_STRING_TABLE_LOOKUP(name_policy, NamePolicy);
514 DEFINE_CONFIG_PARSE_ENUMV(config_parse_name_policy, name_policy, NamePolicy,
515 _NAMEPOLICY_INVALID,
516 "Failed to parse interface name policy");