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) {
124 assert(link->state == LINK_STATE_SETTING_ROUTES);
126 log_info("Link '%s' configured", link->ifname);
128 link->state = LINK_STATE_CONFIGURED;
133 static void link_enter_failed(Link *link) {
136 link->state = LINK_STATE_FAILED;
139 static int route_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
140 Link *link = userdata;
143 assert(link->rtnl_messages > 0);
144 assert(link->state == LINK_STATE_SETTING_ROUTES || link->state == LINK_STATE_FAILED);
146 link->rtnl_messages --;
148 if (link->state == LINK_STATE_FAILED)
151 r = sd_rtnl_message_get_errno(m);
152 if (r < 0 && r != -EEXIST)
153 log_warning("Could not set route on interface '%s': %s",
154 link->ifname, strerror(-r));
156 if (link->rtnl_messages == 0) {
157 log_info("Routes set for link '%s'", link->ifname);
158 link_enter_configured(link);
164 static int link_enter_set_routes(Link *link) {
169 assert(link->network);
170 assert(link->rtnl_messages == 0);
171 assert(link->state == LINK_STATE_SETTING_ADDRESSES);
173 link->state = LINK_STATE_SETTING_ROUTES;
175 if (!link->network->routes)
176 return link_enter_configured(link);
178 LIST_FOREACH(routes, route, link->network->routes) {
179 r = route_configure(route, link, &route_handler);
181 log_warning("Could not set routes for link '%s'", link->ifname);
182 link_enter_failed(link);
186 link->rtnl_messages ++;
192 static int address_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
193 Link *link = userdata;
196 assert(link->rtnl_messages > 0);
197 assert(link->state == LINK_STATE_SETTING_ADDRESSES || link->state == LINK_STATE_FAILED);
199 link->rtnl_messages --;
201 if (link->state == LINK_STATE_FAILED)
204 r = sd_rtnl_message_get_errno(m);
205 if (r < 0 && r != -EEXIST)
206 log_warning("Could not set address on interface '%s': %s",
207 link->ifname, strerror(-r));
209 if (link->rtnl_messages == 0) {
210 log_info("Addresses set for link '%s'", link->ifname);
211 link_enter_set_routes(link);
217 static int link_enter_set_addresses(Link *link) {
222 assert(link->network);
223 assert(link->state == LINK_STATE_JOINING_BRIDGE);
224 assert(link->rtnl_messages == 0);
226 link->state = LINK_STATE_SETTING_ADDRESSES;
228 if (!link->network->addresses)
229 return link_enter_set_routes(link);
231 LIST_FOREACH(addresses, address, link->network->addresses) {
232 r = address_configure(address, link, &address_handler);
234 log_warning("Could not set addresses for link '%s'", link->ifname);
235 link_enter_failed(link);
239 link->rtnl_messages ++;
245 static int link_up_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 bring up interface '%s': %s",
252 link->ifname, strerror(-r));
253 link_enter_failed(link);
259 static int link_up(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_SETLINK, link->ifindex, &req);
269 log_error("Could not allocate RTM_SETLINK message");
273 r = sd_rtnl_message_link_set_flags(req, IFF_UP);
275 log_error("Could not set link flags");
279 r = sd_rtnl_call_async(link->manager->rtnl, req, link_up_handler, link, 0, NULL);
281 log_error("Could not send rtnetlink message: %s", strerror(-r));
288 static int link_bridge_joined(Link *link) {
292 assert(link->state == LINK_STATE_JOINING_BRIDGE);
296 link_enter_failed(link);
300 r = link_enter_set_addresses(link);
302 link_enter_failed(link);
309 static int bridge_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
310 Link *link = userdata;
313 assert(link->state == LINK_STATE_JOINING_BRIDGE || link->state == LINK_STATE_FAILED);
314 assert(link->network);
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': %s",
322 link->ifname, link->network->bridge->name, strerror(-r));
323 link_enter_failed(link);
326 log_info("Join interface '%s' to bridge: %s",
327 link->ifname, link->network->bridge->name);
329 link_bridge_joined(link);
334 static int link_enter_join_bridge(Link *link) {
338 assert(link->network);
339 assert(link->state == _LINK_STATE_INVALID);
341 link->state = LINK_STATE_JOINING_BRIDGE;
343 if (!link->network->bridge)
344 return link_bridge_joined(link);
346 r = bridge_join(link->network->bridge, link, &bridge_handler);
348 log_warning("Could not join link '%s' to bridge '%s'", link->ifname,
349 link->network->bridge->name);
350 link_enter_failed(link);
357 static int link_get_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
358 Link *link = userdata;
361 r = sd_rtnl_message_get_errno(m);
363 log_warning("Could not get state of interface '%s': %s",
364 link->ifname, strerror(-r));
365 link_enter_failed(link);
371 static int link_get(Link *link) {
372 _cleanup_sd_rtnl_message_unref_ sd_rtnl_message *req = NULL;
376 assert(link->manager);
377 assert(link->manager->rtnl);
379 r = sd_rtnl_message_link_new(RTM_GETLINK, link->ifindex, &req);
381 log_error("Could not allocate RTM_GETLINK message");
385 r = sd_rtnl_call_async(link->manager->rtnl, req, link_get_handler, link, 0, NULL);
387 log_error("Could not send rtnetlink message: %s", strerror(-r));
394 int link_configure(Link *link) {
398 assert(link->network);
399 assert(link->state == _LINK_STATE_INVALID);
403 link_enter_failed(link);
407 r = link_enter_join_bridge(link);
414 int link_update(Link *link, sd_rtnl_message *m) {
421 r = sd_rtnl_message_link_get_flags(m, &flags);
423 log_warning("Could not get link flags of '%s'", link->ifname);
427 if (link->flags & IFF_UP && !(flags & IFF_UP))
428 log_info("Interface '%s' is down", link->ifname);
429 else if (!(link->flags & IFF_UP) && flags & IFF_UP)
430 log_info("Interface '%s' is up", link->ifname);
432 if (link->flags & IFF_LOWER_UP && !(flags & IFF_LOWER_UP))
433 log_info("Interface '%s' is disconnected", link->ifname);
434 else if (!(link->flags & IFF_LOWER_UP) && flags & IFF_LOWER_UP)
435 log_info("Interface '%s' is connected", link->ifname);