]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/udev/net/link-config.c
udev: link-config: remove unneded linux/netdevice.h include
[thirdparty/systemd.git] / src / udev / net / link-config.c
CommitLineData
af6f0d42
TG
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
43b3a5ef
TG
22#include <netinet/ether.h>
23
16b9b87a 24#include "sd-id128.h"
af6f0d42 25
04b67d49 26#include "missing.h"
16b9b87a 27#include "link-config.h"
a5010333
TG
28#include "ethtool-util.h"
29
43b3a5ef
TG
30#include "libudev-private.h"
31#include "sd-rtnl.h"
af6f0d42
TG
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"
daeb71a3 38#include "fileio.h"
16b9b87a 39#include "hashmap.h"
3aeb37bc 40#include "rtnl-util.h"
c6f7c917 41#include "network-internal.h"
9bf3b535 42#include "siphash24.h"
af6f0d42
TG
43
44struct link_config_ctx {
45 LIST_HEAD(link_config, links);
46
a5010333
TG
47 int ethtool_fd;
48
f6194225
TG
49 bool enable_name_policy;
50
43b3a5ef
TG
51 sd_rtnl *rtnl;
52
97f2d76d 53 usec_t link_dirs_ts_usec;
af6f0d42
TG
54};
55
2ad8416d
ZJS
56static 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
5b9d4dc0
TG
65DEFINE_TRIVIAL_CLEANUP_FUNC(link_config_ctx*, link_config_ctx_free);
66#define _cleanup_link_config_ctx_free_ _cleanup_(link_config_ctx_freep)
67
af6f0d42 68int link_config_ctx_new(link_config_ctx **ret) {
5b9d4dc0 69 _cleanup_link_config_ctx_free_ link_config_ctx *ctx = NULL;
af6f0d42
TG
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
97708579
TG
80 ctx->ethtool_fd = -1;
81
f6194225
TG
82 ctx->enable_name_policy = true;
83
af6f0d42 84 *ret = ctx;
5b9d4dc0
TG
85 ctx = NULL;
86
af6f0d42
TG
87 return 0;
88}
89
90static 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);
d2df0d0e 102 free(link->alias);
edf029b7 103 free(link->name_policy);
af6f0d42
TG
104
105 free(link);
106 }
107}
108
109void link_config_ctx_free(link_config_ctx *ctx) {
110 if (!ctx)
111 return;
112
03e334a1 113 safe_close(ctx->ethtool_fd);
43b3a5ef
TG
114
115 sd_rtnl_unref(ctx->rtnl);
116
af6f0d42
TG
117 link_configs_free(ctx);
118
119 free(ctx);
120
121 return;
122}
123
124static int load_link(link_config_ctx *ctx, const char *filename) {
ecb08ec6 125 _cleanup_free_ link_config *link = NULL;
6e37cd2f 126 _cleanup_fclose_ FILE *file = NULL;
af6f0d42
TG
127 int r;
128
187dc6e5
TA
129 assert(ctx);
130 assert(filename);
131
af6f0d42
TG
132 file = fopen(filename, "re");
133 if (!file) {
134 if (errno == ENOENT)
135 return 0;
136 else
ecb08ec6 137 return -errno;
af6f0d42
TG
138 }
139
ed88bcfb
ZJS
140 if (null_or_empty_fd(fileno(file))) {
141 log_debug("Skipping empty file: %s", filename);
142 return 0;
143 }
144
af6f0d42 145 link = new0(link_config, 1);
ecb08ec6
ZJS
146 if (!link)
147 return log_oom();
af6f0d42 148
5fde13d7
TG
149 link->mac_policy = _MACPOLICY_INVALID;
150 link->wol = _WOL_INVALID;
151 link->duplex = _DUP_INVALID;
152
e9f3d2d5
ZJS
153 r = config_parse(NULL, filename, file,
154 "Match\0Link\0Ethernet\0",
155 config_item_perf_lookup, link_config_gperf_lookup,
36f822c4
ZJS
156 false, false, true, link);
157 if (r < 0)
ecb08ec6 158 return r;
36f822c4 159 else
98a375f6 160 log_debug("Parsed configuration file %s", filename);
af6f0d42
TG
161
162 link->filename = strdup(filename);
163
164 LIST_PREPEND(links, ctx->links, link);
ecb08ec6 165 link = NULL;
af6f0d42
TG
166
167 return 0;
af6f0d42
TG
168}
169
f6194225 170static bool enable_name_policy(void) {
f8a0bb52 171 _cleanup_free_ char *line = NULL;
a2a5291b 172 const char *word, *state;
f6194225
TG
173 int r;
174 size_t l;
175
74df0fca
LP
176 r = proc_cmdline(&line);
177 if (r < 0)
464cf22f
TG
178 log_warning("Failed to read /proc/cmdline, ignoring: %s",
179 strerror(-r));
74df0fca
LP
180 if (r <= 0)
181 return true;
f6194225 182
a2a5291b
ZJS
183 FOREACH_WORD_QUOTED(word, l, line, state)
184 if (strneq(word, "net.ifnames=0", l))
f6194225
TG
185 return false;
186
187 return true;
188}
189
af6f0d42
TG
190int link_config_load(link_config_ctx *ctx) {
191 int r;
edf029b7
TG
192 _cleanup_strv_free_ char **files;
193 char **f;
af6f0d42
TG
194
195 link_configs_free(ctx);
196
f6194225
TG
197 if (!enable_name_policy()) {
198 ctx->enable_name_policy = false;
199 log_info("Network interface NamePolicy= disabled on kernel commandline, ignoring.");
200 }
201
97f2d76d 202 /* update timestamp */
2ad8416d 203 paths_check_timestamp(link_dirs, &ctx->link_dirs_ts_usec, true);
af6f0d42 204
2ad8416d 205 r = conf_files_list_strv(&files, ".link", NULL, link_dirs);
af6f0d42
TG
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
220bool link_config_should_reload(link_config_ctx *ctx) {
2ad8416d 221 return paths_check_timestamp(link_dirs, &ctx->link_dirs_ts_usec, false);
af6f0d42
TG
222}
223
464cf22f
TG
224int link_config_get(link_config_ctx *ctx, struct udev_device *device,
225 link_config **ret) {
af6f0d42
TG
226 link_config *link;
227
228 LIST_FOREACH(links, link, ctx->links) {
eb7040ec 229 const char* attr_value = udev_device_get_sysattr_value(device, "address");
b3e01314 230
edbb03e9
TG
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,
eb7040ec 234 attr_value ? ether_aton(attr_value) : NULL,
b3e01314 235 udev_device_get_property_value(device, "ID_PATH"),
9b1c2626 236 udev_device_get_driver(udev_device_get_parent(device)),
bf175aaf 237 udev_device_get_property_value(device, "ID_NET_DRIVER"),
b3e01314
TG
238 udev_device_get_devtype(device),
239 NULL)) {
be32eb9b
TG
240 log_debug("Config file %s applies to device %s",
241 link->filename,
242 udev_device_get_sysname(device));
af6f0d42
TG
243 *ret = link;
244 return 0;
245 }
246 }
247
be32eb9b
TG
248 *ret = NULL;
249
af6f0d42
TG
250 return -ENOENT;
251}
252
16b9b87a
TG
253static bool mac_is_random(struct udev_device *device) {
254 const char *s;
f1ac7002
TG
255 unsigned type;
256 int r;
16b9b87a 257
3c9b8860 258 /* if we can't get the assign type, assume it is not random */
16b9b87a
TG
259 s = udev_device_get_sysattr_value(device, "addr_assign_type");
260 if (!s)
3c9b8860
TG
261 return false;
262
f1ac7002
TG
263 r = safe_atou(s, &type);
264 if (r < 0)
265 return false;
16b9b87a 266
04b67d49
TG
267 return type == NET_ADDR_RANDOM;
268}
269
270static bool should_rename(struct udev_device *device, bool respect_predictable) {
271 const char *s;
272 unsigned type;
273 int r;
274
3c9b8860 275 /* if we can't get the assgin type, assume we should rename */
04b67d49
TG
276 s = udev_device_get_sysattr_value(device, "name_assign_type");
277 if (!s)
3c9b8860
TG
278 return true;
279
04b67d49
TG
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:
3c9b8860
TG
287 /* these were already named by userspace, do not touch again */
288 return false;
04b67d49 289 case NET_NAME_PREDICTABLE:
3c9b8860 290 /* the kernel claims to have given a predictable name */
04b67d49 291 if (respect_predictable)
3c9b8860 292 return false;
04b67d49
TG
293 /* fall through */
294 case NET_NAME_ENUM:
295 default:
3c9b8860
TG
296 /* the name is known to be bad, or of an unknown type */
297 return true;
04b67d49 298 }
16b9b87a
TG
299}
300
464cf22f
TG
301static int get_mac(struct udev_device *device, bool want_random,
302 struct ether_addr *mac) {
9bf3b535 303 int r;
16b9b87a 304
16b9b87a 305 if (want_random)
9bf3b535 306 random_bytes(mac->ether_addr_octet, ETH_ALEN);
16b9b87a 307 else {
9bf3b535 308 uint8_t result[8];
9bf3b535 309
b5db00e5 310 r = net_get_unique_predictable_data(device, result);
16b9b87a 311 if (r < 0)
55428d84 312 return r;
16b9b87a 313
9bf3b535
LP
314 assert_cc(ETH_ALEN <= sizeof(result));
315 memcpy(mac->ether_addr_octet, result, ETH_ALEN);
16b9b87a
TG
316 }
317
318 /* see eth_random_addr in the kernel */
3c9b8860
TG
319 mac->ether_addr_octet[0] &= 0xfe; /* clear multicast bit */
320 mac->ether_addr_octet[0] |= 0x02; /* set local assignment bit (IEEE802) */
16b9b87a 321
16b9b87a
TG
322 return 0;
323}
324
464cf22f
TG
325int link_config_apply(link_config_ctx *ctx, link_config *config,
326 struct udev_device *device, const char **name) {
3e137a1b 327 const char *old_name;
5fde13d7
TG
328 const char *new_name = NULL;
329 struct ether_addr generated_mac;
16b9b87a 330 struct ether_addr *mac = NULL;
04b67d49 331 bool respect_predictable = false;
43b3a5ef 332 int r, ifindex;
af6f0d42 333
3e137a1b
TG
334 assert(ctx);
335 assert(config);
336 assert(device);
337 assert(name);
338
3e137a1b
TG
339 old_name = udev_device_get_sysname(device);
340 if (!old_name)
af6f0d42
TG
341 return -EINVAL;
342
aedca892 343 r = ethtool_set_speed(&ctx->ethtool_fd, old_name, config->speed / 1024,
464cf22f 344 config->duplex);
5fde13d7 345 if (r < 0)
733f7a2c 346 log_warning("Could not set speed or duplex of %s to %u Mbps (%s): %s",
464cf22f
TG
347 old_name, config->speed / 1024,
348 duplex_to_string(config->duplex), strerror(-r));
a5010333 349
aedca892 350 r = ethtool_set_wol(&ctx->ethtool_fd, old_name, config->wol);
5fde13d7
TG
351 if (r < 0)
352 log_warning("Could not set WakeOnLan of %s to %s: %s",
3e137a1b 353 old_name, wol_to_string(config->wol), strerror(-r));
af6f0d42 354
43b3a5ef
TG
355 ifindex = udev_device_get_ifindex(device);
356 if (ifindex <= 0) {
357 log_warning("Could not find ifindex");
358 return -ENODEV;
359 }
360
f6194225 361 if (ctx->enable_name_policy && config->name_policy) {
5fde13d7 362 NamePolicy *policy;
daeb71a3 363
68ba3877
TG
364 for (policy = config->name_policy;
365 !new_name && *policy != _NAMEPOLICY_INVALID; policy++) {
5fde13d7 366 switch (*policy) {
04b67d49
TG
367 case NAMEPOLICY_KERNEL:
368 respect_predictable = true;
369 break;
e51660ae
TG
370 case NAMEPOLICY_DATABASE:
371 new_name = udev_device_get_property_value(device, "ID_NET_NAME_FROM_DATABASE");
372 break;
5fde13d7
TG
373 case NAMEPOLICY_ONBOARD:
374 new_name = udev_device_get_property_value(device, "ID_NET_NAME_ONBOARD");
daeb71a3 375 break;
5fde13d7
TG
376 case NAMEPOLICY_SLOT:
377 new_name = udev_device_get_property_value(device, "ID_NET_NAME_SLOT");
daeb71a3 378 break;
5fde13d7
TG
379 case NAMEPOLICY_PATH:
380 new_name = udev_device_get_property_value(device, "ID_NET_NAME_PATH");
daeb71a3 381 break;
5fde13d7
TG
382 case NAMEPOLICY_MAC:
383 new_name = udev_device_get_property_value(device, "ID_NET_NAME_MAC");
daeb71a3 384 break;
5fde13d7
TG
385 default:
386 break;
387 }
daeb71a3
TG
388 }
389 }
390
04b67d49 391 if (should_rename(device, respect_predictable)) {
3c9b8860 392 /* if not set by policy, fall back manually set name */
04b67d49 393 if (!new_name)
04b67d49
TG
394 new_name = config->name;
395 } else
396 new_name = NULL;
397
5fde13d7
TG
398 switch (config->mac_policy) {
399 case MACPOLICY_PERSISTENT:
92d927f8 400 if (mac_is_random(device)) {
5fde13d7 401 r = get_mac(device, false, &generated_mac);
a669ea98
TG
402 if (r == -ENOENT)
403 break;
404 else if (r < 0)
16b9b87a 405 return r;
5fde13d7 406 mac = &generated_mac;
16b9b87a 407 }
5fde13d7
TG
408 break;
409 case MACPOLICY_RANDOM:
16b9b87a 410 if (!mac_is_random(device)) {
5fde13d7 411 r = get_mac(device, true, &generated_mac);
a669ea98
TG
412 if (r == -ENOENT)
413 break;
414 else if (r < 0)
16b9b87a 415 return r;
5fde13d7 416 mac = &generated_mac;
16b9b87a 417 }
5fde13d7
TG
418 break;
419 default:
420 mac = config->mac;
16b9b87a
TG
421 }
422
aedca892 423 r = rtnl_set_link_properties(&ctx->rtnl, ifindex, config->alias, mac,
464cf22f 424 config->mtu);
43b3a5ef 425 if (r < 0) {
464cf22f
TG
426 log_warning("Could not set Alias, MACAddress or MTU on %s: %s",
427 old_name, strerror(-r));
5fde13d7 428 return r;
43b3a5ef
TG
429 }
430
d95b83b8
TG
431 *name = new_name;
432
af6f0d42
TG
433 return 0;
434}
be32eb9b 435
847a8a5f
TG
436int link_get_driver(link_config_ctx *ctx, struct udev_device *device, char **ret) {
437 const char *name;
438 char *driver;
439 int r;
440
847a8a5f
TG
441 name = udev_device_get_sysname(device);
442 if (!name)
443 return -EINVAL;
444
aedca892 445 r = ethtool_get_driver(&ctx->ethtool_fd, name, &driver);
847a8a5f
TG
446 if (r < 0)
447 return r;
448
449 *ret = driver;
450 return 0;
451}
452
2c5859af 453static const char* const mac_policy_table[_MACPOLICY_MAX] = {
be32eb9b
TG
454 [MACPOLICY_PERSISTENT] = "persistent",
455 [MACPOLICY_RANDOM] = "random"
456};
457
458DEFINE_STRING_TABLE_LOOKUP(mac_policy, MACPolicy);
464cf22f
TG
459DEFINE_CONFIG_PARSE_ENUM(config_parse_mac_policy, mac_policy, MACPolicy,
460 "Failed to parse MAC address policy");
be32eb9b 461
2c5859af 462static const char* const name_policy_table[_NAMEPOLICY_MAX] = {
04b67d49 463 [NAMEPOLICY_KERNEL] = "kernel",
e51660ae 464 [NAMEPOLICY_DATABASE] = "database",
be32eb9b
TG
465 [NAMEPOLICY_ONBOARD] = "onboard",
466 [NAMEPOLICY_SLOT] = "slot",
467 [NAMEPOLICY_PATH] = "path",
468 [NAMEPOLICY_MAC] = "mac"
469};
470
471DEFINE_STRING_TABLE_LOOKUP(name_policy, NamePolicy);
464cf22f
TG
472DEFINE_CONFIG_PARSE_ENUMV(config_parse_name_policy, name_policy, NamePolicy,
473 _NAMEPOLICY_INVALID,
474 "Failed to parse interface name policy");