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 & IFF_UP && !(flags & IFF_UP))
454 log_info("%s: interface is down", link->ifname);
455 else if (!(link->flags & IFF_UP) && flags & IFF_UP)
456 log_info("%s: interface is up", link->ifname);
458 if (link->flags & IFF_LOWER_UP && !(flags & IFF_LOWER_UP)) {
459 log_info("%s: disconnected", link->ifname);
461 if (link->network->dhcp) {
462 r = sd_dhcp_client_stop(link->dhcp);
464 link_enter_failed(link);
468 } else if (!(link->flags & IFF_LOWER_UP) && flags & IFF_LOWER_UP) {
469 log_info("%s: connected", link->ifname);
471 if (link->network->dhcp) {
472 r = link_acquire_conf(link);
474 link_enter_failed(link);
485 static int link_up_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
486 Link *link = userdata;
491 if (link->state == LINK_STATE_FAILED)
494 r = sd_rtnl_message_get_errno(m);
496 log_warning("%s: could not bring up interface: %s",
497 link->ifname, strerror(-r));
498 link_enter_failed(link);
501 link_update_flags(link, link->flags | IFF_UP);
506 static int link_up(Link *link) {
507 _cleanup_sd_rtnl_message_unref_ sd_rtnl_message *req = NULL;
511 assert(link->manager);
512 assert(link->manager->rtnl);
514 log_debug("%s: bringing up link", link->ifname);
516 r = sd_rtnl_message_link_new(RTM_SETLINK, link->ifindex, &req);
518 log_error("Could not allocate RTM_SETLINK message");
522 r = sd_rtnl_message_link_set_flags(req, IFF_UP);
524 log_error("Could not set link flags");
528 r = sd_rtnl_call_async(link->manager->rtnl, req, link_up_handler, link, 0, NULL);
530 log_error("Could not send rtnetlink message: %s", strerror(-r));
537 static int link_bridge_joined(Link *link) {
541 assert(link->state == LINK_STATE_JOINING_BRIDGE);
542 assert(link->network);
546 link_enter_failed(link);
550 if (!link->network->dhcp)
551 return link_enter_set_addresses(link);
556 static int bridge_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
557 Link *link = userdata;
561 assert(link->state == LINK_STATE_JOINING_BRIDGE || link->state == LINK_STATE_FAILED);
562 assert(link->network);
564 if (link->state == LINK_STATE_FAILED)
567 r = sd_rtnl_message_get_errno(m);
569 log_warning("%s: could not join bridge '%s': %s",
570 link->ifname, link->network->bridge->name, strerror(-r));
571 link_enter_failed(link);
574 log_debug("%s: joined bridge '%s'",
575 link->ifname, link->network->bridge->name);
577 link_bridge_joined(link);
582 static int link_enter_join_bridge(Link *link) {
586 assert(link->network);
587 assert(link->state == _LINK_STATE_INVALID);
589 link->state = LINK_STATE_JOINING_BRIDGE;
591 if (!link->network->bridge)
592 return link_bridge_joined(link);
594 log_debug("%s: joining bridge", link->ifname);
596 r = bridge_join(link->network->bridge, link, &bridge_handler);
598 log_warning("%s: could not join bridge '%s'", link->ifname,
599 link->network->bridge->name);
600 link_enter_failed(link);
607 static int link_get_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
608 Link *link = userdata;
613 if (link->state == LINK_STATE_FAILED)
616 r = sd_rtnl_message_get_errno(m);
618 log_warning("%s: could not get state: %s",
619 link->ifname, strerror(-r));
620 link_enter_failed(link);
623 log_debug("%s: got link state", link->ifname);
625 link_update(link, m);
630 static int link_get(Link *link) {
631 _cleanup_sd_rtnl_message_unref_ sd_rtnl_message *req = NULL;
635 assert(link->manager);
636 assert(link->manager->rtnl);
638 log_debug("%s: requesting link status", link->ifname);
640 r = sd_rtnl_message_link_new(RTM_GETLINK, link->ifindex, &req);
642 log_error("Could not allocate RTM_GETLINK message");
646 r = sd_rtnl_call_async(link->manager->rtnl, req, link_get_handler, link, 0, NULL);
648 log_error("Could not send rtnetlink message: %s", strerror(-r));
655 int link_configure(Link *link) {
659 assert(link->network);
660 assert(link->state == _LINK_STATE_INVALID);
664 link_enter_failed(link);
668 return link_enter_join_bridge(link);
671 int link_update(Link *link, sd_rtnl_message *m) {
678 if (link->state == LINK_STATE_FAILED)
681 r = sd_rtnl_message_link_get_flags(m, &flags);
683 log_warning("%s: could not get link flags", link->ifname);
687 return link_update_flags(link, flags);