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