chiark / gitweb /
9b4cb4f959cf061b8e9e03f97b88bb82f2fbf6c7
[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_close_container(m);
211         if (r < 0) {
212                 log_error_netdev(netdev,
213                                  "Could not append IFLA_INFO_DATA 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_LINKINFO attribute: %s",
222                                  strerror(-r));
223                 return r;
224         }
225
226         return r;
227 }
228
229 static int netdev_fill_ipgre_rtnl_message(Link *link, sd_rtnl_message *m) {
230         NetDev *netdev;
231         int r;
232
233         assert(link);
234         assert(link->network);
235         assert(link->network->tunnel);
236         assert(m);
237
238         netdev = link->network->tunnel;
239
240         r = sd_rtnl_message_append_string(m, IFLA_IFNAME, netdev->ifname);
241         if (r < 0) {
242                 log_error_netdev(netdev,
243                                  "Could not append IFLA_IFNAME, attribute: %s",
244                                  strerror(-r));
245                 return r;
246         }
247
248         if(netdev->mtu) {
249                 r = sd_rtnl_message_append_u32(m, IFLA_MTU, netdev->mtu);
250                 if (r < 0) {
251                         log_error_netdev(netdev,
252                                          "Could not append IFLA_MTU attribute: %s",
253                                          strerror(-r));
254                         return r;
255                 }
256         }
257
258         r = sd_rtnl_message_open_container(m, IFLA_LINKINFO);
259         if (r < 0) {
260                 log_error_netdev(netdev,
261                                  "Could not append IFLA_LINKINFO attribute: %s",
262                                  strerror(-r));
263                 return r;
264         }
265
266         r = sd_rtnl_message_open_container_union(m, IFLA_INFO_DATA,
267                                                  netdev_kind_to_string(netdev->kind));
268         if (r < 0) {
269                 log_error_netdev(netdev,
270                                  "Could not append IFLA_INFO_DATA attribute: %s",
271                                  strerror(-r));
272                 return r;
273         }
274
275         r = sd_rtnl_message_append_u32(m, IFLA_GRE_LINK, link->ifindex);
276         if (r < 0) {
277                 log_error_netdev(netdev,
278                                  "Could not append IFLA_GRE_LINK attribute: %s",
279                                  strerror(-r));
280                 return r;
281         }
282
283         r = sd_rtnl_message_append_in_addr(m, IFLA_GRE_LOCAL, &netdev->tunnel_local);
284         if (r < 0) {
285                 log_error_netdev(netdev,
286                                  "Could not append IFLA_GRE_LOCAL attribute: %s",
287                                  strerror(-r));
288                 return r;
289         }
290
291         r = sd_rtnl_message_append_in_addr(m, IFLA_GRE_REMOTE, &netdev->tunnel_remote);
292         if (r < 0) {
293                 log_error_netdev(netdev,
294                                  "Could not append IFLA_GRE_REMOTE attribute: %s",
295                                  strerror(-r));
296                 return r;
297         }
298
299         r = sd_rtnl_message_append_u8(m, IFLA_GRE_TTL, netdev->tunnel_ttl);
300         if (r < 0) {
301                 log_error_netdev(netdev,
302                                  "Could not append IFLA_GRE_TTL attribute: %s",
303                                  strerror(-r));
304                 return r;
305         }
306
307         r = sd_rtnl_message_append_u8(m, IFLA_GRE_TOS, netdev->tunnel_tos);
308         if (r < 0) {
309                 log_error_netdev(netdev,
310                                  "Could not append IFLA_GRE_TOS attribute: %s",
311                                  strerror(-r));
312                 return r;
313         }
314
315         r = sd_rtnl_message_close_container(m);
316         if (r < 0) {
317                 log_error_netdev(netdev,
318                                  "Could not append IFLA_INFO_DATA 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_LINKINFO attribute: %s",
327                                  strerror(-r));
328                 return r;
329         }
330
331         return r;
332 }
333
334
335 int netdev_create_tunnel(Link *link, sd_rtnl_message_handler_t callback) {
336         _cleanup_rtnl_message_unref_ sd_rtnl_message *m = NULL;
337         NetDev *netdev;
338         int r;
339
340         assert(link);
341         assert(link->network);
342         assert(link->network->tunnel);
343
344         netdev = link->network->tunnel;
345
346         assert(netdev);
347         assert(netdev->ifname);
348         assert(netdev->manager);
349         assert(netdev->manager->rtnl);
350         assert(netdev->manager->kmod_ctx);
351
352         /* Load kernel module first */
353         switch(netdev->kind) {
354         case NETDEV_KIND_IPIP:
355         case NETDEV_KIND_GRE:
356         case NETDEV_KIND_SIT:
357                 r = load_module(netdev->manager->kmod_ctx,
358                                 netdev_kind_to_string(netdev->kind));
359                 if (r < 0) {
360                         log_error_netdev(netdev,
361                                          "Could not load Kernel module: %s . Ignoring",
362                                          netdev_kind_to_string(netdev->kind));
363                         return r;
364                 }
365                 break;
366         default:
367                 return -ENOTSUP;
368         }
369
370         r = sd_rtnl_message_new_link(netdev->manager->rtnl, &m, RTM_NEWLINK, 0);
371         if (r < 0) {
372                 log_error_netdev(netdev,
373                                  "Could not allocate RTM_NEWLINK message: %s",
374                                  strerror(-r));
375                 return r;
376         }
377
378         switch(netdev->kind) {
379         case NETDEV_KIND_IPIP:
380                 r = netdev_fill_ipip_rtnl_message(link, m);
381                 if(r < 0)
382                         return r;
383                 break;
384         case NETDEV_KIND_SIT:
385                 r = netdev_fill_sit_rtnl_message(link, m);
386                 if(r < 0)
387                         return r;
388                 break;
389         case NETDEV_KIND_GRE:
390                 r = netdev_fill_ipgre_rtnl_message(link, m);
391                 if(r < 0)
392                         return r;
393                 break;
394         default:
395                 return -ENOTSUP;
396         }
397
398         r = sd_rtnl_call_async(netdev->manager->rtnl, m, callback, netdev, 0, NULL);
399         if (r < 0) {
400                 log_error_netdev(netdev,
401                                  "Could not send rtnetlink message: %s", strerror(-r));
402                 return r;
403         }
404
405         log_debug_netdev(netdev, "Creating tunnel netdev: %s",
406                          netdev_kind_to_string(netdev->kind));
407
408         netdev->state = NETDEV_STATE_CREATING;
409
410         return 0;
411 }