chiark / gitweb /
networkd: introduce ipip 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->name);
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_close_container(m);
106         if (r < 0) {
107                 log_error_netdev(netdev,
108                                  "Could not append IFLA_INFO_DATA 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_LINKINFO attribute: %s",
117                                  strerror(-r));
118                 return r;
119         }
120
121         return r;
122 }
123
124 int netdev_create_tunnel(Link *link, sd_rtnl_message_handler_t callback) {
125         _cleanup_rtnl_message_unref_ sd_rtnl_message *m = NULL;
126         NetDev *netdev;
127         int r;
128
129         assert(link);
130         assert(link->network);
131         assert(link->network->tunnel);
132
133         netdev = link->network->tunnel;
134
135         assert(netdev);
136         assert(netdev->name);
137         assert(netdev->manager);
138         assert(netdev->manager->rtnl);
139         assert(netdev->manager->kmod_ctx);
140
141         /* Load kernel module first */
142         switch(netdev->kind) {
143         case NETDEV_KIND_IPIP:
144         case NETDEV_KIND_GRE:
145         case NETDEV_KIND_SIT:
146                 r = load_module(netdev->manager->kmod_ctx,
147                                 netdev_kind_to_string(netdev->kind));
148                 if (r < 0) {
149                         log_error_netdev(netdev,
150                                          "Could not load Kernel module: %s . Ignoring",
151                                          netdev_kind_to_string(netdev->kind));
152                         return r;
153                 }
154                 break;
155         default:
156                 return -ENOTSUP;
157         }
158
159         r = sd_rtnl_message_new_link(netdev->manager->rtnl, &m, RTM_NEWLINK, 0);
160         if (r < 0) {
161                 log_error_netdev(netdev,
162                                  "Could not allocate RTM_NEWLINK message: %s",
163                                  strerror(-r));
164                 return r;
165         }
166
167         switch(netdev->kind) {
168         case NETDEV_KIND_IPIP:
169                 r = netdev_fill_ipip_rtnl_message(link, m);
170                 if(r < 0)
171                         return r;
172                 break;
173         case NETDEV_KIND_GRE:
174         case NETDEV_KIND_SIT:
175         default:
176                 return -ENOTSUP;
177         }
178
179         r = sd_rtnl_call_async(netdev->manager->rtnl, m, callback, netdev, 0, NULL);
180         if (r < 0) {
181                 log_error_netdev(netdev,
182                                  "Could not send rtnetlink message: %s", strerror(-r));
183                 return r;
184         }
185
186         log_debug_netdev(netdev, "Creating tunnel netdev: %s",
187                          netdev_kind_to_string(netdev->kind));
188
189         netdev->state = NETDEV_STATE_CREATING;
190
191         return 0;
192 }