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