1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2013 Tom Gundersen <teg@jklm.no>
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.
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.
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/>.
22 #include <netinet/ether.h>
26 #include "libudev-private.h"
29 int link_new(Manager *manager, struct udev_device *device, Link **ret) {
30 _cleanup_link_free_ Link *link = NULL;
32 struct ether_addr *mac_addr;
43 link->manager = manager;
44 link->state = _LINK_STATE_INVALID;
46 link->ifindex = udev_device_get_ifindex(device);
47 if (link->ifindex <= 0)
50 mac = udev_device_get_sysattr_value(device, "address");
52 mac_addr = ether_aton(mac);
54 memcpy(&link->mac, mac_addr, sizeof(struct ether_addr));
57 ifname = udev_device_get_sysname(device);
58 link->ifname = strdup(ifname);
60 r = hashmap_put(manager->links, &link->ifindex, link);
70 void link_free(Link *link) {
74 assert(link->manager);
76 hashmap_remove(link->manager->links, &link->ifindex);
83 int link_add(Manager *m, struct udev_device *device) {
93 ifindex = udev_device_get_ifindex(device);
94 link = hashmap_get(m->links, &ifindex);
98 r = link_new(m, device, &link);
100 log_error("Could not create link: %s", strerror(-r));
104 devtype = udev_device_get_devtype(device);
105 if (streq_ptr(devtype, "bridge")) {
106 r = bridge_set_link(m, link);
108 return r == -ENOENT ? 0 : r;
111 r = network_get(m, device, &network);
113 return r == -ENOENT ? 0 : r;
115 r = network_apply(m, network, link);
122 static int link_enter_configured(Link *link) {
123 log_info("Link '%s' configured", link->ifname);
125 link->state = LINK_STATE_CONFIGURED;
130 static int link_enter_failed(Link *link) {
131 log_warning("Could not configure link '%s'", link->ifname);
133 link->state = LINK_STATE_FAILED;
138 static bool link_is_up(Link *link) {
139 return link->flags & IFF_UP;
142 static int link_enter_routes_set(Link *link) {
143 log_info("Routes set for link '%s'", link->ifname);
145 if (link_is_up(link))
146 return link_enter_configured(link);
148 link->state = LINK_STATE_ROUTES_SET;
153 static int route_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
154 Link *link = userdata;
157 assert(link->rtnl_messages > 0);
158 assert(link->state == LINK_STATE_SET_ROUTES || link->state == LINK_STATE_FAILED);
160 link->rtnl_messages --;
162 if (link->state == LINK_STATE_FAILED)
165 r = sd_rtnl_message_get_errno(m);
166 if (r < 0 && r != -EEXIST)
167 log_warning("Could not set route on interface '%s': %s",
168 link->ifname, strerror(-r));
170 if (link->rtnl_messages == 0)
171 return link_enter_routes_set(link);
176 static int link_enter_set_routes(Link *link) {
181 assert(link->network);
182 assert(link->rtnl_messages == 0);
183 assert(link->state == LINK_STATE_ADDRESSES_SET);
185 link->state = LINK_STATE_SET_ROUTES;
187 if (!link->network->routes)
188 return link_enter_routes_set(link);
190 LIST_FOREACH(routes, route, link->network->routes) {
191 r = route_configure(route, link, &route_handler);
193 return link_enter_failed(link);
195 link->rtnl_messages ++;
201 static int link_enter_addresses_set(Link *link) {
202 log_info("Addresses set for link '%s'", link->ifname);
204 link->state = LINK_STATE_ADDRESSES_SET;
206 return link_enter_set_routes(link);
209 static int address_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
210 Link *link = userdata;
213 assert(link->rtnl_messages > 0);
214 assert(link->state == LINK_STATE_SET_ADDRESSES || link->state == LINK_STATE_FAILED);
216 link->rtnl_messages --;
218 if (link->state == LINK_STATE_FAILED)
221 r = sd_rtnl_message_get_errno(m);
222 if (r < 0 && r != -EEXIST)
223 log_warning("Could not set address on interface '%s': %s",
224 link->ifname, strerror(-r));
226 if (link->rtnl_messages == 0)
227 link_enter_addresses_set(link);
232 static int link_enter_set_addresses(Link *link) {
237 assert(link->network);
238 assert(link->rtnl_messages == 0);
240 if (!link->network->addresses)
241 return link_enter_addresses_set(link);
243 link->state = LINK_STATE_SET_ADDRESSES;
245 LIST_FOREACH(addresses, address, link->network->addresses) {
246 r = address_configure(address, link, &address_handler);
248 return link_enter_failed(link);
250 link->rtnl_messages ++;
256 static int link_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
257 Link *link = userdata;
260 r = sd_rtnl_message_get_errno(m);
262 log_warning("Could not bring up interface '%s': %s",
263 link->ifname, strerror(-r));
265 link->flags |= IFF_UP;
267 log_info("Link '%s' is up", link->ifname);
269 if (link->state == LINK_STATE_ROUTES_SET)
270 return link_enter_configured(link);
275 static int link_up(Link *link) {
276 _cleanup_sd_rtnl_message_unref_ sd_rtnl_message *req = NULL;
280 assert(link->manager);
281 assert(link->manager->rtnl);
283 r = sd_rtnl_message_link_new(RTM_NEWLINK, link->ifindex, 0, IFF_UP, &req);
285 log_error("Could not allocate RTM_NEWLINK message");
289 r = sd_rtnl_call_async(link->manager->rtnl, req, link_handler, link, 0, NULL);
291 log_error("Could not send rtnetlink message: %s", strerror(-r));
298 static int link_enter_bridge_joined(Link *link) {
303 return link_enter_failed(link);
305 link->state = LINK_STATE_BRIDGE_JOINED;
307 return link_enter_set_addresses(link);
310 static int bridge_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
311 Link *link = userdata;
314 assert(link->state == LINK_STATE_JOIN_BRIDGE || link->state == LINK_STATE_FAILED);
316 if (link->state == LINK_STATE_FAILED)
319 r = sd_rtnl_message_get_errno(m);
321 log_warning("Could not join interface '%s' to bridge: %s",
322 link->ifname, strerror(-r));
324 link_enter_bridge_joined(link);
329 static int link_enter_join_bridge(Link *link) {
333 assert(link->network);
335 if (!link->network->bridge)
336 return link_enter_bridge_joined(link);
338 link->state = LINK_STATE_JOIN_BRIDGE;
340 r = bridge_join(link->network->bridge, link, &bridge_handler);
342 return link_enter_failed(link);
347 int link_configure(Link *link) {
350 r = link_enter_join_bridge(link);
352 return link_enter_failed(link);