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