chiark / gitweb /
0861ff3cc1da958db377cc31e2ffbed4aa814473
[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;
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 }