chiark / gitweb /
networkd: introduce vti tunnel
[elogind.git] / src / network / networkd-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 #include <libkmod.h>
28
29 #include "sd-rtnl.h"
30 #include "networkd.h"
31 #include "network-internal.h"
32 #include "util.h"
33
34
35 static int netdev_fill_ipip_rtnl_message(Link *link, sd_rtnl_message *m) {
36         NetDev *netdev;
37         int r;
38
39         assert(link);
40         assert(link->network);
41         assert(link->network->tunnel);
42         assert(m);
43
44         netdev = link->network->tunnel;
45
46         r = sd_rtnl_message_append_string(m, IFLA_IFNAME, netdev->ifname);
47         if (r < 0) {
48                 log_error_netdev(netdev,
49                                  "Could not append IFLA_IFNAME, attribute: %s",
50                                  strerror(-r));
51                 return r;
52         }
53
54         if(netdev->mtu) {
55                 r = sd_rtnl_message_append_u32(m, IFLA_MTU, netdev->mtu);
56                 if (r < 0) {
57                         log_error_netdev(netdev,
58                                          "Could not append IFLA_MTU attribute: %s",
59                                          strerror(-r));
60                         return r;
61                 }
62         }
63
64         r = sd_rtnl_message_open_container(m, IFLA_LINKINFO);
65         if (r < 0) {
66                 log_error_netdev(netdev,
67                                  "Could not append IFLA_LINKINFO attribute: %s",
68                                  strerror(-r));
69                 return r;
70         }
71
72         r = sd_rtnl_message_open_container_union(m, IFLA_INFO_DATA,
73                                                  netdev_kind_to_string(netdev->kind));
74         if (r < 0) {
75                 log_error_netdev(netdev,
76                                  "Could not append IFLA_INFO_DATA attribute: %s",
77                                  strerror(-r));
78                 return r;
79         }
80
81         r = sd_rtnl_message_append_u32(m, IFLA_IPTUN_LINK, link->ifindex);
82         if (r < 0) {
83                 log_error_netdev(netdev,
84                                  "Could not append IFLA_IPTUN_LINK attribute: %s",
85                                  strerror(-r));
86                 return r;
87         }
88
89         r = sd_rtnl_message_append_in_addr(m, IFLA_IPTUN_LOCAL, &netdev->tunnel_local);
90         if (r < 0) {
91                 log_error_netdev(netdev,
92                                  "Could not append IFLA_IPTUN_LOCAL attribute: %s",
93                                  strerror(-r));
94                 return r;
95         }
96
97         r = sd_rtnl_message_append_in_addr(m, IFLA_IPTUN_REMOTE, &netdev->tunnel_remote);
98         if (r < 0) {
99                 log_error_netdev(netdev,
100                                  "Could not append IFLA_IPTUN_REMOTE attribute: %s",
101                                  strerror(-r));
102                 return r;
103         }
104
105         r = sd_rtnl_message_append_u8(m, IFLA_IPTUN_TTL, netdev->tunnel_ttl);
106         if (r < 0) {
107                 log_error_netdev(netdev,
108                                  "Could not append IFLA_IPTUN_TTL  attribute: %s",
109                                  strerror(-r));
110                 return r;
111         }
112
113         r = sd_rtnl_message_close_container(m);
114         if (r < 0) {
115                 log_error_netdev(netdev,
116                                  "Could not append IFLA_INFO_DATA attribute: %s",
117                                  strerror(-r));
118                 return r;
119         }
120
121         r = sd_rtnl_message_close_container(m);
122         if (r < 0) {
123                 log_error_netdev(netdev,
124                                  "Could not append IFLA_LINKINFO attribute: %s",
125                                  strerror(-r));
126                 return r;
127         }
128
129         return r;
130 }
131
132 static int netdev_fill_sit_rtnl_message(Link *link, sd_rtnl_message *m) {
133         NetDev *netdev;
134         int r;
135
136         assert(link);
137         assert(link->network);
138         assert(link->network->tunnel);
139         assert(m);
140
141         netdev = link->network->tunnel;
142
143         r = sd_rtnl_message_append_string(m, IFLA_IFNAME, netdev->ifname);
144         if (r < 0) {
145                 log_error_netdev(netdev,
146                                  "Could not append IFLA_IFNAME, attribute: %s",
147                                  strerror(-r));
148                 return r;
149         }
150
151         if(netdev->mtu) {
152                 r = sd_rtnl_message_append_u32(m, IFLA_MTU, netdev->mtu);
153                 if (r < 0) {
154                         log_error_netdev(netdev,
155                                          "Could not append IFLA_MTU attribute: %s",
156                                          strerror(-r));
157                         return r;
158                 }
159         }
160
161         r = sd_rtnl_message_open_container(m, IFLA_LINKINFO);
162         if (r < 0) {
163                 log_error_netdev(netdev,
164                                  "Could not append IFLA_LINKINFO attribute: %s",
165                                  strerror(-r));
166                 return r;
167         }
168
169         r = sd_rtnl_message_open_container_union(m, IFLA_INFO_DATA,
170                                                  netdev_kind_to_string(netdev->kind));
171         if (r < 0) {
172                 log_error_netdev(netdev,
173                                  "Could not append IFLA_INFO_DATA attribute: %s",
174                                  strerror(-r));
175                 return r;
176         }
177
178         r = sd_rtnl_message_append_u32(m, IFLA_IPTUN_LINK, link->ifindex);
179         if (r < 0) {
180                 log_error_netdev(netdev,
181                                  "Could not append IFLA_IPTUN_LINK attribute: %s",
182                                  strerror(-r));
183                 return r;
184         }
185
186         r = sd_rtnl_message_append_in_addr(m, IFLA_IPTUN_LOCAL, &netdev->tunnel_local);
187         if (r < 0) {
188                 log_error_netdev(netdev,
189                                  "Could not append IFLA_IPTUN_LOCAL attribute: %s",
190                                  strerror(-r));
191                 return r;
192         }
193
194         r = sd_rtnl_message_append_in_addr(m, IFLA_IPTUN_REMOTE, &netdev->tunnel_remote);
195         if (r < 0) {
196                 log_error_netdev(netdev,
197                                  "Could not append IFLA_IPTUN_REMOTE attribute: %s",
198                                  strerror(-r));
199                 return r;
200         }
201
202         r = sd_rtnl_message_append_u8(m, IFLA_IPTUN_TOS, netdev->tunnel_tos);
203         if (r < 0) {
204                 log_error_netdev(netdev,
205                                  "Could not append IFLA_IPTUN_TOS attribute: %s",
206                                  strerror(-r));
207                 return r;
208         }
209
210         r = sd_rtnl_message_append_u8(m, IFLA_IPTUN_PMTUDISC, netdev->tunnel_pmtudisc);
211         if (r < 0) {
212                 log_error_netdev(netdev,
213                                  "Could not append IFLA_IPTUN_PMTUDISC attribute: %s",
214                                  strerror(-r));
215                 return r;
216         }
217
218         r = sd_rtnl_message_close_container(m);
219         if (r < 0) {
220                 log_error_netdev(netdev,
221                                  "Could not append IFLA_INFO_DATA attribute: %s",
222                                  strerror(-r));
223                 return r;
224         }
225
226         r = sd_rtnl_message_close_container(m);
227         if (r < 0) {
228                 log_error_netdev(netdev,
229                                  "Could not append IFLA_LINKINFO attribute: %s",
230                                  strerror(-r));
231                 return r;
232         }
233
234         return r;
235 }
236
237 static int netdev_fill_ipgre_rtnl_message(Link *link, sd_rtnl_message *m) {
238         NetDev *netdev;
239         int r;
240
241         assert(link);
242         assert(link->network);
243         assert(link->network->tunnel);
244         assert(m);
245
246         netdev = link->network->tunnel;
247
248         r = sd_rtnl_message_append_string(m, IFLA_IFNAME, netdev->ifname);
249         if (r < 0) {
250                 log_error_netdev(netdev,
251                                  "Could not append IFLA_IFNAME, attribute: %s",
252                                  strerror(-r));
253                 return r;
254         }
255
256         if(netdev->mtu) {
257                 r = sd_rtnl_message_append_u32(m, IFLA_MTU, netdev->mtu);
258                 if (r < 0) {
259                         log_error_netdev(netdev,
260                                          "Could not append IFLA_MTU attribute: %s",
261                                          strerror(-r));
262                         return r;
263                 }
264         }
265
266         r = sd_rtnl_message_open_container(m, IFLA_LINKINFO);
267         if (r < 0) {
268                 log_error_netdev(netdev,
269                                  "Could not append IFLA_LINKINFO attribute: %s",
270                                  strerror(-r));
271                 return r;
272         }
273
274         r = sd_rtnl_message_open_container_union(m, IFLA_INFO_DATA,
275                                                  netdev_kind_to_string(netdev->kind));
276         if (r < 0) {
277                 log_error_netdev(netdev,
278                                  "Could not append IFLA_INFO_DATA attribute: %s",
279                                  strerror(-r));
280                 return r;
281         }
282
283         r = sd_rtnl_message_append_u32(m, IFLA_GRE_LINK, link->ifindex);
284         if (r < 0) {
285                 log_error_netdev(netdev,
286                                  "Could not append IFLA_GRE_LINK attribute: %s",
287                                  strerror(-r));
288                 return r;
289         }
290
291         r = sd_rtnl_message_append_in_addr(m, IFLA_GRE_LOCAL, &netdev->tunnel_local);
292         if (r < 0) {
293                 log_error_netdev(netdev,
294                                  "Could not append IFLA_GRE_LOCAL attribute: %s",
295                                  strerror(-r));
296                 return r;
297         }
298
299         r = sd_rtnl_message_append_in_addr(m, IFLA_GRE_REMOTE, &netdev->tunnel_remote);
300         if (r < 0) {
301                 log_error_netdev(netdev,
302                                  "Could not append IFLA_GRE_REMOTE attribute: %s",
303                                  strerror(-r));
304                 return r;
305         }
306
307         r = sd_rtnl_message_append_u8(m, IFLA_GRE_TTL, netdev->tunnel_ttl);
308         if (r < 0) {
309                 log_error_netdev(netdev,
310                                  "Could not append IFLA_GRE_TTL attribute: %s",
311                                  strerror(-r));
312                 return r;
313         }
314
315         r = sd_rtnl_message_append_u8(m, IFLA_GRE_TOS, netdev->tunnel_tos);
316         if (r < 0) {
317                 log_error_netdev(netdev,
318                                  "Could not append IFLA_GRE_TOS attribute: %s",
319                                  strerror(-r));
320                 return r;
321         }
322
323         r = sd_rtnl_message_close_container(m);
324         if (r < 0) {
325                 log_error_netdev(netdev,
326                                  "Could not append IFLA_INFO_DATA attribute: %s",
327                                  strerror(-r));
328                 return r;
329         }
330
331         r = sd_rtnl_message_close_container(m);
332         if (r < 0) {
333                 log_error_netdev(netdev,
334                                  "Could not append IFLA_LINKINFO attribute: %s",
335                                  strerror(-r));
336                 return r;
337         }
338
339         return r;
340 }
341
342 static int netdev_fill_vti_rtnl_message(Link *link, sd_rtnl_message *m) {
343         NetDev *netdev;
344         int r;
345
346         assert(link);
347         assert(link->network);
348         assert(link->network->tunnel);
349         assert(m);
350
351         netdev = link->network->tunnel;
352
353         r = sd_rtnl_message_append_string(m, IFLA_IFNAME, netdev->ifname);
354         if (r < 0) {
355                 log_error_netdev(netdev,
356                                  "Could not append IFLA_IFNAME, attribute: %s",
357                                  strerror(-r));
358                 return r;
359         }
360
361         if(netdev->mtu) {
362                 r = sd_rtnl_message_append_u32(m, IFLA_MTU, netdev->mtu);
363                 if (r < 0) {
364                         log_error_netdev(netdev,
365                                          "Could not append IFLA_MTU attribute: %s",
366                                          strerror(-r));
367                         return r;
368                 }
369         }
370
371         r = sd_rtnl_message_open_container(m, IFLA_LINKINFO);
372         if (r < 0) {
373                 log_error_netdev(netdev,
374                                  "Could not append IFLA_LINKINFO attribute: %s",
375                                  strerror(-r));
376                 return r;
377         }
378
379         r = sd_rtnl_message_open_container_union(m, IFLA_INFO_DATA,
380                                                  netdev_kind_to_string(netdev->kind));
381         if (r < 0) {
382                 log_error_netdev(netdev,
383                                  "Could not append IFLA_INFO_DATA attribute: %s",
384                                  strerror(-r));
385                 return r;
386         }
387
388         r = sd_rtnl_message_append_u32(m, IFLA_VTI_LINK, link->ifindex);
389         if (r < 0) {
390                 log_error_netdev(netdev,
391                                  "Could not append IFLA_IPTUN_LINK attribute: %s",
392                                  strerror(-r));
393                 return r;
394         }
395
396         r = sd_rtnl_message_append_in_addr(m, IFLA_VTI_LOCAL, &netdev->tunnel_local);
397         if (r < 0) {
398                 log_error_netdev(netdev,
399                                  "Could not append IFLA_IPTUN_LOCAL attribute: %s",
400                                  strerror(-r));
401                 return r;
402         }
403
404         r = sd_rtnl_message_append_in_addr(m, IFLA_VTI_REMOTE, &netdev->tunnel_remote);
405         if (r < 0) {
406                 log_error_netdev(netdev,
407                                  "Could not append IFLA_IPTUN_REMOTE attribute: %s",
408                                  strerror(-r));
409                 return r;
410         }
411
412         r = sd_rtnl_message_close_container(m);
413         if (r < 0) {
414                 log_error_netdev(netdev,
415                                  "Could not append IFLA_INFO_DATA attribute: %s",
416                                  strerror(-r));
417                 return r;
418         }
419
420         r = sd_rtnl_message_close_container(m);
421         if (r < 0) {
422                 log_error_netdev(netdev,
423                                  "Could not append IFLA_LINKINFO attribute: %s",
424                                  strerror(-r));
425                 return r;
426         }
427
428         return r;
429 }
430
431 int netdev_create_tunnel(Link *link, sd_rtnl_message_handler_t callback) {
432         _cleanup_rtnl_message_unref_ sd_rtnl_message *m = NULL;
433         NetDev *netdev;
434         int r;
435
436         assert(link);
437         assert(link->network);
438         assert(link->network->tunnel);
439
440         netdev = link->network->tunnel;
441
442         assert(netdev);
443         assert(netdev->ifname);
444         assert(netdev->manager);
445         assert(netdev->manager->rtnl);
446         assert(netdev->manager->kmod_ctx);
447
448         /* Load kernel module first */
449         switch(netdev->kind) {
450         case NETDEV_KIND_IPIP:
451         case NETDEV_KIND_GRE:
452         case NETDEV_KIND_SIT:
453                 r = load_module(netdev->manager->kmod_ctx,
454                                 netdev_kind_to_string(netdev->kind));
455                 if (r < 0) {
456                         log_error_netdev(netdev,
457                                          "Could not load Kernel module: %s . Ignoring",
458                                          netdev_kind_to_string(netdev->kind));
459                         return r;
460                 }
461                 break;
462         case NETDEV_KIND_VTI:
463                 break;
464         default:
465                 return -ENOTSUP;
466         }
467
468         r = sd_rtnl_message_new_link(netdev->manager->rtnl, &m, RTM_NEWLINK, 0);
469         if (r < 0) {
470                 log_error_netdev(netdev,
471                                  "Could not allocate RTM_NEWLINK message: %s",
472                                  strerror(-r));
473                 return r;
474         }
475
476         switch(netdev->kind) {
477         case NETDEV_KIND_IPIP:
478                 r = netdev_fill_ipip_rtnl_message(link, m);
479                 if(r < 0)
480                         return r;
481                 break;
482         case NETDEV_KIND_SIT:
483                 r = netdev_fill_sit_rtnl_message(link, m);
484                 if(r < 0)
485                         return r;
486                 break;
487         case NETDEV_KIND_VTI:
488                 netdev_fill_vti_rtnl_message(link, m);
489                 if(r < 0)
490                         return r;
491                 break;
492         case NETDEV_KIND_GRE:
493                 r = netdev_fill_ipgre_rtnl_message(link, m);
494                 if(r < 0)
495                         return r;
496                 break;
497         default:
498                 return -ENOTSUP;
499         }
500
501         r = sd_rtnl_call_async(netdev->manager->rtnl, m, callback, netdev, 0, NULL);
502         if (r < 0) {
503                 log_error_netdev(netdev,
504                                  "Could not send rtnetlink message: %s", strerror(-r));
505                 return r;
506         }
507
508         log_debug_netdev(netdev, "Creating tunnel netdev: %s",
509                          netdev_kind_to_string(netdev->kind));
510
511         netdev->state = NETDEV_STATE_CREATING;
512
513         return 0;
514 }