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);
77 sd_dhcp_client_free(link->dhcp);
79 route_free(link->dhcp_route);
80 link->dhcp_route = NULL;
82 address_free(link->dhcp_address);
83 link->dhcp_address = NULL;
85 hashmap_remove(link->manager->links, &link->ifindex);
92 int link_add(Manager *m, struct udev_device *device, Link **ret) {
102 ifindex = udev_device_get_ifindex(device);
103 link = hashmap_get(m->links, &ifindex);
109 r = link_new(m, device, &link);
115 devtype = udev_device_get_devtype(device);
116 if (streq_ptr(devtype, "bridge")) {
117 r = bridge_set_link(m, link);
118 if (r < 0 && r != -ENOENT)
122 r = network_get(m, device, &network);
124 return r == -ENOENT ? 0 : r;
126 r = network_apply(m, network, link);
133 static int link_enter_configured(Link *link) {
135 assert(link->state == LINK_STATE_SETTING_ROUTES);
137 log_info("%s: link configured", link->ifname);
139 link->state = LINK_STATE_CONFIGURED;
144 static void link_enter_failed(Link *link) {
147 log_warning("%s: failed", link->ifname);
149 link->state = LINK_STATE_FAILED;
152 static int route_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
153 Link *link = userdata;
156 assert(link->route_messages > 0);
157 assert(link->state == LINK_STATE_SETTING_ADDRESSES ||
158 link->state == LINK_STATE_SETTING_ROUTES ||
159 link->state == LINK_STATE_FAILED);
161 link->route_messages --;
163 if (link->state == LINK_STATE_FAILED)
166 r = sd_rtnl_message_get_errno(m);
167 if (r < 0 && r != -EEXIST)
168 log_warning("%s: could not set route: %s",
169 link->ifname, strerror(-r));
171 /* we might have received an old reply after moving back to SETTING_ADDRESSES,
173 if (link->route_messages == 0 && link->state == LINK_STATE_SETTING_ROUTES) {
174 log_debug("%s: routes set", link->ifname);
175 link_enter_configured(link);
181 static int link_enter_set_routes(Link *link) {
186 assert(link->network);
187 assert(link->state == LINK_STATE_SETTING_ADDRESSES);
189 link->state = LINK_STATE_SETTING_ROUTES;
191 if (!link->network->static_routes && !link->dhcp_route)
192 return link_enter_configured(link);
194 log_debug("%s: setting routes", link->ifname);
196 LIST_FOREACH(static_routes, route, link->network->static_routes) {
197 r = route_configure(route, link, &route_handler);
199 log_warning("%s: could not set routes", link->ifname);
200 link_enter_failed(link);
204 link->route_messages ++;
207 if (link->dhcp_route) {
208 r = route_configure(link->dhcp_route, link, &route_handler);
210 log_warning("%s: could not set routes", link->ifname);
211 link_enter_failed(link);
215 link->route_messages ++;
221 static int address_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
222 Link *link = userdata;
227 assert(link->ifname);
228 assert(link->addr_messages > 0);
229 assert(link->state == LINK_STATE_SETTING_ADDRESSES || link->state == LINK_STATE_FAILED);
231 link->addr_messages --;
233 if (link->state == LINK_STATE_FAILED)
236 r = sd_rtnl_message_get_errno(m);
237 if (r < 0 && r != -EEXIST)
238 log_warning("%s: could not set address: %s",
239 link->ifname, strerror(-r));
241 if (link->addr_messages == 0) {
242 log_debug("%s: addresses set", link->ifname);
243 link_enter_set_routes(link);
249 static int link_enter_set_addresses(Link *link) {
254 assert(link->network);
255 assert(link->state != _LINK_STATE_INVALID);
257 link->state = LINK_STATE_SETTING_ADDRESSES;
259 if (!link->network->static_addresses && !link->dhcp_address)
260 return link_enter_set_routes(link);
262 log_debug("%s: setting addresses", link->ifname);
264 LIST_FOREACH(static_addresses, address, link->network->static_addresses) {
265 r = address_configure(address, link, &address_handler);
267 log_warning("%s: could not set addresses", link->ifname);
268 link_enter_failed(link);
272 link->addr_messages ++;
275 if (link->dhcp_address) {
276 r = address_configure(link->dhcp_address, link, &address_handler);
278 log_warning("%s: could not set addresses", link->ifname);
279 link_enter_failed(link);
283 link->addr_messages ++;
289 static int address_drop_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
290 Link *link = userdata;
295 assert(link->ifname);
297 if (link->state == LINK_STATE_FAILED)
300 r = sd_rtnl_message_get_errno(m);
301 if (r < 0 && r != -EEXIST)
302 log_warning("%s: could not drop address: %s",
303 link->ifname, strerror(-r));
308 static void dhcp_handler(sd_dhcp_client *client, int event, void *userdata) {
309 Link *link = userdata;
310 struct in_addr address;
311 struct in_addr netmask;
312 struct in_addr gateway;
318 if (link->state == LINK_STATE_FAILED)
322 log_warning("%s: DHCP error: %s", link->ifname, strerror(-event));
323 link_enter_failed(link);
327 if (event == DHCP_EVENT_NO_LEASE)
328 log_debug("%s: IP address in use.", link->ifname);
330 if (event == DHCP_EVENT_IP_CHANGE || event == DHCP_EVENT_EXPIRED ||
331 event == DHCP_EVENT_STOP) {
332 if (link->dhcp_address) {
333 address_drop(link->dhcp_address, link, address_drop_handler);
335 address_free(link->dhcp_address);
336 link->dhcp_address = NULL;
339 if (link->dhcp_route) {
340 route_free(link->dhcp_route);
341 link->dhcp_route = NULL;
345 r = sd_dhcp_client_get_address(client, &address);
347 log_warning("%s: DHCP error: no address", link->ifname);
348 link_enter_failed(link);
352 r = sd_dhcp_client_get_netmask(client, &netmask);
354 log_warning("%s: DHCP error: no netmask", link->ifname);
355 link_enter_failed(link);
359 prefixlen = sd_dhcp_client_prefixlen(&netmask);
361 log_warning("%s: DHCP error: no prefixlen", link->ifname);
362 link_enter_failed(link);
366 r = sd_dhcp_client_get_router(client, &gateway);
368 log_warning("%s: DHCP error: no router", link->ifname);
369 link_enter_failed(link);
373 if (event == DHCP_EVENT_IP_CHANGE || event == DHCP_EVENT_IP_ACQUIRE) {
374 _cleanup_address_free_ Address *addr = NULL;
375 _cleanup_route_free_ Route *rt = NULL;
377 log_info("%s: received config over DHCPv4", link->ifname);
379 r = address_new_dynamic(&addr);
381 log_error("Could not allocate address");
382 link_enter_failed(link);
386 addr->family = AF_INET;
387 addr->in_addr.in = address;
388 addr->prefixlen = prefixlen;
389 addr->netmask = netmask;
391 r = route_new_dynamic(&rt);
393 log_error("Could not allocate route");
394 link_enter_failed(link);
398 rt->family = AF_INET;
399 rt->in_addr.in = gateway;
401 link->dhcp_address = addr;
402 link->dhcp_route = rt;
406 link_enter_set_addresses(link);
412 static int link_acquire_conf(Link *link) {
416 assert(link->network);
417 assert(link->network->dhcp);
418 assert(link->manager);
419 assert(link->manager->event);
422 link->dhcp = sd_dhcp_client_new(link->manager->event);
426 r = sd_dhcp_client_set_index(link->dhcp, link->ifindex);
430 r = sd_dhcp_client_set_mac(link->dhcp, &link->mac);
434 r = sd_dhcp_client_set_callback(link->dhcp, dhcp_handler, link);
439 r = sd_dhcp_client_start(link->dhcp);
446 static int link_update_flags(Link *link, unsigned flags) {
450 assert(link->network);
452 if (link->state == LINK_STATE_FAILED)
455 if (link->flags == flags) {
456 log_debug("%s: link status unchanged: %#x", link->ifname, flags);
460 if ((link->flags & IFF_UP) != (flags & IFF_UP)) {
462 log_info("%s: power on", link->ifname);
464 log_info("%s: power off", link->ifname);
467 if ((link->flags & IFF_LOWER_UP) != (flags & IFF_LOWER_UP)) {
468 if (flags & IFF_LOWER_UP) {
469 log_info("%s: carrier on", link->ifname);
471 if (link->network->dhcp) {
472 r = link_acquire_conf(link);
474 link_enter_failed(link);
479 log_info("%s: carrier off", link->ifname);
481 if (link->network->dhcp) {
482 r = sd_dhcp_client_stop(link->dhcp);
484 link_enter_failed(link);
491 log_debug("%s: link status updated: %#x -> %#x", link->ifname, link->flags, flags);
498 static int link_up_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
499 Link *link = userdata;
504 if (link->state == LINK_STATE_FAILED)
507 r = sd_rtnl_message_get_errno(m);
509 log_warning("%s: could not bring up interface: %s",
510 link->ifname, strerror(-r));
511 link_enter_failed(link);
514 link_update_flags(link, link->flags | IFF_UP);
519 static int link_up(Link *link) {
520 _cleanup_sd_rtnl_message_unref_ sd_rtnl_message *req = NULL;
524 assert(link->manager);
525 assert(link->manager->rtnl);
527 log_debug("%s: bringing up link", link->ifname);
529 r = sd_rtnl_message_link_new(RTM_SETLINK, link->ifindex, &req);
531 log_error("Could not allocate RTM_SETLINK message");
535 r = sd_rtnl_message_link_set_flags(req, IFF_UP);
537 log_error("Could not set link flags");
541 r = sd_rtnl_call_async(link->manager->rtnl, req, link_up_handler, link, 0, NULL);
543 log_error("Could not send rtnetlink message: %s", strerror(-r));
550 static int link_bridge_joined(Link *link) {
554 assert(link->state == LINK_STATE_JOINING_BRIDGE);
555 assert(link->network);
559 link_enter_failed(link);
563 if (!link->network->dhcp)
564 return link_enter_set_addresses(link);
569 static int bridge_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
570 Link *link = userdata;
574 assert(link->state == LINK_STATE_JOINING_BRIDGE || link->state == LINK_STATE_FAILED);
575 assert(link->network);
577 if (link->state == LINK_STATE_FAILED)
580 r = sd_rtnl_message_get_errno(m);
582 log_warning("%s: could not join bridge '%s': %s",
583 link->ifname, link->network->bridge->name, strerror(-r));
584 link_enter_failed(link);
587 log_debug("%s: joined bridge '%s'",
588 link->ifname, link->network->bridge->name);
590 link_bridge_joined(link);
595 static int link_enter_join_bridge(Link *link) {
599 assert(link->network);
600 assert(link->state == _LINK_STATE_INVALID);
602 link->state = LINK_STATE_JOINING_BRIDGE;
604 if (!link->network->bridge)
605 return link_bridge_joined(link);
607 log_debug("%s: joining bridge", link->ifname);
609 r = bridge_join(link->network->bridge, link, &bridge_handler);
611 log_warning("%s: could not join bridge '%s'", link->ifname,
612 link->network->bridge->name);
613 link_enter_failed(link);
620 static int link_get_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
621 Link *link = userdata;
626 if (link->state == LINK_STATE_FAILED)
629 r = sd_rtnl_message_get_errno(m);
631 log_warning("%s: could not get state: %s",
632 link->ifname, strerror(-r));
633 link_enter_failed(link);
636 log_debug("%s: got link state", link->ifname);
638 link_update(link, m);
643 static int link_get(Link *link) {
644 _cleanup_sd_rtnl_message_unref_ sd_rtnl_message *req = NULL;
648 assert(link->manager);
649 assert(link->manager->rtnl);
651 log_debug("%s: requesting link status", link->ifname);
653 r = sd_rtnl_message_link_new(RTM_GETLINK, link->ifindex, &req);
655 log_error("Could not allocate RTM_GETLINK message");
659 r = sd_rtnl_call_async(link->manager->rtnl, req, link_get_handler, link, 0, NULL);
661 log_error("Could not send rtnetlink message: %s", strerror(-r));
668 int link_configure(Link *link) {
672 assert(link->network);
673 assert(link->state == _LINK_STATE_INVALID);
677 link_enter_failed(link);
681 return link_enter_join_bridge(link);
684 int link_update(Link *link, sd_rtnl_message *m) {
691 if (link->state == LINK_STATE_FAILED)
694 r = sd_rtnl_message_link_get_flags(m, &flags);
696 log_warning("%s: could not get link flags", link->ifname);
700 return link_update_flags(link, flags);