chiark / gitweb /
networkd: refactor socket activation a bit
[elogind.git] / src / network / networkd-netdev-tunnel.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4     This file is part of systemd.
5
6     Copyright 2014 Susant Sahani
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 <netinet/ether.h>
23 #include <arpa/inet.h>
24 #include <net/if.h>
25 #include <linux/ip.h>
26 #include <linux/if_tunnel.h>
27 #include <linux/ip6_tunnel.h>
28
29 #include "sd-rtnl.h"
30 #include "networkd-netdev-tunnel.h"
31 #include "networkd-link.h"
32 #include "network-internal.h"
33 #include "util.h"
34 #include "missing.h"
35 #include "conf-parser.h"
36
37 #define DEFAULT_TNL_HOP_LIMIT   64
38
39 static const char* const ip6tnl_mode_table[_NETDEV_IP6_TNL_MODE_MAX] = {
40         [NETDEV_IP6_TNL_MODE_IP6IP6] = "ip6ip6",
41         [NETDEV_IP6_TNL_MODE_IPIP6] = "ipip6",
42         [NETDEV_IP6_TNL_MODE_ANYIP6] = "any",
43 };
44
45 DEFINE_STRING_TABLE_LOOKUP(ip6tnl_mode, Ip6TnlMode);
46 DEFINE_CONFIG_PARSE_ENUM(config_parse_ip6tnl_mode, ip6tnl_mode, Ip6TnlMode, "Failed to parse ip6 tunnel Mode");
47
48 static int netdev_ipip_fill_message_create(NetDev *netdev, Link *link, sd_rtnl_message *m) {
49         Tunnel *t = IPIP(netdev);
50         int r;
51
52         assert(netdev);
53         assert(link);
54         assert(m);
55         assert(t);
56         assert(t->family == AF_INET);
57
58         r = sd_rtnl_message_append_u32(m, IFLA_IPTUN_LINK, link->ifindex);
59         if (r < 0) {
60                 log_netdev_error(netdev,
61                                  "Could not append IFLA_IPTUN_LINK attribute: %s",
62                                  strerror(-r));
63                 return r;
64         }
65
66         r = sd_rtnl_message_append_in_addr(m, IFLA_IPTUN_LOCAL, &t->local.in);
67         if (r < 0) {
68                 log_netdev_error(netdev,
69                                  "Could not append IFLA_IPTUN_LOCAL attribute: %s",
70                                  strerror(-r));
71                 return r;
72         }
73
74         r = sd_rtnl_message_append_in_addr(m, IFLA_IPTUN_REMOTE, &t->remote.in);
75         if (r < 0) {
76                 log_netdev_error(netdev,
77                                  "Could not append IFLA_IPTUN_REMOTE attribute: %s",
78                                  strerror(-r));
79                 return r;
80         }
81
82         r = sd_rtnl_message_append_u8(m, IFLA_IPTUN_TTL, t->ttl);
83         if (r < 0) {
84                 log_netdev_error(netdev,
85                                  "Could not append IFLA_IPTUN_TTL  attribute: %s",
86                                  strerror(-r));
87                 return r;
88         }
89
90         r = sd_rtnl_message_append_u8(m, IFLA_IPTUN_PMTUDISC, t->pmtudisc);
91         if (r < 0) {
92                 log_netdev_error(netdev,
93                                  "Could not append IFLA_IPTUN_PMTUDISC attribute: %s",
94                                  strerror(-r));
95                 return r;
96         }
97
98         return r;
99 }
100
101 static int netdev_sit_fill_message_create(NetDev *netdev, Link *link, sd_rtnl_message *m) {
102         Tunnel *t = SIT(netdev);
103         int r;
104
105         assert(netdev);
106         assert(link);
107         assert(m);
108         assert(t);
109         assert(t->family == AF_INET);
110
111         r = sd_rtnl_message_append_u32(m, IFLA_IPTUN_LINK, link->ifindex);
112         if (r < 0) {
113                 log_netdev_error(netdev,
114                                  "Could not append IFLA_IPTUN_LINK attribute: %s",
115                                  strerror(-r));
116                 return r;
117         }
118
119         r = sd_rtnl_message_append_in_addr(m, IFLA_IPTUN_LOCAL, &t->local.in);
120         if (r < 0) {
121                 log_netdev_error(netdev,
122                                  "Could not append IFLA_IPTUN_LOCAL attribute: %s",
123                                  strerror(-r));
124                 return r;
125         }
126
127         r = sd_rtnl_message_append_in_addr(m, IFLA_IPTUN_REMOTE, &t->remote.in);
128         if (r < 0) {
129                 log_netdev_error(netdev,
130                                  "Could not append IFLA_IPTUN_REMOTE attribute: %s",
131                                  strerror(-r));
132                 return r;
133         }
134
135         r = sd_rtnl_message_append_u8(m, IFLA_IPTUN_TTL, t->ttl);
136         if (r < 0) {
137                 log_netdev_error(netdev,
138                                  "Could not append IFLA_IPTUN_TTL attribute: %s",
139                                  strerror(-r));
140                 return r;
141         }
142
143         r = sd_rtnl_message_append_u8(m, IFLA_IPTUN_PMTUDISC, t->pmtudisc);
144         if (r < 0) {
145                 log_netdev_error(netdev,
146                                  "Could not append IFLA_IPTUN_PMTUDISC attribute: %s",
147                                  strerror(-r));
148                 return r;
149         }
150
151         return r;
152 }
153
154 static int netdev_gre_fill_message_create(NetDev *netdev, Link *link, sd_rtnl_message *m) {
155         Tunnel *t;
156         int r;
157
158         assert(netdev);
159
160         if (netdev->kind == NETDEV_KIND_GRE)
161                  t = GRE(netdev);
162         else
163                  t = GRETAP(netdev);
164
165         assert(t);
166         assert(t->family == AF_INET);
167         assert(link);
168         assert(m);
169
170         r = sd_rtnl_message_append_u32(m, IFLA_GRE_LINK, link->ifindex);
171         if (r < 0) {
172                 log_netdev_error(netdev,
173                                  "Could not append IFLA_GRE_LINK attribute: %s",
174                                  strerror(-r));
175                 return r;
176         }
177
178         r = sd_rtnl_message_append_in_addr(m, IFLA_GRE_LOCAL, &t->local.in);
179         if (r < 0) {
180                 log_netdev_error(netdev,
181                                  "Could not append IFLA_GRE_LOCAL attribute: %s",
182                                  strerror(-r));
183                 return r;
184         }
185
186         r = sd_rtnl_message_append_in_addr(m, IFLA_GRE_REMOTE, &t->remote.in);
187         if (r < 0) {
188                 log_netdev_error(netdev,
189                                  "Could not append IFLA_GRE_REMOTE attribute: %s",
190                                  strerror(-r));
191                 return r;
192         }
193
194         r = sd_rtnl_message_append_u8(m, IFLA_GRE_TTL, t->ttl);
195         if (r < 0) {
196                 log_netdev_error(netdev,
197                                  "Could not append IFLA_GRE_TTL attribute: %s",
198                                  strerror(-r));
199                 return r;
200         }
201
202         r = sd_rtnl_message_append_u8(m, IFLA_GRE_TOS, t->tos);
203         if (r < 0) {
204                 log_netdev_error(netdev,
205                                  "Could not append IFLA_GRE_TOS attribute: %s",
206                                  strerror(-r));
207                 return r;
208         }
209
210         r = sd_rtnl_message_append_u8(m, IFLA_GRE_PMTUDISC, t->pmtudisc);
211         if (r < 0) {
212                 log_netdev_error(netdev,
213                                  "Could not append IFLA_GRE_PMTUDISC attribute: %s",
214                                  strerror(-r));
215                 return r;
216         }
217
218         return r;
219 }
220
221 static int netdev_ip6gre_fill_message_create(NetDev *netdev, Link *link, sd_rtnl_message *m) {
222         Tunnel *t;
223         int r;
224
225         assert(netdev);
226
227         if (netdev->kind == NETDEV_KIND_IP6GRE)
228                  t = IP6GRE(netdev);
229         else
230                  t = IP6GRETAP(netdev);
231
232         assert(t);
233         assert(t->family == AF_INET6);
234         assert(link);
235         assert(m);
236
237         r = sd_rtnl_message_append_u32(m, IFLA_GRE_LINK, link->ifindex);
238         if (r < 0) {
239                 log_netdev_error(netdev,
240                                  "Could not append IFLA_GRE_LINK attribute: %s",
241                                  strerror(-r));
242                 return r;
243         }
244
245         r = sd_rtnl_message_append_in6_addr(m, IFLA_GRE_LOCAL, &t->local.in6);
246         if (r < 0) {
247                 log_netdev_error(netdev,
248                                  "Could not append IFLA_GRE_LOCAL attribute: %s",
249                                  strerror(-r));
250                 return r;
251         }
252
253         r = sd_rtnl_message_append_in6_addr(m, IFLA_GRE_REMOTE, &t->remote.in6);
254         if (r < 0) {
255                 log_netdev_error(netdev,
256                                  "Could not append IFLA_GRE_REMOTE attribute: %s",
257                                  strerror(-r));
258                 return r;
259         }
260
261         r = sd_rtnl_message_append_u8(m, IFLA_GRE_TTL, t->ttl);
262         if (r < 0) {
263                 log_netdev_error(netdev,
264                                  "Could not append IFLA_GRE_TTL attribute: %s",
265                                  strerror(-r));
266                 return r;
267         }
268
269         return r;
270 }
271
272 static int netdev_vti_fill_message_create(NetDev *netdev, Link *link, sd_rtnl_message *m) {
273         Tunnel *t = VTI(netdev);
274         int r;
275
276         assert(netdev);
277         assert(link);
278         assert(m);
279         assert(t);
280         assert(t->family == AF_INET);
281
282         r = sd_rtnl_message_append_u32(m, IFLA_VTI_LINK, link->ifindex);
283         if (r < 0) {
284                 log_netdev_error(netdev,
285                                  "Could not append IFLA_IPTUN_LINK attribute: %s",
286                                  strerror(-r));
287                 return r;
288         }
289
290         r = sd_rtnl_message_append_in_addr(m, IFLA_VTI_LOCAL, &t->local.in);
291         if (r < 0) {
292                 log_netdev_error(netdev,
293                                  "Could not append IFLA_IPTUN_LOCAL attribute: %s",
294                                  strerror(-r));
295                 return r;
296         }
297
298         r = sd_rtnl_message_append_in_addr(m, IFLA_VTI_REMOTE, &t->remote.in);
299         if (r < 0) {
300                 log_netdev_error(netdev,
301                                  "Could not append IFLA_IPTUN_REMOTE attribute: %s",
302                                  strerror(-r));
303                 return r;
304         }
305
306         return r;
307 }
308
309 static int netdev_ip6tnl_fill_message_create(NetDev *netdev, Link *link, sd_rtnl_message *m) {
310         Tunnel *t = IP6TNL(netdev);
311         uint8_t proto;
312         int r;
313
314         assert(netdev);
315         assert(link);
316         assert(m);
317         assert(t);
318         assert(t->family == AF_INET6);
319
320         r = sd_rtnl_message_append_u32(m, IFLA_IPTUN_LINK, link->ifindex);
321         if (r < 0) {
322                 log_netdev_error(netdev,
323                                  "Could not append IFLA_IPTUN_LINK attribute: %s",
324                                  strerror(-r));
325                 return r;
326         }
327
328         r = sd_rtnl_message_append_in6_addr(m, IFLA_IPTUN_LOCAL, &t->local.in6);
329         if (r < 0) {
330                 log_netdev_error(netdev,
331                                  "Could not append IFLA_IPTUN_LOCAL attribute: %s",
332                                  strerror(-r));
333                 return r;
334         }
335
336         r = sd_rtnl_message_append_in6_addr(m, IFLA_IPTUN_REMOTE, &t->remote.in6);
337         if (r < 0) {
338                 log_netdev_error(netdev,
339                                  "Could not append IFLA_IPTUN_REMOTE attribute: %s",
340                                  strerror(-r));
341                 return r;
342         }
343
344         r = sd_rtnl_message_append_u8(m, IFLA_IPTUN_TTL, t->ttl);
345         if (r < 0) {
346                 log_netdev_error(netdev,
347                                  "Could not append IFLA_IPTUN_TTL attribute: %s",
348                                  strerror(-r));
349                 return r;
350         }
351
352         switch (t->ip6tnl_mode) {
353         case NETDEV_IP6_TNL_MODE_IP6IP6:
354                 proto = IPPROTO_IPV6;
355                 break;
356         case NETDEV_IP6_TNL_MODE_IPIP6:
357                 proto = IPPROTO_IPIP;
358                 break;
359         case NETDEV_IP6_TNL_MODE_ANYIP6:
360         default:
361                 proto = 0;
362                 break;
363         }
364
365         r = sd_rtnl_message_append_u8(m, IFLA_IPTUN_PROTO, proto);
366         if (r < 0) {
367                 log_netdev_error(netdev,
368                                  "Could not append IFLA_IPTUN_MODE attribute: %s",
369                                  strerror(-r));
370                 return r;
371         }
372
373         return r;
374 }
375
376 static int netdev_tunnel_verify(NetDev *netdev, const char *filename) {
377         Tunnel *t = NULL;
378
379         assert(netdev);
380         assert(filename);
381
382         switch (netdev->kind) {
383         case NETDEV_KIND_IPIP:
384                 t = IPIP(netdev);
385                 break;
386         case NETDEV_KIND_SIT:
387                 t = SIT(netdev);
388                 break;
389         case NETDEV_KIND_GRE:
390                 t = GRE(netdev);
391                 break;
392         case NETDEV_KIND_GRETAP:
393                 t = GRETAP(netdev);
394                 break;
395         case NETDEV_KIND_IP6GRE:
396                 t = IP6GRE(netdev);
397                 break;
398         case NETDEV_KIND_IP6GRETAP:
399                 t = IP6GRETAP(netdev);
400                 break;
401         case NETDEV_KIND_VTI:
402                 t = VTI(netdev);
403                 break;
404         case NETDEV_KIND_IP6TNL:
405                 t = IP6TNL(netdev);
406                 break;
407         default:
408                 assert_not_reached("Invalid tunnel kind");
409         }
410
411         assert(t);
412
413         if (t->remote.in.s_addr == INADDR_ANY) {
414                log_warning("Tunnel without remote address configured in %s. Ignoring", filename);
415                return -EINVAL;
416         }
417
418         if (t->family != AF_INET && t->family != AF_INET6) {
419               log_warning("Tunnel with invalid address family configured in %s. Ignoring", filename);
420               return -EINVAL;
421         }
422
423         if (netdev->kind == NETDEV_KIND_IP6TNL) {
424                 if (t->ip6tnl_mode == _NETDEV_IP6_TNL_MODE_INVALID) {
425                         log_warning("IP6 Tunnel without mode configured in %s. Ignoring", filename);
426                         return -EINVAL;
427                 }
428         }
429
430         return 0;
431 }
432
433 int config_parse_tunnel_address(const char *unit,
434                                 const char *filename,
435                                 unsigned line,
436                                 const char *section,
437                                 unsigned section_line,
438                                 const char *lvalue,
439                                 int ltype,
440                                 const char *rvalue,
441                                 void *data,
442                                 void *userdata) {
443         Tunnel *t = userdata;
444         union in_addr_union *addr = data, buffer;
445         int r, f;
446
447         assert(filename);
448         assert(lvalue);
449         assert(rvalue);
450         assert(data);
451
452         r = in_addr_from_string_auto(rvalue, &f, &buffer);
453         if (r < 0) {
454                 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Tunnel address is invalid, ignoring assignment: %s", rvalue);
455                 return 0;
456         }
457
458         if (t->family != AF_UNSPEC && t->family != f) {
459                 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Tunnel addresses incompatible, ignoring assignment: %s", rvalue);
460                 return 0;
461         }
462
463         t->family = f;
464         *addr = buffer;
465
466         return 0;
467 }
468
469 static void ipip_init(NetDev *n) {
470         Tunnel *t = IPIP(n);
471
472         assert(n);
473         assert(t);
474
475         t->pmtudisc = true;
476 }
477
478 static void sit_init(NetDev *n) {
479         Tunnel *t = SIT(n);
480
481         assert(n);
482         assert(t);
483
484         t->pmtudisc = true;
485 }
486
487 static void vti_init(NetDev *n) {
488         Tunnel *t = VTI(n);
489
490         assert(n);
491         assert(t);
492
493         t->pmtudisc = true;
494 }
495
496 static void gre_init(NetDev *n) {
497         Tunnel *t;
498
499         assert(n);
500
501         if (n->kind == NETDEV_KIND_GRE)
502                 t = GRE(n);
503         else
504                 t = GRETAP(n);
505
506         assert(t);
507
508         t->pmtudisc = true;
509 }
510
511 static void ip6gre_init(NetDev *n) {
512         Tunnel *t;
513
514         assert(n);
515
516         if (n->kind == NETDEV_KIND_IP6GRE)
517                 t = IP6GRE(n);
518         else
519                 t = IP6GRETAP(n);
520
521         assert(t);
522
523         t->ttl = DEFAULT_TNL_HOP_LIMIT;
524 }
525
526 static void ip6tnl_init(NetDev *n) {
527         Tunnel *t = IP6TNL(n);
528
529         assert(n);
530         assert(t);
531
532         t->ttl = DEFAULT_TNL_HOP_LIMIT;
533         t->encap_limit = IPV6_DEFAULT_TNL_ENCAP_LIMIT;
534         t->ip6tnl_mode = _NETDEV_IP6_TNL_MODE_INVALID;
535 }
536
537 const NetDevVTable ipip_vtable = {
538         .object_size = sizeof(Tunnel),
539         .init = ipip_init,
540         .sections = "Match\0NetDev\0Tunnel\0",
541         .fill_message_create = netdev_ipip_fill_message_create,
542         .create_type = NETDEV_CREATE_STACKED,
543         .config_verify = netdev_tunnel_verify,
544 };
545
546 const NetDevVTable sit_vtable = {
547         .object_size = sizeof(Tunnel),
548         .init = sit_init,
549         .sections = "Match\0NetDev\0Tunnel\0",
550         .fill_message_create = netdev_sit_fill_message_create,
551         .create_type = NETDEV_CREATE_STACKED,
552         .config_verify = netdev_tunnel_verify,
553 };
554
555 const NetDevVTable vti_vtable = {
556         .object_size = sizeof(Tunnel),
557         .init = vti_init,
558         .sections = "Match\0NetDev\0Tunnel\0",
559         .fill_message_create = netdev_vti_fill_message_create,
560         .create_type = NETDEV_CREATE_STACKED,
561         .config_verify = netdev_tunnel_verify,
562 };
563
564 const NetDevVTable gre_vtable = {
565         .object_size = sizeof(Tunnel),
566         .init = gre_init,
567         .sections = "Match\0NetDev\0Tunnel\0",
568         .fill_message_create = netdev_gre_fill_message_create,
569         .create_type = NETDEV_CREATE_STACKED,
570         .config_verify = netdev_tunnel_verify,
571 };
572
573 const NetDevVTable gretap_vtable = {
574         .object_size = sizeof(Tunnel),
575         .init = gre_init,
576         .sections = "Match\0NetDev\0Tunnel\0",
577         .fill_message_create = netdev_gre_fill_message_create,
578         .create_type = NETDEV_CREATE_STACKED,
579         .config_verify = netdev_tunnel_verify,
580 };
581
582 const NetDevVTable ip6gre_vtable = {
583         .object_size = sizeof(Tunnel),
584         .init = ip6gre_init,
585         .sections = "Match\0NetDev\0Tunnel\0",
586         .fill_message_create = netdev_ip6gre_fill_message_create,
587         .create_type = NETDEV_CREATE_STACKED,
588         .config_verify = netdev_tunnel_verify,
589 };
590
591 const NetDevVTable ip6gretap_vtable = {
592         .object_size = sizeof(Tunnel),
593         .init = ip6gre_init,
594         .sections = "Match\0NetDev\0Tunnel\0",
595         .fill_message_create = netdev_ip6gre_fill_message_create,
596         .create_type = NETDEV_CREATE_STACKED,
597         .config_verify = netdev_tunnel_verify,
598 };
599
600 const NetDevVTable ip6tnl_vtable = {
601         .object_size = sizeof(Tunnel),
602         .init = ip6tnl_init,
603         .sections = "Match\0NetDev\0Tunnel\0",
604         .fill_message_create = netdev_ip6tnl_fill_message_create,
605         .create_type = NETDEV_CREATE_STACKED,
606         .config_verify = netdev_tunnel_verify,
607 };