chiark / gitweb /
8b96d60dcab6a98d3ec15dc8bfec810ac0de04d0
[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-netdev.h"
25 #include "networkd-netdev-bridge.h"
26 #include "networkd-netdev-bond.h"
27 #include "networkd-netdev-vlan.h"
28 #include "networkd-netdev-macvlan.h"
29 #include "networkd-netdev-vxlan.h"
30 #include "networkd-netdev-tunnel.h"
31 #include "networkd-netdev-veth.h"
32 #include "networkd-netdev-dummy.h"
33 #include "networkd-netdev-tuntap.h"
34 #include "network-internal.h"
35 #include "path-util.h"
36 #include "conf-files.h"
37 #include "conf-parser.h"
38 #include "list.h"
39 #include "siphash24.h"
40
41 const NetDevVTable * const netdev_vtable[_NETDEV_KIND_MAX] = {
42         [NETDEV_KIND_BRIDGE] = &bridge_vtable,
43         [NETDEV_KIND_BOND] = &bond_vtable,
44         [NETDEV_KIND_VLAN] = &vlan_vtable,
45         [NETDEV_KIND_MACVLAN] = &macvlan_vtable,
46         [NETDEV_KIND_VXLAN] = &vxlan_vtable,
47         [NETDEV_KIND_IPIP] = &ipip_vtable,
48         [NETDEV_KIND_GRE] = &gre_vtable,
49         [NETDEV_KIND_SIT] = &sit_vtable,
50         [NETDEV_KIND_VTI] = &vti_vtable,
51         [NETDEV_KIND_VETH] = &veth_vtable,
52         [NETDEV_KIND_DUMMY] = &dummy_vtable,
53         [NETDEV_KIND_TUN] = &tun_vtable,
54         [NETDEV_KIND_TAP] = &tap_vtable,
55 };
56
57 static const char* const netdev_kind_table[_NETDEV_KIND_MAX] = {
58         [NETDEV_KIND_BRIDGE] = "bridge",
59         [NETDEV_KIND_BOND] = "bond",
60         [NETDEV_KIND_VLAN] = "vlan",
61         [NETDEV_KIND_MACVLAN] = "macvlan",
62         [NETDEV_KIND_VXLAN] = "vxlan",
63         [NETDEV_KIND_IPIP] = "ipip",
64         [NETDEV_KIND_GRE] = "gre",
65         [NETDEV_KIND_SIT] = "sit",
66         [NETDEV_KIND_VETH] = "veth",
67         [NETDEV_KIND_VTI] = "vti",
68         [NETDEV_KIND_DUMMY] = "dummy",
69         [NETDEV_KIND_TUN] = "tun",
70         [NETDEV_KIND_TAP] = "tap",
71 };
72
73 DEFINE_STRING_TABLE_LOOKUP(netdev_kind, NetDevKind);
74 DEFINE_CONFIG_PARSE_ENUM(config_parse_netdev_kind, netdev_kind, NetDevKind, "Failed to parse netdev kind");
75
76
77 static void netdev_cancel_callbacks(NetDev *netdev) {
78         _cleanup_rtnl_message_unref_ sd_rtnl_message *m = NULL;
79         netdev_join_callback *callback;
80
81         if (!netdev)
82                 return;
83
84         rtnl_message_new_synthetic_error(-ENODEV, 0, &m);
85
86         while ((callback = netdev->callbacks)) {
87                 if (m) {
88                         assert(callback->link);
89                         assert(callback->callback);
90                         assert(netdev->manager);
91                         assert(netdev->manager->rtnl);
92
93                         callback->callback(netdev->manager->rtnl, m, link);
94                 }
95
96                 LIST_REMOVE(callbacks, netdev->callbacks, callback);
97                 free(callback);
98         }
99 }
100
101 static void netdev_free(NetDev *netdev) {
102         if (!netdev)
103                 return;
104
105         netdev_cancel_callbacks(netdev);
106
107         if (netdev->ifname)
108                 hashmap_remove(netdev->manager->netdevs, netdev->ifname);
109
110         free(netdev->filename);
111
112         free(netdev->description);
113         free(netdev->ifname);
114         free(netdev->ifname_peer);
115         free(netdev->mac);
116         free(netdev->mac_peer);
117         free(netdev->user_name);
118         free(netdev->group_name);
119
120         condition_free_list(netdev->match_host);
121         condition_free_list(netdev->match_virt);
122         condition_free_list(netdev->match_kernel);
123         condition_free_list(netdev->match_arch);
124
125         free(netdev);
126 }
127
128 NetDev *netdev_unref(NetDev *netdev) {
129         if (netdev && (-- netdev->n_ref <= 0))
130                 netdev_free(netdev);
131
132         return NULL;
133 }
134
135 NetDev *netdev_ref(NetDev *netdev) {
136         if (netdev)
137                 assert_se(++ netdev->n_ref >= 2);
138
139         return netdev;
140 }
141
142 void netdev_drop(NetDev *netdev) {
143         if (!netdev || netdev->state == NETDEV_STATE_LINGER)
144                 return;
145
146         netdev->state = NETDEV_STATE_LINGER;
147
148         log_debug_netdev(netdev, "netdev removed");
149
150         netdev_cancel_callbacks(netdev);
151
152         netdev_unref(netdev);
153
154         return;
155 }
156
157 int netdev_get(Manager *manager, const char *name, NetDev **ret) {
158         NetDev *netdev;
159
160         assert(manager);
161         assert(name);
162         assert(ret);
163
164         netdev = hashmap_get(manager->netdevs, name);
165         if (!netdev) {
166                 *ret = NULL;
167                 return -ENOENT;
168         }
169
170         *ret = netdev;
171
172         return 0;
173 }
174
175 static int netdev_enter_failed(NetDev *netdev) {
176         netdev->state = NETDEV_STATE_FAILED;
177
178         return 0;
179 }
180
181 static int netdev_enslave_ready(NetDev *netdev, Link* link, sd_rtnl_message_handler_t callback) {
182         _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL;
183         int r;
184
185         assert(netdev);
186         assert(netdev->state == NETDEV_STATE_READY);
187         assert(netdev->manager);
188         assert(netdev->manager->rtnl);
189         assert(IN_SET(netdev->kind, NETDEV_KIND_BRIDGE, NETDEV_KIND_BOND));
190         assert(link);
191         assert(callback);
192
193         r = sd_rtnl_message_new_link(netdev->manager->rtnl, &req,
194                                      RTM_SETLINK, link->ifindex);
195         if (r < 0) {
196                 log_error_netdev(netdev,
197                                  "Could not allocate RTM_SETLINK message: %s",
198                                  strerror(-r));
199                 return r;
200         }
201
202         r = sd_rtnl_message_append_u32(req, IFLA_MASTER, netdev->ifindex);
203         if (r < 0) {
204                 log_error_netdev(netdev,
205                                  "Could not append IFLA_MASTER attribute: %s",
206                                  strerror(-r));
207                 return r;
208         }
209
210         r = sd_rtnl_call_async(netdev->manager->rtnl, req, callback, link, 0, NULL);
211         if (r < 0) {
212                 log_error_netdev(netdev,
213                                  "Could not send rtnetlink message: %s",
214                                  strerror(-r));
215                 return r;
216         }
217
218         link_ref(link);
219
220         log_debug_netdev(netdev, "enslaving link '%s'", link->ifname);
221
222         return 0;
223 }
224
225 static int netdev_enter_ready(NetDev *netdev) {
226         netdev_join_callback *callback, *callback_next;
227         int r;
228
229         assert(netdev);
230         assert(netdev->ifname);
231
232         if (netdev->state != NETDEV_STATE_CREATING)
233                 return 0;
234
235         netdev->state = NETDEV_STATE_READY;
236
237         log_info_netdev(netdev, "netdev ready");
238
239         LIST_FOREACH_SAFE(callbacks, callback, callback_next, netdev->callbacks) {
240                 /* enslave the links that were attempted to be enslaved before the
241                  * link was ready */
242                 r = netdev_enslave_ready(netdev, callback->link, callback->callback);
243                 if (r < 0)
244                         return r;
245
246                 LIST_REMOVE(callbacks, netdev->callbacks, callback);
247                 link_unref(callback->link);
248                 free(callback);
249         }
250
251         return 0;
252 }
253
254 /* callback for netdev's created without a backing Link */
255 static int netdev_create_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
256         _cleanup_netdev_unref_ NetDev *netdev = userdata;
257         int r;
258
259         assert(netdev->state != _NETDEV_STATE_INVALID);
260
261         r = sd_rtnl_message_get_errno(m);
262         if (r == -EEXIST)
263                 log_debug_netdev(netdev, "netdev exists, using existing");
264         else if (r < 0) {
265                 log_warning_netdev(netdev, "netdev could not be created: %s", strerror(-r));
266                 netdev_drop(netdev);
267
268                 return 1;
269         }
270
271         return 1;
272 }
273
274 int netdev_enslave(NetDev *netdev, Link *link, sd_rtnl_message_handler_t callback) {
275         int r;
276
277         assert(netdev);
278         assert(IN_SET(netdev->kind, NETDEV_KIND_BRIDGE, NETDEV_KIND_BOND));
279
280         if (netdev->state == NETDEV_STATE_READY) {
281                 r = netdev_enslave_ready(netdev, link, callback);
282                 if (r < 0)
283                         return r;
284         } else {
285                 /* the netdev is not yet read, save this request for when it is*/
286                 netdev_join_callback *cb;
287
288                 cb = new0(netdev_join_callback, 1);
289                 if (!cb)
290                         return log_oom();
291
292                 cb->callback = callback;
293                 cb->link = link;
294                 link_ref(link);
295
296                 LIST_PREPEND(callbacks, netdev->callbacks, cb);
297         }
298
299         return 0;
300 }
301
302 /* the callback must be called, possibly after a timeout, as otherwise the Link will hang */
303 int netdev_join(NetDev *netdev, Link *link, sd_rtnl_message_handler_t callback) {
304         int r;
305
306         assert(netdev);
307         assert(netdev->manager);
308         assert(netdev->manager->rtnl);
309         assert(NETDEV_VTABLE(netdev));
310
311         if (NETDEV_VTABLE(netdev)->fill_message_create_on_link) {
312                 _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL;
313
314                 r = sd_rtnl_message_new_link(netdev->manager->rtnl, &req,
315                                              RTM_NEWLINK, 0);
316                 if (r < 0) {
317                         log_error_netdev(netdev,
318                                          "Could not allocate RTM_SETLINK message: %s",
319                                          strerror(-r));
320                         return r;
321                 }
322
323                 NETDEV_VTABLE(netdev)->fill_message_create_on_link(netdev, link, req);
324
325                 r = sd_rtnl_call_async(netdev->manager->rtnl, req, callback, link, 0, NULL);
326                 if (r < 0) {
327                         log_error_netdev(netdev,
328                                          "Could not send rtnetlink message: %s", strerror(-r));
329                         return r;
330                 }
331
332                 link_ref(link);
333         } else if (NETDEV_VTABLE(netdev)->enslave) {
334                 return NETDEV_VTABLE(netdev)->enslave(netdev, link, callback);
335         } else
336                 assert_not_reached("Joining link to netdev of invalid kind");
337
338         return 0;
339 }
340
341 int netdev_set_ifindex(NetDev *netdev, sd_rtnl_message *message) {
342         uint16_t type;
343         const char *kind;
344         char *received_kind;
345         char *received_name;
346         int r, ifindex;
347
348         assert(netdev);
349         assert(message);
350
351         r = sd_rtnl_message_get_type(message, &type);
352         if (r < 0) {
353                 log_error_netdev(netdev, "Could not get rtnl message type");
354                 return r;
355         }
356
357         if (type != RTM_NEWLINK) {
358                 log_error_netdev(netdev, "Can not set ifindex from unexpected rtnl message type");
359                 return -EINVAL;
360         }
361
362         r = sd_rtnl_message_link_get_ifindex(message, &ifindex);
363         if (r < 0) {
364                 log_error_netdev(netdev, "Could not get ifindex: %s", strerror(-r));
365                 netdev_enter_failed(netdev);
366                 return r;
367         } else if (ifindex <= 0) {
368                 log_error_netdev(netdev, "Got invalid ifindex: %d", ifindex);
369                 netdev_enter_failed(netdev);
370                 return r;
371         }
372
373         if (netdev->ifindex > 0) {
374                 if (netdev->ifindex != ifindex) {
375                         log_error_netdev(netdev, "Could not set ifindex to %d, already set to %d",
376                                          ifindex, netdev->ifindex);
377                         netdev_enter_failed(netdev);
378                         return -EEXIST;
379                 } else
380                         /* ifindex already set to the same for this netdev */
381                         return 0;
382         }
383
384         r = sd_rtnl_message_read_string(message, IFLA_IFNAME, &received_name);
385         if (r < 0) {
386                 log_error_netdev(netdev, "Could not get IFNAME");
387                 return r;
388         }
389
390         if (!streq(netdev->ifname, received_name)) {
391                 log_error_netdev(netdev, "Received newlink with wrong IFNAME %s",
392                                  received_name);
393                 netdev_enter_failed(netdev);
394                 return r;
395         }
396
397         r = sd_rtnl_message_enter_container(message, IFLA_LINKINFO);
398         if (r < 0) {
399                 log_error_netdev(netdev, "Could not get LINKINFO");
400                 return r;
401         }
402
403         r = sd_rtnl_message_read_string(message, IFLA_INFO_KIND, &received_kind);
404         if (r < 0) {
405                 log_error_netdev(netdev, "Could not get KIND");
406                 return r;
407         }
408
409         r = sd_rtnl_message_exit_container(message);
410         if (r < 0) {
411                 log_error_netdev(netdev, "Could not exit container");
412                 return r;
413         }
414
415         if (netdev->kind == NETDEV_KIND_TAP)
416                 /* the kernel does not distinguish between tun and tap */
417                 kind = "tun";
418         else {
419                 kind = netdev_kind_to_string(netdev->kind);
420                 if (!kind) {
421                         log_error_netdev(netdev, "Could not get kind");
422                         netdev_enter_failed(netdev);
423                         return -EINVAL;
424                 }
425         }
426
427         if (!streq(kind, received_kind)) {
428                 log_error_netdev(netdev,
429                                  "Received newlink with wrong KIND %s, "
430                                  "expected %s", received_kind, kind);
431                 netdev_enter_failed(netdev);
432                 return r;
433         }
434
435         netdev->ifindex = ifindex;
436
437         log_debug_netdev(netdev, "netdev has index %d", netdev->ifindex);
438
439         netdev_enter_ready(netdev);
440
441         return 0;
442 }
443
444 #define HASH_KEY SD_ID128_MAKE(52,e1,45,bd,00,6f,29,96,21,c6,30,6d,83,71,04,48)
445
446 int netdev_get_mac(const char *ifname, struct ether_addr **ret) {
447         _cleanup_free_ struct ether_addr *mac = NULL;
448         uint8_t result[8];
449         size_t l, sz;
450         uint8_t *v;
451         int r;
452
453         assert(ifname);
454         assert(ret);
455
456         mac = new0(struct ether_addr, 1);
457         if (!mac)
458                 return -ENOMEM;
459
460         l = strlen(ifname);
461         sz = sizeof(sd_id128_t) + l;
462         v = alloca(sz);
463
464         /* fetch some persistent data unique to the machine */
465         r = sd_id128_get_machine((sd_id128_t*) v);
466         if (r < 0)
467                 return r;
468
469         /* combine with some data unique (on this machine) to this
470          * netdev */
471         memcpy(v + sizeof(sd_id128_t), ifname, l);
472
473         /* Let's hash the host machine ID plus the container name. We
474          * use a fixed, but originally randomly created hash key here. */
475         siphash24(result, v, sz, HASH_KEY.bytes);
476
477         assert_cc(ETH_ALEN <= sizeof(result));
478         memcpy(mac->ether_addr_octet, result, ETH_ALEN);
479
480         /* see eth_random_addr in the kernel */
481         mac->ether_addr_octet[0] &= 0xfe;        /* clear multicast bit */
482         mac->ether_addr_octet[0] |= 0x02;        /* set local assignment bit (IEEE802) */
483
484         *ret = mac;
485         mac = NULL;
486
487         return 0;
488 }
489
490 static int netdev_load_one(Manager *manager, const char *filename) {
491         _cleanup_netdev_unref_ NetDev *netdev = NULL;
492         _cleanup_fclose_ FILE *file = NULL;
493         int r;
494
495         assert(manager);
496         assert(filename);
497
498         file = fopen(filename, "re");
499         if (!file) {
500                 if (errno == ENOENT)
501                         return 0;
502                 else
503                         return -errno;
504         }
505
506         if (null_or_empty_fd(fileno(file))) {
507                 log_debug("Skipping empty file: %s", filename);
508                 return 0;
509         }
510
511         netdev = new0(NetDev, 1);
512         if (!netdev)
513                 return log_oom();
514
515         netdev->n_ref = 1;
516         netdev->manager = manager;
517         netdev->state = _NETDEV_STATE_INVALID;
518         netdev->kind = _NETDEV_KIND_INVALID;
519         netdev->macvlan_mode = _NETDEV_MACVLAN_MODE_INVALID;
520         netdev->bond_mode = _NETDEV_BOND_MODE_INVALID;
521         netdev->vlanid = VLANID_MAX + 1;
522         netdev->vxlanid = VXLAN_VID_MAX + 1;
523         netdev->tunnel_pmtudisc = true;
524         netdev->learning = true;
525
526         r = config_parse(NULL, filename, file,
527                          "Match\0NetDev\0VLAN\0MACVLAN\0VXLAN\0Tunnel\0Peer\0Tun\0Tap\0Bond\0",
528                          config_item_perf_lookup, network_netdev_gperf_lookup,
529                          false, false, true, netdev);
530         if (r < 0)
531                 return r;
532
533         /* skip out early if configuration does not match the environment */
534         if (net_match_config(NULL, NULL, NULL, NULL, NULL,
535                              netdev->match_host, netdev->match_virt,
536                              netdev->match_kernel, netdev->match_arch,
537                              NULL, NULL, NULL, NULL, NULL, NULL) <= 0)
538                 return 0;
539
540         if (!NETDEV_VTABLE(netdev)) {
541                 log_warning("NetDev with invalid Kind configured in %s. Igonring", filename);
542                 return 0;
543         }
544
545         /* verify configuration */
546         if (NETDEV_VTABLE(netdev)->config_verify) {
547                 r = NETDEV_VTABLE(netdev)->config_verify(netdev, filename);
548                 if (r < 0)
549                         return 0;
550         }
551
552         if (!netdev->ifname) {
553                 log_warning("NetDev without Name configured in %s. Ignoring", filename);
554                 return 0;
555         }
556
557         if (netdev->kind != NETDEV_KIND_VLAN && netdev->vlanid <= VLANID_MAX) {
558                 log_warning("VLAN Id configured for a %s in %s. Ignoring",
559                             netdev_kind_to_string(netdev->kind), filename);
560                 return 0;
561         }
562
563         if (netdev->kind != NETDEV_KIND_VXLAN && netdev->vxlanid <= VXLAN_VID_MAX) {
564                 log_warning("VXLAN Id configured for a %s in %s. Ignoring",
565                             netdev_kind_to_string(netdev->kind), filename);
566                 return 0;
567         }
568
569         if (netdev->kind != NETDEV_KIND_MACVLAN &&
570             netdev->macvlan_mode != _NETDEV_MACVLAN_MODE_INVALID) {
571                 log_warning("MACVLAN Mode configured for a %s in %s. Ignoring",
572                             netdev_kind_to_string(netdev->kind), filename);
573                 return 0;
574         }
575
576         netdev->filename = strdup(filename);
577         if (!netdev->filename)
578                 return log_oom();
579
580         if (!netdev->mac) {
581                 r = netdev_get_mac(netdev->ifname, &netdev->mac);
582                 if (r < 0) {
583                         log_error("Failed to generate predictable MAC address for %s",
584                                   netdev->ifname);
585                         return r;
586                 }
587         }
588
589         r = hashmap_put(netdev->manager->netdevs, netdev->ifname, netdev);
590         if (r < 0)
591                 return r;
592
593         LIST_HEAD_INIT(netdev->callbacks);
594
595         log_debug_netdev(netdev, "loaded %s", netdev_kind_to_string(netdev->kind));
596
597         /* create netdev */
598         if (NETDEV_VTABLE(netdev)->fill_message_create) {
599                 _cleanup_rtnl_message_unref_ sd_rtnl_message *m = NULL;
600
601                 r = sd_rtnl_message_new_link(netdev->manager->rtnl, &m, RTM_NEWLINK, 0);
602                 if (r < 0) {
603                         log_error_netdev(netdev,
604                                          "Could not allocate RTM_NEWLINK message: %s",
605                                          strerror(-r));
606                         return r;
607                 }
608
609                 r = NETDEV_VTABLE(netdev)->fill_message_create(netdev, m);
610                 if (r < 0)
611                         return r;
612
613                 r = sd_rtnl_call_async(netdev->manager->rtnl, m, netdev_create_handler, netdev, 0, NULL);
614                 if (r < 0) {
615                         log_error_netdev(netdev,
616                                          "Could not send rtnetlink message: %s", strerror(-r));
617                         return r;
618                 }
619
620                 netdev_ref(netdev);
621
622                 log_debug_netdev(netdev, "creating");
623
624                 netdev->state = NETDEV_STATE_CREATING;
625         } else if (NETDEV_VTABLE(netdev)->create) {
626                 r = NETDEV_VTABLE(netdev)->create(netdev);
627                 if (r < 0)
628                         return r;
629         }
630
631         netdev = NULL;
632
633         return 0;
634 }
635
636 int netdev_load(Manager *manager) {
637         NetDev *netdev;
638         char **files, **f;
639         int r;
640
641         assert(manager);
642
643         while ((netdev = hashmap_first(manager->netdevs)))
644                 netdev_unref(netdev);
645
646         r = conf_files_list_strv(&files, ".netdev", NULL, network_dirs);
647         if (r < 0) {
648                 log_error("Failed to enumerate netdev files: %s", strerror(-r));
649                 return r;
650         }
651
652         STRV_FOREACH_BACKWARDS(f, files) {
653                 r = netdev_load_one(manager, *f);
654                 if (r < 0)
655                         return r;
656         }
657
658         strv_free(files);
659
660         return 0;
661 }