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;
42 ifindex = udev_device_get_ifindex(device);
46 mac = udev_device_get_sysattr_value(device, "address");
50 memcpy(&link->mac.ether_addr_octet[0], ether_aton(mac), ETH_ALEN);
51 link->ifindex = ifindex;
52 link->manager = manager;
53 link->state = _LINK_STATE_INVALID;
55 r = hashmap_put(manager->links, &ifindex, link);
65 void link_free(Link *link) {
69 network_free(link->network);
71 hashmap_remove(link->manager->links, link);
76 int link_add(Manager *m, struct udev_device *device) {
85 ifindex = udev_device_get_ifindex(device);
86 link = hashmap_get(m->links, &ifindex);
90 r = link_new(m, device, &link);
92 log_error("could not create link: %s", strerror(-r));
96 r = network_get(m, device, &network);
98 return r == -ENOENT ? 0 : r;
100 r = network_apply(m, network, link);
107 static int link_enter_configured(Link *link) {
108 log_info("Link configured successfully.");
110 link->state = LINK_STATE_CONFIGURED;
115 static int link_enter_failed(Link *link) {
116 log_warning("Could not configure link.");
118 link->state = LINK_STATE_FAILED;
123 static bool link_is_up(Link *link) {
124 return link->flags & IFF_UP;
127 static int link_enter_routes_set(Link *link) {
128 log_info("Routes set for link %d", link->ifindex);
130 if (link_is_up(link))
131 return link_enter_configured(link);
133 link->state = LINK_STATE_ROUTES_SET;
138 static int route_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
139 Link *link = userdata;
142 assert(link->rtnl_messages > 0);
143 assert(link->state == LINK_STATE_SET_ROUTES || link->state == LINK_STATE_FAILED);
145 link->rtnl_messages --;
147 if (link->state == LINK_STATE_FAILED)
150 r = sd_rtnl_message_get_errno(m);
151 if (r < 0 && r != -EEXIST) {
152 log_warning("Could not set route on interface %d: %s",
153 link->ifindex, strerror(-r));
154 return link_enter_failed(link);
157 if (link->rtnl_messages == 0)
158 return link_enter_routes_set(link);
163 static int link_enter_set_routes(Link *link) {
168 assert(link->network);
169 assert(link->rtnl_messages == 0);
170 assert(link->state == LINK_STATE_ADDRESSES_SET);
172 link->state = LINK_STATE_SET_ROUTES;
174 if (!link->network->routes)
175 return link_enter_routes_set(link);
177 LIST_FOREACH(routes, route, link->network->routes) {
178 r = route_configure(route, link, &route_handler);
180 link_enter_failed(link);
186 static int link_enter_addresses_set(Link *link) {
187 log_info("Addresses set for link %d", link->ifindex);
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 %d: %s",
209 link->ifindex, strerror(-r));
210 link_enter_failed(link);
213 if (link->rtnl_messages == 0)
214 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 link_enter_failed(link);
241 static int link_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
242 Link *link = userdata;
245 r = sd_rtnl_message_get_errno(m);
247 log_warning("Could not bring up interface %d: %s",
248 link->ifindex, strerror(-r));
249 return link_enter_failed(link);
252 link->flags |= IFF_UP;
254 log_info("Link is UP.");
256 if (link->state == LINK_STATE_ROUTES_SET)
257 return link_enter_configured(link);
262 static int link_up(Link *link) {
263 _cleanup_sd_rtnl_message_unref_ sd_rtnl_message *req = NULL;
267 assert(link->manager);
268 assert(link->manager->rtnl);
270 r = sd_rtnl_message_link_new(RTM_NEWLINK, link->ifindex, 0, IFF_UP, &req);
272 log_error("Could not allocate RTM_NEWLINK message");
276 r = sd_rtnl_call_async(link->manager->rtnl, req, link_handler, link, 0, NULL);
278 log_error("Could not send rtnetlink message: %s", strerror(-r));
285 int link_configure(Link *link) {
290 return link_enter_failed(link);
292 r = link_enter_set_addresses(link);
294 return link_enter_failed(link);