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