chiark / gitweb /
0a2e319db17121641d127637eadc678348b96dfd
[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         switch (netdev->kind) {
499         case _NETDEV_KIND_INVALID:
500                 log_warning("NetDev without Kind configured in %s. Ignoring", filename);
501                 return 0;
502         case NETDEV_KIND_VLAN:
503                 if (netdev->vlanid > VLANID_MAX) {
504                         log_warning("VLAN without valid Id configured in %s. Ignoring", filename);
505                         return 0;
506                 }
507                 break;
508         case NETDEV_KIND_VXLAN:
509                 if (netdev->vxlanid > VXLAN_VID_MAX) {
510                         log_warning("VXLAN without valid Id configured in %s. Ignoring", filename);
511                         return 0;
512                 }
513                 break;
514         case NETDEV_KIND_IPIP:
515         case NETDEV_KIND_GRE:
516         case NETDEV_KIND_SIT:
517         case NETDEV_KIND_VTI:
518                 if (netdev->local.in.s_addr == INADDR_ANY) {
519                         log_warning("Tunnel without local address configured in %s. Ignoring", filename);
520                         return 0;
521                 }
522                 if (netdev->remote.in.s_addr == INADDR_ANY) {
523                         log_warning("Tunnel without remote address configured in %s. Ignoring", filename);
524                         return 0;
525                 }
526                 if (netdev->family != AF_INET) {
527                         log_warning("Tunnel with invalid address family configured in %s. Ignoring", filename);
528                         return 0;
529                 }
530                 break;
531         default:
532                 break;
533         }
534
535         if (!netdev->ifname) {
536                 log_warning("NetDev without Name configured in %s. Ignoring", filename);
537                 return 0;
538         }
539
540         if (netdev->kind != NETDEV_KIND_VLAN && netdev->vlanid <= VLANID_MAX) {
541                 log_warning("VLAN Id configured for a %s in %s. Ignoring",
542                             netdev_kind_to_string(netdev->kind), filename);
543                 return 0;
544         }
545
546         if (netdev->kind != NETDEV_KIND_VXLAN && netdev->vxlanid <= VXLAN_VID_MAX) {
547                 log_warning("VXLAN Id configured for a %s in %s. Ignoring",
548                             netdev_kind_to_string(netdev->kind), filename);
549                 return 0;
550         }
551
552         if (netdev->kind != NETDEV_KIND_MACVLAN &&
553             netdev->macvlan_mode != _NETDEV_MACVLAN_MODE_INVALID) {
554                 log_warning("MACVLAN Mode configured for a %s in %s. Ignoring",
555                             netdev_kind_to_string(netdev->kind), filename);
556                 return 0;
557         }
558
559         netdev->filename = strdup(filename);
560         if (!netdev->filename)
561                 return log_oom();
562
563         if (net_match_config(NULL, NULL, NULL, NULL, NULL,
564                              netdev->match_host, netdev->match_virt,
565                              netdev->match_kernel, netdev->match_arch,
566                              NULL, NULL, NULL, NULL, NULL, NULL) <= 0)
567                 return 0;
568
569         if (!netdev->mac) {
570                 r = netdev_get_mac(netdev->ifname, &netdev->mac);
571                 if (r < 0) {
572                         log_error("Failed to generate predictable MAC address for %s",
573                                   netdev->ifname);
574                         return r;
575                 }
576         }
577
578         r = hashmap_put(netdev->manager->netdevs, netdev->ifname, netdev);
579         if (r < 0)
580                 return r;
581
582         LIST_HEAD_INIT(netdev->callbacks);
583
584         switch (netdev->kind) {
585         case NETDEV_KIND_VETH:
586                 if (!netdev->ifname_peer) {
587                         log_warning("Veth NetDev without peer name configured "
588                                     "in %s. Ignoring", filename);
589                         return 0;
590                 }
591
592                 if (!netdev->mac) {
593                         r = netdev_get_mac(netdev->ifname_peer, &netdev->mac_peer);
594                         if (r < 0) {
595                                 log_error("Failed to generate predictable MAC address for %s",
596                                           netdev->ifname_peer);
597                                 return r;
598                         }
599                 }
600
601                 r = netdev_create_veth(netdev, netdev_create_handler);
602                 if (r < 0)
603                         return r;
604
605                 break;
606         case NETDEV_KIND_DUMMY:
607                 r = netdev_create_dummy(netdev, netdev_create_handler);
608                 if (r < 0)
609                         return r;
610
611                 break;
612         case NETDEV_KIND_BRIDGE:
613                 r = netdev_create_bridge(netdev, netdev_create_handler);
614                 if (r < 0)
615                         return r;
616                 break;
617         case NETDEV_KIND_BOND:
618                 r = netdev_create_bond(netdev, netdev_create_handler);
619                 if (r < 0)
620                         return r;
621                 break;
622         default:
623                 break;
624         }
625
626         log_debug_netdev(netdev, "loaded %s", netdev_kind_to_string(netdev->kind));
627
628         netdev = NULL;
629
630         return 0;
631 }
632
633 int netdev_load(Manager *manager) {
634         NetDev *netdev;
635         char **files, **f;
636         int r;
637
638         assert(manager);
639
640         while ((netdev = hashmap_first(manager->netdevs)))
641                 netdev_unref(netdev);
642
643         r = conf_files_list_strv(&files, ".netdev", NULL, network_dirs);
644         if (r < 0) {
645                 log_error("Failed to enumerate netdev files: %s", strerror(-r));
646                 return r;
647         }
648
649         STRV_FOREACH_BACKWARDS(f, files) {
650                 r = netdev_load_one(manager, *f);
651                 if (r < 0)
652                         return r;
653         }
654
655         strv_free(files);
656
657         return 0;
658 }