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