chiark / gitweb /
0d08e564e57735e7248c914905f8327bcf750b9d
[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
31 #define VLANID_MAX 4094
32
33 static const char* const netdev_kind_table[_NETDEV_KIND_MAX] = {
34         [NETDEV_KIND_BRIDGE] = "bridge",
35         [NETDEV_KIND_BOND] = "bond",
36         [NETDEV_KIND_VLAN] = "vlan",
37         [NETDEV_KIND_MACVLAN] = "macvlan",
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 };
44
45 DEFINE_STRING_TABLE_LOOKUP(netdev_kind, NetDevKind);
46 DEFINE_CONFIG_PARSE_ENUM(config_parse_netdev_kind, netdev_kind, NetDevKind, "Failed to parse netdev kind");
47
48 static const char* const macvlan_mode_table[_NETDEV_MACVLAN_MODE_MAX] = {
49         [NETDEV_MACVLAN_MODE_PRIVATE] = "private",
50         [NETDEV_MACVLAN_MODE_VEPA] = "vepa",
51         [NETDEV_MACVLAN_MODE_BRIDGE] = "bridge",
52         [NETDEV_MACVLAN_MODE_PASSTHRU] = "passthru",
53 };
54
55 DEFINE_STRING_TABLE_LOOKUP(macvlan_mode, MacVlanMode);
56 DEFINE_CONFIG_PARSE_ENUM(config_parse_macvlan_mode, macvlan_mode, MacVlanMode, "Failed to parse macvlan mode");
57
58 static void netdev_cancel_callbacks(NetDev *netdev) {
59         _cleanup_rtnl_message_unref_ sd_rtnl_message *m = NULL;
60         netdev_enslave_callback *callback;
61
62         if (!netdev)
63                 return;
64
65         rtnl_message_new_synthetic_error(-ENODEV, 0, &m);
66
67         while ((callback = netdev->callbacks)) {
68                 if (m) {
69                         assert(callback->link);
70                         assert(callback->callback);
71                         assert(netdev->manager);
72                         assert(netdev->manager->rtnl);
73
74                         callback->callback(netdev->manager->rtnl, m, link);
75                 }
76
77                 LIST_REMOVE(callbacks, netdev->callbacks, callback);
78                 free(callback);
79         }
80 }
81
82 static void netdev_free(NetDev *netdev) {
83         if (!netdev)
84                 return;
85
86         netdev_cancel_callbacks(netdev);
87
88         if (netdev->ifname)
89                 hashmap_remove(netdev->manager->netdevs, netdev->ifname);
90
91         free(netdev->filename);
92
93         free(netdev->description);
94         free(netdev->ifname);
95         free(netdev->mac);
96         free(netdev->mac_peer);
97
98         condition_free_list(netdev->match_host);
99         condition_free_list(netdev->match_virt);
100         condition_free_list(netdev->match_kernel);
101         condition_free_list(netdev->match_arch);
102
103         free(netdev);
104 }
105
106 NetDev *netdev_unref(NetDev *netdev) {
107         if (netdev && (-- netdev->n_ref <= 0))
108                 netdev_free(netdev);
109
110         return NULL;
111 }
112
113 NetDev *netdev_ref(NetDev *netdev) {
114         if (netdev)
115                 assert_se(++ netdev->n_ref >= 2);
116
117         return netdev;
118 }
119
120 void netdev_drop(NetDev *netdev) {
121         if (!netdev || netdev->state == NETDEV_STATE_LINGER)
122                 return;
123
124         netdev->state = NETDEV_STATE_LINGER;
125
126         log_debug_netdev(netdev, "netdev removed");
127
128         netdev_cancel_callbacks(netdev);
129
130         netdev_unref(netdev);
131
132         return;
133 }
134
135 int netdev_get(Manager *manager, const char *name, NetDev **ret) {
136         NetDev *netdev;
137
138         assert(manager);
139         assert(name);
140         assert(ret);
141
142         netdev = hashmap_get(manager->netdevs, name);
143         if (!netdev) {
144                 *ret = NULL;
145                 return -ENOENT;
146         }
147
148         *ret = netdev;
149
150         return 0;
151 }
152
153 static int netdev_enter_failed(NetDev *netdev) {
154         netdev->state = NETDEV_STATE_FAILED;
155
156         return 0;
157 }
158
159 static int netdev_enslave_ready(NetDev *netdev, Link* link, sd_rtnl_message_handler_t callback) {
160         _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL;
161         int r;
162
163         assert(netdev);
164         assert(netdev->state == NETDEV_STATE_READY);
165         assert(netdev->manager);
166         assert(netdev->manager->rtnl);
167         assert(link);
168         assert(callback);
169
170         r = sd_rtnl_message_new_link(netdev->manager->rtnl, &req,
171                                      RTM_SETLINK, link->ifindex);
172         if (r < 0) {
173                 log_error_netdev(netdev,
174                                  "Could not allocate RTM_SETLINK message: %s",
175                                  strerror(-r));
176                 return r;
177         }
178
179         r = sd_rtnl_message_append_u32(req, IFLA_MASTER, netdev->ifindex);
180         if (r < 0) {
181                 log_error_netdev(netdev,
182                                  "Could not append IFLA_MASTER attribute: %s",
183                                  strerror(-r));
184                 return r;
185         }
186
187         r = sd_rtnl_call_async(netdev->manager->rtnl, req, callback, link, 0, NULL);
188         if (r < 0) {
189                 log_error_netdev(netdev,
190                                  "Could not send rtnetlink message: %s",
191                                  strerror(-r));
192                 return r;
193         }
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_enslave_callback *callback;
202
203         assert(netdev);
204         assert(netdev->ifname);
205
206         if (netdev->state != NETDEV_STATE_CREATING)
207                 return 0;
208
209         netdev->state = NETDEV_STATE_READY;
210
211         log_info_netdev(netdev, "netdev ready");
212
213         LIST_FOREACH(callbacks, callback, netdev->callbacks) {
214                 /* enslave the links that were attempted to be enslaved before the
215                  * link was ready */
216                 netdev_enslave_ready(netdev, callback->link, callback->callback);
217         }
218
219         return 0;
220 }
221 static int netdev_create_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
222         NetDev *netdev = userdata;
223         int r;
224
225         assert(netdev->state != _NETDEV_STATE_INVALID);
226
227         r = sd_rtnl_message_get_errno(m);
228         if (r == -EEXIST)
229                 log_debug_netdev(netdev, "netdev exists, using existing");
230         else if (r < 0) {
231                 log_warning_netdev(netdev, "netdev could not be created: %s", strerror(-r));
232                 netdev_drop(netdev);
233
234                 return 1;
235         }
236
237         return 1;
238 }
239
240 int config_parse_tunnel_address(const char *unit,
241                                 const char *filename,
242                                 unsigned line,
243                                 const char *section,
244                                 unsigned section_line,
245                                 const char *lvalue,
246                                 int ltype,
247                                 const char *rvalue,
248                                 void *data,
249                                 void *userdata) {
250         NetDev *n = data;
251         unsigned char family = AF_INET;
252         int r;
253
254         assert(filename);
255         assert(lvalue);
256         assert(rvalue);
257         assert(data);
258
259         r = net_parse_inaddr(rvalue, &family, n);
260         if (r < 0) {
261                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
262                            "Tunnel address is invalid, ignoring assignment: %s", rvalue);
263                 return 0;
264         }
265        return 0;
266 }
267
268 static int netdev_create(NetDev *netdev, Link *link, sd_rtnl_message_handler_t callback) {
269         _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL;
270         const char *kind;
271         int r;
272
273         assert(netdev);
274         assert(!(netdev->kind == NETDEV_KIND_VLAN || netdev->kind == NETDEV_KIND_MACVLAN) ||
275                (link && callback));
276         assert(netdev->ifname);
277         assert(netdev->manager);
278         assert(netdev->manager->rtnl);
279
280         r = sd_rtnl_message_new_link(netdev->manager->rtnl, &req, RTM_NEWLINK, 0);
281         if (r < 0) {
282                 log_error_netdev(netdev,
283                                  "Could not allocate RTM_NEWLINK message: %s",
284                                  strerror(-r));
285                 return r;
286         }
287
288         if (link) {
289                 r = sd_rtnl_message_append_u32(req, IFLA_LINK, link->ifindex);
290                 if (r < 0) {
291                         log_error_netdev(netdev,
292                                          "Could not append IFLA_LINK attribute: %s",
293                                          strerror(-r));
294                         return r;
295                 }
296         }
297
298         r = sd_rtnl_message_append_string(req, IFLA_IFNAME, netdev->ifname);
299         if (r < 0) {
300                 log_error_netdev(netdev,
301                                  "Could not append IFLA_IFNAME attribute: %s",
302                                  strerror(-r));
303                 return r;
304         }
305
306         if (netdev->mtu) {
307                 r = sd_rtnl_message_append_u32(req, IFLA_MTU, netdev->mtu);
308                 if (r < 0) {
309                         log_error_netdev(netdev,
310                                          "Could not append IFLA_MTU attribute: %s",
311                                          strerror(-r));
312                         return r;
313                 }
314         }
315
316         if (netdev->mac) {
317                 r = sd_rtnl_message_append_ether_addr(req, IFLA_ADDRESS, netdev->mac);
318                 if (r < 0) {
319                         log_error_netdev(netdev,
320                                          "Colud not append IFLA_ADDRESS attribute: %s",
321                                          strerror(-r));
322                     return r;
323                 }
324         }
325
326         r = sd_rtnl_message_open_container(req, IFLA_LINKINFO);
327         if (r < 0) {
328                 log_error_netdev(netdev,
329                                  "Could not open IFLA_LINKINFO container: %s",
330                                  strerror(-r));
331                 return r;
332         }
333
334         kind = netdev_kind_to_string(netdev->kind);
335         if (!kind) {
336                 log_error_netdev(netdev, "Invalid kind");
337                 return -EINVAL;
338         }
339
340         r = sd_rtnl_message_open_container_union(req, IFLA_INFO_DATA, kind);
341         if (r < 0) {
342                 log_error_netdev(netdev,
343                                  "Could not open IFLA_INFO_DATA container: %s",
344                                   strerror(-r));
345                 return r;
346         }
347
348         if (netdev->vlanid <= VLANID_MAX) {
349                 r = sd_rtnl_message_append_u16(req, IFLA_VLAN_ID, netdev->vlanid);
350                 if (r < 0) {
351                         log_error_netdev(netdev,
352                                          "Could not append IFLA_VLAN_ID attribute: %s",
353                                          strerror(-r));
354                         return r;
355                 }
356         }
357
358         if (netdev->macvlan_mode != _NETDEV_MACVLAN_MODE_INVALID) {
359         r = sd_rtnl_message_append_u32(req, IFLA_MACVLAN_MODE, netdev->macvlan_mode);
360         if (r < 0) {
361                 log_error_netdev(netdev,
362                                  "Could not append IFLA_MACVLAN_MODE attribute: %s",
363                                  strerror(-r));
364                         return r;
365                 }
366         }
367
368         r = sd_rtnl_message_close_container(req);
369         if (r < 0) {
370                 log_error_netdev(netdev,
371                                  "Could not close IFLA_INFO_DATA container %s",
372                                  strerror(-r));
373                 return r;
374         }
375
376         r = sd_rtnl_message_close_container(req);
377         if (r < 0) {
378                 log_error_netdev(netdev,
379                                  "Could not close IFLA_LINKINFO container %s",
380                                  strerror(-r));
381                 return r;
382         }
383
384         if (link)
385                 r = sd_rtnl_call_async(netdev->manager->rtnl, req, callback, link, 0, NULL);
386         else
387                 r = sd_rtnl_call_async(netdev->manager->rtnl, req, &netdev_create_handler, netdev, 0, NULL);
388         if (r < 0) {
389                 log_error_netdev(netdev,
390                                  "Could not send rtnetlink message: %s", strerror(-r));
391                 return r;
392         }
393
394         log_debug_netdev(netdev, "creating netdev");
395
396         netdev->state = NETDEV_STATE_CREATING;
397
398         return 0;
399 }
400
401 int netdev_enslave(NetDev *netdev, Link *link, sd_rtnl_message_handler_t callback) {
402         int r;
403
404         if (netdev->kind == NETDEV_KIND_VLAN || netdev->kind == NETDEV_KIND_MACVLAN)
405                 return netdev_create(netdev, link, callback);
406
407         if(netdev->kind == NETDEV_KIND_IPIP ||
408            netdev->kind == NETDEV_KIND_GRE ||
409            netdev->kind ==  NETDEV_KIND_SIT ||
410            netdev->kind ==  NETDEV_KIND_VTI)
411                 return netdev_create_tunnel(link, netdev_create_handler);
412
413         if (netdev->state == NETDEV_STATE_READY) {
414                 r = netdev_enslave_ready(netdev, link, callback);
415                 if (r < 0)
416                         return r;
417         } else {
418                 /* the netdev is not yet read, save this request for when it is*/
419                 netdev_enslave_callback *cb;
420
421                 cb = new0(netdev_enslave_callback, 1);
422                 if (!cb)
423                         return log_oom();
424
425                 cb->callback = callback;
426                 cb->link = link;
427
428                 LIST_PREPEND(callbacks, netdev->callbacks, cb);
429         }
430
431         return 0;
432 }
433
434 int netdev_set_ifindex(NetDev *netdev, sd_rtnl_message *message) {
435         uint16_t type;
436         const char *kind;
437         char *received_kind;
438         char *received_name;
439         int r, ifindex;
440
441         assert(netdev);
442         assert(message);
443
444         r = sd_rtnl_message_get_type(message, &type);
445         if (r < 0) {
446                 log_error_netdev(netdev, "Could not get rtnl message type");
447                 return r;
448         }
449
450         if (type != RTM_NEWLINK) {
451                 log_error_netdev(netdev, "Can not set ifindex from unexpected rtnl message type");
452                 return -EINVAL;
453         }
454
455         r = sd_rtnl_message_link_get_ifindex(message, &ifindex);
456         if (r < 0) {
457                 log_error_netdev(netdev, "Could not get ifindex: %s", strerror(-r));
458                 netdev_enter_failed(netdev);
459                 return r;
460         } else if (ifindex <= 0) {
461                 log_error_netdev(netdev, "Got invalid ifindex: %d", ifindex);
462                 netdev_enter_failed(netdev);
463                 return r;
464         }
465
466         if (netdev->ifindex > 0) {
467                 if (netdev->ifindex != ifindex) {
468                         log_error_netdev(netdev, "Could not set ifindex to %d, already set to %d",
469                                          ifindex, netdev->ifindex);
470                         netdev_enter_failed(netdev);
471                         return -EEXIST;
472                 } else
473                         /* ifindex already set to the same for this netdev */
474                         return 0;
475         }
476
477         r = sd_rtnl_message_read_string(message, IFLA_IFNAME, &received_name);
478         if (r < 0) {
479                 log_error_netdev(netdev, "Could not get IFNAME");
480                 return r;
481         }
482
483         if (!streq(netdev->ifname, received_name)) {
484                 log_error_netdev(netdev, "Received newlink with wrong IFNAME %s",
485                                  received_name);
486                 netdev_enter_failed(netdev);
487                 return r;
488         }
489
490         r = sd_rtnl_message_enter_container(message, IFLA_LINKINFO);
491         if (r < 0) {
492                 log_error_netdev(netdev, "Could not get LINKINFO");
493                 return r;
494         }
495
496         r = sd_rtnl_message_read_string(message, IFLA_INFO_KIND, &received_kind);
497         if (r < 0) {
498                 log_error_netdev(netdev, "Could not get KIND");
499                 return r;
500         }
501
502         r = sd_rtnl_message_exit_container(message);
503         if (r < 0) {
504                 log_error_netdev(netdev, "Could not exit container");
505                 return r;
506         }
507
508         kind = netdev_kind_to_string(netdev->kind);
509         if (!kind) {
510                 log_error_netdev(netdev, "Could not get kind");
511                 netdev_enter_failed(netdev);
512                 return -EINVAL;
513         }
514
515         if (!streq(kind, received_kind)) {
516                 log_error_netdev(netdev, "Received newlink with wrong KIND %s, "
517                                  "expected %s", received_kind, kind);
518                 netdev_enter_failed(netdev);
519                 return r;
520         }
521
522         netdev->ifindex = ifindex;
523
524         log_debug_netdev(netdev, "netdev has index %d", netdev->ifindex);
525
526         netdev_enter_ready(netdev);
527
528         return 0;
529 }
530
531 static int netdev_load_one(Manager *manager, const char *filename) {
532         _cleanup_netdev_unref_ NetDev *netdev = NULL;
533         _cleanup_fclose_ FILE *file = NULL;
534         int r;
535
536         assert(manager);
537         assert(filename);
538
539         if (null_or_empty_path(filename)) {
540                 log_debug("skipping empty file: %s", filename);
541                 return 0;
542         }
543
544         file = fopen(filename, "re");
545         if (!file) {
546                 if (errno == ENOENT)
547                         return 0;
548                 else
549                         return -errno;
550         }
551
552         netdev = new0(NetDev, 1);
553         if (!netdev)
554                 return log_oom();
555
556         netdev->n_ref = 1;
557         netdev->manager = manager;
558         netdev->state = _NETDEV_STATE_INVALID;
559         netdev->kind = _NETDEV_KIND_INVALID;
560         netdev->macvlan_mode = _NETDEV_MACVLAN_MODE_INVALID;
561         netdev->vlanid = VLANID_MAX + 1;
562         netdev->tunnel_pmtudisc = true;
563
564         r = config_parse(NULL, filename, file, "Match\0NetDev\0VLAN\0MACVLAN\0Tunnel\0Peer\0",
565                          config_item_perf_lookup, (void*) network_netdev_gperf_lookup,
566                          false, false, netdev);
567         if (r < 0) {
568                 log_warning("Could not parse config file %s: %s", filename, strerror(-r));
569                 return r;
570         }
571
572         if (netdev->kind == _NETDEV_KIND_INVALID) {
573                 log_warning("NetDev without Kind configured in %s. Ignoring", filename);
574                 return 0;
575         }
576
577         if (!netdev->ifname) {
578                 log_warning("NetDev without Name configured in %s. Ignoring", filename);
579                 return 0;
580         }
581
582         if (netdev->kind == NETDEV_KIND_VLAN && netdev->vlanid > VLANID_MAX) {
583                 log_warning("VLAN without valid Id configured in %s. Ignoring", filename);
584                 return 0;
585         }
586
587         if (netdev->kind != NETDEV_KIND_VLAN && netdev->vlanid <= VLANID_MAX) {
588                 log_warning("VLAN Id configured for a %s in %s. Ignoring",
589                             netdev_kind_to_string(netdev->kind), filename);
590                 return 0;
591         }
592
593         if (netdev->kind != NETDEV_KIND_MACVLAN &&
594             netdev->macvlan_mode != _NETDEV_MACVLAN_MODE_INVALID) {
595                 log_warning("MACVLAN Mode configured for a %s in %s. Ignoring",
596                             netdev_kind_to_string(netdev->kind), filename);
597                 return 0;
598         }
599
600         netdev->filename = strdup(filename);
601         if (!netdev->filename)
602                 return log_oom();
603
604         if (net_match_config(NULL, NULL, NULL, NULL, NULL,
605                              netdev->match_host, netdev->match_virt,
606                              netdev->match_kernel, netdev->match_arch,
607                              NULL, NULL, NULL, NULL, NULL, NULL) <= 0)
608                 return 0;
609
610         r = hashmap_put(netdev->manager->netdevs, netdev->ifname, netdev);
611         if (r < 0)
612                 return r;
613
614         LIST_HEAD_INIT(netdev->callbacks);
615
616         if(netdev->kind == NETDEV_KIND_VETH)
617                 return netdev_create_veth(netdev, netdev_create_handler);
618
619         if (netdev->kind != NETDEV_KIND_VLAN &&
620             netdev->kind != NETDEV_KIND_MACVLAN &&
621             netdev->kind != NETDEV_KIND_IPIP &&
622             netdev->kind != NETDEV_KIND_GRE &&
623             netdev->kind != NETDEV_KIND_SIT &&
624             netdev->kind != NETDEV_KIND_VTI) {
625                 r = netdev_create(netdev, NULL, NULL);
626                 if (r < 0)
627                         return r;
628         }
629
630         log_debug_netdev(netdev, "loaded %s", netdev_kind_to_string(netdev->kind));
631
632         netdev = NULL;
633
634         return 0;
635 }
636
637 int netdev_load(Manager *manager) {
638         NetDev *netdev;
639         char **files, **f;
640         int r;
641
642         assert(manager);
643
644         while ((netdev = hashmap_first(manager->netdevs)))
645                 netdev_unref(netdev);
646
647         r = conf_files_list_strv(&files, ".netdev", NULL, network_dirs);
648         if (r < 0) {
649                 log_error("Failed to enumerate netdev files: %s", strerror(-r));
650                 return r;
651         }
652
653         STRV_FOREACH_BACKWARDS(f, files) {
654                 r = netdev_load_one(manager, *f);
655                 if (r < 0)
656                         return r;
657         }
658
659         strv_free(files);
660
661         return 0;
662 }