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