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