]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/udev/net/link-config.c
udev: link-config: remove unneded linux/netdevice.h include
[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("Failed to read /proc/cmdline, ignoring: %s",
179 strerror(-r));
180 if (r <= 0)
181 return true;
182
183 FOREACH_WORD_QUOTED(word, l, line, state)
184 if (strneq(word, "net.ifnames=0", l))
185 return false;
186
187 return true;
188 }
189
190 int link_config_load(link_config_ctx *ctx) {
191 int r;
192 _cleanup_strv_free_ char **files;
193 char **f;
194
195 link_configs_free(ctx);
196
197 if (!enable_name_policy()) {
198 ctx->enable_name_policy = false;
199 log_info("Network interface NamePolicy= disabled on kernel commandline, ignoring.");
200 }
201
202 /* update timestamp */
203 paths_check_timestamp(link_dirs, &ctx->link_dirs_ts_usec, true);
204
205 r = conf_files_list_strv(&files, ".link", NULL, link_dirs);
206 if (r < 0) {
207 log_error("failed to enumerate link files: %s", strerror(-r));
208 return r;
209 }
210
211 STRV_FOREACH_BACKWARDS(f, files) {
212 r = load_link(ctx, *f);
213 if (r < 0)
214 return r;
215 }
216
217 return 0;
218 }
219
220 bool link_config_should_reload(link_config_ctx *ctx) {
221 return paths_check_timestamp(link_dirs, &ctx->link_dirs_ts_usec, false);
222 }
223
224 int link_config_get(link_config_ctx *ctx, struct udev_device *device,
225 link_config **ret) {
226 link_config *link;
227
228 LIST_FOREACH(links, link, ctx->links) {
229 const char* attr_value = udev_device_get_sysattr_value(device, "address");
230
231 if (net_match_config(link->match_mac, link->match_path, link->match_driver,
232 link->match_type, NULL, link->match_host,
233 link->match_virt, link->match_kernel, link->match_arch,
234 attr_value ? ether_aton(attr_value) : NULL,
235 udev_device_get_property_value(device, "ID_PATH"),
236 udev_device_get_driver(udev_device_get_parent(device)),
237 udev_device_get_property_value(device, "ID_NET_DRIVER"),
238 udev_device_get_devtype(device),
239 NULL)) {
240 log_debug("Config file %s applies to device %s",
241 link->filename,
242 udev_device_get_sysname(device));
243 *ret = link;
244 return 0;
245 }
246 }
247
248 *ret = NULL;
249
250 return -ENOENT;
251 }
252
253 static bool mac_is_random(struct udev_device *device) {
254 const char *s;
255 unsigned type;
256 int r;
257
258 /* if we can't get the assign type, assume it is not random */
259 s = udev_device_get_sysattr_value(device, "addr_assign_type");
260 if (!s)
261 return false;
262
263 r = safe_atou(s, &type);
264 if (r < 0)
265 return false;
266
267 return type == NET_ADDR_RANDOM;
268 }
269
270 static bool should_rename(struct udev_device *device, bool respect_predictable) {
271 const char *s;
272 unsigned type;
273 int r;
274
275 /* if we can't get the assgin type, assume we should rename */
276 s = udev_device_get_sysattr_value(device, "name_assign_type");
277 if (!s)
278 return true;
279
280 r = safe_atou(s, &type);
281 if (r < 0)
282 return true;
283
284 switch (type) {
285 case NET_NAME_USER:
286 case NET_NAME_RENAMED:
287 /* these were already named by userspace, do not touch again */
288 return false;
289 case NET_NAME_PREDICTABLE:
290 /* the kernel claims to have given a predictable name */
291 if (respect_predictable)
292 return false;
293 /* fall through */
294 case NET_NAME_ENUM:
295 default:
296 /* the name is known to be bad, or of an unknown type */
297 return true;
298 }
299 }
300
301 static int get_mac(struct udev_device *device, bool want_random,
302 struct ether_addr *mac) {
303 int r;
304
305 if (want_random)
306 random_bytes(mac->ether_addr_octet, ETH_ALEN);
307 else {
308 uint8_t result[8];
309
310 r = net_get_unique_predictable_data(device, result);
311 if (r < 0)
312 return r;
313
314 assert_cc(ETH_ALEN <= sizeof(result));
315 memcpy(mac->ether_addr_octet, result, ETH_ALEN);
316 }
317
318 /* see eth_random_addr in the kernel */
319 mac->ether_addr_octet[0] &= 0xfe; /* clear multicast bit */
320 mac->ether_addr_octet[0] |= 0x02; /* set local assignment bit (IEEE802) */
321
322 return 0;
323 }
324
325 int link_config_apply(link_config_ctx *ctx, link_config *config,
326 struct udev_device *device, const char **name) {
327 const char *old_name;
328 const char *new_name = NULL;
329 struct ether_addr generated_mac;
330 struct ether_addr *mac = NULL;
331 bool respect_predictable = false;
332 int r, ifindex;
333
334 assert(ctx);
335 assert(config);
336 assert(device);
337 assert(name);
338
339 old_name = udev_device_get_sysname(device);
340 if (!old_name)
341 return -EINVAL;
342
343 r = ethtool_set_speed(&ctx->ethtool_fd, old_name, config->speed / 1024,
344 config->duplex);
345 if (r < 0)
346 log_warning("Could not set speed or duplex of %s to %u Mbps (%s): %s",
347 old_name, config->speed / 1024,
348 duplex_to_string(config->duplex), strerror(-r));
349
350 r = ethtool_set_wol(&ctx->ethtool_fd, old_name, config->wol);
351 if (r < 0)
352 log_warning("Could not set WakeOnLan of %s to %s: %s",
353 old_name, wol_to_string(config->wol), strerror(-r));
354
355 ifindex = udev_device_get_ifindex(device);
356 if (ifindex <= 0) {
357 log_warning("Could not find ifindex");
358 return -ENODEV;
359 }
360
361 if (ctx->enable_name_policy && config->name_policy) {
362 NamePolicy *policy;
363
364 for (policy = config->name_policy;
365 !new_name && *policy != _NAMEPOLICY_INVALID; policy++) {
366 switch (*policy) {
367 case NAMEPOLICY_KERNEL:
368 respect_predictable = true;
369 break;
370 case NAMEPOLICY_DATABASE:
371 new_name = udev_device_get_property_value(device, "ID_NET_NAME_FROM_DATABASE");
372 break;
373 case NAMEPOLICY_ONBOARD:
374 new_name = udev_device_get_property_value(device, "ID_NET_NAME_ONBOARD");
375 break;
376 case NAMEPOLICY_SLOT:
377 new_name = udev_device_get_property_value(device, "ID_NET_NAME_SLOT");
378 break;
379 case NAMEPOLICY_PATH:
380 new_name = udev_device_get_property_value(device, "ID_NET_NAME_PATH");
381 break;
382 case NAMEPOLICY_MAC:
383 new_name = udev_device_get_property_value(device, "ID_NET_NAME_MAC");
384 break;
385 default:
386 break;
387 }
388 }
389 }
390
391 if (should_rename(device, respect_predictable)) {
392 /* if not set by policy, fall back manually set name */
393 if (!new_name)
394 new_name = config->name;
395 } else
396 new_name = NULL;
397
398 switch (config->mac_policy) {
399 case MACPOLICY_PERSISTENT:
400 if (mac_is_random(device)) {
401 r = get_mac(device, false, &generated_mac);
402 if (r == -ENOENT)
403 break;
404 else if (r < 0)
405 return r;
406 mac = &generated_mac;
407 }
408 break;
409 case MACPOLICY_RANDOM:
410 if (!mac_is_random(device)) {
411 r = get_mac(device, true, &generated_mac);
412 if (r == -ENOENT)
413 break;
414 else if (r < 0)
415 return r;
416 mac = &generated_mac;
417 }
418 break;
419 default:
420 mac = config->mac;
421 }
422
423 r = rtnl_set_link_properties(&ctx->rtnl, ifindex, config->alias, mac,
424 config->mtu);
425 if (r < 0) {
426 log_warning("Could not set Alias, MACAddress or MTU on %s: %s",
427 old_name, strerror(-r));
428 return r;
429 }
430
431 *name = new_name;
432
433 return 0;
434 }
435
436 int link_get_driver(link_config_ctx *ctx, struct udev_device *device, char **ret) {
437 const char *name;
438 char *driver;
439 int r;
440
441 name = udev_device_get_sysname(device);
442 if (!name)
443 return -EINVAL;
444
445 r = ethtool_get_driver(&ctx->ethtool_fd, name, &driver);
446 if (r < 0)
447 return r;
448
449 *ret = driver;
450 return 0;
451 }
452
453 static const char* const mac_policy_table[_MACPOLICY_MAX] = {
454 [MACPOLICY_PERSISTENT] = "persistent",
455 [MACPOLICY_RANDOM] = "random"
456 };
457
458 DEFINE_STRING_TABLE_LOOKUP(mac_policy, MACPolicy);
459 DEFINE_CONFIG_PARSE_ENUM(config_parse_mac_policy, mac_policy, MACPolicy,
460 "Failed to parse MAC address policy");
461
462 static const char* const name_policy_table[_NAMEPOLICY_MAX] = {
463 [NAMEPOLICY_KERNEL] = "kernel",
464 [NAMEPOLICY_DATABASE] = "database",
465 [NAMEPOLICY_ONBOARD] = "onboard",
466 [NAMEPOLICY_SLOT] = "slot",
467 [NAMEPOLICY_PATH] = "path",
468 [NAMEPOLICY_MAC] = "mac"
469 };
470
471 DEFINE_STRING_TABLE_LOOKUP(name_policy, NamePolicy);
472 DEFINE_CONFIG_PARSE_ENUMV(config_parse_name_policy, name_policy, NamePolicy,
473 _NAMEPOLICY_INVALID,
474 "Failed to parse interface name policy");