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