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