chiark / gitweb /
shared: add MIN3 macro
[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 "network-internal.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 == -1) {
94                 r = ethtool_connect(&ctx->ethtool_fd);
95                 if (r < 0) {
96                         log_warning("link_config: could not connect to ethtool: %s",
97                                     strerror(-r));
98                         return r;
99                 }
100         }
101
102         if (!ctx->rtnl) {
103                 r = sd_rtnl_open(&ctx->rtnl, 0);
104                 if (r < 0) {
105                         log_warning("link_config: could not connect to rtnl: %s",
106                                     strerror(-r));
107                         return r;
108                 }
109         }
110
111         return 0;
112 }
113
114 static 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);
126                 free(link->alias);
127                 free(link->name_policy);
128
129                 free(link);
130         }
131 }
132
133 void link_config_ctx_free(link_config_ctx *ctx) {
134         if (!ctx)
135                 return;
136
137         safe_close(ctx->ethtool_fd);
138
139         sd_rtnl_unref(ctx->rtnl);
140
141         link_configs_free(ctx);
142
143         free(ctx);
144
145         return;
146 }
147
148 static int load_link(link_config_ctx *ctx, const char *filename) {
149         _cleanup_free_ link_config *link = NULL;
150         _cleanup_fclose_ FILE *file = NULL;
151         int r;
152
153         assert(ctx);
154         assert(filename);
155
156         if (null_or_empty_path(filename)) {
157                 log_debug("skipping empty file: %s", filename);
158                 return 0;
159         }
160
161         file = fopen(filename, "re");
162         if (!file) {
163                 if (errno == ENOENT)
164                         return 0;
165                 else
166                         return -errno;
167         }
168
169         link = new0(link_config, 1);
170         if (!link)
171                 return log_oom();
172
173         link->mac_policy = _MACPOLICY_INVALID;
174         link->wol = _WOL_INVALID;
175         link->duplex = _DUP_INVALID;
176
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) {
180                 log_warning("Could not parse config file %s: %s", filename, strerror(-r));
181                 return r;
182         } else
183                 log_debug("Parsed configuration file %s", filename);
184
185         link->filename = strdup(filename);
186
187         LIST_PREPEND(links, ctx->links, link);
188         link = NULL;
189
190         return 0;
191 }
192
193 static bool enable_name_policy(void) {
194         _cleanup_free_ char *line = NULL;
195         char *w, *state;
196         int r;
197         size_t l;
198
199         r = proc_cmdline(&line);
200         if (r < 0)
201                 log_warning("Failed to read /proc/cmdline, ignoring: %s", strerror(-r));
202         if (r <= 0)
203                 return true;
204
205         FOREACH_WORD_QUOTED(w, l, line, state)
206                 if (strneq(w, "net.ifnames=0", l))
207                         return false;
208
209         return true;
210 }
211
212 int link_config_load(link_config_ctx *ctx) {
213         int r;
214         _cleanup_strv_free_ char **files;
215         char **f;
216
217         link_configs_free(ctx);
218
219         if (!enable_name_policy()) {
220                 ctx->enable_name_policy = false;
221                 log_info("Network interface NamePolicy= disabled on kernel commandline, ignoring.");
222         }
223
224         /* update timestamp */
225         paths_check_timestamp(link_dirs, &ctx->link_dirs_ts_usec, true);
226
227         r = conf_files_list_strv(&files, ".link", NULL, link_dirs);
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
242 bool link_config_should_reload(link_config_ctx *ctx) {
243         return paths_check_timestamp(link_dirs, &ctx->link_dirs_ts_usec, false);
244 }
245
246 int 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) {
250
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,
254                                      ether_aton(udev_device_get_sysattr_value(device, "address")),
255                                      udev_device_get_property_value(device, "ID_PATH"),
256                                      udev_device_get_driver(udev_device_get_parent(device)),
257                                      udev_device_get_property_value(device, "ID_NET_DRIVER"),
258                                      udev_device_get_devtype(device),
259                                      NULL)) {
260                         log_debug("Config file %s applies to device %s",
261                                   link->filename,
262                                   udev_device_get_sysname(device));
263                         *ret = link;
264                         return 0;
265                 }
266         }
267
268         *ret = NULL;
269
270         return -ENOENT;
271 }
272
273 static bool mac_is_random(struct udev_device *device) {
274         const char *s;
275         unsigned type;
276         int r;
277
278         s = udev_device_get_sysattr_value(device, "addr_assign_type");
279         if (!s)
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;
284
285         /* check for NET_ADDR_RANDOM */
286         return type == 1;
287 }
288
289 static int get_mac(struct udev_device *device, bool want_random, struct ether_addr *mac) {
290         int r;
291
292         if (want_random)
293                 random_bytes(mac->ether_addr_octet, ETH_ALEN);
294         else {
295                 uint8_t result[8];
296
297                 r = net_get_unique_predictable_data(device, result);
298                 if (r < 0)
299                         return r;
300
301                 assert_cc(ETH_ALEN <= sizeof(result));
302                 memcpy(mac->ether_addr_octet, result, ETH_ALEN);
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
309         return 0;
310 }
311
312 int link_config_apply(link_config_ctx *ctx, link_config *config, struct udev_device *device, const char **name) {
313         const char *old_name;
314         const char *new_name = NULL;
315         struct ether_addr generated_mac;
316         struct ether_addr *mac = NULL;
317         int r, ifindex;
318
319         assert(ctx);
320         assert(config);
321         assert(device);
322         assert(name);
323
324         r = link_config_ctx_connect(ctx);
325         if (r < 0)
326                 return r;
327
328         old_name = udev_device_get_sysname(device);
329         if (!old_name)
330                 return -EINVAL;
331
332         r = ethtool_set_speed(ctx->ethtool_fd, old_name, config->speed / 1024, config->duplex);
333         if (r < 0)
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));
337
338         r = ethtool_set_wol(ctx->ethtool_fd, old_name, config->wol);
339         if (r < 0)
340                 log_warning("Could not set WakeOnLan of %s to %s: %s",
341                             old_name, wol_to_string(config->wol), strerror(-r));
342
343         ifindex = udev_device_get_ifindex(device);
344         if (ifindex <= 0) {
345                 log_warning("Could not find ifindex");
346                 return -ENODEV;
347         }
348
349         if (ctx->enable_name_policy && config->name_policy) {
350                 NamePolicy *policy;
351
352                 for (policy = config->name_policy; !new_name && *policy != _NAMEPOLICY_INVALID; policy++) {
353                         switch (*policy) {
354                                 case NAMEPOLICY_DATABASE:
355                                         new_name = udev_device_get_property_value(device, "ID_NET_NAME_FROM_DATABASE");
356                                         break;
357                                 case NAMEPOLICY_ONBOARD:
358                                         new_name = udev_device_get_property_value(device, "ID_NET_NAME_ONBOARD");
359                                         break;
360                                 case NAMEPOLICY_SLOT:
361                                         new_name = udev_device_get_property_value(device, "ID_NET_NAME_SLOT");
362                                         break;
363                                 case NAMEPOLICY_PATH:
364                                         new_name = udev_device_get_property_value(device, "ID_NET_NAME_PATH");
365                                         break;
366                                 case NAMEPOLICY_MAC:
367                                         new_name = udev_device_get_property_value(device, "ID_NET_NAME_MAC");
368                                         break;
369                                 default:
370                                         break;
371                         }
372                 }
373         }
374
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;
381
382         switch (config->mac_policy) {
383                 case MACPOLICY_PERSISTENT:
384                         if (mac_is_random(device)) {
385                                 r = get_mac(device, false, &generated_mac);
386                                 if (r == -ENOENT)
387                                         break;
388                                 else if (r < 0)
389                                         return r;
390                                 mac = &generated_mac;
391                         }
392                         break;
393                 case MACPOLICY_RANDOM:
394                         if (!mac_is_random(device)) {
395                                 r = get_mac(device, true, &generated_mac);
396                                 if (r == -ENOENT)
397                                         break;
398                                 else if (r < 0)
399                                         return r;
400                                 mac = &generated_mac;
401                         }
402                         break;
403                 default:
404                         mac = config->mac;
405         }
406
407         r = rtnl_set_link_properties(ctx->rtnl, ifindex, config->alias, mac, config->mtu);
408         if (r < 0) {
409                 log_warning("Could not set Alias, MACAddress or MTU on %s: %s", old_name, strerror(-r));
410                 return r;
411         }
412
413         return 0;
414 }
415
416 int 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
437 static const char* const mac_policy_table[_MACPOLICY_MAX] = {
438         [MACPOLICY_PERSISTENT] = "persistent",
439         [MACPOLICY_RANDOM] = "random"
440 };
441
442 DEFINE_STRING_TABLE_LOOKUP(mac_policy, MACPolicy);
443 DEFINE_CONFIG_PARSE_ENUM(config_parse_mac_policy, mac_policy, MACPolicy, "Failed to parse MAC address policy");
444
445 static const char* const name_policy_table[_NAMEPOLICY_MAX] = {
446         [NAMEPOLICY_DATABASE] = "database",
447         [NAMEPOLICY_ONBOARD] = "onboard",
448         [NAMEPOLICY_SLOT] = "slot",
449         [NAMEPOLICY_PATH] = "path",
450         [NAMEPOLICY_MAC] = "mac"
451 };
452
453 DEFINE_STRING_TABLE_LOOKUP(name_policy, NamePolicy);
454 DEFINE_CONFIG_PARSE_ENUMV(config_parse_name_policy, name_policy, NamePolicy, _NAMEPOLICY_INVALID, "Failed to parse interface name policy");