]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/network/networkd-link.c
networkd: minor fixes
[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;
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) {
c166a070 99 log_error("Could not create link: %s", strerror(-r));
f579559b
TG
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
f882c247 114static int link_enter_configured(Link *link) {
c166a070 115 log_info("Link '%s' configured", link->ifname);
f882c247
TG
116
117 link->state = LINK_STATE_CONFIGURED;
118
119 return 0;
120}
121
122static int link_enter_failed(Link *link) {
c166a070 123 log_warning("Could not configure link '%s'", link->ifname);
f882c247
TG
124
125 link->state = LINK_STATE_FAILED;
126
127 return 0;
128}
129
130static bool link_is_up(Link *link) {
131 return link->flags & IFF_UP;
132}
133
134static int link_enter_routes_set(Link *link) {
c166a070 135 log_info("Routes set for link '%s'", link->ifname);
f882c247
TG
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
145static 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);
c166a070
TG
158 if (r < 0 && r != -EEXIST)
159 log_warning("Could not set route on interface '%s': %s",
160 link->ifname, strerror(-r));
f882c247
TG
161
162 if (link->rtnl_messages == 0)
163 return link_enter_routes_set(link);
164
165 return 1;
166}
167
168static 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)
c166a070
TG
185 return link_enter_failed(link);
186
187 link->rtnl_messages ++;
f882c247
TG
188 }
189
190 return 0;
191}
192
193static int link_enter_addresses_set(Link *link) {
c166a070 194 log_info("Addresses set for link '%s'", link->ifname);
f882c247
TG
195
196 link->state = LINK_STATE_ADDRESSES_SET;
197
198 return link_enter_set_routes(link);
199}
200
201static 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);
c166a070
TG
214 if (r < 0 && r != -EEXIST)
215 log_warning("Could not set address on interface '%s': %s",
216 link->ifname, strerror(-r));
f882c247
TG
217
218 if (link->rtnl_messages == 0)
219 link_enter_addresses_set(link);
220
221 return 1;
222}
223
224static 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)
c166a070
TG
240 return link_enter_failed(link);
241
242 link->rtnl_messages ++;
f882c247
TG
243 }
244
245 return 0;
246}
247
248static 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);
c166a070
TG
253 if (r < 0)
254 log_warning("Could not bring up interface '%s': %s",
255 link->ifname, strerror(-r));
f882c247
TG
256
257 link->flags |= IFF_UP;
258
c166a070 259 log_info("Link '%s' is up", link->ifname);
f882c247
TG
260
261 if (link->state == LINK_STATE_ROUTES_SET)
262 return link_enter_configured(link);
263
264 return 1;
265}
266
267static int link_up(Link *link) {
f579559b
TG
268 _cleanup_sd_rtnl_message_unref_ sd_rtnl_message *req = NULL;
269 int r;
270
f882c247
TG
271 assert(link);
272 assert(link->manager);
273 assert(link->manager->rtnl);
274
f579559b
TG
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
f882c247 281 r = sd_rtnl_call_async(link->manager->rtnl, req, link_handler, link, 0, NULL);
f579559b 282 if (r < 0) {
f882c247 283 log_error("Could not send rtnetlink message: %s", strerror(-r));
f579559b
TG
284 return r;
285 }
286
f882c247
TG
287 return 0;
288}
289
290int 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);
f579559b
TG
300
301 return 0;
302}