]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/network/networkd-link.c
rtnl: add link_get_flags
[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) {
c166a070 131 log_warning("Could not configure link '%s'", link->ifname);
f882c247
TG
132
133 link->state = LINK_STATE_FAILED;
134
135 return 0;
136}
137
138static bool link_is_up(Link *link) {
139 return link->flags & IFF_UP;
140}
141
142static int link_enter_routes_set(Link *link) {
c166a070 143 log_info("Routes set for link '%s'", link->ifname);
f882c247
TG
144
145 if (link_is_up(link))
146 return link_enter_configured(link);
147
148 link->state = LINK_STATE_ROUTES_SET;
149
150 return 0;
151}
152
153static int route_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
154 Link *link = userdata;
155 int r;
156
157 assert(link->rtnl_messages > 0);
158 assert(link->state == LINK_STATE_SET_ROUTES || link->state == LINK_STATE_FAILED);
159
160 link->rtnl_messages --;
161
162 if (link->state == LINK_STATE_FAILED)
163 return 1;
164
165 r = sd_rtnl_message_get_errno(m);
c166a070
TG
166 if (r < 0 && r != -EEXIST)
167 log_warning("Could not set route on interface '%s': %s",
168 link->ifname, strerror(-r));
f882c247
TG
169
170 if (link->rtnl_messages == 0)
171 return link_enter_routes_set(link);
172
173 return 1;
174}
175
176static int link_enter_set_routes(Link *link) {
177 Route *route;
178 int r;
179
180 assert(link);
181 assert(link->network);
182 assert(link->rtnl_messages == 0);
183 assert(link->state == LINK_STATE_ADDRESSES_SET);
184
185 link->state = LINK_STATE_SET_ROUTES;
186
187 if (!link->network->routes)
188 return link_enter_routes_set(link);
189
190 LIST_FOREACH(routes, route, link->network->routes) {
191 r = route_configure(route, link, &route_handler);
192 if (r < 0)
c166a070
TG
193 return link_enter_failed(link);
194
195 link->rtnl_messages ++;
f882c247
TG
196 }
197
198 return 0;
199}
200
201static int link_enter_addresses_set(Link *link) {
c166a070 202 log_info("Addresses set for link '%s'", link->ifname);
f882c247
TG
203
204 link->state = LINK_STATE_ADDRESSES_SET;
205
206 return link_enter_set_routes(link);
207}
208
209static int address_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
210 Link *link = userdata;
211 int r;
212
213 assert(link->rtnl_messages > 0);
214 assert(link->state == LINK_STATE_SET_ADDRESSES || link->state == LINK_STATE_FAILED);
215
216 link->rtnl_messages --;
217
218 if (link->state == LINK_STATE_FAILED)
219 return 1;
220
221 r = sd_rtnl_message_get_errno(m);
c166a070
TG
222 if (r < 0 && r != -EEXIST)
223 log_warning("Could not set address on interface '%s': %s",
224 link->ifname, strerror(-r));
f882c247
TG
225
226 if (link->rtnl_messages == 0)
227 link_enter_addresses_set(link);
228
229 return 1;
230}
231
232static int link_enter_set_addresses(Link *link) {
233 Address *address;
234 int r;
235
236 assert(link);
237 assert(link->network);
238 assert(link->rtnl_messages == 0);
239
240 if (!link->network->addresses)
241 return link_enter_addresses_set(link);
242
243 link->state = LINK_STATE_SET_ADDRESSES;
244
245 LIST_FOREACH(addresses, address, link->network->addresses) {
246 r = address_configure(address, link, &address_handler);
247 if (r < 0)
c166a070
TG
248 return link_enter_failed(link);
249
250 link->rtnl_messages ++;
f882c247
TG
251 }
252
253 return 0;
254}
255
256static int link_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
257 Link *link = userdata;
258 int r;
259
260 r = sd_rtnl_message_get_errno(m);
c166a070
TG
261 if (r < 0)
262 log_warning("Could not bring up interface '%s': %s",
263 link->ifname, strerror(-r));
f882c247
TG
264
265 link->flags |= IFF_UP;
266
c166a070 267 log_info("Link '%s' is up", link->ifname);
f882c247
TG
268
269 if (link->state == LINK_STATE_ROUTES_SET)
270 return link_enter_configured(link);
271
272 return 1;
273}
274
275static int link_up(Link *link) {
f579559b
TG
276 _cleanup_sd_rtnl_message_unref_ sd_rtnl_message *req = NULL;
277 int r;
278
f882c247
TG
279 assert(link);
280 assert(link->manager);
281 assert(link->manager->rtnl);
282
f579559b
TG
283 r = sd_rtnl_message_link_new(RTM_NEWLINK, link->ifindex, 0, IFF_UP, &req);
284 if (r < 0) {
285 log_error("Could not allocate RTM_NEWLINK message");
286 return r;
287 }
288
f882c247 289 r = sd_rtnl_call_async(link->manager->rtnl, req, link_handler, link, 0, NULL);
f579559b 290 if (r < 0) {
f882c247 291 log_error("Could not send rtnetlink message: %s", strerror(-r));
f579559b
TG
292 return r;
293 }
294
f882c247
TG
295 return 0;
296}
297
02b59d57 298static int link_enter_bridge_joined(Link *link) {
f882c247
TG
299 int r;
300
301 r = link_up(link);
302 if (r < 0)
303 return link_enter_failed(link);
304
02b59d57
TG
305 link->state = LINK_STATE_BRIDGE_JOINED;
306
307 return link_enter_set_addresses(link);
308}
309
310static int bridge_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
311 Link *link = userdata;
312 int r;
313
314 assert(link->state == LINK_STATE_JOIN_BRIDGE || link->state == LINK_STATE_FAILED);
315
316 if (link->state == LINK_STATE_FAILED)
317 return 1;
318
319 r = sd_rtnl_message_get_errno(m);
320 if (r < 0)
321 log_warning("Could not join interface '%s' to bridge: %s",
322 link->ifname, strerror(-r));
323
324 link_enter_bridge_joined(link);
325
326 return 1;
327}
328
329static int link_enter_join_bridge(Link *link) {
330 int r;
331
332 assert(link);
333 assert(link->network);
334
335 if (!link->network->bridge)
336 return link_enter_bridge_joined(link);
337
338 link->state = LINK_STATE_JOIN_BRIDGE;
339
340 r = bridge_join(link->network->bridge, link, &bridge_handler);
341 if (r < 0)
342 return link_enter_failed(link);
343
344 return 0;
345}
346
347int link_configure(Link *link) {
348 int r;
349
350 r = link_enter_join_bridge(link);
f882c247
TG
351 if (r < 0)
352 return link_enter_failed(link);
f579559b
TG
353
354 return 0;
355}