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;
41 link->ifindex = udev_device_get_ifindex(device);
42 if (link->ifindex <= 0)
45 mac = udev_device_get_sysattr_value(device, "address");
49 memcpy(&link->mac.ether_addr_octet[0], ether_aton(mac), ETH_ALEN);
50 link->manager = manager;
51 link->state = _LINK_STATE_INVALID;
53 r = hashmap_put(manager->links, &link->ifindex, link);
63 void link_free(Link *link) {
67 assert(link->manager);
69 hashmap_remove(link->manager->links, &link->ifindex);
74 int link_add(Manager *m, struct udev_device *device) {
83 ifindex = udev_device_get_ifindex(device);
84 link = hashmap_get(m->links, &ifindex);
88 r = link_new(m, device, &link);
90 log_error("could not create link: %s", strerror(-r));
94 r = network_get(m, device, &network);
96 return r == -ENOENT ? 0 : r;
98 r = network_apply(m, network, link);
105 static int link_enter_configured(Link *link) {
106 log_info("Link configured successfully.");
108 link->state = LINK_STATE_CONFIGURED;
113 static int link_enter_failed(Link *link) {
114 log_warning("Could not configure link.");
116 link->state = LINK_STATE_FAILED;
121 static bool link_is_up(Link *link) {
122 return link->flags & IFF_UP;
125 static int link_enter_routes_set(Link *link) {
126 log_info("Routes set for link %u", (unsigned)link->ifindex);
128 if (link_is_up(link))
129 return link_enter_configured(link);
131 link->state = LINK_STATE_ROUTES_SET;
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 %u: %s",
151 (unsigned)link->ifindex, strerror(-r));
152 return link_enter_failed(link);
155 if (link->rtnl_messages == 0)
156 return link_enter_routes_set(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_routes_set(link);
175 LIST_FOREACH(routes, route, link->network->routes) {
176 r = route_configure(route, link, &route_handler);
178 link_enter_failed(link);
184 static int link_enter_addresses_set(Link *link) {
185 log_info("Addresses set for link %u", (unsigned)link->ifindex);
187 link->state = LINK_STATE_ADDRESSES_SET;
189 return link_enter_set_routes(link);
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_SET_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 %u: %s",
207 (unsigned)link->ifindex, strerror(-r));
208 link_enter_failed(link);
211 if (link->rtnl_messages == 0)
212 link_enter_addresses_set(link);
217 static int link_enter_set_addresses(Link *link) {
222 assert(link->network);
223 assert(link->rtnl_messages == 0);
225 if (!link->network->addresses)
226 return link_enter_addresses_set(link);
228 link->state = LINK_STATE_SET_ADDRESSES;
230 LIST_FOREACH(addresses, address, link->network->addresses) {
231 r = address_configure(address, link, &address_handler);
233 link_enter_failed(link);
239 static int link_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
240 Link *link = userdata;
243 r = sd_rtnl_message_get_errno(m);
245 log_warning("Could not bring up interface %u: %s",
246 (unsigned)link->ifindex, strerror(-r));
247 return link_enter_failed(link);
250 link->flags |= IFF_UP;
252 log_info("Link is UP.");
254 if (link->state == LINK_STATE_ROUTES_SET)
255 return link_enter_configured(link);
260 static int link_up(Link *link) {
261 _cleanup_sd_rtnl_message_unref_ sd_rtnl_message *req = NULL;
265 assert(link->manager);
266 assert(link->manager->rtnl);
268 r = sd_rtnl_message_link_new(RTM_NEWLINK, link->ifindex, 0, IFF_UP, &req);
270 log_error("Could not allocate RTM_NEWLINK message");
274 r = sd_rtnl_call_async(link->manager->rtnl, req, link_handler, link, 0, NULL);
276 log_error("Could not send rtnetlink message: %s", strerror(-r));
283 int link_configure(Link *link) {
288 return link_enter_failed(link);
290 r = link_enter_set_addresses(link);
292 return link_enter_failed(link);