chiark / gitweb /
networkd: add back path of MTU discovery for SIT
[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 <susant@redhat.com>
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
28 #include "sd-rtnl.h"
29 #include "networkd-netdev-tunnel.h"
30 #include "networkd-link.h"
31 #include "network-internal.h"
32 #include "util.h"
33 #include "missing.h"
34 #include "conf-parser.h"
35
36 static int netdev_ipip_fill_message_create(NetDev *netdev, Link *link, sd_rtnl_message *m) {
37         Tunnel *t = IPIP(netdev);
38         int r;
39
40         assert(netdev);
41         assert(link);
42         assert(m);
43         assert(t);
44         assert(t->family == AF_INET);
45
46         r = sd_rtnl_message_append_u32(m, IFLA_IPTUN_LINK, link->ifindex);
47         if (r < 0) {
48                 log_error_netdev(netdev,
49                                  "Could not append IFLA_IPTUN_LINK attribute: %s",
50                                  strerror(-r));
51                 return r;
52         }
53
54         r = sd_rtnl_message_append_in_addr(m, IFLA_IPTUN_LOCAL, &t->local.in);
55         if (r < 0) {
56                 log_error_netdev(netdev,
57                                  "Could not append IFLA_IPTUN_LOCAL attribute: %s",
58                                  strerror(-r));
59                 return r;
60         }
61
62         r = sd_rtnl_message_append_in_addr(m, IFLA_IPTUN_REMOTE, &t->remote.in);
63         if (r < 0) {
64                 log_error_netdev(netdev,
65                                  "Could not append IFLA_IPTUN_REMOTE attribute: %s",
66                                  strerror(-r));
67                 return r;
68         }
69
70         r = sd_rtnl_message_append_u8(m, IFLA_IPTUN_TTL, t->ttl);
71         if (r < 0) {
72                 log_error_netdev(netdev,
73                                  "Could not append IFLA_IPTUN_TTL  attribute: %s",
74                                  strerror(-r));
75                 return r;
76         }
77
78         return r;
79 }
80
81 static int netdev_sit_fill_message_create(NetDev *netdev, Link *link, sd_rtnl_message *m) {
82         Tunnel *t = SIT(netdev);
83         int r;
84
85         assert(netdev);
86         assert(link);
87         assert(m);
88         assert(t);
89         assert(t->family == AF_INET);
90
91         r = sd_rtnl_message_append_u32(m, IFLA_IPTUN_LINK, link->ifindex);
92         if (r < 0) {
93                 log_error_netdev(netdev,
94                                  "Could not append IFLA_IPTUN_LINK attribute: %s",
95                                  strerror(-r));
96                 return r;
97         }
98
99         r = sd_rtnl_message_append_in_addr(m, IFLA_IPTUN_LOCAL, &t->local.in);
100         if (r < 0) {
101                 log_error_netdev(netdev,
102                                  "Could not append IFLA_IPTUN_LOCAL attribute: %s",
103                                  strerror(-r));
104                 return r;
105         }
106
107         r = sd_rtnl_message_append_in_addr(m, IFLA_IPTUN_REMOTE, &t->remote.in);
108         if (r < 0) {
109                 log_error_netdev(netdev,
110                                  "Could not append IFLA_IPTUN_REMOTE attribute: %s",
111                                  strerror(-r));
112                 return r;
113         }
114
115         r = sd_rtnl_message_append_u8(m, IFLA_IPTUN_TTL, t->ttl);
116         if (r < 0) {
117                 log_error_netdev(netdev,
118                                  "Could not append IFLA_IPTUN_TTL attribute: %s",
119                                  strerror(-r));
120                 return r;
121         }
122
123         r = sd_rtnl_message_append_u8(m, IFLA_IPTUN_PMTUDISC, t->pmtudisc);
124         if (r < 0) {
125                 log_error_netdev(netdev,
126                                  "Could not append IFLA_IPTUN_PMTUDISC attribute: %s",
127                                  strerror(-r));
128                 return r;
129         }
130
131         return r;
132 }
133
134 static int netdev_gre_fill_message_create(NetDev *netdev, Link *link, sd_rtnl_message *m) {
135         Tunnel *t = GRE(netdev);
136         int r;
137
138         assert(netdev);
139         assert(link);
140         assert(m);
141         assert(t);
142         assert(t->family == AF_INET);
143
144         r = sd_rtnl_message_append_u32(m, IFLA_GRE_LINK, link->ifindex);
145         if (r < 0) {
146                 log_error_netdev(netdev,
147                                  "Could not append IFLA_GRE_LINK attribute: %s",
148                                  strerror(-r));
149                 return r;
150         }
151
152         r = sd_rtnl_message_append_in_addr(m, IFLA_GRE_LOCAL, &t->local.in);
153         if (r < 0) {
154                 log_error_netdev(netdev,
155                                  "Could not append IFLA_GRE_LOCAL attribute: %s",
156                                  strerror(-r));
157                 return r;
158         }
159
160         r = sd_rtnl_message_append_in_addr(m, IFLA_GRE_REMOTE, &t->remote.in);
161         if (r < 0) {
162                 log_error_netdev(netdev,
163                                  "Could not append IFLA_GRE_REMOTE attribute: %s",
164                                  strerror(-r));
165                 return r;
166         }
167
168         r = sd_rtnl_message_append_u8(m, IFLA_GRE_TTL, t->ttl);
169         if (r < 0) {
170                 log_error_netdev(netdev,
171                                  "Could not append IFLA_GRE_TTL attribute: %s",
172                                  strerror(-r));
173                 return r;
174         }
175
176         r = sd_rtnl_message_append_u8(m, IFLA_GRE_TOS, t->tos);
177         if (r < 0) {
178                 log_error_netdev(netdev,
179                                  "Could not append IFLA_GRE_TOS attribute: %s",
180                                  strerror(-r));
181                 return r;
182         }
183
184         return r;
185 }
186
187 static int netdev_vti_fill_message_create(NetDev *netdev, Link *link, sd_rtnl_message *m) {
188         Tunnel *t = VTI(netdev);
189         int r;
190
191         assert(netdev);
192         assert(link);
193         assert(m);
194         assert(t);
195         assert(t->family == AF_INET);
196
197         r = sd_rtnl_message_append_u32(m, IFLA_VTI_LINK, link->ifindex);
198         if (r < 0) {
199                 log_error_netdev(netdev,
200                                  "Could not append IFLA_IPTUN_LINK attribute: %s",
201                                  strerror(-r));
202                 return r;
203         }
204
205         r = sd_rtnl_message_append_in_addr(m, IFLA_VTI_LOCAL, &t->local.in);
206         if (r < 0) {
207                 log_error_netdev(netdev,
208                                  "Could not append IFLA_IPTUN_LOCAL attribute: %s",
209                                  strerror(-r));
210                 return r;
211         }
212
213         r = sd_rtnl_message_append_in_addr(m, IFLA_VTI_REMOTE, &t->remote.in);
214         if (r < 0) {
215                 log_error_netdev(netdev,
216                                  "Could not append IFLA_IPTUN_REMOTE attribute: %s",
217                                  strerror(-r));
218                 return r;
219         }
220
221         return r;
222 }
223
224 static int netdev_tunnel_verify(NetDev *netdev, const char *filename) {
225         Tunnel *t = NULL;
226
227         assert(netdev);
228         assert(filename);
229
230         switch (netdev->kind) {
231         case NETDEV_KIND_IPIP:
232                 t = IPIP(netdev);
233                 break;
234         case NETDEV_KIND_SIT:
235                 t = SIT(netdev);
236                 break;
237         case NETDEV_KIND_GRE:
238                 t = GRE(netdev);
239                 break;
240         case NETDEV_KIND_VTI:
241                 t = VTI(netdev);
242                 break;
243         default:
244                 assert_not_reached("Invalid tunnel kind");
245         }
246
247         assert(t);
248
249         if (t->local.in.s_addr == INADDR_ANY) {
250                log_warning("Tunnel without local address configured in %s. Ignoring", filename);
251                return -EINVAL;
252         }
253
254         if (t->remote.in.s_addr == INADDR_ANY) {
255                log_warning("Tunnel without remote address configured in %s. Ignoring", filename);
256                return -EINVAL;
257         }
258
259         if (t->family != AF_INET) {
260               log_warning("Tunnel with invalid address family configured in %s. Ignoring", filename);
261               return -EINVAL;
262         }
263
264         return 0;
265 }
266
267 int config_parse_tunnel_address(const char *unit,
268                                 const char *filename,
269                                 unsigned line,
270                                 const char *section,
271                                 unsigned section_line,
272                                 const char *lvalue,
273                                 int ltype,
274                                 const char *rvalue,
275                                 void *data,
276                                 void *userdata) {
277         Tunnel *t = userdata;
278         union in_addr_union *addr = data, buffer;
279         int r, f;
280
281         assert(filename);
282         assert(lvalue);
283         assert(rvalue);
284         assert(data);
285
286         r = in_addr_from_string_auto(rvalue, &f, &buffer);
287         if (r < 0) {
288                 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Tunnel address is invalid, ignoring assignment: %s", rvalue);
289                 return 0;
290         }
291
292         if (t->family != AF_UNSPEC && t->family != f) {
293                 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Tunnel addresses incompatible, ignoring assignment: %s", rvalue);
294                 return 0;
295         }
296
297         t->family = f;
298         *addr = buffer;
299
300         return 0;
301 }
302
303 static void ipip_init(NetDev *n) {
304         Tunnel *t = IPIP(n);
305
306         assert(n);
307         assert(t);
308
309         t->pmtudisc = true;
310 }
311
312 static void sit_init(NetDev *n) {
313         Tunnel *t = SIT(n);
314
315         assert(n);
316         assert(t);
317
318         t->pmtudisc = true;
319 }
320
321 static void vti_init(NetDev *n) {
322         Tunnel *t = VTI(n);
323
324         assert(n);
325         assert(t);
326
327         t->pmtudisc = true;
328 }
329
330 static void gre_init(NetDev *n) {
331         Tunnel *t = GRE(n);
332
333         assert(n);
334         assert(t);
335
336         t->pmtudisc = true;
337 }
338
339 const NetDevVTable ipip_vtable = {
340         .object_size = sizeof(Tunnel),
341         .init = ipip_init,
342         .sections = "Match\0NetDev\0Tunnel\0",
343         .fill_message_create = netdev_ipip_fill_message_create,
344         .create_type = NETDEV_CREATE_STACKED,
345         .config_verify = netdev_tunnel_verify,
346 };
347
348 const NetDevVTable sit_vtable = {
349         .object_size = sizeof(Tunnel),
350         .init = sit_init,
351         .sections = "Match\0NetDev\0Tunnel\0",
352         .fill_message_create = netdev_sit_fill_message_create,
353         .create_type = NETDEV_CREATE_STACKED,
354         .config_verify = netdev_tunnel_verify,
355 };
356
357 const NetDevVTable vti_vtable = {
358         .object_size = sizeof(Tunnel),
359         .init = vti_init,
360         .sections = "Match\0NetDev\0Tunnel\0",
361         .fill_message_create = netdev_vti_fill_message_create,
362         .create_type = NETDEV_CREATE_STACKED,
363         .config_verify = netdev_tunnel_verify,
364 };
365
366 const NetDevVTable gre_vtable = {
367         .object_size = sizeof(Tunnel),
368         .init = gre_init,
369         .sections = "Match\0NetDev\0Tunnel\0",
370         .fill_message_create = netdev_gre_fill_message_create,
371         .create_type = NETDEV_CREATE_STACKED,
372         .config_verify = netdev_tunnel_verify,
373 };