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) {
92 ifindex = udev_device_get_ifindex(device);
93 link = hashmap_get(m->links, &ifindex);
97 r = link_new(m, device, &link);
99 log_error("Could not create link: %s", strerror(-r));
103 r = network_get(m, device, &network);
105 return r == -ENOENT ? 0 : r;
107 r = network_apply(m, network, link);
114 static int link_enter_configured(Link *link) {
115 log_info("Link '%s' configured", link->ifname);
117 link->state = LINK_STATE_CONFIGURED;
122 static int link_enter_failed(Link *link) {
123 log_warning("Could not configure link '%s'", link->ifname);
125 link->state = LINK_STATE_FAILED;
130 static bool link_is_up(Link *link) {
131 return link->flags & IFF_UP;
134 static int link_enter_routes_set(Link *link) {
135 log_info("Routes set for link '%s'", link->ifname);
137 if (link_is_up(link))
138 return link_enter_configured(link);
140 link->state = LINK_STATE_ROUTES_SET;
145 static int route_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
146 Link *link = userdata;
149 assert(link->rtnl_messages > 0);
150 assert(link->state == LINK_STATE_SET_ROUTES || link->state == LINK_STATE_FAILED);
152 link->rtnl_messages --;
154 if (link->state == LINK_STATE_FAILED)
157 r = sd_rtnl_message_get_errno(m);
158 if (r < 0 && r != -EEXIST)
159 log_warning("Could not set route on interface '%s': %s",
160 link->ifname, strerror(-r));
162 if (link->rtnl_messages == 0)
163 return link_enter_routes_set(link);
168 static int link_enter_set_routes(Link *link) {
173 assert(link->network);
174 assert(link->rtnl_messages == 0);
175 assert(link->state == LINK_STATE_ADDRESSES_SET);
177 link->state = LINK_STATE_SET_ROUTES;
179 if (!link->network->routes)
180 return link_enter_routes_set(link);
182 LIST_FOREACH(routes, route, link->network->routes) {
183 r = route_configure(route, link, &route_handler);
185 return link_enter_failed(link);
187 link->rtnl_messages ++;
193 static int link_enter_addresses_set(Link *link) {
194 log_info("Addresses set for link '%s'", link->ifname);
196 link->state = LINK_STATE_ADDRESSES_SET;
198 return link_enter_set_routes(link);
201 static int address_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
202 Link *link = userdata;
205 assert(link->rtnl_messages > 0);
206 assert(link->state == LINK_STATE_SET_ADDRESSES || link->state == LINK_STATE_FAILED);
208 link->rtnl_messages --;
210 if (link->state == LINK_STATE_FAILED)
213 r = sd_rtnl_message_get_errno(m);
214 if (r < 0 && r != -EEXIST)
215 log_warning("Could not set address on interface '%s': %s",
216 link->ifname, strerror(-r));
218 if (link->rtnl_messages == 0)
219 link_enter_addresses_set(link);
224 static int link_enter_set_addresses(Link *link) {
229 assert(link->network);
230 assert(link->rtnl_messages == 0);
232 if (!link->network->addresses)
233 return link_enter_addresses_set(link);
235 link->state = LINK_STATE_SET_ADDRESSES;
237 LIST_FOREACH(addresses, address, link->network->addresses) {
238 r = address_configure(address, link, &address_handler);
240 return link_enter_failed(link);
242 link->rtnl_messages ++;
248 static int link_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
249 Link *link = userdata;
252 r = sd_rtnl_message_get_errno(m);
254 log_warning("Could not bring up interface '%s': %s",
255 link->ifname, strerror(-r));
257 link->flags |= IFF_UP;
259 log_info("Link '%s' is up", link->ifname);
261 if (link->state == LINK_STATE_ROUTES_SET)
262 return link_enter_configured(link);
267 static int link_up(Link *link) {
268 _cleanup_sd_rtnl_message_unref_ sd_rtnl_message *req = NULL;
272 assert(link->manager);
273 assert(link->manager->rtnl);
275 r = sd_rtnl_message_link_new(RTM_NEWLINK, link->ifindex, 0, IFF_UP, &req);
277 log_error("Could not allocate RTM_NEWLINK message");
281 r = sd_rtnl_call_async(link->manager->rtnl, req, link_handler, link, 0, NULL);
283 log_error("Could not send rtnetlink message: %s", strerror(-r));
290 int link_configure(Link *link) {
295 return link_enter_failed(link);
297 r = link_enter_set_addresses(link);
299 return link_enter_failed(link);