chiark / gitweb /
5156ba6f8ad781c9fde6fae47a4ecad1d297c57b
[elogind.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
43 struct link_config_ctx {
44         LIST_HEAD(link_config, links);
45
46         int ethtool_fd;
47
48         bool enable_name_policy;
49
50         sd_rtnl *rtnl;
51
52         char **link_dirs;
53         usec_t link_dirs_ts_usec;
54 };
55
56 DEFINE_TRIVIAL_CLEANUP_FUNC(link_config_ctx*, link_config_ctx_free);
57 #define _cleanup_link_config_ctx_free_ _cleanup_(link_config_ctx_freep)
58
59 int link_config_ctx_new(link_config_ctx **ret) {
60         _cleanup_link_config_ctx_free_ link_config_ctx *ctx = NULL;
61
62         if (!ret)
63                 return -EINVAL;
64
65         ctx = new0(link_config_ctx, 1);
66         if (!ctx)
67                 return -ENOMEM;
68
69         LIST_HEAD_INIT(ctx->links);
70
71         ctx->ethtool_fd = -1;
72
73         ctx->enable_name_policy = true;
74
75         ctx->link_dirs = strv_new("/etc/systemd/network",
76                                   "/run/systemd/network",
77                                   "/usr/lib/systemd/network",
78 #ifdef HAVE_SPLIT_USR
79                                   "/lib/systemd/network",
80 #endif
81                                   NULL);
82         if (!ctx->link_dirs) {
83                 log_error("failed to build link config directory array");
84                 return -ENOMEM;
85         }
86
87         if (!path_strv_canonicalize_uniq(ctx->link_dirs)) {
88                 log_error("failed to canonicalize link config directories\n");
89                 return -ENOMEM;
90         }
91
92         *ret = ctx;
93         ctx = NULL;
94
95         return 0;
96 }
97
98 static int link_config_ctx_connect(link_config_ctx *ctx) {
99         int r;
100
101         if (ctx->ethtool_fd >= 0 && ctx->rtnl)
102                 return 0;
103
104         r = ethtool_connect(&ctx->ethtool_fd);
105         if (r < 0)
106                 return r;
107
108         r = sd_rtnl_open(0, &ctx->rtnl);
109         if (r < 0)
110                 return r;
111
112         return 0;
113 }
114
115 static void link_configs_free(link_config_ctx *ctx) {
116         link_config *link, *link_next;
117
118         if (!ctx)
119                 return;
120
121         LIST_FOREACH_SAFE(links, link, link_next, ctx->links) {
122                 free(link->filename);
123                 free(link->match_path);
124                 free(link->match_driver);
125                 free(link->match_type);
126                 free(link->description);
127
128                 free(link);
129         }
130 }
131
132 void link_config_ctx_free(link_config_ctx *ctx) {
133         if (!ctx)
134                 return;
135
136         if (ctx->ethtool_fd >= 0)
137                 close_nointr_nofail(ctx->ethtool_fd);
138
139         sd_rtnl_unref(ctx->rtnl);
140
141         strv_free(ctx->link_dirs);
142         link_configs_free(ctx);
143
144         free(ctx);
145
146         return;
147 }
148
149 static int load_link(link_config_ctx *ctx, const char *filename) {
150         link_config *link;
151         FILE *file;
152         int r;
153
154         file = fopen(filename, "re");
155         if (!file) {
156                 if (errno == ENOENT)
157                         return 0;
158                 else
159                         return errno;
160         }
161
162         link = new0(link_config, 1);
163         if (!link) {
164                 r = log_oom();
165                 goto failure;
166         }
167
168         link->mac_policy = _MACPOLICY_INVALID;
169         link->wol = _WOL_INVALID;
170         link->duplex = _DUP_INVALID;
171
172         r = config_parse(NULL, filename, file, "Match\0Link\0Ethernet\0", config_item_perf_lookup,
173                          (void*) link_config_gperf_lookup, false, false, link);
174         if (r < 0) {
175                 log_warning("Could not parse config file %s: %s", filename, strerror(-r));
176                 goto failure;
177         } else
178                 log_debug("Parsed configuration file %s", filename);
179
180         link->filename = strdup(filename);
181
182         LIST_PREPEND(links, ctx->links, link);
183
184         return 0;
185
186 failure:
187         free(link);
188         return r;
189 }
190
191 static bool enable_name_policy(void) {
192         _cleanup_free_ char *line;
193         char *w, *state;
194         int r;
195         size_t l;
196
197         r = proc_cmdline(&line);
198         if (r < 0)
199                 log_warning("Failed to read /proc/cmdline, ignoring: %s", strerror(-r));
200         if (r <= 0)
201                 return true;
202
203         FOREACH_WORD_QUOTED(w, l, line, state)
204                 if (l == sizeof("net.ifnames=0") - 1 && strneq(w, "net.ifnames=0", l))
205                         return false;
206
207         return true;
208 }
209
210 int link_config_load(link_config_ctx *ctx) {
211         int r;
212         char **files, **f;
213
214         link_configs_free(ctx);
215
216         if (!enable_name_policy()) {
217                 ctx->enable_name_policy = false;
218                 log_info("Network interface NamePolicy= disabled on kernel commandline, ignoring.");
219         }
220
221         /* update timestamp */
222         paths_check_timestamp(ctx->link_dirs, &ctx->link_dirs_ts_usec, true);
223
224         r = conf_files_list_strv(&files, ".link", NULL, (const char **)ctx->link_dirs);
225         if (r < 0) {
226                 log_error("failed to enumerate link files: %s", strerror(-r));
227                 return r;
228         }
229
230         STRV_FOREACH_BACKWARDS(f, files) {
231                 r = load_link(ctx, *f);
232                 if (r < 0)
233                         return r;
234         }
235
236         return 0;
237 }
238
239 bool link_config_should_reload(link_config_ctx *ctx) {
240         return paths_check_timestamp(ctx->link_dirs, &ctx->link_dirs_ts_usec, false);
241 }
242
243 int link_config_get(link_config_ctx *ctx, struct udev_device *device, link_config **ret) {
244         link_config *link;
245
246         LIST_FOREACH(links, link, ctx->links) {
247
248                 if (net_match_config(link->match_mac, link->match_path,
249                                      link->match_driver, link->match_type, NULL,
250                                      udev_device_get_sysattr_value(device, "address"),
251                                      udev_device_get_property_value(device, "ID_PATH"),
252                                      udev_device_get_driver(device),
253                                      udev_device_get_devtype(device),
254                                      NULL)) {
255                         log_debug("Config file %s applies to device %s",
256                                   link->filename,
257                                   udev_device_get_sysname(device));
258                         *ret = link;
259                         return 0;
260                 }
261         }
262
263         *ret = NULL;
264
265         return -ENOENT;
266 }
267
268 static bool mac_is_random(struct udev_device *device) {
269         const char *s;
270         unsigned type;
271         int r;
272
273         s = udev_device_get_sysattr_value(device, "addr_assign_type");
274         if (!s)
275                 return false; /* if we don't know, assume it is not random */
276         r = safe_atou(s, &type);
277         if (r < 0)
278                 return false;
279
280         /* check for NET_ADDR_RANDOM */
281         return type == 1;
282 }
283
284 static bool mac_is_permanent(struct udev_device *device) {
285         const char *s;
286         unsigned type;
287         int r;
288
289         s = udev_device_get_sysattr_value(device, "addr_assign_type");
290         if (!s)
291                 return true; /* if we don't know, assume it is permanent */
292         r = safe_atou(s, &type);
293         if (r < 0)
294                 return true;
295
296         /* check for NET_ADDR_PERM */
297         return type == 0;
298 }
299
300 static int get_mac(struct udev_device *device, bool want_random, struct ether_addr *mac) {
301         unsigned int seed;
302         int r, i;
303
304         if (want_random)
305                 seed = random_u();
306         else {
307                 const char *name;
308                 sd_id128_t machine;
309                 char machineid_buf[33];
310                 const char *seed_str;
311
312                 /* fetch some persistent data unique (on this machine) to this device */
313                 name = udev_device_get_property_value(device, "ID_NET_NAME_ONBOARD");
314                 if (!name) {
315                         name = udev_device_get_property_value(device, "ID_NET_NAME_SLOT");
316                         if (!name) {
317                                 name = udev_device_get_property_value(device, "ID_NET_NAME_PATH");
318                                 if (!name)
319                                         return -ENOENT;
320                         }
321                 }
322                 /* fetch some persistent data unique to this machine */
323                 r = sd_id128_get_machine(&machine);
324                 if (r < 0)
325                         return r;
326
327                 /* combine the data */
328                 seed_str = strappenda(name, sd_id128_to_string(machine, machineid_buf));
329
330                 /* hash to get seed */
331                 seed = string_hash_func(seed_str);
332         }
333
334         srandom(seed);
335
336         for(i = 0; i < ETH_ALEN; i++) {
337                 mac->ether_addr_octet[i] = random();
338         }
339
340         /* see eth_random_addr in the kernel */
341         mac->ether_addr_octet[0] &= 0xfe;        /* clear multicast bit */
342         mac->ether_addr_octet[0] |= 0x02;        /* set local assignment bit (IEEE802) */
343
344         return 0;
345 }
346
347 int link_config_apply(link_config_ctx *ctx, link_config *config, struct udev_device *device, const char **name) {
348         const char *old_name;
349         const char *new_name = NULL;
350         struct ether_addr generated_mac;
351         struct ether_addr *mac = NULL;
352         int r, ifindex;
353
354         assert(ctx);
355         assert(config);
356         assert(device);
357         assert(name);
358
359         r = link_config_ctx_connect(ctx);
360         if (r < 0)
361                 return r;
362
363         old_name = udev_device_get_sysname(device);
364         if (!old_name)
365                 return -EINVAL;
366
367         if (config->description) {
368                 r = udev_device_set_sysattr_value(device, "ifalias",
369                                                   config->description);
370                 if (r < 0)
371                         log_warning("Could not set description of %s to '%s': %s",
372                                     old_name, config->description, strerror(-r));
373         }
374
375         r = ethtool_set_speed(ctx->ethtool_fd, old_name, config->speed, config->duplex);
376         if (r < 0)
377                 log_warning("Could not set speed or duplex of %s to %u Mbytes (%s): %s",
378                              old_name, config->speed, duplex_to_string(config->duplex), strerror(-r));
379
380         r = ethtool_set_wol(ctx->ethtool_fd, old_name, config->wol);
381         if (r < 0)
382                 log_warning("Could not set WakeOnLan of %s to %s: %s",
383                             old_name, wol_to_string(config->wol), strerror(-r));
384
385         ifindex = udev_device_get_ifindex(device);
386         if (ifindex <= 0) {
387                 log_warning("Could not find ifindex");
388                 return -ENODEV;
389         }
390
391         if (ctx->enable_name_policy && config->name_policy) {
392                 NamePolicy *policy;
393
394                 for (policy = config->name_policy; !new_name && *policy != _NAMEPOLICY_INVALID; policy++) {
395                         switch (*policy) {
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 (new_name)
415                 *name = new_name; /* a name was set by a policy */
416         else if (config->name)
417                 *name = config->name; /* a name was set manually in the config */
418         else
419                 *name = NULL;
420
421         switch (config->mac_policy) {
422                 case MACPOLICY_PERSISTENT:
423                         if (!mac_is_permanent(device)) {
424                                 r = get_mac(device, false, &generated_mac);
425                                 if (r < 0)
426                                         return r;
427                                 mac = &generated_mac;
428                         }
429                         break;
430                 case MACPOLICY_RANDOM:
431                         if (!mac_is_random(device)) {
432                                 r = get_mac(device, true, &generated_mac);
433                                 if (r < 0)
434                                         return r;
435                                 mac = &generated_mac;
436                         }
437                         break;
438                 default:
439                         mac = config->mac;
440         }
441
442         r = rtnl_set_link_properties(ctx->rtnl, ifindex, mac, config->mtu);
443         if (r < 0) {
444                 log_warning("Could not set MACAddress or MTU on %s: %s", old_name, strerror(-r));
445                 return r;
446         }
447
448         return 0;
449 }
450
451 static const char* const mac_policy_table[] = {
452         [MACPOLICY_PERSISTENT] = "persistent",
453         [MACPOLICY_RANDOM] = "random"
454 };
455
456 DEFINE_STRING_TABLE_LOOKUP(mac_policy, MACPolicy);
457 DEFINE_CONFIG_PARSE_ENUM(config_parse_mac_policy, mac_policy, MACPolicy, "Failed to parse MAC address policy");
458
459 static const char* const name_policy_table[] = {
460         [NAMEPOLICY_ONBOARD] = "onboard",
461         [NAMEPOLICY_SLOT] = "slot",
462         [NAMEPOLICY_PATH] = "path",
463         [NAMEPOLICY_MAC] = "mac"
464 };
465
466 DEFINE_STRING_TABLE_LOOKUP(name_policy, NamePolicy);
467 DEFINE_CONFIG_PARSE_ENUMV(config_parse_name_policy, name_policy, NamePolicy, _NAMEPOLICY_INVALID, "Failed to parse interface name policy");