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