]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/udev/net/link-config.c
journal-remote: allow splitting incoming logs by source host
[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 22#include <netinet/ether.h>
2a73e0d3 23#include <net/if.h>
43b3a5ef 24
16b9b87a 25#include "sd-id128.h"
af6f0d42 26
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
97708579
TG
90static int link_config_ctx_connect(link_config_ctx *ctx) {
91 int r;
92
847a8a5f
TG
93 if (ctx->ethtool_fd == -1) {
94 r = ethtool_connect(&ctx->ethtool_fd);
866ee368
TG
95 if (r < 0) {
96 log_warning("link_config: could not connect to ethtool: %s",
97 strerror(-r));
847a8a5f 98 return r;
866ee368 99 }
847a8a5f 100 }
97708579 101
847a8a5f
TG
102 if (!ctx->rtnl) {
103 r = sd_rtnl_open(&ctx->rtnl, 0);
866ee368
TG
104 if (r < 0) {
105 log_warning("link_config: could not connect to rtnl: %s",
106 strerror(-r));
847a8a5f 107 return r;
866ee368 108 }
847a8a5f 109 }
97708579
TG
110
111 return 0;
112}
113
af6f0d42
TG
114static void link_configs_free(link_config_ctx *ctx) {
115 link_config *link, *link_next;
116
117 if (!ctx)
118 return;
119
120 LIST_FOREACH_SAFE(links, link, link_next, ctx->links) {
121 free(link->filename);
122 free(link->match_path);
123 free(link->match_driver);
124 free(link->match_type);
125 free(link->description);
d2df0d0e 126 free(link->alias);
edf029b7 127 free(link->name_policy);
af6f0d42
TG
128
129 free(link);
130 }
131}
132
133void link_config_ctx_free(link_config_ctx *ctx) {
134 if (!ctx)
135 return;
136
03e334a1 137 safe_close(ctx->ethtool_fd);
43b3a5ef
TG
138
139 sd_rtnl_unref(ctx->rtnl);
140
af6f0d42
TG
141 link_configs_free(ctx);
142
143 free(ctx);
144
145 return;
146}
147
148static int load_link(link_config_ctx *ctx, const char *filename) {
ecb08ec6 149 _cleanup_free_ link_config *link = NULL;
6e37cd2f 150 _cleanup_fclose_ FILE *file = NULL;
af6f0d42
TG
151 int r;
152
187dc6e5
TA
153 assert(ctx);
154 assert(filename);
155
6916ec29
TG
156 if (null_or_empty_path(filename)) {
157 log_debug("skipping empty file: %s", filename);
158 return 0;
159 }
160
af6f0d42
TG
161 file = fopen(filename, "re");
162 if (!file) {
163 if (errno == ENOENT)
164 return 0;
165 else
ecb08ec6 166 return -errno;
af6f0d42
TG
167 }
168
169 link = new0(link_config, 1);
ecb08ec6
ZJS
170 if (!link)
171 return log_oom();
af6f0d42 172
5fde13d7
TG
173 link->mac_policy = _MACPOLICY_INVALID;
174 link->wol = _WOL_INVALID;
175 link->duplex = _DUP_INVALID;
176
af6f0d42
TG
177 r = config_parse(NULL, filename, file, "Match\0Link\0Ethernet\0", config_item_perf_lookup,
178 (void*) link_config_gperf_lookup, false, false, link);
179 if (r < 0) {
48912436 180 log_warning("Could not parse config file %s: %s", filename, strerror(-r));
ecb08ec6 181 return r;
af6f0d42 182 } else
98a375f6 183 log_debug("Parsed configuration file %s", filename);
af6f0d42
TG
184
185 link->filename = strdup(filename);
186
187 LIST_PREPEND(links, ctx->links, link);
ecb08ec6 188 link = NULL;
af6f0d42
TG
189
190 return 0;
af6f0d42
TG
191}
192
f6194225 193static bool enable_name_policy(void) {
f8a0bb52 194 _cleanup_free_ char *line = NULL;
f6194225
TG
195 char *w, *state;
196 int r;
197 size_t l;
198
74df0fca
LP
199 r = proc_cmdline(&line);
200 if (r < 0)
f6194225 201 log_warning("Failed to read /proc/cmdline, ignoring: %s", strerror(-r));
74df0fca
LP
202 if (r <= 0)
203 return true;
f6194225
TG
204
205 FOREACH_WORD_QUOTED(w, l, line, state)
ff83aac3 206 if (strneq(w, "net.ifnames=0", l))
f6194225
TG
207 return false;
208
209 return true;
210}
211
af6f0d42
TG
212int link_config_load(link_config_ctx *ctx) {
213 int r;
edf029b7
TG
214 _cleanup_strv_free_ char **files;
215 char **f;
af6f0d42
TG
216
217 link_configs_free(ctx);
218
f6194225
TG
219 if (!enable_name_policy()) {
220 ctx->enable_name_policy = false;
221 log_info("Network interface NamePolicy= disabled on kernel commandline, ignoring.");
222 }
223
97f2d76d 224 /* update timestamp */
2ad8416d 225 paths_check_timestamp(link_dirs, &ctx->link_dirs_ts_usec, true);
af6f0d42 226
2ad8416d 227 r = conf_files_list_strv(&files, ".link", NULL, link_dirs);
af6f0d42
TG
228 if (r < 0) {
229 log_error("failed to enumerate link files: %s", strerror(-r));
230 return r;
231 }
232
233 STRV_FOREACH_BACKWARDS(f, files) {
234 r = load_link(ctx, *f);
235 if (r < 0)
236 return r;
237 }
238
239 return 0;
240}
241
242bool link_config_should_reload(link_config_ctx *ctx) {
2ad8416d 243 return paths_check_timestamp(link_dirs, &ctx->link_dirs_ts_usec, false);
af6f0d42
TG
244}
245
af6f0d42
TG
246int link_config_get(link_config_ctx *ctx, struct udev_device *device, link_config **ret) {
247 link_config *link;
248
249 LIST_FOREACH(links, link, ctx->links) {
b3e01314 250
edbb03e9
TG
251 if (net_match_config(link->match_mac, link->match_path, link->match_driver,
252 link->match_type, NULL, link->match_host,
253 link->match_virt, link->match_kernel, link->match_arch,
505f8da7 254 ether_aton(udev_device_get_sysattr_value(device, "address")),
b3e01314 255 udev_device_get_property_value(device, "ID_PATH"),
9b1c2626 256 udev_device_get_driver(udev_device_get_parent(device)),
bf175aaf 257 udev_device_get_property_value(device, "ID_NET_DRIVER"),
b3e01314
TG
258 udev_device_get_devtype(device),
259 NULL)) {
be32eb9b
TG
260 log_debug("Config file %s applies to device %s",
261 link->filename,
262 udev_device_get_sysname(device));
af6f0d42
TG
263 *ret = link;
264 return 0;
265 }
266 }
267
be32eb9b
TG
268 *ret = NULL;
269
af6f0d42
TG
270 return -ENOENT;
271}
272
16b9b87a
TG
273static bool mac_is_random(struct udev_device *device) {
274 const char *s;
f1ac7002
TG
275 unsigned type;
276 int r;
16b9b87a
TG
277
278 s = udev_device_get_sysattr_value(device, "addr_assign_type");
279 if (!s)
f1ac7002
TG
280 return false; /* if we don't know, assume it is not random */
281 r = safe_atou(s, &type);
282 if (r < 0)
283 return false;
16b9b87a
TG
284
285 /* check for NET_ADDR_RANDOM */
286 return type == 1;
287}
288
5fde13d7 289static int get_mac(struct udev_device *device, bool want_random, struct ether_addr *mac) {
9bf3b535 290 int r;
16b9b87a 291
16b9b87a 292 if (want_random)
9bf3b535 293 random_bytes(mac->ether_addr_octet, ETH_ALEN);
16b9b87a 294 else {
9bf3b535 295 uint8_t result[8];
9bf3b535 296
b5db00e5 297 r = net_get_unique_predictable_data(device, result);
16b9b87a 298 if (r < 0)
55428d84 299 return r;
16b9b87a 300
9bf3b535
LP
301 assert_cc(ETH_ALEN <= sizeof(result));
302 memcpy(mac->ether_addr_octet, result, ETH_ALEN);
16b9b87a
TG
303 }
304
305 /* see eth_random_addr in the kernel */
306 mac->ether_addr_octet[0] &= 0xfe; /* clear multicast bit */
307 mac->ether_addr_octet[0] |= 0x02; /* set local assignment bit (IEEE802) */
308
16b9b87a
TG
309 return 0;
310}
311
3e137a1b
TG
312int link_config_apply(link_config_ctx *ctx, link_config *config, struct udev_device *device, const char **name) {
313 const char *old_name;
5fde13d7
TG
314 const char *new_name = NULL;
315 struct ether_addr generated_mac;
16b9b87a 316 struct ether_addr *mac = NULL;
43b3a5ef 317 int r, ifindex;
af6f0d42 318
3e137a1b
TG
319 assert(ctx);
320 assert(config);
321 assert(device);
322 assert(name);
323
97708579
TG
324 r = link_config_ctx_connect(ctx);
325 if (r < 0)
326 return r;
327
3e137a1b
TG
328 old_name = udev_device_get_sysname(device);
329 if (!old_name)
af6f0d42
TG
330 return -EINVAL;
331
733f7a2c 332 r = ethtool_set_speed(ctx->ethtool_fd, old_name, config->speed / 1024, config->duplex);
5fde13d7 333 if (r < 0)
733f7a2c
TG
334 log_warning("Could not set speed or duplex of %s to %u Mbps (%s): %s",
335 old_name, config->speed / 1024, duplex_to_string(config->duplex),
336 strerror(-r));
a5010333 337
3e137a1b 338 r = ethtool_set_wol(ctx->ethtool_fd, old_name, config->wol);
5fde13d7
TG
339 if (r < 0)
340 log_warning("Could not set WakeOnLan of %s to %s: %s",
3e137a1b 341 old_name, wol_to_string(config->wol), strerror(-r));
af6f0d42 342
43b3a5ef
TG
343 ifindex = udev_device_get_ifindex(device);
344 if (ifindex <= 0) {
345 log_warning("Could not find ifindex");
346 return -ENODEV;
347 }
348
f6194225 349 if (ctx->enable_name_policy && config->name_policy) {
5fde13d7 350 NamePolicy *policy;
daeb71a3 351
5fde13d7
TG
352 for (policy = config->name_policy; !new_name && *policy != _NAMEPOLICY_INVALID; policy++) {
353 switch (*policy) {
e51660ae
TG
354 case NAMEPOLICY_DATABASE:
355 new_name = udev_device_get_property_value(device, "ID_NET_NAME_FROM_DATABASE");
356 break;
5fde13d7
TG
357 case NAMEPOLICY_ONBOARD:
358 new_name = udev_device_get_property_value(device, "ID_NET_NAME_ONBOARD");
daeb71a3 359 break;
5fde13d7
TG
360 case NAMEPOLICY_SLOT:
361 new_name = udev_device_get_property_value(device, "ID_NET_NAME_SLOT");
daeb71a3 362 break;
5fde13d7
TG
363 case NAMEPOLICY_PATH:
364 new_name = udev_device_get_property_value(device, "ID_NET_NAME_PATH");
daeb71a3 365 break;
5fde13d7
TG
366 case NAMEPOLICY_MAC:
367 new_name = udev_device_get_property_value(device, "ID_NET_NAME_MAC");
daeb71a3 368 break;
5fde13d7
TG
369 default:
370 break;
371 }
daeb71a3
TG
372 }
373 }
374
3e137a1b
TG
375 if (new_name)
376 *name = new_name; /* a name was set by a policy */
377 else if (config->name)
378 *name = config->name; /* a name was set manually in the config */
379 else
380 *name = NULL;
daeb71a3 381
5fde13d7
TG
382 switch (config->mac_policy) {
383 case MACPOLICY_PERSISTENT:
92d927f8 384 if (mac_is_random(device)) {
5fde13d7 385 r = get_mac(device, false, &generated_mac);
a669ea98
TG
386 if (r == -ENOENT)
387 break;
388 else if (r < 0)
16b9b87a 389 return r;
5fde13d7 390 mac = &generated_mac;
16b9b87a 391 }
5fde13d7
TG
392 break;
393 case MACPOLICY_RANDOM:
16b9b87a 394 if (!mac_is_random(device)) {
5fde13d7 395 r = get_mac(device, true, &generated_mac);
a669ea98
TG
396 if (r == -ENOENT)
397 break;
398 else if (r < 0)
16b9b87a 399 return r;
5fde13d7 400 mac = &generated_mac;
16b9b87a 401 }
5fde13d7
TG
402 break;
403 default:
404 mac = config->mac;
16b9b87a
TG
405 }
406
d2df0d0e 407 r = rtnl_set_link_properties(ctx->rtnl, ifindex, config->alias, mac, config->mtu);
43b3a5ef 408 if (r < 0) {
d2df0d0e 409 log_warning("Could not set Alias, MACAddress or MTU on %s: %s", old_name, strerror(-r));
5fde13d7 410 return r;
43b3a5ef
TG
411 }
412
af6f0d42
TG
413 return 0;
414}
be32eb9b 415
847a8a5f
TG
416int link_get_driver(link_config_ctx *ctx, struct udev_device *device, char **ret) {
417 const char *name;
418 char *driver;
419 int r;
420
421 r = link_config_ctx_connect(ctx);
422 if (r < 0)
423 return r;
424
425 name = udev_device_get_sysname(device);
426 if (!name)
427 return -EINVAL;
428
429 r = ethtool_get_driver(ctx->ethtool_fd, name, &driver);
430 if (r < 0)
431 return r;
432
433 *ret = driver;
434 return 0;
435}
436
2c5859af 437static const char* const mac_policy_table[_MACPOLICY_MAX] = {
be32eb9b
TG
438 [MACPOLICY_PERSISTENT] = "persistent",
439 [MACPOLICY_RANDOM] = "random"
440};
441
442DEFINE_STRING_TABLE_LOOKUP(mac_policy, MACPolicy);
443DEFINE_CONFIG_PARSE_ENUM(config_parse_mac_policy, mac_policy, MACPolicy, "Failed to parse MAC address policy");
444
2c5859af 445static const char* const name_policy_table[_NAMEPOLICY_MAX] = {
e51660ae 446 [NAMEPOLICY_DATABASE] = "database",
be32eb9b
TG
447 [NAMEPOLICY_ONBOARD] = "onboard",
448 [NAMEPOLICY_SLOT] = "slot",
449 [NAMEPOLICY_PATH] = "path",
450 [NAMEPOLICY_MAC] = "mac"
451};
452
453DEFINE_STRING_TABLE_LOOKUP(name_policy, NamePolicy);
454DEFINE_CONFIG_PARSE_ENUMV(config_parse_name_policy, name_policy, NamePolicy, _NAMEPOLICY_INVALID, "Failed to parse interface name policy");