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 link->state = LINK_STATE_FAILED;
136 static int route_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
137 Link *link = userdata;
140 assert(link->rtnl_messages > 0);
141 assert(link->state == LINK_STATE_SET_ROUTES || link->state == LINK_STATE_FAILED);
143 link->rtnl_messages --;
145 if (link->state == LINK_STATE_FAILED)
148 r = sd_rtnl_message_get_errno(m);
149 if (r < 0 && r != -EEXIST)
150 log_warning("Could not set route on interface '%s': %s",
151 link->ifname, strerror(-r));
153 if (link->rtnl_messages == 0) {
154 log_info("Routes set for link '%s'", link->ifname);
155 link_enter_configured(link);
161 static int link_enter_set_routes(Link *link) {
166 assert(link->network);
167 assert(link->rtnl_messages == 0);
168 assert(link->state == LINK_STATE_ADDRESSES_SET);
170 link->state = LINK_STATE_SET_ROUTES;
172 if (!link->network->routes)
173 return link_enter_configured(link);
175 LIST_FOREACH(routes, route, link->network->routes) {
176 r = route_configure(route, link, &route_handler);
178 log_warning("Could not set routes for link '%s'", link->ifname);
179 return link_enter_failed(link);
182 link->rtnl_messages ++;
188 static int link_enter_addresses_set(Link *link) {
189 link->state = LINK_STATE_ADDRESSES_SET;
191 return link_enter_set_routes(link);
194 static int address_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
195 Link *link = userdata;
198 assert(link->rtnl_messages > 0);
199 assert(link->state == LINK_STATE_SET_ADDRESSES || link->state == LINK_STATE_FAILED);
201 link->rtnl_messages --;
203 if (link->state == LINK_STATE_FAILED)
206 r = sd_rtnl_message_get_errno(m);
207 if (r < 0 && r != -EEXIST)
208 log_warning("Could not set address on interface '%s': %s",
209 link->ifname, strerror(-r));
211 if (link->rtnl_messages == 0) {
212 log_info("Addresses set for link '%s'", link->ifname);
213 link_enter_addresses_set(link);
219 static int link_enter_set_addresses(Link *link) {
224 assert(link->network);
225 assert(link->rtnl_messages == 0);
227 if (!link->network->addresses)
228 return link_enter_addresses_set(link);
230 link->state = LINK_STATE_SET_ADDRESSES;
232 LIST_FOREACH(addresses, address, link->network->addresses) {
233 r = address_configure(address, link, &address_handler);
235 log_warning("Could not set addresses for link '%s'", link->ifname);
236 return link_enter_failed(link);
239 link->rtnl_messages ++;
245 static int link_get_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
246 Link *link = userdata;
249 r = sd_rtnl_message_get_errno(m);
251 log_warning("Could not get state of interface '%s': %s",
252 link->ifname, strerror(-r));
253 link_enter_failed(link);
259 static int link_get(Link *link) {
260 _cleanup_sd_rtnl_message_unref_ sd_rtnl_message *req = NULL;
264 assert(link->manager);
265 assert(link->manager->rtnl);
267 r = sd_rtnl_message_link_new(RTM_GETLINK, link->ifindex, &req);
269 log_error("Could not allocate RTM_GETLINK message");
273 r = sd_rtnl_call_async(link->manager->rtnl, req, link_get_handler, link, 0, NULL);
275 log_error("Could not send rtnetlink message: %s", strerror(-r));
282 static int link_up_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
283 Link *link = userdata;
286 r = sd_rtnl_message_get_errno(m);
288 log_warning("Could not bring up interface '%s': %s",
289 link->ifname, strerror(-r));
290 link_enter_failed(link);
296 static int link_up(Link *link) {
297 _cleanup_sd_rtnl_message_unref_ sd_rtnl_message *req = NULL;
301 assert(link->manager);
302 assert(link->manager->rtnl);
304 r = sd_rtnl_message_link_new(RTM_SETLINK, link->ifindex, &req);
306 log_error("Could not allocate RTM_SETLINK message");
310 r = sd_rtnl_message_link_set_flags(req, IFF_UP);
312 log_error("Could not set link flags");
316 r = sd_rtnl_call_async(link->manager->rtnl, req, link_up_handler, link, 0, NULL);
318 log_error("Could not send rtnetlink message: %s", strerror(-r));
325 static int link_enter_bridge_joined(Link *link) {
328 link->state = LINK_STATE_BRIDGE_JOINED;
332 return link_enter_failed(link);
334 return link_enter_set_addresses(link);
337 static int bridge_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
338 Link *link = userdata;
341 assert(link->state == LINK_STATE_JOIN_BRIDGE || link->state == LINK_STATE_FAILED);
343 if (link->state == LINK_STATE_FAILED)
346 r = sd_rtnl_message_get_errno(m);
348 log_warning("Could not join interface '%s' to bridge '%s': %s",
349 link->ifname, link->network->bridge->name, strerror(-r));
351 log_info("Join interface '%s' to bridge: %s",
352 link->ifname, link->network->bridge->name);
354 link_enter_bridge_joined(link);
359 static int link_enter_join_bridge(Link *link) {
363 assert(link->network);
365 if (!link->network->bridge)
366 return link_enter_bridge_joined(link);
368 link->state = LINK_STATE_JOIN_BRIDGE;
370 r = bridge_join(link->network->bridge, link, &bridge_handler);
372 log_warning("Could not join link '%s' to bridge '%s'", link->ifname,
373 link->network->bridge->name);
374 return link_enter_failed(link);
380 int link_configure(Link *link) {
385 return link_enter_failed(link);
387 r = link_enter_join_bridge(link);
389 return link_enter_failed(link);
394 int link_update_flags(Link *link, unsigned flags) {
397 if (link->flags & IFF_UP && !(flags & IFF_UP))
398 log_info("Interface '%s' is down", link->ifname);
399 else if (!(link->flags & IFF_UP) && flags & IFF_UP)
400 log_info("Interface '%s' is up", link->ifname);
402 if (link->flags & IFF_LOWER_UP && !(flags & IFF_LOWER_UP))
403 log_info("Interface '%s' is disconnected", link->ifname);
404 else if (!(link->flags & IFF_LOWER_UP) && flags & IFF_LOWER_UP)
405 log_info("Interface '%s' is connected", link->ifname);