]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/network/networkd-link.c
networkd: make all calls async
[thirdparty/systemd.git] / src / network / networkd-link.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4 This file is part of systemd.
5
6 Copyright 2013 Tom Gundersen <teg@jklm.no>
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 <linux/if.h>
24
25 #include "networkd.h"
26 #include "libudev-private.h"
27 #include "util.h"
28
29 int link_new(Manager *manager, struct udev_device *device, Link **ret) {
30 _cleanup_link_free_ Link *link = NULL;
31 uint64_t ifindex;
32 const char *mac;
33 int r;
34
35 assert(device);
36 assert(ret);
37
38 link = new0(Link, 1);
39 if (!link)
40 return -ENOMEM;
41
42 ifindex = udev_device_get_ifindex(device);
43 if (ifindex <= 0)
44 return -EINVAL;
45
46 mac = udev_device_get_sysattr_value(device, "address");
47 if (!mac)
48 return -EINVAL;
49
50 memcpy(&link->mac.ether_addr_octet[0], ether_aton(mac), ETH_ALEN);
51 link->ifindex = ifindex;
52 link->manager = manager;
53 link->state = _LINK_STATE_INVALID;
54
55 r = hashmap_put(manager->links, &ifindex, link);
56 if (r < 0)
57 return r;
58
59 *ret = link;
60 link = NULL;
61
62 return 0;
63 }
64
65 void link_free(Link *link) {
66 if (!link)
67 return;
68
69 network_free(link->network);
70
71 hashmap_remove(link->manager->links, link);
72
73 free(link);
74 }
75
76 int link_add(Manager *m, struct udev_device *device) {
77 Link *link;
78 Network *network;
79 int r;
80 uint64_t ifindex;
81
82 assert(m);
83 assert(device);
84
85 ifindex = udev_device_get_ifindex(device);
86 link = hashmap_get(m->links, &ifindex);
87 if (link)
88 return 0;
89
90 r = link_new(m, device, &link);
91 if (r < 0) {
92 log_error("could not create link: %s", strerror(-r));
93 return r;
94 }
95
96 r = network_get(m, device, &network);
97 if (r < 0)
98 return r == -ENOENT ? 0 : r;
99
100 r = network_apply(m, network, link);
101 if (r < 0)
102 return r;
103
104 return 0;
105 }
106
107 static int link_enter_configured(Link *link) {
108 log_info("Link configured successfully.");
109
110 link->state = LINK_STATE_CONFIGURED;
111
112 return 0;
113 }
114
115 static int link_enter_failed(Link *link) {
116 log_warning("Could not configure link.");
117
118 link->state = LINK_STATE_FAILED;
119
120 return 0;
121 }
122
123 static bool link_is_up(Link *link) {
124 return link->flags & IFF_UP;
125 }
126
127 static int link_enter_routes_set(Link *link) {
128 log_info("Routes set for link %d", link->ifindex);
129
130 if (link_is_up(link))
131 return link_enter_configured(link);
132
133 link->state = LINK_STATE_ROUTES_SET;
134
135 return 0;
136 }
137
138 static int route_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
139 Link *link = userdata;
140 int r;
141
142 assert(link->rtnl_messages > 0);
143 assert(link->state == LINK_STATE_SET_ROUTES || link->state == LINK_STATE_FAILED);
144
145 link->rtnl_messages --;
146
147 if (link->state == LINK_STATE_FAILED)
148 return 1;
149
150 r = sd_rtnl_message_get_errno(m);
151 if (r < 0 && r != -EEXIST) {
152 log_warning("Could not set route on interface %d: %s",
153 link->ifindex, strerror(-r));
154 return link_enter_failed(link);
155 }
156
157 if (link->rtnl_messages == 0)
158 return link_enter_routes_set(link);
159
160 return 1;
161 }
162
163 static int link_enter_set_routes(Link *link) {
164 Route *route;
165 int r;
166
167 assert(link);
168 assert(link->network);
169 assert(link->rtnl_messages == 0);
170 assert(link->state == LINK_STATE_ADDRESSES_SET);
171
172 link->state = LINK_STATE_SET_ROUTES;
173
174 if (!link->network->routes)
175 return link_enter_routes_set(link);
176
177 LIST_FOREACH(routes, route, link->network->routes) {
178 r = route_configure(route, link, &route_handler);
179 if (r < 0)
180 link_enter_failed(link);
181 }
182
183 return 0;
184 }
185
186 static int link_enter_addresses_set(Link *link) {
187 log_info("Addresses set for link %d", link->ifindex);
188
189 link->state = LINK_STATE_ADDRESSES_SET;
190
191 return link_enter_set_routes(link);
192 }
193
194 static int address_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
195 Link *link = userdata;
196 int r;
197
198 assert(link->rtnl_messages > 0);
199 assert(link->state == LINK_STATE_SET_ADDRESSES || link->state == LINK_STATE_FAILED);
200
201 link->rtnl_messages --;
202
203 if (link->state == LINK_STATE_FAILED)
204 return 1;
205
206 r = sd_rtnl_message_get_errno(m);
207 if (r < 0 && r != -EEXIST) {
208 log_warning("Could not set address on interface %d: %s",
209 link->ifindex, strerror(-r));
210 link_enter_failed(link);
211 }
212
213 if (link->rtnl_messages == 0)
214 link_enter_addresses_set(link);
215
216 return 1;
217 }
218
219 static int link_enter_set_addresses(Link *link) {
220 Address *address;
221 int r;
222
223 assert(link);
224 assert(link->network);
225 assert(link->rtnl_messages == 0);
226
227 if (!link->network->addresses)
228 return link_enter_addresses_set(link);
229
230 link->state = LINK_STATE_SET_ADDRESSES;
231
232 LIST_FOREACH(addresses, address, link->network->addresses) {
233 r = address_configure(address, link, &address_handler);
234 if (r < 0)
235 link_enter_failed(link);
236 }
237
238 return 0;
239 }
240
241 static int link_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
242 Link *link = userdata;
243 int r;
244
245 r = sd_rtnl_message_get_errno(m);
246 if (r < 0) {
247 log_warning("Could not bring up interface %d: %s",
248 link->ifindex, strerror(-r));
249 return link_enter_failed(link);
250 }
251
252 link->flags |= IFF_UP;
253
254 log_info("Link is UP.");
255
256 if (link->state == LINK_STATE_ROUTES_SET)
257 return link_enter_configured(link);
258
259 return 1;
260 }
261
262 static int link_up(Link *link) {
263 _cleanup_sd_rtnl_message_unref_ sd_rtnl_message *req = NULL;
264 int r;
265
266 assert(link);
267 assert(link->manager);
268 assert(link->manager->rtnl);
269
270 r = sd_rtnl_message_link_new(RTM_NEWLINK, link->ifindex, 0, IFF_UP, &req);
271 if (r < 0) {
272 log_error("Could not allocate RTM_NEWLINK message");
273 return r;
274 }
275
276 r = sd_rtnl_call_async(link->manager->rtnl, req, link_handler, link, 0, NULL);
277 if (r < 0) {
278 log_error("Could not send rtnetlink message: %s", strerror(-r));
279 return r;
280 }
281
282 return 0;
283 }
284
285 int link_configure(Link *link) {
286 int r;
287
288 r = link_up(link);
289 if (r < 0)
290 return link_enter_failed(link);
291
292 r = link_enter_set_addresses(link);
293 if (r < 0)
294 return link_enter_failed(link);
295
296 return 0;
297 }