Coverage Report

Created: 2019-06-19 13:33

/src/systemd/src/udev/net/link-config.c
Line
Count
Source (jump to first uncovered line)
1
/* SPDX-License-Identifier: LGPL-2.1+ */
2
3
#include <linux/netdevice.h>
4
#include <netinet/ether.h>
5
6
#include "sd-device.h"
7
#include "sd-netlink.h"
8
9
#include "alloc-util.h"
10
#include "conf-files.h"
11
#include "conf-parser.h"
12
#include "def.h"
13
#include "device-util.h"
14
#include "ethtool-util.h"
15
#include "fd-util.h"
16
#include "link-config.h"
17
#include "log.h"
18
#include "memory-util.h"
19
#include "naming-scheme.h"
20
#include "netlink-util.h"
21
#include "network-internal.h"
22
#include "parse-util.h"
23
#include "path-util.h"
24
#include "proc-cmdline.h"
25
#include "random-util.h"
26
#include "stat-util.h"
27
#include "string-table.h"
28
#include "string-util.h"
29
#include "strv.h"
30
31
struct link_config_ctx {
32
        LIST_HEAD(link_config, links);
33
34
        int ethtool_fd;
35
36
        bool enable_name_policy;
37
38
        sd_netlink *rtnl;
39
40
        usec_t network_dirs_ts_usec;
41
};
42
43
4.45k
static void link_config_free(link_config *link) {
44
4.45k
        if (!link)
45
0
                return;
46
4.45k
47
4.45k
        free(link->filename);
48
4.45k
49
4.45k
        set_free_free(link->match_mac);
50
4.45k
        strv_free(link->match_path);
51
4.45k
        strv_free(link->match_driver);
52
4.45k
        strv_free(link->match_type);
53
4.45k
        strv_free(link->match_name);
54
4.45k
        condition_free_list(link->conditions);
55
4.45k
56
4.45k
        free(link->description);
57
4.45k
        free(link->mac);
58
4.45k
        free(link->name_policy);
59
4.45k
        free(link->name);
60
4.45k
        free(link->alias);
61
4.45k
62
4.45k
        free(link);
63
4.45k
}
64
65
DEFINE_TRIVIAL_CLEANUP_FUNC(link_config*, link_config_free);
66
67
4.45k
static void link_configs_free(link_config_ctx *ctx) {
68
4.45k
        link_config *link, *link_next;
69
4.45k
70
4.45k
        if (!ctx)
71
0
                return;
72
4.45k
73
4.45k
        LIST_FOREACH_SAFE(links, link, link_next, ctx->links)
74
4.45k
                link_config_free(link);
75
4.45k
}
76
77
4.45k
void link_config_ctx_free(link_config_ctx *ctx) {
78
4.45k
        if (!ctx)
79
0
                return;
80
4.45k
81
4.45k
        safe_close(ctx->ethtool_fd);
82
4.45k
83
4.45k
        sd_netlink_unref(ctx->rtnl);
84
4.45k
85
4.45k
        link_configs_free(ctx);
86
4.45k
87
4.45k
        free(ctx);
88
4.45k
89
4.45k
        return;
90
4.45k
}
91
92
4.45k
int link_config_ctx_new(link_config_ctx **ret) {
93
4.45k
        _cleanup_(link_config_ctx_freep) link_config_ctx *ctx = NULL;
94
4.45k
95
4.45k
        if (!ret)
96
0
                return -EINVAL;
97
4.45k
98
4.45k
        ctx = new0(link_config_ctx, 1);
99
4.45k
        if (!ctx)
100
0
                return -ENOMEM;
101
4.45k
102
4.45k
        LIST_HEAD_INIT(ctx->links);
103
4.45k
104
4.45k
        ctx->ethtool_fd = -1;
105
4.45k
106
4.45k
        ctx->enable_name_policy = true;
107
4.45k
108
4.45k
        *ret = TAKE_PTR(ctx);
109
4.45k
110
4.45k
        return 0;
111
4.45k
}
112
113
4.45k
int link_load_one(link_config_ctx *ctx, const char *filename) {
114
4.45k
        _cleanup_(link_config_freep) link_config *link = NULL;
115
4.45k
        _cleanup_fclose_ FILE *file = NULL;
116
4.45k
        _cleanup_free_ char *name = NULL;
117
4.45k
        size_t i;
118
4.45k
        int r;
119
4.45k
120
4.45k
        assert(ctx);
121
4.45k
        assert(filename);
122
4.45k
123
4.45k
        file = fopen(filename, "re");
124
4.45k
        if (!file)
125
0
                return errno == ENOENT ? 0 : -errno;
126
4.45k
127
4.45k
        if (null_or_empty_fd(fileno(file))) {
128
0
                log_debug("Skipping empty file: %s", filename);
129
0
                return 0;
130
0
        }
131
4.45k
132
4.45k
        name = strdup(filename);
133
4.45k
        if (!name)
134
0
                return -ENOMEM;
135
4.45k
136
4.45k
        link = new(link_config, 1);
137
4.45k
        if (!link)
138
0
                return -ENOMEM;
139
4.45k
140
4.45k
        *link = (link_config) {
141
4.45k
                .filename = TAKE_PTR(name),
142
4.45k
                .mac_address_policy = _MAC_ADDRESS_POLICY_INVALID,
143
4.45k
                .wol = _WOL_INVALID,
144
4.45k
                .duplex = _DUP_INVALID,
145
4.45k
                .port = _NET_DEV_PORT_INVALID,
146
4.45k
                .autonegotiation = -1,
147
4.45k
        };
148
4.45k
149
26.7k
        for (i = 0; i < ELEMENTSOF(link->features); i++)
150
22.2k
                link->features[i] = -1;
151
4.45k
152
4.45k
        r = config_parse(NULL, filename, file,
153
4.45k
                         "Match\0Link\0",
154
4.45k
                         config_item_perf_lookup, link_config_gperf_lookup,
155
4.45k
                         CONFIG_PARSE_WARN, link);
156
4.45k
        if (r < 0)
157
415
                return r;
158
4.04k
159
4.04k
        if (link->speed > UINT_MAX)
160
4.04k
                return -ERANGE;
161
3.98k
162
3.98k
        if (set_isempty(link->match_mac) && strv_isempty(link->match_path) &&
163
3.98k
            strv_isempty(link->match_driver) && strv_isempty(link->match_type) &&
164
3.98k
            strv_isempty(link->match_name) && !link->conditions)
165
3.98k
                log_warning("%s: No valid settings found in the [Match] section. "
166
3.98k
                            "The file will match all interfaces. "
167
3.98k
                            "If that is intended, please add OriginalName=* in the [Match] section.",
168
3.98k
                            filename);
169
3.98k
170
3.98k
        if (!condition_test_list(link->conditions, NULL, NULL, NULL)) {
171
849
                log_debug("%s: Conditions do not match the system environment, skipping.", filename);
172
849
                return 0;
173
849
        }
174
3.13k
175
3.13k
        log_debug("Parsed configuration file %s", filename);
176
3.13k
177
3.13k
        LIST_PREPEND(links, ctx->links, TAKE_PTR(link));
178
3.13k
        return 0;
179
3.13k
}
180
181
0
static bool enable_name_policy(void) {
182
0
        bool b;
183
0
184
0
        return proc_cmdline_get_bool("net.ifnames", &b) <= 0 || b;
185
0
}
186
187
0
static int link_unsigned_attribute(sd_device *device, const char *attr, unsigned *type) {
188
0
        const char *s;
189
0
        int r;
190
0
191
0
        r = sd_device_get_sysattr_value(device, attr, &s);
192
0
        if (r < 0)
193
0
                return log_device_debug_errno(device, r, "Failed to query %s: %m", attr);
194
0
195
0
        r = safe_atou(s, type);
196
0
        if (r < 0)
197
0
                return log_device_warning_errno(device, r, "Failed to parse %s \"%s\": %m", attr, s);
198
0
199
0
        log_device_debug(device, "Device has %s=%u", attr, *type);
200
0
        return 0;
201
0
}
202
203
0
int link_config_load(link_config_ctx *ctx) {
204
0
        _cleanup_strv_free_ char **files;
205
0
        char **f;
206
0
        int r;
207
0
208
0
        link_configs_free(ctx);
209
0
210
0
        if (!enable_name_policy()) {
211
0
                ctx->enable_name_policy = false;
212
0
                log_info("Network interface NamePolicy= disabled on kernel command line, ignoring.");
213
0
        }
214
0
215
0
        /* update timestamp */
216
0
        paths_check_timestamp(NETWORK_DIRS, &ctx->network_dirs_ts_usec, true);
217
0
218
0
        r = conf_files_list_strv(&files, ".link", NULL, 0, NETWORK_DIRS);
219
0
        if (r < 0)
220
0
                return log_error_errno(r, "failed to enumerate link files: %m");
221
0
222
0
        STRV_FOREACH_BACKWARDS(f, files) {
223
0
                r = link_load_one(ctx, *f);
224
0
                if (r < 0)
225
0
                        log_error_errno(r, "Failed to load %s, ignoring: %m", *f);
226
0
        }
227
0
228
0
        return 0;
229
0
}
230
231
0
bool link_config_should_reload(link_config_ctx *ctx) {
232
0
        return paths_check_timestamp(NETWORK_DIRS, &ctx->network_dirs_ts_usec, false);
233
0
}
234
235
0
int link_config_get(link_config_ctx *ctx, sd_device *device, link_config **ret) {
236
0
        link_config *link;
237
0
238
0
        assert(ctx);
239
0
        assert(device);
240
0
        assert(ret);
241
0
242
0
        LIST_FOREACH(links, link, ctx->links) {
243
0
                const char *address = NULL, *id_path = NULL, *id_net_driver = NULL, *devtype = NULL, *sysname = NULL;
244
0
245
0
                (void) sd_device_get_sysattr_value(device, "address", &address);
246
0
                (void) sd_device_get_property_value(device, "ID_PATH", &id_path);
247
0
                (void) sd_device_get_property_value(device, "ID_NET_DRIVER", &id_net_driver);
248
0
                (void) sd_device_get_devtype(device, &devtype);
249
0
                (void) sd_device_get_sysname(device, &sysname);
250
0
251
0
                if (net_match_config(link->match_mac, link->match_path, link->match_driver,
252
0
                                     link->match_type, link->match_name,
253
0
                                     address ? ether_aton(address) : NULL,
254
0
                                     id_path,
255
0
                                     id_net_driver,
256
0
                                     devtype,
257
0
                                     sysname)) {
258
0
                        if (link->match_name) {
259
0
                                unsigned name_assign_type = NET_NAME_UNKNOWN;
260
0
261
0
                                (void) link_unsigned_attribute(device, "name_assign_type", &name_assign_type);
262
0
263
0
                                if (name_assign_type == NET_NAME_ENUM && !strv_contains(link->match_name, "*")) {
264
0
                                        log_warning("Config file %s applies to device based on potentially unpredictable interface name '%s'",
265
0
                                                    link->filename, sysname);
266
0
                                        *ret = link;
267
0
268
0
                                        return 0;
269
0
                                } else if (name_assign_type == NET_NAME_RENAMED) {
270
0
                                        log_warning("Config file %s matches device based on renamed interface name '%s', ignoring",
271
0
                                                    link->filename, sysname);
272
0
273
0
                                        continue;
274
0
                                }
275
0
                        }
276
0
277
0
                        log_debug("Config file %s applies to device %s",
278
0
                                  link->filename, sysname);
279
0
280
0
                        *ret = link;
281
0
                        return 0;
282
0
                }
283
0
        }
284
0
285
0
        *ret = NULL;
286
0
        return -ENOENT;
287
0
}
288
289
0
static int get_mac(sd_device *device, MACAddressPolicy policy, struct ether_addr *mac) {
290
0
        unsigned addr_type;
291
0
        bool want_random = policy == MAC_ADDRESS_POLICY_RANDOM;
292
0
        int r;
293
0
294
0
        assert(IN_SET(policy, MAC_ADDRESS_POLICY_RANDOM, MAC_ADDRESS_POLICY_PERSISTENT));
295
0
296
0
        r = link_unsigned_attribute(device, "addr_assign_type", &addr_type);
297
0
        if (r < 0)
298
0
                return r;
299
0
        switch (addr_type) {
300
0
        case NET_ADDR_SET:
301
0
                return log_device_debug(device, "MAC on the device already set by userspace");
302
0
        case NET_ADDR_STOLEN:
303
0
                return log_device_debug(device, "MAC on the device already set based on another device");
304
0
        case NET_ADDR_RANDOM:
305
0
        case NET_ADDR_PERM:
306
0
                break;
307
0
        default:
308
0
                return log_device_warning(device, "Unknown addr_assign_type %u, ignoring", addr_type);
309
0
        }
310
0
311
0
        if (want_random == (addr_type == NET_ADDR_RANDOM))
312
0
                return log_device_debug(device, "MAC on the device already matches policy *%s*",
313
0
                                        mac_address_policy_to_string(policy));
314
0
315
0
        if (want_random) {
316
0
                log_device_debug(device, "Using random bytes to generate MAC");
317
0
                random_bytes(mac->ether_addr_octet, ETH_ALEN);
318
0
        } else {
319
0
                uint64_t result;
320
0
321
0
                r = net_get_unique_predictable_data(device,
322
0
                                                    naming_scheme_has(NAMING_STABLE_VIRTUAL_MACS),
323
0
                                                    &result);
324
0
                if (r < 0)
325
0
                        return log_device_warning_errno(device, r, "Could not generate persistent MAC: %m");
326
0
327
0
                log_device_debug(device, "Using generated persistent MAC address");
328
0
                assert_cc(ETH_ALEN <= sizeof(result));
329
0
                memcpy(mac->ether_addr_octet, &result, ETH_ALEN);
330
0
        }
331
0
332
0
        /* see eth_random_addr in the kernel */
333
0
        mac->ether_addr_octet[0] &= 0xfe;  /* clear multicast bit */
334
0
        mac->ether_addr_octet[0] |= 0x02;  /* set local assignment bit (IEEE802) */
335
0
        return 1;
336
0
}
337
338
int link_config_apply(link_config_ctx *ctx, link_config *config,
339
0
                      sd_device *device, const char **name) {
340
0
        struct ether_addr generated_mac;
341
0
        struct ether_addr *mac = NULL;
342
0
        const char *new_name = NULL;
343
0
        const char *old_name;
344
0
        unsigned speed, name_type = NET_NAME_UNKNOWN;
345
0
        NamePolicy policy;
346
0
        int r, ifindex;
347
0
348
0
        assert(ctx);
349
0
        assert(config);
350
0
        assert(device);
351
0
        assert(name);
352
0
353
0
        r = sd_device_get_sysname(device, &old_name);
354
0
        if (r < 0)
355
0
                return r;
356
0
357
0
        r = ethtool_set_glinksettings(&ctx->ethtool_fd, old_name, config);
358
0
        if (r < 0) {
359
0
360
0
                if (config->port != _NET_DEV_PORT_INVALID)
361
0
                        log_warning_errno(r, "Could not set port (%s) of %s: %m", port_to_string(config->port), old_name);
362
0
363
0
                if (!eqzero(config->advertise))
364
0
                        log_warning_errno(r, "Could not set advertise mode: %m"); /* TODO: include modes in the log message. */
365
0
366
0
                if (config->speed) {
367
0
                        speed = DIV_ROUND_UP(config->speed, 1000000);
368
0
                        if (r == -EOPNOTSUPP) {
369
0
                                r = ethtool_set_speed(&ctx->ethtool_fd, old_name, speed, config->duplex);
370
0
                                if (r < 0)
371
0
                                        log_warning_errno(r, "Could not set speed of %s to %u Mbps: %m", old_name, speed);
372
0
                        }
373
0
                }
374
0
375
0
                if (config->duplex !=_DUP_INVALID)
376
0
                        log_warning_errno(r, "Could not set duplex of %s to (%s): %m", old_name, duplex_to_string(config->duplex));
377
0
        }
378
0
379
0
        r = ethtool_set_wol(&ctx->ethtool_fd, old_name, config->wol);
380
0
        if (r < 0)
381
0
                log_warning_errno(r, "Could not set WakeOnLan of %s to %s: %m",
382
0
                                  old_name, wol_to_string(config->wol));
383
0
384
0
        r = ethtool_set_features(&ctx->ethtool_fd, old_name, config->features);
385
0
        if (r < 0)
386
0
                log_warning_errno(r, "Could not set offload features of %s: %m", old_name);
387
0
388
0
        if (config->channels.rx_count_set || config->channels.tx_count_set || config->channels.other_count_set || config->channels.combined_count_set) {
389
0
                r = ethtool_set_channels(&ctx->ethtool_fd, old_name, &config->channels);
390
0
                if (r < 0)
391
0
                        log_warning_errno(r, "Could not set channels of %s: %m", old_name);
392
0
        }
393
0
394
0
        r = sd_device_get_ifindex(device, &ifindex);
395
0
        if (r < 0)
396
0
                return log_device_warning_errno(device, r, "Could not find ifindex: %m");
397
0
398
0
399
0
        (void) link_unsigned_attribute(device, "name_assign_type", &name_type);
400
0
401
0
        if (IN_SET(name_type, NET_NAME_USER, NET_NAME_RENAMED)
402
0
            && !naming_scheme_has(NAMING_ALLOW_RERENAMES)) {
403
0
                log_device_debug(device, "Device already has a name given by userspace, not renaming.");
404
0
                goto no_rename;
405
0
        }
406
0
407
0
        if (ctx->enable_name_policy && config->name_policy)
408
0
                for (NamePolicy *p = config->name_policy; !new_name && *p != _NAMEPOLICY_INVALID; p++) {
409
0
                        policy = *p;
410
0
411
0
                        switch (policy) {
412
0
                        case NAMEPOLICY_KERNEL:
413
0
                                if (name_type != NET_NAME_PREDICTABLE)
414
0
                                        continue;
415
0
416
0
                                /* The kernel claims to have given a predictable name, keep it. */
417
0
                                log_device_debug(device, "Policy *%s*: keeping predictable kernel name",
418
0
                                                 name_policy_to_string(policy));
419
0
                                goto no_rename;
420
0
                        case NAMEPOLICY_KEEP:
421
0
                                if (!IN_SET(name_type, NET_NAME_USER, NET_NAME_RENAMED))
422
0
                                        continue;
423
0
424
0
                                log_device_debug(device, "Policy *%s*: keeping existing userspace name",
425
0
                                                 name_policy_to_string(policy));
426
0
                                goto no_rename;
427
0
                        case NAMEPOLICY_DATABASE:
428
0
                                (void) sd_device_get_property_value(device, "ID_NET_NAME_FROM_DATABASE", &new_name);
429
0
                                break;
430
0
                        case NAMEPOLICY_ONBOARD:
431
0
                                (void) sd_device_get_property_value(device, "ID_NET_NAME_ONBOARD", &new_name);
432
0
                                break;
433
0
                        case NAMEPOLICY_SLOT:
434
0
                                (void) sd_device_get_property_value(device, "ID_NET_NAME_SLOT", &new_name);
435
0
                                break;
436
0
                        case NAMEPOLICY_PATH:
437
0
                                (void) sd_device_get_property_value(device, "ID_NET_NAME_PATH", &new_name);
438
0
                                break;
439
0
                        case NAMEPOLICY_MAC:
440
0
                                (void) sd_device_get_property_value(device, "ID_NET_NAME_MAC", &new_name);
441
0
                                break;
442
0
                        default:
443
0
                                assert_not_reached("invalid policy");
444
0
                        }
445
0
                }
446
0
447
0
        if (new_name)
448
0
                log_device_debug(device, "Policy *%s* yields \"%s\".", name_policy_to_string(policy), new_name);
449
0
        else if (config->name) {
450
0
                new_name = config->name;
451
0
                log_device_debug(device, "Policies didn't yield a name, using specified Name=%s.", new_name);
452
0
        } else
453
0
                log_device_debug(device, "Policies didn't yield a name and Name= is not given, not renaming.");
454
0
 no_rename:
455
0
456
0
        if (IN_SET(config->mac_address_policy, MAC_ADDRESS_POLICY_PERSISTENT, MAC_ADDRESS_POLICY_RANDOM)) {
457
0
                if (get_mac(device, config->mac_address_policy, &generated_mac) > 0)
458
0
                        mac = &generated_mac;
459
0
        } else
460
0
                mac = config->mac;
461
0
462
0
        r = rtnl_set_link_properties(&ctx->rtnl, ifindex, config->alias, mac, config->mtu);
463
0
        if (r < 0)
464
0
                return log_warning_errno(r, "Could not set Alias=, MACAddress= or MTU= on %s: %m", old_name);
465
0
466
0
        *name = new_name;
467
0
468
0
        return 0;
469
0
}
470
471
0
int link_get_driver(link_config_ctx *ctx, sd_device *device, char **ret) {
472
0
        const char *name;
473
0
        char *driver = NULL;
474
0
        int r;
475
0
476
0
        r = sd_device_get_sysname(device, &name);
477
0
        if (r < 0)
478
0
                return r;
479
0
480
0
        r = ethtool_get_driver(&ctx->ethtool_fd, name, &driver);
481
0
        if (r < 0)
482
0
                return r;
483
0
484
0
        *ret = driver;
485
0
        return 0;
486
0
}
487
488
static const char* const mac_address_policy_table[_MAC_ADDRESS_POLICY_MAX] = {
489
        [MAC_ADDRESS_POLICY_PERSISTENT] = "persistent",
490
        [MAC_ADDRESS_POLICY_RANDOM] = "random",
491
        [MAC_ADDRESS_POLICY_NONE] = "none",
492
};
493
494
DEFINE_STRING_TABLE_LOOKUP(mac_address_policy, MACAddressPolicy);
495
DEFINE_CONFIG_PARSE_ENUM(config_parse_mac_address_policy, mac_address_policy, MACAddressPolicy,
496
                         "Failed to parse MAC address policy");
497
498
static const char* const name_policy_table[_NAMEPOLICY_MAX] = {
499
        [NAMEPOLICY_KERNEL] = "kernel",
500
        [NAMEPOLICY_KEEP] = "keep",
501
        [NAMEPOLICY_DATABASE] = "database",
502
        [NAMEPOLICY_ONBOARD] = "onboard",
503
        [NAMEPOLICY_SLOT] = "slot",
504
        [NAMEPOLICY_PATH] = "path",
505
        [NAMEPOLICY_MAC] = "mac",
506
};
507
508
DEFINE_STRING_TABLE_LOOKUP(name_policy, NamePolicy);
509
DEFINE_CONFIG_PARSE_ENUMV(config_parse_name_policy, name_policy, NamePolicy,
510
                          _NAMEPOLICY_INVALID,
511
                          "Failed to parse interface name policy");