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) {
102 ifindex = udev_device_get_ifindex(device);
103 link = hashmap_get(m->links, &ifindex);
107 r = link_new(m, device, &link);
109 log_error("Could not create link: %s", strerror(-r));
113 devtype = udev_device_get_devtype(device);
114 if (streq_ptr(devtype, "bridge")) {
115 r = bridge_set_link(m, link);
117 return r == -ENOENT ? 0 : r;
120 r = network_get(m, device, &network);
122 return r == -ENOENT ? 0 : r;
124 r = network_apply(m, network, link);
131 static int link_enter_configured(Link *link) {
133 assert(link->state == LINK_STATE_SETTING_ROUTES);
135 log_info("%s: link configured", link->ifname);
137 link->state = LINK_STATE_CONFIGURED;
142 static void link_enter_failed(Link *link) {
145 log_warning("%s: failed", link->ifname);
147 link->state = LINK_STATE_FAILED;
150 static int route_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
151 Link *link = userdata;
154 assert(link->route_messages > 0);
155 assert(link->state == LINK_STATE_SETTING_ADDRESSES ||
156 link->state == LINK_STATE_SETTING_ROUTES ||
157 link->state == LINK_STATE_FAILED);
159 link->route_messages --;
161 if (link->state == LINK_STATE_FAILED)
164 r = sd_rtnl_message_get_errno(m);
165 if (r < 0 && r != -EEXIST)
166 log_warning("%s: could not set route: %s",
167 link->ifname, strerror(-r));
169 /* we might have received an old reply after moving back to SETTING_ADDRESSES,
171 if (link->route_messages == 0 && link->state == LINK_STATE_SETTING_ROUTES) {
172 log_debug("%s: routes set", link->ifname);
173 link_enter_configured(link);
179 static int link_enter_set_routes(Link *link) {
184 assert(link->network);
185 assert(link->state == LINK_STATE_SETTING_ADDRESSES);
187 link->state = LINK_STATE_SETTING_ROUTES;
189 if (!link->network->static_routes && !link->dhcp_route)
190 return link_enter_configured(link);
192 log_debug("%s: setting routes", link->ifname);
194 LIST_FOREACH(static_routes, route, link->network->static_routes) {
195 r = route_configure(route, link, &route_handler);
197 log_warning("%s: could not set routes", link->ifname);
198 link_enter_failed(link);
202 link->route_messages ++;
205 if (link->dhcp_route) {
206 r = route_configure(link->dhcp_route, link, &route_handler);
208 log_warning("%s: could not set routes", link->ifname);
209 link_enter_failed(link);
213 link->route_messages ++;
219 static int address_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
220 Link *link = userdata;
225 assert(link->ifname);
226 assert(link->addr_messages > 0);
227 assert(link->state == LINK_STATE_SETTING_ADDRESSES || link->state == LINK_STATE_FAILED);
229 link->addr_messages --;
231 if (link->state == LINK_STATE_FAILED)
234 r = sd_rtnl_message_get_errno(m);
235 if (r < 0 && r != -EEXIST)
236 log_warning("%s: could not set address: %s",
237 link->ifname, strerror(-r));
239 if (link->addr_messages == 0) {
240 log_debug("%s: addresses set", link->ifname);
241 link_enter_set_routes(link);
247 static int link_enter_set_addresses(Link *link) {
252 assert(link->network);
253 assert(link->state != _LINK_STATE_INVALID);
255 link->state = LINK_STATE_SETTING_ADDRESSES;
257 if (!link->network->static_addresses && !link->dhcp_address)
258 return link_enter_set_routes(link);
260 log_debug("%s: setting addresses", link->ifname);
262 LIST_FOREACH(static_addresses, address, link->network->static_addresses) {
263 r = address_configure(address, link, &address_handler);
265 log_warning("%s: could not set addresses", link->ifname);
266 link_enter_failed(link);
270 link->addr_messages ++;
273 if (link->dhcp_address) {
274 r = address_configure(link->dhcp_address, link, &address_handler);
276 log_warning("%s: could not set addresses", link->ifname);
277 link_enter_failed(link);
281 link->addr_messages ++;
287 static int address_drop_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
288 Link *link = userdata;
293 assert(link->ifname);
295 if (link->state == LINK_STATE_FAILED)
298 r = sd_rtnl_message_get_errno(m);
299 if (r < 0 && r != -EEXIST)
300 log_warning("%s: could not drop address: %s",
301 link->ifname, strerror(-r));
306 static void dhcp_handler(sd_dhcp_client *client, int event, void *userdata) {
307 Link *link = userdata;
308 struct in_addr address;
309 struct in_addr netmask;
310 struct in_addr gateway;
316 if (link->state == LINK_STATE_FAILED)
320 log_warning("%s: DHCP error: %s", link->ifname, strerror(-event));
321 link_enter_failed(link);
325 if (event == DHCP_EVENT_NO_LEASE)
326 log_debug("%s: IP address in use.", link->ifname);
328 if (event == DHCP_EVENT_IP_CHANGE || event == DHCP_EVENT_EXPIRED ||
329 event == DHCP_EVENT_STOP) {
330 if (link->dhcp_address) {
331 address_drop(link->dhcp_address, link, address_drop_handler);
333 address_free(link->dhcp_address);
334 link->dhcp_address = NULL;
337 if (link->dhcp_route) {
338 route_free(link->dhcp_route);
339 link->dhcp_route = NULL;
343 r = sd_dhcp_client_get_address(client, &address);
345 log_warning("%s: DHCP error: no address", link->ifname);
346 link_enter_failed(link);
350 r = sd_dhcp_client_get_netmask(client, &netmask);
352 log_warning("%s: DHCP error: no netmask", link->ifname);
353 link_enter_failed(link);
357 prefixlen = sd_dhcp_client_prefixlen(&netmask);
359 log_warning("%s: DHCP error: no prefixlen", link->ifname);
360 link_enter_failed(link);
364 r = sd_dhcp_client_get_router(client, &gateway);
366 log_warning("%s: DHCP error: no router", link->ifname);
367 link_enter_failed(link);
371 if (event == DHCP_EVENT_IP_CHANGE || event == DHCP_EVENT_IP_ACQUIRE) {
372 _cleanup_address_free_ Address *addr = NULL;
373 _cleanup_route_free_ Route *rt = NULL;
375 log_info("%s: received config over DHCPv4", link->ifname);
377 r = address_new_dynamic(&addr);
379 log_error("Could not allocate address");
380 link_enter_failed(link);
384 addr->family = AF_INET;
385 addr->in_addr.in = address;
386 addr->prefixlen = prefixlen;
387 addr->netmask = netmask;
389 r = route_new_dynamic(&rt);
391 log_error("Could not allocate route");
392 link_enter_failed(link);
396 rt->family = AF_INET;
397 rt->in_addr.in = gateway;
399 link->dhcp_address = addr;
400 link->dhcp_route = rt;
404 link_enter_set_addresses(link);
410 static int link_acquire_conf(Link *link) {
414 assert(link->network);
415 assert(link->network->dhcp);
416 assert(link->manager);
417 assert(link->manager->event);
420 link->dhcp = sd_dhcp_client_new(link->manager->event);
424 r = sd_dhcp_client_set_index(link->dhcp, link->ifindex);
428 r = sd_dhcp_client_set_mac(link->dhcp, &link->mac);
432 r = sd_dhcp_client_set_callback(link->dhcp, dhcp_handler, link);
437 r = sd_dhcp_client_start(link->dhcp);
444 static int link_update_flags(Link *link, unsigned flags) {
448 assert(link->network);
450 if (link->state == LINK_STATE_FAILED)
453 if (link->flags == flags) {
454 log_debug("%s: link status unchanged: %#x", link->ifname, flags);
458 if ((link->flags & IFF_UP) != (flags & IFF_UP)) {
460 log_info("%s: power on", link->ifname);
462 log_info("%s: power off", link->ifname);
465 if ((link->flags & IFF_LOWER_UP) != (flags & IFF_LOWER_UP)) {
466 if (flags & IFF_LOWER_UP) {
467 log_info("%s: carrier on", link->ifname);
469 if (link->network->dhcp) {
470 r = link_acquire_conf(link);
472 link_enter_failed(link);
477 log_info("%s: carrier off", link->ifname);
479 if (link->network->dhcp) {
480 r = sd_dhcp_client_stop(link->dhcp);
482 link_enter_failed(link);
489 log_debug("%s: link status updated: %#x -> %#x", link->ifname, link->flags, flags);
496 static int link_up_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
497 Link *link = userdata;
502 if (link->state == LINK_STATE_FAILED)
505 r = sd_rtnl_message_get_errno(m);
507 log_warning("%s: could not bring up interface: %s",
508 link->ifname, strerror(-r));
509 link_enter_failed(link);
512 link_update_flags(link, link->flags | IFF_UP);
517 static int link_up(Link *link) {
518 _cleanup_sd_rtnl_message_unref_ sd_rtnl_message *req = NULL;
522 assert(link->manager);
523 assert(link->manager->rtnl);
525 log_debug("%s: bringing up link", link->ifname);
527 r = sd_rtnl_message_link_new(RTM_SETLINK, link->ifindex, &req);
529 log_error("Could not allocate RTM_SETLINK message");
533 r = sd_rtnl_message_link_set_flags(req, IFF_UP);
535 log_error("Could not set link flags");
539 r = sd_rtnl_call_async(link->manager->rtnl, req, link_up_handler, link, 0, NULL);
541 log_error("Could not send rtnetlink message: %s", strerror(-r));
548 static int link_bridge_joined(Link *link) {
552 assert(link->state == LINK_STATE_JOINING_BRIDGE);
553 assert(link->network);
557 link_enter_failed(link);
561 if (!link->network->dhcp)
562 return link_enter_set_addresses(link);
567 static int bridge_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
568 Link *link = userdata;
572 assert(link->state == LINK_STATE_JOINING_BRIDGE || link->state == LINK_STATE_FAILED);
573 assert(link->network);
575 if (link->state == LINK_STATE_FAILED)
578 r = sd_rtnl_message_get_errno(m);
580 log_warning("%s: could not join bridge '%s': %s",
581 link->ifname, link->network->bridge->name, strerror(-r));
582 link_enter_failed(link);
585 log_debug("%s: joined bridge '%s'",
586 link->ifname, link->network->bridge->name);
588 link_bridge_joined(link);
593 static int link_enter_join_bridge(Link *link) {
597 assert(link->network);
598 assert(link->state == _LINK_STATE_INVALID);
600 link->state = LINK_STATE_JOINING_BRIDGE;
602 if (!link->network->bridge)
603 return link_bridge_joined(link);
605 log_debug("%s: joining bridge", link->ifname);
607 r = bridge_join(link->network->bridge, link, &bridge_handler);
609 log_warning("%s: could not join bridge '%s'", link->ifname,
610 link->network->bridge->name);
611 link_enter_failed(link);
618 static int link_get_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
619 Link *link = userdata;
624 if (link->state == LINK_STATE_FAILED)
627 r = sd_rtnl_message_get_errno(m);
629 log_warning("%s: could not get state: %s",
630 link->ifname, strerror(-r));
631 link_enter_failed(link);
634 log_debug("%s: got link state", link->ifname);
636 link_update(link, m);
641 static int link_get(Link *link) {
642 _cleanup_sd_rtnl_message_unref_ sd_rtnl_message *req = NULL;
646 assert(link->manager);
647 assert(link->manager->rtnl);
649 log_debug("%s: requesting link status", link->ifname);
651 r = sd_rtnl_message_link_new(RTM_GETLINK, link->ifindex, &req);
653 log_error("Could not allocate RTM_GETLINK message");
657 r = sd_rtnl_call_async(link->manager->rtnl, req, link_get_handler, link, 0, NULL);
659 log_error("Could not send rtnetlink message: %s", strerror(-r));
666 int link_configure(Link *link) {
670 assert(link->network);
671 assert(link->state == _LINK_STATE_INVALID);
675 link_enter_failed(link);
679 return link_enter_join_bridge(link);
682 int link_update(Link *link, sd_rtnl_message *m) {
689 if (link->state == LINK_STATE_FAILED)
692 r = sd_rtnl_message_link_get_flags(m, &flags);
694 log_warning("%s: could not get link flags", link->ifname);
698 return link_update_flags(link, flags);