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