]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/network/networkd-netdev.c
networkd: add support for mode
[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_enslave_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(link);
165 assert(callback);
166
167 r = sd_rtnl_message_new_link(netdev->manager->rtnl, &req,
168 RTM_SETLINK, link->ifindex);
169 if (r < 0) {
170 log_error_netdev(netdev,
171 "Could not allocate RTM_SETLINK message: %s",
172 strerror(-r));
173 return r;
174 }
175
176 r = sd_rtnl_message_append_u32(req, IFLA_MASTER, netdev->ifindex);
177 if (r < 0) {
178 log_error_netdev(netdev,
179 "Could not append IFLA_MASTER attribute: %s",
180 strerror(-r));
181 return r;
182 }
183
184 r = sd_rtnl_call_async(netdev->manager->rtnl, req, callback, link, 0, NULL);
185 if (r < 0) {
186 log_error_netdev(netdev,
187 "Could not send rtnetlink message: %s",
188 strerror(-r));
189 return r;
190 }
191
192 link_ref(link);
193
194 log_debug_netdev(netdev, "enslaving link '%s'", link->ifname);
195
196 return 0;
197 }
198
199 static int netdev_enter_ready(NetDev *netdev) {
200 netdev_enslave_callback *callback, *callback_next;
201 int r;
202
203 assert(netdev);
204 assert(netdev->ifname);
205
206 if (netdev->state != NETDEV_STATE_CREATING)
207 return 0;
208
209 netdev->state = NETDEV_STATE_READY;
210
211 log_info_netdev(netdev, "netdev ready");
212
213 LIST_FOREACH_SAFE(callbacks, callback, callback_next, netdev->callbacks) {
214 /* enslave the links that were attempted to be enslaved before the
215 * link was ready */
216 r = netdev_enslave_ready(netdev, callback->link, callback->callback);
217 if (r < 0)
218 return r;
219
220 LIST_REMOVE(callbacks, netdev->callbacks, callback);
221 link_unref(callback->link);
222 free(callback);
223 }
224
225 return 0;
226 }
227
228 /* callback for netdev's created without a backing Link */
229 static int netdev_create_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
230 _cleanup_netdev_unref_ NetDev *netdev = userdata;
231 int r;
232
233 assert(netdev->state != _NETDEV_STATE_INVALID);
234
235 r = sd_rtnl_message_get_errno(m);
236 if (r == -EEXIST)
237 log_debug_netdev(netdev, "netdev exists, using existing");
238 else if (r < 0) {
239 log_warning_netdev(netdev, "netdev could not be created: %s", strerror(-r));
240 netdev_drop(netdev);
241
242 return 1;
243 }
244
245 return 1;
246 }
247
248 static int netdev_create(NetDev *netdev) {
249 _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL;
250 const char *kind;
251 int r;
252
253 assert(netdev);
254 assert(netdev->ifname);
255 assert(netdev->manager);
256 assert(netdev->manager->rtnl);
257
258 r = sd_rtnl_message_new_link(netdev->manager->rtnl, &req, RTM_NEWLINK, 0);
259 if (r < 0) {
260 log_error_netdev(netdev,
261 "Could not allocate RTM_NEWLINK message: %s",
262 strerror(-r));
263 return r;
264 }
265
266 r = sd_rtnl_message_append_string(req, IFLA_IFNAME, netdev->ifname);
267 if (r < 0) {
268 log_error_netdev(netdev,
269 "Could not append IFLA_IFNAME attribute: %s",
270 strerror(-r));
271 return r;
272 }
273
274 if (netdev->mtu) {
275 r = sd_rtnl_message_append_u32(req, IFLA_MTU, netdev->mtu);
276 if (r < 0) {
277 log_error_netdev(netdev,
278 "Could not append IFLA_MTU attribute: %s",
279 strerror(-r));
280 return r;
281 }
282 }
283
284 if (netdev->mac) {
285 r = sd_rtnl_message_append_ether_addr(req, IFLA_ADDRESS, netdev->mac);
286 if (r < 0) {
287 log_error_netdev(netdev,
288 "Colud not append IFLA_ADDRESS attribute: %s",
289 strerror(-r));
290 return r;
291 }
292 }
293
294 r = sd_rtnl_message_open_container(req, IFLA_LINKINFO);
295 if (r < 0) {
296 log_error_netdev(netdev,
297 "Could not open IFLA_LINKINFO container: %s",
298 strerror(-r));
299 return r;
300 }
301
302 kind = netdev_kind_to_string(netdev->kind);
303 if (!kind) {
304 log_error_netdev(netdev, "Invalid kind");
305 return -EINVAL;
306 }
307
308 r = sd_rtnl_message_open_container_union(req, IFLA_INFO_DATA, kind);
309 if (r < 0) {
310 log_error_netdev(netdev,
311 "Could not open IFLA_INFO_DATA container: %s",
312 strerror(-r));
313 return r;
314 }
315
316 r = sd_rtnl_message_close_container(req);
317 if (r < 0) {
318 log_error_netdev(netdev,
319 "Could not close IFLA_INFO_DATA container %s",
320 strerror(-r));
321 return r;
322 }
323
324 r = sd_rtnl_message_close_container(req);
325 if (r < 0) {
326 log_error_netdev(netdev,
327 "Could not close IFLA_LINKINFO container %s",
328 strerror(-r));
329 return r;
330 }
331
332 r = sd_rtnl_call_async(netdev->manager->rtnl, req, &netdev_create_handler, netdev, 0, NULL);
333 if (r < 0) {
334 log_error_netdev(netdev,
335 "Could not send rtnetlink message: %s", strerror(-r));
336 return r;
337 }
338
339 netdev_ref(netdev);
340
341 log_debug_netdev(netdev, "creating netdev");
342
343 netdev->state = NETDEV_STATE_CREATING;
344
345 return 0;
346 }
347
348 /* the callback must be called, possibly after a timeout, as otherwise the Link will hang */
349 int netdev_enslave(NetDev *netdev, Link *link, sd_rtnl_message_handler_t callback) {
350 int r;
351
352 switch(netdev->kind) {
353 case NETDEV_KIND_VLAN:
354 return netdev_create_vlan(netdev, link, callback);
355 case NETDEV_KIND_MACVLAN:
356 return netdev_create_macvlan(netdev, link, callback);
357 case NETDEV_KIND_VXLAN:
358 return netdev_create_vxlan(netdev, link, callback);
359 case NETDEV_KIND_IPIP:
360 case NETDEV_KIND_GRE:
361 case NETDEV_KIND_SIT:
362 case NETDEV_KIND_VTI:
363 return netdev_create_tunnel(netdev, link, callback);
364 default:
365 break;
366 }
367
368 if (netdev->state == NETDEV_STATE_READY) {
369 r = netdev_enslave_ready(netdev, link, callback);
370 if (r < 0)
371 return r;
372 } else {
373 /* the netdev is not yet read, save this request for when it is*/
374 netdev_enslave_callback *cb;
375
376 cb = new0(netdev_enslave_callback, 1);
377 if (!cb)
378 return log_oom();
379
380 cb->callback = callback;
381 cb->link = link;
382 link_ref(link);
383
384 LIST_PREPEND(callbacks, netdev->callbacks, cb);
385 }
386
387 return 0;
388 }
389
390 int netdev_set_ifindex(NetDev *netdev, sd_rtnl_message *message) {
391 uint16_t type;
392 const char *kind;
393 char *received_kind;
394 char *received_name;
395 int r, ifindex;
396
397 assert(netdev);
398 assert(message);
399
400 r = sd_rtnl_message_get_type(message, &type);
401 if (r < 0) {
402 log_error_netdev(netdev, "Could not get rtnl message type");
403 return r;
404 }
405
406 if (type != RTM_NEWLINK) {
407 log_error_netdev(netdev, "Can not set ifindex from unexpected rtnl message type");
408 return -EINVAL;
409 }
410
411 r = sd_rtnl_message_link_get_ifindex(message, &ifindex);
412 if (r < 0) {
413 log_error_netdev(netdev, "Could not get ifindex: %s", strerror(-r));
414 netdev_enter_failed(netdev);
415 return r;
416 } else if (ifindex <= 0) {
417 log_error_netdev(netdev, "Got invalid ifindex: %d", ifindex);
418 netdev_enter_failed(netdev);
419 return r;
420 }
421
422 if (netdev->ifindex > 0) {
423 if (netdev->ifindex != ifindex) {
424 log_error_netdev(netdev, "Could not set ifindex to %d, already set to %d",
425 ifindex, netdev->ifindex);
426 netdev_enter_failed(netdev);
427 return -EEXIST;
428 } else
429 /* ifindex already set to the same for this netdev */
430 return 0;
431 }
432
433 r = sd_rtnl_message_read_string(message, IFLA_IFNAME, &received_name);
434 if (r < 0) {
435 log_error_netdev(netdev, "Could not get IFNAME");
436 return r;
437 }
438
439 if (!streq(netdev->ifname, received_name)) {
440 log_error_netdev(netdev, "Received newlink with wrong IFNAME %s",
441 received_name);
442 netdev_enter_failed(netdev);
443 return r;
444 }
445
446 r = sd_rtnl_message_enter_container(message, IFLA_LINKINFO);
447 if (r < 0) {
448 log_error_netdev(netdev, "Could not get LINKINFO");
449 return r;
450 }
451
452 r = sd_rtnl_message_read_string(message, IFLA_INFO_KIND, &received_kind);
453 if (r < 0) {
454 log_error_netdev(netdev, "Could not get KIND");
455 return r;
456 }
457
458 r = sd_rtnl_message_exit_container(message);
459 if (r < 0) {
460 log_error_netdev(netdev, "Could not exit container");
461 return r;
462 }
463
464 if (netdev->kind == NETDEV_KIND_TAP)
465 /* the kernel does not distinguish between tun and tap */
466 kind = "tun";
467 else {
468 kind = netdev_kind_to_string(netdev->kind);
469 if (!kind) {
470 log_error_netdev(netdev, "Could not get kind");
471 netdev_enter_failed(netdev);
472 return -EINVAL;
473 }
474 }
475
476 if (!streq(kind, received_kind)) {
477 log_error_netdev(netdev,
478 "Received newlink with wrong KIND %s, "
479 "expected %s", received_kind, kind);
480 netdev_enter_failed(netdev);
481 return r;
482 }
483
484 netdev->ifindex = ifindex;
485
486 log_debug_netdev(netdev, "netdev has index %d", netdev->ifindex);
487
488 netdev_enter_ready(netdev);
489
490 return 0;
491 }
492
493 #define HASH_KEY SD_ID128_MAKE(52,e1,45,bd,00,6f,29,96,21,c6,30,6d,83,71,04,48)
494
495 static int netdev_get_mac(const char *ifname, struct ether_addr **ret) {
496 _cleanup_free_ struct ether_addr *mac = NULL;
497 uint8_t result[8];
498 size_t l, sz;
499 uint8_t *v;
500 int r;
501
502 assert(ifname);
503 assert(ret);
504
505 mac = new0(struct ether_addr, 1);
506 if (!mac)
507 return -ENOMEM;
508
509 l = strlen(ifname);
510 sz = sizeof(sd_id128_t) + l;
511 v = alloca(sz);
512
513 /* fetch some persistent data unique to the machine */
514 r = sd_id128_get_machine((sd_id128_t*) v);
515 if (r < 0)
516 return r;
517
518 /* combine with some data unique (on this machine) to this
519 * netdev */
520 memcpy(v + sizeof(sd_id128_t), ifname, l);
521
522 /* Let's hash the host machine ID plus the container name. We
523 * use a fixed, but originally randomly created hash key here. */
524 siphash24(result, v, sz, HASH_KEY.bytes);
525
526 assert_cc(ETH_ALEN <= sizeof(result));
527 memcpy(mac->ether_addr_octet, result, ETH_ALEN);
528
529 /* see eth_random_addr in the kernel */
530 mac->ether_addr_octet[0] &= 0xfe; /* clear multicast bit */
531 mac->ether_addr_octet[0] |= 0x02; /* set local assignment bit (IEEE802) */
532
533 *ret = mac;
534 mac = NULL;
535
536 return 0;
537 }
538
539 static int netdev_load_one(Manager *manager, const char *filename) {
540 _cleanup_netdev_unref_ NetDev *netdev = NULL;
541 _cleanup_fclose_ FILE *file = NULL;
542 int r;
543
544 assert(manager);
545 assert(filename);
546
547 if (null_or_empty_path(filename)) {
548 log_debug("skipping empty file: %s", filename);
549 return 0;
550 }
551
552 file = fopen(filename, "re");
553 if (!file) {
554 if (errno == ENOENT)
555 return 0;
556 else
557 return -errno;
558 }
559
560 netdev = new0(NetDev, 1);
561 if (!netdev)
562 return log_oom();
563
564 netdev->n_ref = 1;
565 netdev->manager = manager;
566 netdev->state = _NETDEV_STATE_INVALID;
567 netdev->kind = _NETDEV_KIND_INVALID;
568 netdev->macvlan_mode = _NETDEV_MACVLAN_MODE_INVALID;
569 netdev->bond_mode = _NETDEV_BOND_MODE_INVALID;
570 netdev->vlanid = VLANID_MAX + 1;
571 netdev->vxlanid = VXLAN_VID_MAX + 1;
572 netdev->tunnel_pmtudisc = true;
573 netdev->learning = true;
574
575 r = config_parse(NULL, filename, file,
576 "Match\0NetDev\0VLAN\0MACVLAN\0VXLAN\0Tunnel\0Peer\0Tun\0Tap\0Bond\0",
577 config_item_perf_lookup, (void*) network_netdev_gperf_lookup,
578 false, false, netdev);
579 if (r < 0) {
580 log_warning("Could not parse config file %s: %s", filename, strerror(-r));
581 return r;
582 }
583
584 switch (netdev->kind) {
585 case _NETDEV_KIND_INVALID:
586 log_warning("NetDev without Kind configured in %s. Ignoring", filename);
587 return 0;
588 case NETDEV_KIND_VLAN:
589 if (netdev->vlanid > VLANID_MAX) {
590 log_warning("VLAN without valid Id configured in %s. Ignoring", filename);
591 return 0;
592 }
593 break;
594 case NETDEV_KIND_VXLAN:
595 if (netdev->vxlanid > VXLAN_VID_MAX) {
596 log_warning("VXLAN without valid Id configured in %s. Ignoring", filename);
597 return 0;
598 }
599 break;
600 case NETDEV_KIND_IPIP:
601 case NETDEV_KIND_GRE:
602 case NETDEV_KIND_SIT:
603 case NETDEV_KIND_VTI:
604 if (netdev->local.in.s_addr == INADDR_ANY) {
605 log_warning("Tunnel without local address configured in %s. Ignoring", filename);
606 return 0;
607 }
608 if (netdev->remote.in.s_addr == INADDR_ANY) {
609 log_warning("Tunnel without remote address configured in %s. Ignoring", filename);
610 return 0;
611 }
612 if (netdev->family != AF_INET) {
613 log_warning("Tunnel with invalid address family configured in %s. Ignoring", filename);
614 return 0;
615 }
616 break;
617 default:
618 break;
619 }
620
621 if (!netdev->ifname) {
622 log_warning("NetDev without Name configured in %s. Ignoring", filename);
623 return 0;
624 }
625
626 if (netdev->kind != NETDEV_KIND_VLAN && netdev->vlanid <= VLANID_MAX) {
627 log_warning("VLAN Id configured for a %s in %s. Ignoring",
628 netdev_kind_to_string(netdev->kind), filename);
629 return 0;
630 }
631
632 if (netdev->kind != NETDEV_KIND_VXLAN && netdev->vxlanid <= VXLAN_VID_MAX) {
633 log_warning("VXLAN Id configured for a %s in %s. Ignoring",
634 netdev_kind_to_string(netdev->kind), filename);
635 return 0;
636 }
637
638 if (netdev->kind != NETDEV_KIND_MACVLAN &&
639 netdev->macvlan_mode != _NETDEV_MACVLAN_MODE_INVALID) {
640 log_warning("MACVLAN Mode configured for a %s in %s. Ignoring",
641 netdev_kind_to_string(netdev->kind), filename);
642 return 0;
643 }
644
645 netdev->filename = strdup(filename);
646 if (!netdev->filename)
647 return log_oom();
648
649 if (net_match_config(NULL, NULL, NULL, NULL, NULL,
650 netdev->match_host, netdev->match_virt,
651 netdev->match_kernel, netdev->match_arch,
652 NULL, NULL, NULL, NULL, NULL, NULL) <= 0)
653 return 0;
654
655 if (!netdev->mac) {
656 r = netdev_get_mac(netdev->ifname, &netdev->mac);
657 if (r < 0) {
658 log_error("Failed to generate predictable MAC address for %s",
659 netdev->ifname);
660 return r;
661 }
662 }
663
664 r = hashmap_put(netdev->manager->netdevs, netdev->ifname, netdev);
665 if (r < 0)
666 return r;
667
668 LIST_HEAD_INIT(netdev->callbacks);
669
670 switch (netdev->kind) {
671 case NETDEV_KIND_VETH:
672 if (!netdev->ifname_peer) {
673 log_warning("Veth NetDev without peer name configured "
674 "in %s. Ignoring", filename);
675 return 0;
676 }
677
678 if (!netdev->mac) {
679 r = netdev_get_mac(netdev->ifname_peer, &netdev->mac_peer);
680 if (r < 0) {
681 log_error("Failed to generate predictable MAC address for %s",
682 netdev->ifname_peer);
683 return r;
684 }
685 }
686
687 r = netdev_create_veth(netdev, netdev_create_handler);
688 if (r < 0)
689 return r;
690
691 break;
692 case NETDEV_KIND_DUMMY:
693 r = netdev_create_dummy(netdev, netdev_create_handler);
694 if (r < 0)
695 return r;
696
697 break;
698 case NETDEV_KIND_BRIDGE:
699 r = netdev_create(netdev);
700 if (r < 0)
701 return r;
702 break;
703 case NETDEV_KIND_BOND:
704 r = netdev_create_bond(netdev, netdev_create_handler);
705 if (r < 0)
706 return r;
707 break;
708 default:
709 break;
710 }
711
712 log_debug_netdev(netdev, "loaded %s", netdev_kind_to_string(netdev->kind));
713
714 netdev = NULL;
715
716 return 0;
717 }
718
719 int netdev_load(Manager *manager) {
720 NetDev *netdev;
721 char **files, **f;
722 int r;
723
724 assert(manager);
725
726 while ((netdev = hashmap_first(manager->netdevs)))
727 netdev_unref(netdev);
728
729 r = conf_files_list_strv(&files, ".netdev", NULL, network_dirs);
730 if (r < 0) {
731 log_error("Failed to enumerate netdev files: %s", strerror(-r));
732 return r;
733 }
734
735 STRV_FOREACH_BACKWARDS(f, files) {
736 r = netdev_load_one(manager, *f);
737 if (r < 0)
738 return r;
739 }
740
741 strv_free(files);
742
743 return 0;
744 }