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