diff --git a/src/network/netdev/netdev.c b/src/network/netdev/netdev.c index 0a311544b27..1e046397d50 100644 --- a/src/network/netdev/netdev.c +++ b/src/network/netdev/netdev.c @@ -242,6 +242,7 @@ static NetDev* netdev_free(NetDev *netdev) { condition_free_list(netdev->conditions); free(netdev->filename); strv_free(netdev->dropins); + hashmap_free(netdev->stats_by_path); free(netdev->description); free(netdev->ifname); @@ -1003,7 +1004,7 @@ int netdev_load_one(Manager *manager, const char *filename, NetDev **ret) { config_item_perf_lookup, network_netdev_gperf_lookup, CONFIG_PARSE_WARN, netdev, - NULL, + &netdev->stats_by_path, &netdev->dropins); if (r < 0) return r; /* config_parse_many() logs internally. */ @@ -1053,6 +1054,81 @@ int netdev_load(Manager *manager) { return 0; } +int netdev_reload(Manager *manager) { + _cleanup_hashmap_free_ Hashmap *new_netdevs = NULL; + _cleanup_strv_free_ char **files = NULL; + int r; + + assert(manager); + + r = conf_files_list_strv(&files, ".netdev", NULL, 0, NETWORK_DIRS); + if (r < 0) + return log_error_errno(r, "Failed to enumerate netdev files: %m"); + + STRV_FOREACH(f, files) { + _cleanup_(netdev_unrefp) NetDev *netdev = NULL; + NetDev *old; + + if (netdev_load_one(manager, *f, &netdev) < 0) + continue; + + if (netdev_get(manager, netdev->ifname, &old) < 0) { + log_netdev_debug(netdev, "Found new .netdev file: %s", netdev->filename); + + if (netdev_attach_name_full(netdev, netdev->ifname, &new_netdevs) >= 0) + TAKE_PTR(netdev); + + continue; + } + + if (!stats_by_path_equal(netdev->stats_by_path, old->stats_by_path)) { + log_netdev_debug(netdev, "Found updated .netdev file: %s", netdev->filename); + + /* Copy ifindex. */ + netdev->ifindex = old->ifindex; + + if (netdev_attach_name_full(netdev, netdev->ifname, &new_netdevs) >= 0) + TAKE_PTR(netdev); + + continue; + } + + /* Keep the original object, and drop the new one. */ + if (netdev_attach_name_full(old, old->ifname, &new_netdevs) >= 0) + netdev_ref(old); + } + + /* Detach old NetDev objects from Manager. + * Note, the same object may be registered with multiple names, and netdev_detach() may drop multiple + * entries. Hence, hashmap_free_with_destructor() cannot be used. */ + for (NetDev *n; (n = hashmap_first(manager->netdevs)); ) + netdev_detach(n); + + /* Attach new NetDev objects to Manager. */ + for (;;) { + _cleanup_(netdev_unrefp) NetDev *netdev = hashmap_steal_first(new_netdevs); + if (!netdev) + break; + + netdev->manager = manager; + if (netdev_attach(netdev) < 0) + continue; + + /* Create a new netdev or update existing netdev, */ + if (netdev_request_to_create(netdev) < 0) + continue; + + TAKE_PTR(netdev); + } + + /* Reassign NetDev objects to Link object. */ + Link *link; + HASHMAP_FOREACH(link, manager->links_by_index) + link_assign_netdev(link); + + return 0; +} + int config_parse_netdev_kind( const char *unit, const char *filename, diff --git a/src/network/netdev/netdev.h b/src/network/netdev/netdev.h index a91ef506544..106f47acada 100644 --- a/src/network/netdev/netdev.h +++ b/src/network/netdev/netdev.h @@ -118,6 +118,7 @@ typedef struct NetDev { char *filename; char **dropins; + Hashmap *stats_by_path; LIST_HEAD(Condition, conditions); @@ -218,6 +219,7 @@ void netdev_detach(NetDev *netdev); int netdev_set_ifindex_internal(NetDev *netdev, int ifindex); int netdev_load(Manager *manager); +int netdev_reload(Manager *manager); int netdev_load_one(Manager *manager, const char *filename, NetDev **ret); void netdev_drop(NetDev *netdev); void netdev_enter_failed(NetDev *netdev); diff --git a/src/network/networkd-manager.c b/src/network/networkd-manager.c index ca2b008a349..6639d59b321 100644 --- a/src/network/networkd-manager.c +++ b/src/network/networkd-manager.c @@ -1188,7 +1188,7 @@ int manager_reload(Manager *m, sd_bus_message *message) { (void) notify_reloading(); - r = netdev_load(m); + r = netdev_reload(m); if (r < 0) goto finish;