diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c index 17fb932f81a..8900534cd67 100644 --- a/src/network/networkd-link.c +++ b/src/network/networkd-link.c @@ -690,6 +690,12 @@ static int link_acquire_dynamic_conf(Link *link) { if (r < 0) return log_link_warning_errno(link, r, "Failed to start LLDP transmission: %m"); + if (link->lldp) { + r = sd_lldp_start(link->lldp); + if (r < 0) + return log_link_warning_errno(link, r, "Failed to start LLDP client: %m"); + } + return 0; } @@ -999,6 +1005,16 @@ static int link_drop_foreign_config(Link *link) { assert(link); assert(link->manager); + /* Drop foreign config, but ignore unmanaged, loopback, or critical interfaces. We do not want + * to remove loopback address or addresses used for root NFS. */ + + if (IN_SET(link->state, LINK_STATE_UNMANAGED, LINK_STATE_PENDING, LINK_STATE_INITIALIZED)) + return 0; + if (FLAGS_SET(link->flags, IFF_LOOPBACK)) + return 0; + if (link->network->keep_configuration == KEEP_CONFIGURATION_YES) + return 0; + r = link_drop_foreign_routes(link); k = link_drop_foreign_nexthops(link); @@ -1151,14 +1167,9 @@ static int link_configure(Link *link) { if (r < 0) return r; - /* Drop foreign config, but ignore loopback or critical devices. - * We do not want to remove loopback address or addresses used for root NFS. */ - if (!(link->flags & IFF_LOOPBACK) && - link->network->keep_configuration != KEEP_CONFIGURATION_YES) { - r = link_drop_foreign_config(link); - if (r < 0) - return r; - } + r = link_drop_foreign_config(link); + if (r < 0) + return r; r = link_request_static_configs(link); if (r < 0) @@ -1224,23 +1235,22 @@ static int link_get_network(Link *link, Network **ret) { } static int link_reconfigure_impl(Link *link, bool force) { - Network *network; + Network *network = NULL; int r; assert(link); r = link_get_network(link, &network); - if (r == -ENOENT) { - link_set_state(link, LINK_STATE_UNMANAGED); - return 0; - } - if (r < 0) + if (r < 0 && r != -ENOENT) return r; if (link->network == network && !force) return 0; - log_link_info(link, "Re-configuring with %s", network->filename); + if (network) + log_link_info(link, "Reconfiguring with %s.", network->filename); + else + log_link_info(link, "Unmanaging interface."); /* Dropping old .network file */ r = link_stop_engines(link, false); @@ -1253,18 +1263,16 @@ static int link_reconfigure_impl(Link *link, bool force) { if (r < 0) return r; - if (!IN_SET(link->state, LINK_STATE_UNMANAGED, LINK_STATE_PENDING, LINK_STATE_INITIALIZED)) { - log_link_debug(link, "State is %s, dropping foreign config", link_state_to_string(link->state)); - r = link_drop_foreign_config(link); - if (r < 0) - return r; - } - link_free_carrier_maps(link); link_free_engines(link); link->network = network_unref(link->network); link_unref(set_remove(link->manager->links_requesting_uuid, link)); + if (!network) { + link_set_state(link, LINK_STATE_UNMANAGED); + return 0; + } + /* Then, apply new .network file */ link->network = network_ref(network); link_update_operstate(link, true); @@ -1284,44 +1292,107 @@ static int link_reconfigure_impl(Link *link, bool force) { return 1; } -static int link_reconfigure_handler_internal(sd_netlink *rtnl, sd_netlink_message *m, Link *link, bool force) { +static int link_reconfigure_handler_internal(sd_netlink *rtnl, sd_netlink_message *m, Link *link, bool force, bool update_wifi) { + bool link_was_lower_up; int r; + assert(link); + + link_was_lower_up = link->flags & IFF_LOWER_UP; + r = link_getlink_handler_internal(rtnl, m, link, "Failed to update link state"); if (r <= 0) return r; + if (update_wifi && link_was_lower_up && link->flags & IFF_LOWER_UP) { + /* If the interface's L1 was not up, then wifi_get_info() is already called in + * link_update_flags(). So, it is not necessary to re-call here. */ + r = wifi_get_info(link); + if (r < 0) { + link_enter_failed(link); + return 0; + } + } + r = link_reconfigure_impl(link, force); - if (r < 0) + if (r < 0) { link_enter_failed(link); + return 0; + } + + return r; +} + +static int link_reconfigure_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) { + return link_reconfigure_handler_internal(rtnl, m, link, /* force = */ false, /* update_wifi = */ false); +} + +static int link_force_reconfigure_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) { + return link_reconfigure_handler_internal(rtnl, m, link, /* force = */ true, /* update_wifi = */ false); +} + +static int link_reconfigure_after_sleep_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) { + int r; + + assert(link); + + r = link_reconfigure_handler_internal(rtnl, m, link, /* force = */ false, /* update_wifi = */ true); + if (r != 0) + return r; + + /* r == 0 means an error occurs, the link is unmanaged, or the matching network file is unchanged. */ + if (!IN_SET(link->state, LINK_STATE_CONFIGURING, LINK_STATE_CONFIGURED)) + return 0; + + /* re-request static configs, and restart engines. */ + r = link_stop_engines(link, false); + if (r < 0) { + link_enter_failed(link); + return 0; + } + + r = link_acquire_dynamic_conf(link); + if (r < 0) { + link_enter_failed(link); + return 0; + } + + r = link_request_static_configs(link); + if (r < 0) { + link_enter_failed(link); + return 0; + } return 0; } -static int link_reconfigure_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) { - return link_reconfigure_handler_internal(rtnl, m, link, false); -} - -static int link_force_reconfigure_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) { - return link_reconfigure_handler_internal(rtnl, m, link, true); -} - -int link_reconfigure(Link *link, bool force) { +static int link_reconfigure_internal(Link *link, link_netlink_message_handler_t callback) { int r; + assert(link); + assert(callback); + /* When link in pending or initialized state, then link_configure() will be called. To prevent * the function from being called multiple times simultaneously, refuse to reconfigure the * interface in these cases. */ if (IN_SET(link->state, LINK_STATE_PENDING, LINK_STATE_INITIALIZED, LINK_STATE_LINGER)) return 0; /* 0 means no-op. */ - r = link_call_getlink(link, force ? link_force_reconfigure_handler : link_reconfigure_handler); + r = link_call_getlink(link, callback); if (r < 0) return r; return 1; /* 1 means the interface will be reconfigured. */ } +int link_reconfigure(Link *link, bool force) { + return link_reconfigure_internal(link, force ? link_force_reconfigure_handler : link_reconfigure_handler); +} + +int link_reconfigure_after_sleep(Link *link) { + return link_reconfigure_internal(link, link_reconfigure_after_sleep_handler); +} + static int link_initialized_and_synced(Link *link) { Network *network; int r; @@ -1560,34 +1631,7 @@ static int link_carrier_lost(Link *link) { if (r < 0) return r; - if (!IN_SET(link->state, LINK_STATE_UNMANAGED, LINK_STATE_PENDING, LINK_STATE_INITIALIZED)) { - log_link_debug(link, "State is %s, dropping foreign config", link_state_to_string(link->state)); - r = link_drop_foreign_config(link); - if (r < 0) - return r; - } - - return 0; -} - -int link_carrier_reset(Link *link) { - int r; - - assert(link); - - if (!link_has_carrier(link)) - return 0; - - r = link_carrier_lost(link); - if (r < 0) - return r; - - r = link_carrier_gained(link); - if (r < 0) - return r; - - log_link_info(link, "Reset carrier"); - return 0; + return link_drop_foreign_config(link); } static int link_admin_state_up(Link *link) { @@ -1943,10 +1987,6 @@ static int link_update_flags(Link *link, sd_netlink_message *message) { return r; } - r = link_update_lldp(link); - if (r < 0) - return r; - if (!had_carrier && link_has_carrier(link)) { log_link_info(link, "Gained carrier"); diff --git a/src/network/networkd-link.h b/src/network/networkd-link.h index 4077ccaf09c..79400dee2e9 100644 --- a/src/network/networkd-link.h +++ b/src/network/networkd-link.h @@ -232,7 +232,6 @@ void link_check_ready(Link *link); void link_update_operstate(Link *link, bool also_update_bond_master); -int link_carrier_reset(Link *link); bool link_has_carrier(Link *link); bool link_ipv6_enabled(Link *link); @@ -247,6 +246,7 @@ const char* link_state_to_string(LinkState s) _const_; LinkState link_state_from_string(const char *s) _pure_; int link_reconfigure(Link *link, bool force); +int link_reconfigure_after_sleep(Link *link); int manager_udev_process_link(sd_device_monitor *monitor, sd_device *device, void *userdata); int manager_rtnl_process_link(sd_netlink *rtnl, sd_netlink_message *message, Manager *m); diff --git a/src/network/networkd-lldp-rx.c b/src/network/networkd-lldp-rx.c index c30cc36b51c..57c8446adef 100644 --- a/src/network/networkd-lldp-rx.c +++ b/src/network/networkd-lldp-rx.c @@ -103,38 +103,9 @@ int link_lldp_rx_configure(Link *link) { if (r < 0) return r; - r = link_update_lldp(link); - if (r < 0) - return r; - return 0; } -int link_update_lldp(Link *link) { - int r; - - assert(link); - - if (!link->lldp) - return 0; - - if (link->flags & IFF_UP) { - r = sd_lldp_start(link->lldp); - if (r < 0) - return log_link_warning_errno(link, r, "Failed to start LLDP: %m"); - if (r > 0) - log_link_debug(link, "Started LLDP."); - } else { - r = sd_lldp_stop(link->lldp); - if (r < 0) - return log_link_warning_errno(link, r, "Failed to stop LLDP: %m"); - if (r > 0) - log_link_debug(link, "Stopped LLDP."); - } - - return r; -} - int link_lldp_save(Link *link) { _cleanup_(unlink_and_freep) char *temp_path = NULL; _cleanup_fclose_ FILE *f = NULL; diff --git a/src/network/networkd-lldp-rx.h b/src/network/networkd-lldp-rx.h index 49306eafd0a..22f6602bd0f 100644 --- a/src/network/networkd-lldp-rx.h +++ b/src/network/networkd-lldp-rx.h @@ -14,7 +14,6 @@ typedef enum LLDPMode { } LLDPMode; int link_lldp_rx_configure(Link *link); -int link_update_lldp(Link *link); int link_lldp_save(Link *link); const char* lldp_mode_to_string(LLDPMode m) _const_; diff --git a/src/network/networkd-manager.c b/src/network/networkd-manager.c index 374d27bef34..82aecf1c76b 100644 --- a/src/network/networkd-manager.c +++ b/src/network/networkd-manager.c @@ -59,9 +59,9 @@ static int manager_reset_all(Manager *m) { assert(m); HASHMAP_FOREACH(link, m->links_by_index) { - r = link_carrier_reset(link); + r = link_reconfigure_after_sleep(link); if (r < 0) { - log_link_warning_errno(link, r, "Could not reset carrier: %m"); + log_link_warning_errno(link, r, "Failed to reconfigure interface: %m"); link_enter_failed(link); } } diff --git a/test/test-network/systemd-networkd-tests.py b/test/test-network/systemd-networkd-tests.py index df9b6eadad7..d3e3a212e7f 100755 --- a/test/test-network/systemd-networkd-tests.py +++ b/test/test-network/systemd-networkd-tests.py @@ -674,9 +674,9 @@ class NetworkctlTests(unittest.TestCase, Utilities): output = check_output('ip -4 address show dev dummy98') print(output) - self.assertRegex(output, 'inet 10.1.2.3/16 brd 10.1.255.255 scope global dummy98') - self.assertRegex(output, 'inet 10.1.2.4/16 brd 10.1.255.255 scope global secondary dummy98') - self.assertRegex(output, 'inet 10.2.2.4/16 brd 10.2.255.255 scope global dummy98') + self.assertIn('inet 10.1.2.3/16 brd 10.1.255.255 scope global dummy98', output) + self.assertIn('inet 10.1.2.4/16 brd 10.1.255.255 scope global secondary dummy98', output) + self.assertIn('inet 10.2.2.4/16 brd 10.2.255.255 scope global dummy98', output) check_output('ip address del 10.1.2.3/16 dev dummy98') check_output('ip address del 10.1.2.4/16 dev dummy98') @@ -687,9 +687,30 @@ class NetworkctlTests(unittest.TestCase, Utilities): output = check_output('ip -4 address show dev dummy98') print(output) - self.assertRegex(output, 'inet 10.1.2.3/16 brd 10.1.255.255 scope global dummy98') - self.assertRegex(output, 'inet 10.1.2.4/16 brd 10.1.255.255 scope global secondary dummy98') - self.assertRegex(output, 'inet 10.2.2.4/16 brd 10.2.255.255 scope global dummy98') + self.assertIn('inet 10.1.2.3/16 brd 10.1.255.255 scope global dummy98', output) + self.assertIn('inet 10.1.2.4/16 brd 10.1.255.255 scope global secondary dummy98', output) + self.assertIn('inet 10.2.2.4/16 brd 10.2.255.255 scope global dummy98', output) + + remove_unit_from_networkd_path(['25-address-static.network']) + + check_output(*networkctl_cmd, 'reload', env=env) + self.wait_operstate('dummy98', 'degraded', setup_state='unmanaged') + + output = check_output('ip -4 address show dev dummy98') + print(output) + self.assertNotIn('inet 10.1.2.3/16 brd 10.1.255.255 scope global dummy98', output) + self.assertNotIn('inet 10.1.2.4/16 brd 10.1.255.255 scope global secondary dummy98', output) + self.assertNotIn('inet 10.2.2.4/16 brd 10.2.255.255 scope global dummy98', output) + + copy_unit_to_networkd_unit_path('25-address-static.network') + check_output(*networkctl_cmd, 'reload', env=env) + self.wait_online(['dummy98:routable']) + + output = check_output('ip -4 address show dev dummy98') + print(output) + self.assertIn('inet 10.1.2.3/16 brd 10.1.255.255 scope global dummy98', output) + self.assertIn('inet 10.1.2.4/16 brd 10.1.255.255 scope global secondary dummy98', output) + self.assertIn('inet 10.2.2.4/16 brd 10.2.255.255 scope global dummy98', output) def test_reload(self): start_networkd(3)