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