chiark / gitweb /
util: simplify proc_cmdline() to reuse get_process_cmdline()
[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
24 #include "sd-id128.h"
25
26 #include "missing.h"
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 void link_configs_free(link_config_ctx *ctx) {
91         link_config *link, *link_next;
92
93         if (!ctx)
94                 return;
95
96         LIST_FOREACH_SAFE(links, link, link_next, ctx->links) {
97                 free(link->filename);
98                 free(link->match_path);
99                 free(link->match_driver);
100                 free(link->match_type);
101                 free(link->description);
102                 free(link->alias);
103                 free(link->name_policy);
104
105                 free(link);
106         }
107 }
108
109 void link_config_ctx_free(link_config_ctx *ctx) {
110         if (!ctx)
111                 return;
112
113         safe_close(ctx->ethtool_fd);
114
115         sd_rtnl_unref(ctx->rtnl);
116
117         link_configs_free(ctx);
118
119         free(ctx);
120
121         return;
122 }
123
124 static int load_link(link_config_ctx *ctx, const char *filename) {
125         _cleanup_free_ link_config *link = NULL;
126         _cleanup_fclose_ FILE *file = NULL;
127         int r;
128
129         assert(ctx);
130         assert(filename);
131
132         file = fopen(filename, "re");
133         if (!file) {
134                 if (errno == ENOENT)
135                         return 0;
136                 else
137                         return -errno;
138         }
139
140         if (null_or_empty_fd(fileno(file))) {
141                 log_debug("Skipping empty file: %s", filename);
142                 return 0;
143         }
144
145         link = new0(link_config, 1);
146         if (!link)
147                 return log_oom();
148
149         link->mac_policy = _MACPOLICY_INVALID;
150         link->wol = _WOL_INVALID;
151         link->duplex = _DUP_INVALID;
152
153         r = config_parse(NULL, filename, file,
154                          "Match\0Link\0Ethernet\0",
155                          config_item_perf_lookup, link_config_gperf_lookup,
156                          false, false, true, link);
157         if (r < 0)
158                 return r;
159         else
160                 log_debug("Parsed configuration file %s", filename);
161
162         link->filename = strdup(filename);
163
164         LIST_PREPEND(links, ctx->links, link);
165         link = NULL;
166
167         return 0;
168 }
169
170 static bool enable_name_policy(void) {
171         _cleanup_free_ char *line = NULL;
172         const char *word, *state;
173         int r;
174         size_t l;
175
176         r = proc_cmdline(&line);
177         if (r < 0) {
178                 log_warning("Failed to read /proc/cmdline, ignoring: %s", strerror(-r));
179                 return true;
180         }
181
182         FOREACH_WORD_QUOTED(word, l, line, state)
183                 if (strneq(word, "net.ifnames=0", l))
184                         return false;
185
186         return true;
187 }
188
189 int link_config_load(link_config_ctx *ctx) {
190         int r;
191         _cleanup_strv_free_ char **files;
192         char **f;
193
194         link_configs_free(ctx);
195
196         if (!enable_name_policy()) {
197                 ctx->enable_name_policy = false;
198                 log_info("Network interface NamePolicy= disabled on kernel command line, ignoring.");
199         }
200
201         /* update timestamp */
202         paths_check_timestamp(link_dirs, &ctx->link_dirs_ts_usec, true);
203
204         r = conf_files_list_strv(&files, ".link", NULL, link_dirs);
205         if (r < 0) {
206                 log_error("failed to enumerate link files: %s", strerror(-r));
207                 return r;
208         }
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 = udev_device_get_sysattr_value(device, "address");
229
230                 if (net_match_config(link->match_mac, link->match_path, link->match_driver,
231                                      link->match_type, NULL, link->match_host,
232                                      link->match_virt, link->match_kernel, link->match_arch,
233                                      attr_value ? ether_aton(attr_value) : NULL,
234                                      udev_device_get_property_value(device, "ID_PATH"),
235                                      udev_device_get_driver(udev_device_get_parent(device)),
236                                      udev_device_get_property_value(device, "ID_NET_DRIVER"),
237                                      udev_device_get_devtype(device),
238                                      NULL)) {
239                         log_debug("Config file %s applies to device %s",
240                                   link->filename,
241                                   udev_device_get_sysname(device));
242                         *ret = link;
243                         return 0;
244                 }
245         }
246
247         *ret = NULL;
248
249         return -ENOENT;
250 }
251
252 static bool mac_is_random(struct udev_device *device) {
253         const char *s;
254         unsigned type;
255         int r;
256
257         /* if we can't get the assign type, assume it is not random */
258         s = udev_device_get_sysattr_value(device, "addr_assign_type");
259         if (!s)
260                 return false;
261
262         r = safe_atou(s, &type);
263         if (r < 0)
264                 return false;
265
266         return type == NET_ADDR_RANDOM;
267 }
268
269 static bool should_rename(struct udev_device *device, bool respect_predictable) {
270         const char *s;
271         unsigned type;
272         int r;
273
274         /* if we can't get the assgin type, assume we should rename */
275         s = udev_device_get_sysattr_value(device, "name_assign_type");
276         if (!s)
277                 return true;
278
279         r = safe_atou(s, &type);
280         if (r < 0)
281                 return true;
282
283         switch (type) {
284         case NET_NAME_USER:
285         case NET_NAME_RENAMED:
286                 /* these were already named by userspace, do not touch again */
287                 return false;
288         case NET_NAME_PREDICTABLE:
289                 /* the kernel claims to have given a predictable name */
290                 if (respect_predictable)
291                         return false;
292                 /* fall through */
293         case NET_NAME_ENUM:
294         default:
295                 /* the name is known to be bad, or of an unknown type */
296                 return true;
297         }
298 }
299
300 static int get_mac(struct udev_device *device, bool want_random,
301                    struct ether_addr *mac) {
302         int r;
303
304         if (want_random)
305                 random_bytes(mac->ether_addr_octet, ETH_ALEN);
306         else {
307                 uint8_t result[8];
308
309                 r = net_get_unique_predictable_data(device, result);
310                 if (r < 0)
311                         return r;
312
313                 assert_cc(ETH_ALEN <= sizeof(result));
314                 memcpy(mac->ether_addr_octet, result, ETH_ALEN);
315         }
316
317         /* see eth_random_addr in the kernel */
318         mac->ether_addr_octet[0] &= 0xfe;  /* clear multicast bit */
319         mac->ether_addr_octet[0] |= 0x02;  /* set local assignment bit (IEEE802) */
320
321         return 0;
322 }
323
324 int link_config_apply(link_config_ctx *ctx, link_config *config,
325                       struct udev_device *device, const char **name) {
326         const char *old_name;
327         const char *new_name = NULL;
328         struct ether_addr generated_mac;
329         struct ether_addr *mac = NULL;
330         bool respect_predictable = false;
331         int r, ifindex;
332
333         assert(ctx);
334         assert(config);
335         assert(device);
336         assert(name);
337
338         old_name = udev_device_get_sysname(device);
339         if (!old_name)
340                 return -EINVAL;
341
342         r = ethtool_set_speed(&ctx->ethtool_fd, old_name, config->speed / 1024,
343                               config->duplex);
344         if (r < 0)
345                 log_warning("Could not set speed or duplex of %s to %u Mbps (%s): %s",
346                             old_name, config->speed / 1024,
347                             duplex_to_string(config->duplex), strerror(-r));
348
349         r = ethtool_set_wol(&ctx->ethtool_fd, old_name, config->wol);
350         if (r < 0)
351                 log_warning("Could not set WakeOnLan of %s to %s: %s",
352                             old_name, wol_to_string(config->wol), strerror(-r));
353
354         ifindex = udev_device_get_ifindex(device);
355         if (ifindex <= 0) {
356                 log_warning("Could not find ifindex");
357                 return -ENODEV;
358         }
359
360         if (ctx->enable_name_policy && config->name_policy) {
361                 NamePolicy *policy;
362
363                 for (policy = config->name_policy;
364                      !new_name && *policy != _NAMEPOLICY_INVALID; policy++) {
365                         switch (*policy) {
366                                 case NAMEPOLICY_KERNEL:
367                                         respect_predictable = true;
368                                         break;
369                                 case NAMEPOLICY_DATABASE:
370                                         new_name = udev_device_get_property_value(device, "ID_NET_NAME_FROM_DATABASE");
371                                         break;
372                                 case NAMEPOLICY_ONBOARD:
373                                         new_name = udev_device_get_property_value(device, "ID_NET_NAME_ONBOARD");
374                                         break;
375                                 case NAMEPOLICY_SLOT:
376                                         new_name = udev_device_get_property_value(device, "ID_NET_NAME_SLOT");
377                                         break;
378                                 case NAMEPOLICY_PATH:
379                                         new_name = udev_device_get_property_value(device, "ID_NET_NAME_PATH");
380                                         break;
381                                 case NAMEPOLICY_MAC:
382                                         new_name = udev_device_get_property_value(device, "ID_NET_NAME_MAC");
383                                         break;
384                                 default:
385                                         break;
386                         }
387                 }
388         }
389
390         if (should_rename(device, respect_predictable)) {
391                 /* if not set by policy, fall back manually set name */
392                 if (!new_name)
393                         new_name = config->name;
394         } else
395                 new_name = NULL;
396
397         switch (config->mac_policy) {
398                 case MACPOLICY_PERSISTENT:
399                         if (mac_is_random(device)) {
400                                 r = get_mac(device, false, &generated_mac);
401                                 if (r == -ENOENT)
402                                         break;
403                                 else if (r < 0)
404                                         return r;
405                                 mac = &generated_mac;
406                         }
407                         break;
408                 case MACPOLICY_RANDOM:
409                         if (!mac_is_random(device)) {
410                                 r = get_mac(device, true, &generated_mac);
411                                 if (r == -ENOENT)
412                                         break;
413                                 else if (r < 0)
414                                         return r;
415                                 mac = &generated_mac;
416                         }
417                         break;
418                 default:
419                         mac = config->mac;
420         }
421
422         r = rtnl_set_link_properties(&ctx->rtnl, ifindex, config->alias, mac,
423                                      config->mtu);
424         if (r < 0) {
425                 log_warning("Could not set Alias, MACAddress or MTU on %s: %s",
426                             old_name, strerror(-r));
427                 return r;
428         }
429
430         *name = new_name;
431
432         return 0;
433 }
434
435 int link_get_driver(link_config_ctx *ctx, struct udev_device *device, char **ret) {
436         const char *name;
437         char *driver;
438         int r;
439
440         name = udev_device_get_sysname(device);
441         if (!name)
442                 return -EINVAL;
443
444         r = ethtool_get_driver(&ctx->ethtool_fd, name, &driver);
445         if (r < 0)
446                 return r;
447
448         *ret = driver;
449         return 0;
450 }
451
452 static const char* const mac_policy_table[_MACPOLICY_MAX] = {
453         [MACPOLICY_PERSISTENT] = "persistent",
454         [MACPOLICY_RANDOM] = "random"
455 };
456
457 DEFINE_STRING_TABLE_LOOKUP(mac_policy, MACPolicy);
458 DEFINE_CONFIG_PARSE_ENUM(config_parse_mac_policy, mac_policy, MACPolicy,
459                          "Failed to parse MAC address policy");
460
461 static const char* const name_policy_table[_NAMEPOLICY_MAX] = {
462         [NAMEPOLICY_KERNEL] = "kernel",
463         [NAMEPOLICY_DATABASE] = "database",
464         [NAMEPOLICY_ONBOARD] = "onboard",
465         [NAMEPOLICY_SLOT] = "slot",
466         [NAMEPOLICY_PATH] = "path",
467         [NAMEPOLICY_MAC] = "mac"
468 };
469
470 DEFINE_STRING_TABLE_LOOKUP(name_policy, NamePolicy);
471 DEFINE_CONFIG_PARSE_ENUMV(config_parse_name_policy, name_policy, NamePolicy,
472                           _NAMEPOLICY_INVALID,
473                           "Failed to parse interface name policy");