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