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 bring up 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, 0, 0, &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_NEWLINK, link->ifindex, 0, IFF_UP, &req);
306 log_error("Could not allocate RTM_NEWLINK message");
310 r = sd_rtnl_call_async(link->manager->rtnl, req, link_up_handler, link, 0, NULL);
312 log_error("Could not send rtnetlink message: %s", strerror(-r));
319 static int link_enter_bridge_joined(Link *link) {
322 link->state = LINK_STATE_BRIDGE_JOINED;
326 return link_enter_failed(link);
328 return link_enter_set_addresses(link);
331 static int bridge_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
332 Link *link = userdata;
335 assert(link->state == LINK_STATE_JOIN_BRIDGE || link->state == LINK_STATE_FAILED);
337 if (link->state == LINK_STATE_FAILED)
340 r = sd_rtnl_message_get_errno(m);
342 log_warning("Could not join interface '%s' to bridge '%s': %s",
343 link->ifname, link->network->bridge->name, strerror(-r));
345 log_info("Join interface '%s' to bridge: %s",
346 link->ifname, link->network->bridge->name);
348 link_enter_bridge_joined(link);
353 static int link_enter_join_bridge(Link *link) {
357 assert(link->network);
359 if (!link->network->bridge)
360 return link_enter_bridge_joined(link);
362 link->state = LINK_STATE_JOIN_BRIDGE;
364 r = bridge_join(link->network->bridge, link, &bridge_handler);
366 log_warning("Could not join link '%s' to bridge '%s'", link->ifname,
367 link->network->bridge->name);
368 return link_enter_failed(link);
374 int link_configure(Link *link) {
379 return link_enter_failed(link);
381 r = link_enter_join_bridge(link);
383 return link_enter_failed(link);
388 int link_update_flags(Link *link, unsigned flags) {
391 if (link->flags & IFF_UP && !(flags & IFF_UP))
392 log_info("Interface '%s' is down", link->ifname);
393 else if (!(link->flags & IFF_UP) && flags & IFF_UP)
394 log_info("Interface '%s' is up", link->ifname);
396 if (link->flags & IFF_LOWER_UP && !(flags & IFF_LOWER_UP))
397 log_info("Interface '%s' is disconnected", link->ifname);
398 else if (!(link->flags & IFF_LOWER_UP) && flags & IFF_LOWER_UP)
399 log_info("Interface '%s' is connected", link->ifname);