chiark / gitweb /
networkd: Introduce IP6 tunnel
[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] = "ip4ipv6",
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_vti_fill_message_create(NetDev *netdev, Link *link, sd_rtnl_message *m) {
222         Tunnel *t = VTI(netdev);
223         int r;
224
225         assert(netdev);
226         assert(link);
227         assert(m);
228         assert(t);
229         assert(t->family == AF_INET);
230
231         r = sd_rtnl_message_append_u32(m, IFLA_VTI_LINK, link->ifindex);
232         if (r < 0) {
233                 log_netdev_error(netdev,
234                                  "Could not append IFLA_IPTUN_LINK attribute: %s",
235                                  strerror(-r));
236                 return r;
237         }
238
239         r = sd_rtnl_message_append_in_addr(m, IFLA_VTI_LOCAL, &t->local.in);
240         if (r < 0) {
241                 log_netdev_error(netdev,
242                                  "Could not append IFLA_IPTUN_LOCAL attribute: %s",
243                                  strerror(-r));
244                 return r;
245         }
246
247         r = sd_rtnl_message_append_in_addr(m, IFLA_VTI_REMOTE, &t->remote.in);
248         if (r < 0) {
249                 log_netdev_error(netdev,
250                                  "Could not append IFLA_IPTUN_REMOTE attribute: %s",
251                                  strerror(-r));
252                 return r;
253         }
254
255         return r;
256 }
257
258 static int netdev_ip6tnl_fill_message_create(NetDev *netdev, Link *link, sd_rtnl_message *m) {
259         Tunnel *t = IP6TNL(netdev);
260         uint8_t proto;
261         int r;
262
263         assert(netdev);
264         assert(link);
265         assert(m);
266         assert(t);
267         assert(t->family == AF_INET6);
268
269         r = sd_rtnl_message_append_u32(m, IFLA_IPTUN_LINK, link->ifindex);
270         if (r < 0) {
271                 log_netdev_error(netdev,
272                                  "Could not append IFLA_IPTUN_LINK attribute: %s",
273                                  strerror(-r));
274                 return r;
275         }
276
277         r = sd_rtnl_message_append_in6_addr(m, IFLA_IPTUN_LOCAL, &t->local.in6);
278         if (r < 0) {
279                 log_netdev_error(netdev,
280                                  "Could not append IFLA_IPTUN_LOCAL attribute: %s",
281                                  strerror(-r));
282                 return r;
283         }
284
285         r = sd_rtnl_message_append_in6_addr(m, IFLA_IPTUN_REMOTE, &t->remote.in6);
286         if (r < 0) {
287                 log_netdev_error(netdev,
288                                  "Could not append IFLA_IPTUN_REMOTE attribute: %s",
289                                  strerror(-r));
290                 return r;
291         }
292
293         r = sd_rtnl_message_append_u8(m, IFLA_IPTUN_TTL, t->ttl);
294         if (r < 0) {
295                 log_netdev_error(netdev,
296                                  "Could not append IFLA_IPTUN_TTL attribute: %s",
297                                  strerror(-r));
298                 return r;
299         }
300
301         switch (t->ip6tnl_mode) {
302         case NETDEV_IP6_TNL_MODE_IP6IP6:
303                 proto = IPPROTO_IPV6;
304                 break;
305         case NETDEV_IP6_TNL_MODE_IPIP6:
306                 proto = IPPROTO_IPIP;
307                 break;
308         case NETDEV_IP6_TNL_MODE_ANYIP6:
309         default:
310                 proto = 0;
311                 break;
312         }
313
314         r = sd_rtnl_message_append_u8(m, IFLA_IPTUN_PROTO, proto);
315         if (r < 0) {
316                 log_netdev_error(netdev,
317                                  "Could not append IFLA_IPTUN_MODE attribute: %s",
318                                  strerror(-r));
319                 return r;
320         }
321
322         return r;
323 }
324
325 static int netdev_tunnel_verify(NetDev *netdev, const char *filename) {
326         Tunnel *t = NULL;
327
328         assert(netdev);
329         assert(filename);
330
331         switch (netdev->kind) {
332         case NETDEV_KIND_IPIP:
333                 t = IPIP(netdev);
334                 break;
335         case NETDEV_KIND_SIT:
336                 t = SIT(netdev);
337                 break;
338         case NETDEV_KIND_GRE:
339                 t = GRE(netdev);
340                 break;
341         case NETDEV_KIND_GRETAP:
342                 t = GRETAP(netdev);
343                 break;
344         case NETDEV_KIND_VTI:
345                 t = VTI(netdev);
346                 break;
347         case NETDEV_KIND_IP6TNL:
348                 t = IP6TNL(netdev);
349                 break;
350         default:
351                 assert_not_reached("Invalid tunnel kind");
352         }
353
354         assert(t);
355
356         if (t->remote.in.s_addr == INADDR_ANY) {
357                log_warning("Tunnel without remote address configured in %s. Ignoring", filename);
358                return -EINVAL;
359         }
360
361         if (t->family != AF_INET && t->family != AF_INET6) {
362               log_warning("Tunnel with invalid address family configured in %s. Ignoring", filename);
363               return -EINVAL;
364         }
365
366         if (netdev->kind == NETDEV_KIND_IP6TNL) {
367                 if (t->ip6tnl_mode == _NETDEV_IP6_TNL_MODE_INVALID) {
368                         log_warning("IP6 Tunnel without mode configured in %s. Ignoring", filename);
369                         return -EINVAL;
370                 }
371         }
372
373         return 0;
374 }
375
376 int config_parse_tunnel_address(const char *unit,
377                                 const char *filename,
378                                 unsigned line,
379                                 const char *section,
380                                 unsigned section_line,
381                                 const char *lvalue,
382                                 int ltype,
383                                 const char *rvalue,
384                                 void *data,
385                                 void *userdata) {
386         Tunnel *t = userdata;
387         union in_addr_union *addr = data, buffer;
388         int r, f;
389
390         assert(filename);
391         assert(lvalue);
392         assert(rvalue);
393         assert(data);
394
395         r = in_addr_from_string_auto(rvalue, &f, &buffer);
396         if (r < 0) {
397                 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Tunnel address is invalid, ignoring assignment: %s", rvalue);
398                 return 0;
399         }
400
401         if (t->family != AF_UNSPEC && t->family != f) {
402                 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Tunnel addresses incompatible, ignoring assignment: %s", rvalue);
403                 return 0;
404         }
405
406         t->family = f;
407         *addr = buffer;
408
409         return 0;
410 }
411
412 static void ipip_init(NetDev *n) {
413         Tunnel *t = IPIP(n);
414
415         assert(n);
416         assert(t);
417
418         t->pmtudisc = true;
419 }
420
421 static void sit_init(NetDev *n) {
422         Tunnel *t = SIT(n);
423
424         assert(n);
425         assert(t);
426
427         t->pmtudisc = true;
428 }
429
430 static void vti_init(NetDev *n) {
431         Tunnel *t = VTI(n);
432
433         assert(n);
434         assert(t);
435
436         t->pmtudisc = true;
437 }
438
439 static void gre_init(NetDev *n) {
440         Tunnel *t;
441
442         assert(n);
443
444         if (n->kind == NETDEV_KIND_GRE)
445                 t = GRE(n);
446         else
447                 t = GRETAP(n);
448
449         assert(t);
450
451         t->pmtudisc = true;
452 }
453
454 static void ip6tnl_init(NetDev *n) {
455         Tunnel *t = IP6TNL(n);
456
457         assert(n);
458         assert(t);
459
460         t->ttl = DEFAULT_TNL_HOP_LIMIT;
461         t->encap_limit = IPV6_DEFAULT_TNL_ENCAP_LIMIT;
462         t->ip6tnl_mode = _NETDEV_IP6_TNL_MODE_INVALID;
463 }
464
465 const NetDevVTable ipip_vtable = {
466         .object_size = sizeof(Tunnel),
467         .init = ipip_init,
468         .sections = "Match\0NetDev\0Tunnel\0",
469         .fill_message_create = netdev_ipip_fill_message_create,
470         .create_type = NETDEV_CREATE_STACKED,
471         .config_verify = netdev_tunnel_verify,
472 };
473
474 const NetDevVTable sit_vtable = {
475         .object_size = sizeof(Tunnel),
476         .init = sit_init,
477         .sections = "Match\0NetDev\0Tunnel\0",
478         .fill_message_create = netdev_sit_fill_message_create,
479         .create_type = NETDEV_CREATE_STACKED,
480         .config_verify = netdev_tunnel_verify,
481 };
482
483 const NetDevVTable vti_vtable = {
484         .object_size = sizeof(Tunnel),
485         .init = vti_init,
486         .sections = "Match\0NetDev\0Tunnel\0",
487         .fill_message_create = netdev_vti_fill_message_create,
488         .create_type = NETDEV_CREATE_STACKED,
489         .config_verify = netdev_tunnel_verify,
490 };
491
492 const NetDevVTable gre_vtable = {
493         .object_size = sizeof(Tunnel),
494         .init = gre_init,
495         .sections = "Match\0NetDev\0Tunnel\0",
496         .fill_message_create = netdev_gre_fill_message_create,
497         .create_type = NETDEV_CREATE_STACKED,
498         .config_verify = netdev_tunnel_verify,
499 };
500
501 const NetDevVTable gretap_vtable = {
502         .object_size = sizeof(Tunnel),
503         .init = gre_init,
504         .sections = "Match\0NetDev\0Tunnel\0",
505         .fill_message_create = netdev_gre_fill_message_create,
506         .create_type = NETDEV_CREATE_STACKED,
507         .config_verify = netdev_tunnel_verify,
508 };
509
510 const NetDevVTable ip6tnl_vtable = {
511         .object_size = sizeof(Tunnel),
512         .init = ip6tnl_init,
513         .sections = "Match\0NetDev\0Tunnel\0",
514         .fill_message_create = netdev_ip6tnl_fill_message_create,
515         .create_type = NETDEV_CREATE_STACKED,
516         .config_verify = netdev_tunnel_verify,
517 };