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