chiark / gitweb /
1a06a17c7bca173311091a51e4840c20286cf19b
[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
343 int netdev_create_tunnel(Link *link, sd_rtnl_message_handler_t callback) {
344         _cleanup_rtnl_message_unref_ sd_rtnl_message *m = NULL;
345         NetDev *netdev;
346         int r;
347
348         assert(link);
349         assert(link->network);
350         assert(link->network->tunnel);
351
352         netdev = link->network->tunnel;
353
354         assert(netdev);
355         assert(netdev->ifname);
356         assert(netdev->manager);
357         assert(netdev->manager->rtnl);
358         assert(netdev->manager->kmod_ctx);
359
360         /* Load kernel module first */
361         switch(netdev->kind) {
362         case NETDEV_KIND_IPIP:
363         case NETDEV_KIND_GRE:
364         case NETDEV_KIND_SIT:
365                 r = load_module(netdev->manager->kmod_ctx,
366                                 netdev_kind_to_string(netdev->kind));
367                 if (r < 0) {
368                         log_error_netdev(netdev,
369                                          "Could not load Kernel module: %s . Ignoring",
370                                          netdev_kind_to_string(netdev->kind));
371                         return r;
372                 }
373                 break;
374         default:
375                 return -ENOTSUP;
376         }
377
378         r = sd_rtnl_message_new_link(netdev->manager->rtnl, &m, RTM_NEWLINK, 0);
379         if (r < 0) {
380                 log_error_netdev(netdev,
381                                  "Could not allocate RTM_NEWLINK message: %s",
382                                  strerror(-r));
383                 return r;
384         }
385
386         switch(netdev->kind) {
387         case NETDEV_KIND_IPIP:
388                 r = netdev_fill_ipip_rtnl_message(link, m);
389                 if(r < 0)
390                         return r;
391                 break;
392         case NETDEV_KIND_SIT:
393                 r = netdev_fill_sit_rtnl_message(link, m);
394                 if(r < 0)
395                         return r;
396                 break;
397         case NETDEV_KIND_GRE:
398                 r = netdev_fill_ipgre_rtnl_message(link, m);
399                 if(r < 0)
400                         return r;
401                 break;
402         default:
403                 return -ENOTSUP;
404         }
405
406         r = sd_rtnl_call_async(netdev->manager->rtnl, m, callback, netdev, 0, NULL);
407         if (r < 0) {
408                 log_error_netdev(netdev,
409                                  "Could not send rtnetlink message: %s", strerror(-r));
410                 return r;
411         }
412
413         log_debug_netdev(netdev, "Creating tunnel netdev: %s",
414                          netdev_kind_to_string(netdev->kind));
415
416         netdev->state = NETDEV_STATE_CREATING;
417
418         return 0;
419 }