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