]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/network/networkd-link.c
networkd: rename link_update_flags to link_update
[thirdparty/systemd.git] / src / network / networkd-link.c
CommitLineData
f579559b
TG
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
29int link_new(Manager *manager, struct udev_device *device, Link **ret) {
30 _cleanup_link_free_ Link *link = NULL;
8cd11a0f 31 const char *mac;
602cc437 32 struct ether_addr *mac_addr;
c166a070 33 const char *ifname;
f579559b
TG
34 int r;
35
36 assert(device);
37 assert(ret);
38
39 link = new0(Link, 1);
40 if (!link)
41 return -ENOMEM;
42
5a3eb5a7
TG
43 link->manager = manager;
44 link->state = _LINK_STATE_INVALID;
45
0617ffab
TG
46 link->ifindex = udev_device_get_ifindex(device);
47 if (link->ifindex <= 0)
f579559b
TG
48 return -EINVAL;
49
8cd11a0f 50 mac = udev_device_get_sysattr_value(device, "address");
5a3eb5a7
TG
51 if (mac) {
52 mac_addr = ether_aton(mac);
53 if (mac_addr)
54 memcpy(&link->mac, mac_addr, sizeof(struct ether_addr));
55 }
f579559b 56
c166a070
TG
57 ifname = udev_device_get_sysname(device);
58 link->ifname = strdup(ifname);
59
0617ffab 60 r = hashmap_put(manager->links, &link->ifindex, link);
f579559b
TG
61 if (r < 0)
62 return r;
63
64 *ret = link;
65 link = NULL;
66
67 return 0;
68}
69
70void link_free(Link *link) {
71 if (!link)
72 return;
73
0617ffab 74 assert(link->manager);
f579559b 75
0617ffab 76 hashmap_remove(link->manager->links, &link->ifindex);
f579559b 77
c166a070
TG
78 free(link->ifname);
79
f579559b
TG
80 free(link);
81}
82
83int link_add(Manager *m, struct udev_device *device) {
84 Link *link;
85 Network *network;
86 int r;
87 uint64_t ifindex;
02b59d57 88 const char *devtype;
f579559b
TG
89
90 assert(m);
91 assert(device);
92
93 ifindex = udev_device_get_ifindex(device);
94 link = hashmap_get(m->links, &ifindex);
95 if (link)
96 return 0;
97
98 r = link_new(m, device, &link);
99 if (r < 0) {
c166a070 100 log_error("Could not create link: %s", strerror(-r));
f579559b
TG
101 return r;
102 }
103
02b59d57
TG
104 devtype = udev_device_get_devtype(device);
105 if (streq_ptr(devtype, "bridge")) {
106 r = bridge_set_link(m, link);
107 if (r < 0)
108 return r == -ENOENT ? 0 : r;
109 }
110
f579559b
TG
111 r = network_get(m, device, &network);
112 if (r < 0)
113 return r == -ENOENT ? 0 : r;
114
115 r = network_apply(m, network, link);
116 if (r < 0)
117 return r;
118
119 return 0;
120}
121
f882c247 122static int link_enter_configured(Link *link) {
c166a070 123 log_info("Link '%s' configured", link->ifname);
f882c247
TG
124
125 link->state = LINK_STATE_CONFIGURED;
126
127 return 0;
128}
129
130static int link_enter_failed(Link *link) {
f882c247
TG
131 link->state = LINK_STATE_FAILED;
132
133 return 0;
134}
135
f882c247
TG
136static int route_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
137 Link *link = userdata;
138 int r;
139
140 assert(link->rtnl_messages > 0);
141 assert(link->state == LINK_STATE_SET_ROUTES || link->state == LINK_STATE_FAILED);
142
143 link->rtnl_messages --;
144
145 if (link->state == LINK_STATE_FAILED)
146 return 1;
147
148 r = sd_rtnl_message_get_errno(m);
c166a070
TG
149 if (r < 0 && r != -EEXIST)
150 log_warning("Could not set route on interface '%s': %s",
151 link->ifname, strerror(-r));
f882c247 152
dd3efc09
TG
153 if (link->rtnl_messages == 0) {
154 log_info("Routes set for link '%s'", link->ifname);
155 link_enter_configured(link);
156 }
f882c247
TG
157
158 return 1;
159}
160
161static int link_enter_set_routes(Link *link) {
162 Route *route;
163 int r;
164
165 assert(link);
166 assert(link->network);
167 assert(link->rtnl_messages == 0);
168 assert(link->state == LINK_STATE_ADDRESSES_SET);
169
170 link->state = LINK_STATE_SET_ROUTES;
171
172 if (!link->network->routes)
dd3efc09 173 return link_enter_configured(link);
f882c247
TG
174
175 LIST_FOREACH(routes, route, link->network->routes) {
176 r = route_configure(route, link, &route_handler);
dd3efc09
TG
177 if (r < 0) {
178 log_warning("Could not set routes for link '%s'", link->ifname);
c166a070 179 return link_enter_failed(link);
dd3efc09 180 }
c166a070
TG
181
182 link->rtnl_messages ++;
f882c247
TG
183 }
184
185 return 0;
186}
187
188static int link_enter_addresses_set(Link *link) {
f882c247
TG
189 link->state = LINK_STATE_ADDRESSES_SET;
190
191 return link_enter_set_routes(link);
192}
193
194static 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);
c166a070
TG
207 if (r < 0 && r != -EEXIST)
208 log_warning("Could not set address on interface '%s': %s",
209 link->ifname, strerror(-r));
f882c247 210
dd3efc09
TG
211 if (link->rtnl_messages == 0) {
212 log_info("Addresses set for link '%s'", link->ifname);
f882c247 213 link_enter_addresses_set(link);
dd3efc09 214 }
f882c247
TG
215
216 return 1;
217}
218
219static 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);
dd3efc09
TG
234 if (r < 0) {
235 log_warning("Could not set addresses for link '%s'", link->ifname);
c166a070 236 return link_enter_failed(link);
dd3efc09 237 }
c166a070
TG
238
239 link->rtnl_messages ++;
f882c247
TG
240 }
241
242 return 0;
243}
244
dd3efc09 245static int link_get_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
f882c247
TG
246 Link *link = userdata;
247 int r;
248
249 r = sd_rtnl_message_get_errno(m);
dd3efc09 250 if (r < 0) {
b0d27a25 251 log_warning("Could not get state of interface '%s': %s",
c166a070 252 link->ifname, strerror(-r));
dd3efc09
TG
253 link_enter_failed(link);
254 }
f882c247 255
dd3efc09
TG
256 return 1;
257}
f882c247 258
dd3efc09
TG
259static int link_get(Link *link) {
260 _cleanup_sd_rtnl_message_unref_ sd_rtnl_message *req = NULL;
261 int r;
f882c247 262
dd3efc09
TG
263 assert(link);
264 assert(link->manager);
265 assert(link->manager->rtnl);
266
fc25d7f8 267 r = sd_rtnl_message_link_new(RTM_GETLINK, link->ifindex, &req);
dd3efc09
TG
268 if (r < 0) {
269 log_error("Could not allocate RTM_GETLINK message");
270 return r;
271 }
272
273 r = sd_rtnl_call_async(link->manager->rtnl, req, link_get_handler, link, 0, NULL);
274 if (r < 0) {
275 log_error("Could not send rtnetlink message: %s", strerror(-r));
276 return r;
277 }
278
279 return 0;
280}
281
282static int link_up_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
283 Link *link = userdata;
284 int r;
285
286 r = sd_rtnl_message_get_errno(m);
287 if (r < 0) {
288 log_warning("Could not bring up interface '%s': %s",
289 link->ifname, strerror(-r));
290 link_enter_failed(link);
291 }
f882c247
TG
292
293 return 1;
294}
295
296static int link_up(Link *link) {
f579559b
TG
297 _cleanup_sd_rtnl_message_unref_ sd_rtnl_message *req = NULL;
298 int r;
299
f882c247
TG
300 assert(link);
301 assert(link->manager);
302 assert(link->manager->rtnl);
303
0f49a5f7 304 r = sd_rtnl_message_link_new(RTM_SETLINK, link->ifindex, &req);
f579559b 305 if (r < 0) {
0f49a5f7 306 log_error("Could not allocate RTM_SETLINK message");
f579559b
TG
307 return r;
308 }
309
fc25d7f8
TG
310 r = sd_rtnl_message_link_set_flags(req, IFF_UP);
311 if (r < 0) {
312 log_error("Could not set link flags");
313 return r;
314 }
315
dd3efc09 316 r = sd_rtnl_call_async(link->manager->rtnl, req, link_up_handler, link, 0, NULL);
f579559b 317 if (r < 0) {
f882c247 318 log_error("Could not send rtnetlink message: %s", strerror(-r));
f579559b
TG
319 return r;
320 }
321
f882c247
TG
322 return 0;
323}
324
02b59d57 325static int link_enter_bridge_joined(Link *link) {
f882c247
TG
326 int r;
327
dd3efc09
TG
328 link->state = LINK_STATE_BRIDGE_JOINED;
329
f882c247
TG
330 r = link_up(link);
331 if (r < 0)
332 return link_enter_failed(link);
333
02b59d57
TG
334 return link_enter_set_addresses(link);
335}
336
337static int bridge_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
338 Link *link = userdata;
339 int r;
340
341 assert(link->state == LINK_STATE_JOIN_BRIDGE || link->state == LINK_STATE_FAILED);
342
343 if (link->state == LINK_STATE_FAILED)
344 return 1;
345
346 r = sd_rtnl_message_get_errno(m);
347 if (r < 0)
dd3efc09
TG
348 log_warning("Could not join interface '%s' to bridge '%s': %s",
349 link->ifname, link->network->bridge->name, strerror(-r));
350 else
351 log_info("Join interface '%s' to bridge: %s",
352 link->ifname, link->network->bridge->name);
02b59d57
TG
353
354 link_enter_bridge_joined(link);
355
356 return 1;
357}
358
359static int link_enter_join_bridge(Link *link) {
360 int r;
361
362 assert(link);
363 assert(link->network);
364
365 if (!link->network->bridge)
366 return link_enter_bridge_joined(link);
367
368 link->state = LINK_STATE_JOIN_BRIDGE;
369
370 r = bridge_join(link->network->bridge, link, &bridge_handler);
dd3efc09
TG
371 if (r < 0) {
372 log_warning("Could not join link '%s' to bridge '%s'", link->ifname,
373 link->network->bridge->name);
02b59d57 374 return link_enter_failed(link);
dd3efc09 375 }
02b59d57
TG
376
377 return 0;
378}
379
380int link_configure(Link *link) {
381 int r;
382
dd3efc09
TG
383 r = link_get(link);
384 if (r < 0)
385 return link_enter_failed(link);
386
02b59d57 387 r = link_enter_join_bridge(link);
f882c247
TG
388 if (r < 0)
389 return link_enter_failed(link);
f579559b
TG
390
391 return 0;
392}
dd3efc09 393
22936833
TG
394int link_update(Link *link, sd_rtnl_message *m) {
395 unsigned flags;
396 int r;
397
dd3efc09 398 assert(link);
22936833
TG
399 assert(m);
400
401 r = sd_rtnl_message_link_get_flags(m, &flags);
402 if (r < 0) {
403 log_warning("Could not get link flags of '%s'", link->ifname);
404 return r;
405 }
dd3efc09
TG
406
407 if (link->flags & IFF_UP && !(flags & IFF_UP))
408 log_info("Interface '%s' is down", link->ifname);
409 else if (!(link->flags & IFF_UP) && flags & IFF_UP)
410 log_info("Interface '%s' is up", link->ifname);
411
412 if (link->flags & IFF_LOWER_UP && !(flags & IFF_LOWER_UP))
413 log_info("Interface '%s' is disconnected", link->ifname);
414 else if (!(link->flags & IFF_LOWER_UP) && flags & IFF_LOWER_UP)
415 log_info("Interface '%s' is connected", link->ifname);
416
417 link->flags = flags;
418
419 return 0;
420}