X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=blobdiff_plain;f=src%2Fnetwork%2Fnetworkd-manager.c;h=d4b05bb98710e6ca06e50eabc27cdf9afadd0325;hb=4d473d5dded03d3b682dc389d610bb6b2db6e5f7;hp=28de7919daebf83f8211d1bf09867d5d391564bf;hpb=667fcc6d7dab1b98dfbbb65f8f14127d8690e70f;p=elogind.git diff --git a/src/network/networkd-manager.c b/src/network/networkd-manager.c index 28de7919d..d4b05bb98 100644 --- a/src/network/networkd-manager.c +++ b/src/network/networkd-manager.c @@ -20,6 +20,7 @@ ***/ #include +#include #include "path-util.h" #include "networkd.h" @@ -80,6 +81,10 @@ int manager_new(Manager **ret) { if (!m) return -ENOMEM; + m->state_file = strdup("/run/systemd/network/state"); + if (!m->state_file) + return -ENOMEM; + r = sd_event_default(&m->event); if (r < 0) return r; @@ -135,6 +140,8 @@ void manager_free(Manager *m) { if (!m) return; + free(m->state_file); + udev_monitor_unref(m->udev_monitor); udev_unref(m->udev); sd_bus_unref(m->bus); @@ -144,14 +151,14 @@ void manager_free(Manager *m) { sd_event_unref(m->event); while ((link = hashmap_first(m->links))) - link_free(link); + link_unref(link); hashmap_free(m->links); while ((network = m->networks)) network_free(network); while ((netdev = hashmap_first(m->netdevs))) - netdev_free(netdev); + netdev_unref(netdev); hashmap_free(m->netdevs); sd_rtnl_unref(m->rtnl); @@ -212,6 +219,8 @@ static int manager_udev_process_link(Manager *m, struct udev_device *device) { static int manager_rtnl_process_link(sd_rtnl *rtnl, sd_rtnl_message *message, void *userdata) { Manager *m = userdata; Link *link = NULL; + NetDev *netdev = NULL; + uint16_t type; char *name; int r, ifindex; @@ -219,41 +228,61 @@ static int manager_rtnl_process_link(sd_rtnl *rtnl, sd_rtnl_message *message, vo assert(message); assert(m); + r = sd_rtnl_message_get_type(message, &type); + if (r < 0) { + log_warning("rtnl: could not get message type"); + return 0; + } + r = sd_rtnl_message_link_get_ifindex(message, &ifindex); if (r < 0 || ifindex <= 0) { log_warning("rtnl: received link message without valid ifindex"); return 0; - } - - link_get(m, ifindex, &link); - if (!link) { - /* link is new, so add it */ - r = link_add(m, message, &link); - if (r < 0) { - log_debug("could not add new link"); - return 0; - } - } + } else + link_get(m, ifindex, &link); r = sd_rtnl_message_read_string(message, IFLA_IFNAME, &name); - if (r < 0) + if (r < 0 || !name) { log_warning("rtnl: received link message without valid ifname"); - else { - NetDev *netdev; + return 0; + } else + netdev_get(m, name, &netdev); + + switch (type) { + case RTM_NEWLINK: + if (!link) { + /* link is new, so add it */ + r = link_add(m, message, &link); + if (r < 0) { + log_debug("could not add new link"); + return 0; + } + } - r = netdev_get(m, name, &netdev); - if (r >= 0) { + if (netdev) { + /* netdev exists, so make sure the ifindex matches */ r = netdev_set_ifindex(netdev, message); if (r < 0) { log_debug("could not set ifindex on netdev"); return 0; } } - } - r = link_update(link, message); - if (r < 0) - return 0; + r = link_update(link, message); + if (r < 0) + return 0; + + break; + + case RTM_DELLINK: + link_drop(link); + netdev_drop(netdev); + + break; + + default: + assert_not_reached("Received invalid RTNL message type."); + } return 1; } @@ -351,6 +380,10 @@ int manager_rtnl_listen(Manager *m) { if (r < 0) return r; + r = sd_rtnl_add_match(m->rtnl, RTM_DELLINK, &manager_rtnl_process_link, m); + if (r < 0) + return r; + return 0; } @@ -457,3 +490,55 @@ int manager_update_resolv_conf(Manager *m) { return 0; } + +int manager_save(Manager *m) { + Link *link; + Iterator i; + _cleanup_free_ char *temp_path = NULL; + _cleanup_fclose_ FILE *f = NULL; + const char *oper_state = "unknown"; + bool dormant, carrier; + int r; + + assert(m); + assert(m->state_file); + + HASHMAP_FOREACH(link, m->links, i) { + if (link->flags & IFF_LOOPBACK) + continue; + + if (link_has_carrier(link->flags, link->operstate)) + carrier = true; + else if (link->operstate == IF_OPER_DORMANT) + dormant = true; + } + + if (carrier) + oper_state = "carrier"; + else if (dormant) + oper_state = "dormant"; + + r = fopen_temporary(m->state_file, &f, &temp_path); + if (r < 0) + goto finish; + + fchmod(fileno(f), 0644); + + fprintf(f, + "# This is private data. Do not parse.\n" + "OPER_STATE=%s\n", oper_state); + + fflush(f); + + if (ferror(f) || rename(temp_path, m->state_file) < 0) { + r = -errno; + unlink(m->state_file); + unlink(temp_path); + } + +finish: + if (r < 0) + log_error("Failed to save network state to %s: %s", m->state_file, strerror(-r)); + + return r; +}