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