]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/network/networkd-netdev.c
Let config_parse open file where applicable
[thirdparty/systemd.git] / src / network / networkd-netdev.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4 This file is part of systemd.
5
6 Copyright 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 <net/if.h>
23
24 #include "networkd-netdev.h"
25 #include "networkd-netdev-bridge.h"
26 #include "networkd-netdev-bond.h"
27 #include "networkd-netdev-vlan.h"
28 #include "networkd-netdev-macvlan.h"
29 #include "networkd-netdev-vxlan.h"
30 #include "networkd-netdev-tunnel.h"
31 #include "networkd-netdev-veth.h"
32 #include "networkd-netdev-dummy.h"
33 #include "networkd-netdev-tuntap.h"
34 #include "network-internal.h"
35 #include "path-util.h"
36 #include "conf-files.h"
37 #include "conf-parser.h"
38 #include "list.h"
39 #include "siphash24.h"
40
41 const NetDevVTable * const netdev_vtable[_NETDEV_KIND_MAX] = {
42 [NETDEV_KIND_BRIDGE] = &bridge_vtable,
43 [NETDEV_KIND_BOND] = &bond_vtable,
44 [NETDEV_KIND_VLAN] = &vlan_vtable,
45 [NETDEV_KIND_MACVLAN] = &macvlan_vtable,
46 [NETDEV_KIND_VXLAN] = &vxlan_vtable,
47 [NETDEV_KIND_IPIP] = &ipip_vtable,
48 [NETDEV_KIND_GRE] = &gre_vtable,
49 [NETDEV_KIND_SIT] = &sit_vtable,
50 [NETDEV_KIND_VTI] = &vti_vtable,
51 [NETDEV_KIND_VETH] = &veth_vtable,
52 [NETDEV_KIND_DUMMY] = &dummy_vtable,
53 [NETDEV_KIND_TUN] = &tun_vtable,
54 [NETDEV_KIND_TAP] = &tap_vtable,
55 };
56
57 static const char* const netdev_kind_table[_NETDEV_KIND_MAX] = {
58 [NETDEV_KIND_BRIDGE] = "bridge",
59 [NETDEV_KIND_BOND] = "bond",
60 [NETDEV_KIND_VLAN] = "vlan",
61 [NETDEV_KIND_MACVLAN] = "macvlan",
62 [NETDEV_KIND_VXLAN] = "vxlan",
63 [NETDEV_KIND_IPIP] = "ipip",
64 [NETDEV_KIND_GRE] = "gre",
65 [NETDEV_KIND_SIT] = "sit",
66 [NETDEV_KIND_VETH] = "veth",
67 [NETDEV_KIND_VTI] = "vti",
68 [NETDEV_KIND_DUMMY] = "dummy",
69 [NETDEV_KIND_TUN] = "tun",
70 [NETDEV_KIND_TAP] = "tap",
71 };
72
73 DEFINE_STRING_TABLE_LOOKUP(netdev_kind, NetDevKind);
74 DEFINE_CONFIG_PARSE_ENUM(config_parse_netdev_kind, netdev_kind, NetDevKind, "Failed to parse netdev kind");
75
76
77 static void netdev_cancel_callbacks(NetDev *netdev) {
78 _cleanup_rtnl_message_unref_ sd_rtnl_message *m = NULL;
79 netdev_join_callback *callback;
80
81 if (!netdev)
82 return;
83
84 rtnl_message_new_synthetic_error(-ENODEV, 0, &m);
85
86 while ((callback = netdev->callbacks)) {
87 if (m) {
88 assert(callback->link);
89 assert(callback->callback);
90 assert(netdev->manager);
91 assert(netdev->manager->rtnl);
92
93 callback->callback(netdev->manager->rtnl, m, link);
94 }
95
96 LIST_REMOVE(callbacks, netdev->callbacks, callback);
97 free(callback);
98 }
99 }
100
101 static void netdev_free(NetDev *netdev) {
102 if (!netdev)
103 return;
104
105 netdev_cancel_callbacks(netdev);
106
107 if (netdev->ifname)
108 hashmap_remove(netdev->manager->netdevs, netdev->ifname);
109
110 free(netdev->filename);
111
112 free(netdev->description);
113 free(netdev->ifname);
114 free(netdev->ifname_peer);
115 free(netdev->mac);
116 free(netdev->mac_peer);
117 free(netdev->user_name);
118 free(netdev->group_name);
119
120 condition_free_list(netdev->match_host);
121 condition_free_list(netdev->match_virt);
122 condition_free_list(netdev->match_kernel);
123 condition_free_list(netdev->match_arch);
124
125 free(netdev);
126 }
127
128 NetDev *netdev_unref(NetDev *netdev) {
129 if (netdev && (-- netdev->n_ref <= 0))
130 netdev_free(netdev);
131
132 return NULL;
133 }
134
135 NetDev *netdev_ref(NetDev *netdev) {
136 if (netdev)
137 assert_se(++ netdev->n_ref >= 2);
138
139 return netdev;
140 }
141
142 void netdev_drop(NetDev *netdev) {
143 if (!netdev || netdev->state == NETDEV_STATE_LINGER)
144 return;
145
146 netdev->state = NETDEV_STATE_LINGER;
147
148 log_debug_netdev(netdev, "netdev removed");
149
150 netdev_cancel_callbacks(netdev);
151
152 netdev_unref(netdev);
153
154 return;
155 }
156
157 int netdev_get(Manager *manager, const char *name, NetDev **ret) {
158 NetDev *netdev;
159
160 assert(manager);
161 assert(name);
162 assert(ret);
163
164 netdev = hashmap_get(manager->netdevs, name);
165 if (!netdev) {
166 *ret = NULL;
167 return -ENOENT;
168 }
169
170 *ret = netdev;
171
172 return 0;
173 }
174
175 static int netdev_enter_failed(NetDev *netdev) {
176 netdev->state = NETDEV_STATE_FAILED;
177
178 return 0;
179 }
180
181 static int netdev_enslave_ready(NetDev *netdev, Link* link, sd_rtnl_message_handler_t callback) {
182 _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL;
183 int r;
184
185 assert(netdev);
186 assert(netdev->state == NETDEV_STATE_READY);
187 assert(netdev->manager);
188 assert(netdev->manager->rtnl);
189 assert(IN_SET(netdev->kind, NETDEV_KIND_BRIDGE, NETDEV_KIND_BOND));
190 assert(link);
191 assert(callback);
192
193 r = sd_rtnl_message_new_link(netdev->manager->rtnl, &req,
194 RTM_SETLINK, link->ifindex);
195 if (r < 0) {
196 log_error_netdev(netdev,
197 "Could not allocate RTM_SETLINK message: %s",
198 strerror(-r));
199 return r;
200 }
201
202 r = sd_rtnl_message_append_u32(req, IFLA_MASTER, netdev->ifindex);
203 if (r < 0) {
204 log_error_netdev(netdev,
205 "Could not append IFLA_MASTER attribute: %s",
206 strerror(-r));
207 return r;
208 }
209
210 r = sd_rtnl_call_async(netdev->manager->rtnl, req, callback, link, 0, NULL);
211 if (r < 0) {
212 log_error_netdev(netdev,
213 "Could not send rtnetlink message: %s",
214 strerror(-r));
215 return r;
216 }
217
218 link_ref(link);
219
220 log_debug_netdev(netdev, "enslaving link '%s'", link->ifname);
221
222 return 0;
223 }
224
225 static int netdev_enter_ready(NetDev *netdev) {
226 netdev_join_callback *callback, *callback_next;
227 int r;
228
229 assert(netdev);
230 assert(netdev->ifname);
231
232 if (netdev->state != NETDEV_STATE_CREATING)
233 return 0;
234
235 netdev->state = NETDEV_STATE_READY;
236
237 log_info_netdev(netdev, "netdev ready");
238
239 LIST_FOREACH_SAFE(callbacks, callback, callback_next, netdev->callbacks) {
240 /* enslave the links that were attempted to be enslaved before the
241 * link was ready */
242 r = netdev_enslave_ready(netdev, callback->link, callback->callback);
243 if (r < 0)
244 return r;
245
246 LIST_REMOVE(callbacks, netdev->callbacks, callback);
247 link_unref(callback->link);
248 free(callback);
249 }
250
251 return 0;
252 }
253
254 /* callback for netdev's created without a backing Link */
255 static int netdev_create_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
256 _cleanup_netdev_unref_ NetDev *netdev = userdata;
257 int r;
258
259 assert(netdev->state != _NETDEV_STATE_INVALID);
260
261 r = sd_rtnl_message_get_errno(m);
262 if (r == -EEXIST)
263 log_debug_netdev(netdev, "netdev exists, using existing");
264 else if (r < 0) {
265 log_warning_netdev(netdev, "netdev could not be created: %s", strerror(-r));
266 netdev_drop(netdev);
267
268 return 1;
269 }
270
271 return 1;
272 }
273
274 int netdev_enslave(NetDev *netdev, Link *link, sd_rtnl_message_handler_t callback) {
275 int r;
276
277 assert(netdev);
278 assert(IN_SET(netdev->kind, NETDEV_KIND_BRIDGE, NETDEV_KIND_BOND));
279
280 if (netdev->state == NETDEV_STATE_READY) {
281 r = netdev_enslave_ready(netdev, link, callback);
282 if (r < 0)
283 return r;
284 } else {
285 /* the netdev is not yet read, save this request for when it is*/
286 netdev_join_callback *cb;
287
288 cb = new0(netdev_join_callback, 1);
289 if (!cb)
290 return log_oom();
291
292 cb->callback = callback;
293 cb->link = link;
294 link_ref(link);
295
296 LIST_PREPEND(callbacks, netdev->callbacks, cb);
297 }
298
299 return 0;
300 }
301
302 /* the callback must be called, possibly after a timeout, as otherwise the Link will hang */
303 int netdev_join(NetDev *netdev, Link *link, sd_rtnl_message_handler_t callback) {
304 int r;
305
306 assert(netdev);
307 assert(netdev->manager);
308 assert(netdev->manager->rtnl);
309 assert(NETDEV_VTABLE(netdev));
310
311 if (NETDEV_VTABLE(netdev)->fill_message_create_on_link) {
312 _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL;
313
314 r = sd_rtnl_message_new_link(netdev->manager->rtnl, &req,
315 RTM_NEWLINK, 0);
316 if (r < 0) {
317 log_error_netdev(netdev,
318 "Could not allocate RTM_SETLINK message: %s",
319 strerror(-r));
320 return r;
321 }
322
323 NETDEV_VTABLE(netdev)->fill_message_create_on_link(netdev, link, req);
324
325 r = sd_rtnl_call_async(netdev->manager->rtnl, req, callback, link, 0, NULL);
326 if (r < 0) {
327 log_error_netdev(netdev,
328 "Could not send rtnetlink message: %s", strerror(-r));
329 return r;
330 }
331
332 link_ref(link);
333 } else if (NETDEV_VTABLE(netdev)->enslave) {
334 return NETDEV_VTABLE(netdev)->enslave(netdev, link, callback);
335 } else
336 assert_not_reached("Joining link to netdev of invalid kind");
337
338 return 0;
339 }
340
341 int netdev_set_ifindex(NetDev *netdev, sd_rtnl_message *message) {
342 uint16_t type;
343 const char *kind;
344 char *received_kind;
345 char *received_name;
346 int r, ifindex;
347
348 assert(netdev);
349 assert(message);
350
351 r = sd_rtnl_message_get_type(message, &type);
352 if (r < 0) {
353 log_error_netdev(netdev, "Could not get rtnl message type");
354 return r;
355 }
356
357 if (type != RTM_NEWLINK) {
358 log_error_netdev(netdev, "Can not set ifindex from unexpected rtnl message type");
359 return -EINVAL;
360 }
361
362 r = sd_rtnl_message_link_get_ifindex(message, &ifindex);
363 if (r < 0) {
364 log_error_netdev(netdev, "Could not get ifindex: %s", strerror(-r));
365 netdev_enter_failed(netdev);
366 return r;
367 } else if (ifindex <= 0) {
368 log_error_netdev(netdev, "Got invalid ifindex: %d", ifindex);
369 netdev_enter_failed(netdev);
370 return r;
371 }
372
373 if (netdev->ifindex > 0) {
374 if (netdev->ifindex != ifindex) {
375 log_error_netdev(netdev, "Could not set ifindex to %d, already set to %d",
376 ifindex, netdev->ifindex);
377 netdev_enter_failed(netdev);
378 return -EEXIST;
379 } else
380 /* ifindex already set to the same for this netdev */
381 return 0;
382 }
383
384 r = sd_rtnl_message_read_string(message, IFLA_IFNAME, &received_name);
385 if (r < 0) {
386 log_error_netdev(netdev, "Could not get IFNAME");
387 return r;
388 }
389
390 if (!streq(netdev->ifname, received_name)) {
391 log_error_netdev(netdev, "Received newlink with wrong IFNAME %s",
392 received_name);
393 netdev_enter_failed(netdev);
394 return r;
395 }
396
397 r = sd_rtnl_message_enter_container(message, IFLA_LINKINFO);
398 if (r < 0) {
399 log_error_netdev(netdev, "Could not get LINKINFO");
400 return r;
401 }
402
403 r = sd_rtnl_message_read_string(message, IFLA_INFO_KIND, &received_kind);
404 if (r < 0) {
405 log_error_netdev(netdev, "Could not get KIND");
406 return r;
407 }
408
409 r = sd_rtnl_message_exit_container(message);
410 if (r < 0) {
411 log_error_netdev(netdev, "Could not exit container");
412 return r;
413 }
414
415 if (netdev->kind == NETDEV_KIND_TAP)
416 /* the kernel does not distinguish between tun and tap */
417 kind = "tun";
418 else {
419 kind = netdev_kind_to_string(netdev->kind);
420 if (!kind) {
421 log_error_netdev(netdev, "Could not get kind");
422 netdev_enter_failed(netdev);
423 return -EINVAL;
424 }
425 }
426
427 if (!streq(kind, received_kind)) {
428 log_error_netdev(netdev,
429 "Received newlink with wrong KIND %s, "
430 "expected %s", received_kind, kind);
431 netdev_enter_failed(netdev);
432 return r;
433 }
434
435 netdev->ifindex = ifindex;
436
437 log_debug_netdev(netdev, "netdev has index %d", netdev->ifindex);
438
439 netdev_enter_ready(netdev);
440
441 return 0;
442 }
443
444 #define HASH_KEY SD_ID128_MAKE(52,e1,45,bd,00,6f,29,96,21,c6,30,6d,83,71,04,48)
445
446 int netdev_get_mac(const char *ifname, struct ether_addr **ret) {
447 _cleanup_free_ struct ether_addr *mac = NULL;
448 uint8_t result[8];
449 size_t l, sz;
450 uint8_t *v;
451 int r;
452
453 assert(ifname);
454 assert(ret);
455
456 mac = new0(struct ether_addr, 1);
457 if (!mac)
458 return -ENOMEM;
459
460 l = strlen(ifname);
461 sz = sizeof(sd_id128_t) + l;
462 v = alloca(sz);
463
464 /* fetch some persistent data unique to the machine */
465 r = sd_id128_get_machine((sd_id128_t*) v);
466 if (r < 0)
467 return r;
468
469 /* combine with some data unique (on this machine) to this
470 * netdev */
471 memcpy(v + sizeof(sd_id128_t), ifname, l);
472
473 /* Let's hash the host machine ID plus the container name. We
474 * use a fixed, but originally randomly created hash key here. */
475 siphash24(result, v, sz, HASH_KEY.bytes);
476
477 assert_cc(ETH_ALEN <= sizeof(result));
478 memcpy(mac->ether_addr_octet, result, ETH_ALEN);
479
480 /* see eth_random_addr in the kernel */
481 mac->ether_addr_octet[0] &= 0xfe; /* clear multicast bit */
482 mac->ether_addr_octet[0] |= 0x02; /* set local assignment bit (IEEE802) */
483
484 *ret = mac;
485 mac = NULL;
486
487 return 0;
488 }
489
490 static int netdev_load_one(Manager *manager, const char *filename) {
491 _cleanup_netdev_unref_ NetDev *netdev = NULL;
492 _cleanup_fclose_ FILE *file = NULL;
493 int r;
494
495 assert(manager);
496 assert(filename);
497
498 if (null_or_empty_path(filename)) {
499 log_debug("skipping empty file: %s", filename);
500 return 0;
501 }
502
503 file = fopen(filename, "re");
504 if (!file) {
505 if (errno == ENOENT)
506 return 0;
507 else
508 return -errno;
509 }
510
511 netdev = new0(NetDev, 1);
512 if (!netdev)
513 return log_oom();
514
515 netdev->n_ref = 1;
516 netdev->manager = manager;
517 netdev->state = _NETDEV_STATE_INVALID;
518 netdev->kind = _NETDEV_KIND_INVALID;
519 netdev->macvlan_mode = _NETDEV_MACVLAN_MODE_INVALID;
520 netdev->bond_mode = _NETDEV_BOND_MODE_INVALID;
521 netdev->vlanid = VLANID_MAX + 1;
522 netdev->vxlanid = VXLAN_VID_MAX + 1;
523 netdev->tunnel_pmtudisc = true;
524 netdev->learning = true;
525
526 r = config_parse(NULL, filename, file,
527 "Match\0NetDev\0VLAN\0MACVLAN\0VXLAN\0Tunnel\0Peer\0Tun\0Tap\0Bond\0",
528 config_item_perf_lookup, network_netdev_gperf_lookup,
529 false, false, true, netdev);
530 if (r < 0)
531 return r;
532
533 /* skip out early if configuration does not match the environment */
534 if (net_match_config(NULL, NULL, NULL, NULL, NULL,
535 netdev->match_host, netdev->match_virt,
536 netdev->match_kernel, netdev->match_arch,
537 NULL, NULL, NULL, NULL, NULL, NULL) <= 0)
538 return 0;
539
540 if (!NETDEV_VTABLE(netdev)) {
541 log_warning("NetDev with invalid Kind configured in %s. Igonring", filename);
542 return 0;
543 }
544
545 /* verify configuration */
546 if (NETDEV_VTABLE(netdev)->config_verify) {
547 r = NETDEV_VTABLE(netdev)->config_verify(netdev, filename);
548 if (r < 0)
549 return 0;
550 }
551
552 if (!netdev->ifname) {
553 log_warning("NetDev without Name configured in %s. Ignoring", filename);
554 return 0;
555 }
556
557 if (netdev->kind != NETDEV_KIND_VLAN && netdev->vlanid <= VLANID_MAX) {
558 log_warning("VLAN Id configured for a %s in %s. Ignoring",
559 netdev_kind_to_string(netdev->kind), filename);
560 return 0;
561 }
562
563 if (netdev->kind != NETDEV_KIND_VXLAN && netdev->vxlanid <= VXLAN_VID_MAX) {
564 log_warning("VXLAN Id configured for a %s in %s. Ignoring",
565 netdev_kind_to_string(netdev->kind), filename);
566 return 0;
567 }
568
569 if (netdev->kind != NETDEV_KIND_MACVLAN &&
570 netdev->macvlan_mode != _NETDEV_MACVLAN_MODE_INVALID) {
571 log_warning("MACVLAN Mode configured for a %s in %s. Ignoring",
572 netdev_kind_to_string(netdev->kind), filename);
573 return 0;
574 }
575
576 netdev->filename = strdup(filename);
577 if (!netdev->filename)
578 return log_oom();
579
580 if (!netdev->mac) {
581 r = netdev_get_mac(netdev->ifname, &netdev->mac);
582 if (r < 0) {
583 log_error("Failed to generate predictable MAC address for %s",
584 netdev->ifname);
585 return r;
586 }
587 }
588
589 r = hashmap_put(netdev->manager->netdevs, netdev->ifname, netdev);
590 if (r < 0)
591 return r;
592
593 LIST_HEAD_INIT(netdev->callbacks);
594
595 log_debug_netdev(netdev, "loaded %s", netdev_kind_to_string(netdev->kind));
596
597 /* create netdev */
598 if (NETDEV_VTABLE(netdev)->fill_message_create) {
599 _cleanup_rtnl_message_unref_ sd_rtnl_message *m = NULL;
600
601 r = sd_rtnl_message_new_link(netdev->manager->rtnl, &m, RTM_NEWLINK, 0);
602 if (r < 0) {
603 log_error_netdev(netdev,
604 "Could not allocate RTM_NEWLINK message: %s",
605 strerror(-r));
606 return r;
607 }
608
609 r = NETDEV_VTABLE(netdev)->fill_message_create(netdev, m);
610 if (r < 0)
611 return r;
612
613 r = sd_rtnl_call_async(netdev->manager->rtnl, m, netdev_create_handler, netdev, 0, NULL);
614 if (r < 0) {
615 log_error_netdev(netdev,
616 "Could not send rtnetlink message: %s", strerror(-r));
617 return r;
618 }
619
620 netdev_ref(netdev);
621
622 log_debug_netdev(netdev, "creating");
623
624 netdev->state = NETDEV_STATE_CREATING;
625 } else if (NETDEV_VTABLE(netdev)->create) {
626 r = NETDEV_VTABLE(netdev)->create(netdev);
627 if (r < 0)
628 return r;
629 }
630
631 netdev = NULL;
632
633 return 0;
634 }
635
636 int netdev_load(Manager *manager) {
637 NetDev *netdev;
638 char **files, **f;
639 int r;
640
641 assert(manager);
642
643 while ((netdev = hashmap_first(manager->netdevs)))
644 netdev_unref(netdev);
645
646 r = conf_files_list_strv(&files, ".netdev", NULL, network_dirs);
647 if (r < 0) {
648 log_error("Failed to enumerate netdev files: %s", strerror(-r));
649 return r;
650 }
651
652 STRV_FOREACH_BACKWARDS(f, files) {
653 r = netdev_load_one(manager, *f);
654 if (r < 0)
655 return r;
656 }
657
658 strv_free(files);
659
660 return 0;
661 }