diff options
author | Yu Watanabe <watanabe.yu+github@gmail.com> | 2021-11-16 02:27:01 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-11-16 02:27:01 +0100 |
commit | 7777024dab402b780472daf1ceb6afb3460b388d (patch) | |
tree | f08cd702577d8962e25fbe8f7a6d3699da16656f | |
parent | Merge pull request #21235 from bacher09/slava/supress_ifgroup (diff) | |
parent | network: make IgnoreCarrierLoss= also take timespan (diff) | |
download | systemd-7777024dab402b780472daf1ceb6afb3460b388d.tar.xz systemd-7777024dab402b780472daf1ceb6afb3460b388d.zip |
Merge pull request #21344 from yuwata/network-ignore-carrier-loss-timespan
network: make IgnoreCarrierLoss= also take a timespan
-rw-r--r-- | man/systemd.network.xml | 18 | ||||
-rw-r--r-- | src/libsystemd/sd-event/event-util.c | 24 | ||||
-rw-r--r-- | src/libsystemd/sd-event/event-util.h | 26 | ||||
-rw-r--r-- | src/network/networkd-link.c | 96 | ||||
-rw-r--r-- | src/network/networkd-link.h | 3 | ||||
-rw-r--r-- | src/network/networkd-network-gperf.gperf | 2 | ||||
-rw-r--r-- | src/network/networkd-network.c | 61 | ||||
-rw-r--r-- | src/network/networkd-network.h | 4 | ||||
-rw-r--r-- | src/network/networkd-wifi.c | 2 |
9 files changed, 200 insertions, 36 deletions
diff --git a/man/systemd.network.xml b/man/systemd.network.xml index 0fbefa6e76..a8fff46fe2 100644 --- a/man/systemd.network.xml +++ b/man/systemd.network.xml @@ -952,18 +952,21 @@ Table=1234</programlisting></para> <term><varname>ConfigureWithoutCarrier=</varname></term> <listitem> <para>Takes a boolean. Allows networkd to configure a specific link even if it has no carrier. - Defaults to false. If <option>IgnoreCarrierLoss=</option> is not explicitly set, it will - default to this value. + Defaults to false. If enabled, and the <varname>IgnoreCarrierLoss=</varname> setting is not + explicitly set, then it is enabled as well. </para> </listitem> </varlistentry> <varlistentry> <term><varname>IgnoreCarrierLoss=</varname></term> <listitem> - <para>Takes a boolean. Allows networkd to retain both the static and dynamic configuration - of the interface even if its carrier is lost. When unset, the value specified with - <option>ConfigureWithoutCarrier=</option> is used. - </para> + <para>Takes a boolean or a timespan. When true, networkd retains both the static and dynamic + configuration of the interface even if its carrier is lost. When a timespan is specified, + networkd waits for the specified timespan, and ignores the carrier loss if the link regain + its carrier within the timespan. Setting a finite timespan may be useful for a wireless + interface connecting to a network which has multiple access points with the same SSID, or an + interface which is reset on changing MTU. When unset, the value specified with + <varname>ConfigureWithoutCarrier=</varname> is used.</para> <para>When <varname>ActivationPolicy=</varname> is set to <literal>always-up</literal>, this is forced to <literal>true</literal>. @@ -1813,6 +1816,9 @@ Table=1234</programlisting></para> <para>When true, the interface maximum transmission unit from the DHCP server will be used on the current link. If <varname>MTUBytes=</varname> is set, then this setting is ignored. Defaults to false.</para> + <para>Note, some drivers will reset the interfaces if the MTU is changed. For such + interfaces, please try to use <varname>IgnoreCarrierLoss=</varname> with a short timespan, + e.g. <literal>3 seconds</literal>.</para> </listitem> </varlistentry> diff --git a/src/libsystemd/sd-event/event-util.c b/src/libsystemd/sd-event/event-util.c index 132796fc6c..0e53406a94 100644 --- a/src/libsystemd/sd-event/event-util.c +++ b/src/libsystemd/sd-event/event-util.c @@ -84,6 +84,30 @@ int event_reset_time( return created; } +int event_reset_time_relative( + sd_event *e, + sd_event_source **s, + clockid_t clock, + uint64_t usec, + uint64_t accuracy, + sd_event_time_handler_t callback, + void *userdata, + int64_t priority, + const char *description, + bool force_reset) { + + usec_t usec_now; + int r; + + assert(e); + + r = sd_event_now(e, clock, &usec_now); + if (r < 0) + return log_debug_errno(r, "sd-event: Failed to get the current time: %m"); + + return event_reset_time(e, s, clock, usec_add(usec_now, usec), accuracy, callback, userdata, priority, description, force_reset); +} + int event_source_disable(sd_event_source *s) { if (!s) return 0; diff --git a/src/libsystemd/sd-event/event-util.h b/src/libsystemd/sd-event/event-util.h index c8f97bc8d6..64a4199244 100644 --- a/src/libsystemd/sd-event/event-util.h +++ b/src/libsystemd/sd-event/event-util.h @@ -5,9 +5,27 @@ #include "sd-event.h" -int event_reset_time(sd_event *e, sd_event_source **s, - clockid_t clock, uint64_t usec, uint64_t accuracy, - sd_event_time_handler_t callback, void *userdata, - int64_t priority, const char *description, bool force_reset); +int event_reset_time( + sd_event *e, + sd_event_source **s, + clockid_t clock, + uint64_t usec, + uint64_t accuracy, + sd_event_time_handler_t callback, + void *userdata, + int64_t priority, + const char *description, + bool force_reset); +int event_reset_time_relative( + sd_event *e, + sd_event_source **s, + clockid_t clock, + uint64_t usec, + uint64_t accuracy, + sd_event_time_handler_t callback, + void *userdata, + int64_t priority, + const char *description, + bool force_reset); int event_source_disable(sd_event_source *s); int event_source_is_enabled(sd_event_source *s); diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c index f03e5c6dbf..e0e7cd8cd7 100644 --- a/src/network/networkd-link.c +++ b/src/network/networkd-link.c @@ -21,6 +21,7 @@ #include "dhcp-lease-internal.h" #include "env-file.h" #include "ethtool-util.h" +#include "event-util.h" #include "fd-util.h" #include "fileio.h" #include "format-util.h" @@ -244,6 +245,7 @@ static Link *link_free(Link *link) { strv_free(link->alternative_names); free(link->kind); free(link->ssid); + free(link->previous_ssid); free(link->driver); unlink_and_free(link->lease_file); @@ -259,6 +261,8 @@ static Link *link_free(Link *link) { network_unref(link->network); + sd_event_source_disable_unref(link->carrier_lost_timer); + return mfree(link); } @@ -1581,10 +1585,34 @@ int manager_udev_process_link(sd_device_monitor *monitor, sd_device *device, voi } static int link_carrier_gained(Link *link) { + bool force_reconfigure; int r; assert(link); + r = event_source_disable(link->carrier_lost_timer); + if (r < 0) + log_link_warning_errno(link, r, "Failed to disable carrier lost timer, ignoring: %m"); + + /* If the SSID is changed, then the connected wireless network could be changed. So, always + * reconfigure the link. Which means e.g. the DHCP client will be restarted, and the correct + * network information will be gained. + * For non-wireless interfaces, we have no way to detect the connected network change. So, + * setting force_reconfigure = false. Note, both ssid and previous_ssid should be NULL for + * non-wireless interfaces, and streq_ptr() returns true. */ + force_reconfigure = !streq_ptr(link->previous_ssid, link->ssid); + link->previous_ssid = mfree(link->previous_ssid); + + if (IN_SET(link->state, LINK_STATE_CONFIGURING, LINK_STATE_CONFIGURED)) { + /* At this stage, both wlan and link information should be up-to-date. Hence, + * it is not necessary to call RTM_GETLINK, NL80211_CMD_GET_INTERFACE, or + * NL80211_CMD_GET_STATION commands, and simply call link_reconfigure_impl(). + * Note, link_reconfigure_impl() returns 1 when the link is reconfigured. */ + r = link_reconfigure_impl(link, force_reconfigure); + if (r != 0) + return r; + } + r = link_handle_bound_by_list(link); if (r < 0) return r; @@ -1606,6 +1634,45 @@ static int link_carrier_gained(Link *link) { return 0; } +static int link_carrier_lost_impl(Link *link) { + int r, ret = 0; + + assert(link); + + link->previous_ssid = mfree(link->previous_ssid); + + if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER)) + return 0; + + if (!link->network) + return 0; + + r = link_stop_engines(link, false); + if (r < 0) + ret = r; + + r = link_drop_config(link); + if (r < 0 && ret >= 0) + ret = r; + + return ret; +} + +static int link_carrier_lost_handler(sd_event_source *s, uint64_t usec, void *userdata) { + Link *link = userdata; + int r; + + assert(link); + + r = link_carrier_lost_impl(link); + if (r < 0) { + log_link_warning_errno(link, r, "Failed to process carrier lost event: %m"); + link_enter_failed(link); + } + + return 0; +} + static int link_carrier_lost(Link *link) { int r; @@ -1622,16 +1689,22 @@ static int link_carrier_lost(Link *link) { if (!link->network) return 0; - if (link->network->ignore_carrier_loss) + if (link->network->ignore_carrier_loss_usec == USEC_INFINITY) return 0; - r = link_stop_engines(link, false); - if (r < 0) { - link_enter_failed(link); - return r; - } + if (link->network->ignore_carrier_loss_usec == 0) + return link_carrier_lost_impl(link); - return link_drop_config(link); + return event_reset_time_relative(link->manager->event, + &link->carrier_lost_timer, + clock_boottime_or_monotonic(), + link->network->ignore_carrier_loss_usec, + 0, + link_carrier_lost_handler, + link, + 0, + "link-carrier-loss", + true); } static int link_admin_state_up(Link *link) { @@ -1958,15 +2031,6 @@ static int link_update_flags(Link *link, sd_netlink_message *message) { if (!had_carrier && link_has_carrier(link)) { log_link_info(link, "Gained carrier"); - if (IN_SET(link->state, LINK_STATE_CONFIGURING, LINK_STATE_CONFIGURED)) { - /* At this stage, both wlan and link information should be up-to-date. Hence, - * it is not necessary to call RTM_GETLINK, NL80211_CMD_GET_INTERFACE, or - * NL80211_CMD_GET_STATION commands, and simply call link_reconfigure_impl(). */ - r = link_reconfigure_impl(link, /* force = */ false); - if (r < 0) - return r; - } - r = link_carrier_gained(link); if (r < 0) return r; diff --git a/src/network/networkd-link.h b/src/network/networkd-link.h index 7006f3df65..edf93d720e 100644 --- a/src/network/networkd-link.h +++ b/src/network/networkd-link.h @@ -67,11 +67,14 @@ typedef struct Link { /* wlan */ enum nl80211_iftype wlan_iftype; char *ssid; + char *previous_ssid; struct ether_addr bssid; unsigned flags; uint8_t kernel_operstate; + sd_event_source *carrier_lost_timer; + Network *network; LinkState state; diff --git a/src/network/networkd-network-gperf.gperf b/src/network/networkd-network-gperf.gperf index 525d0158bc..2fdfb16689 100644 --- a/src/network/networkd-network-gperf.gperf +++ b/src/network/networkd-network-gperf.gperf @@ -135,7 +135,7 @@ Network.ProxyARP, config_parse_tristate, Network.IPv6ProxyNDPAddress, config_parse_ipv6_proxy_ndp_address, 0, 0 Network.BindCarrier, config_parse_strv, 0, offsetof(Network, bind_carrier) Network.ConfigureWithoutCarrier, config_parse_bool, 0, offsetof(Network, configure_without_carrier) -Network.IgnoreCarrierLoss, config_parse_tristate, 0, offsetof(Network, ignore_carrier_loss) +Network.IgnoreCarrierLoss, config_parse_ignore_carrier_loss, 0, 0 Network.KeepConfiguration, config_parse_keep_configuration, 0, offsetof(Network, keep_configuration) Network.IPv6SendRA, config_parse_router_prefix_delegation, 0, offsetof(Network, router_prefix_delegation) Network.DHCPv6PrefixDelegation, config_parse_tristate, 0, offsetof(Network, dhcp6_pd) diff --git a/src/network/networkd-network.c b/src/network/networkd-network.c index 90da1670f0..82094a49b1 100644 --- a/src/network/networkd-network.c +++ b/src/network/networkd-network.c @@ -271,14 +271,17 @@ int network_verify(Network *network) { network->activation_policy = ACTIVATION_POLICY_UP; if (network->activation_policy == ACTIVATION_POLICY_ALWAYS_UP) { - if (network->ignore_carrier_loss == false) - log_warning("%s: IgnoreCarrierLoss=false conflicts with ActivationPolicy=always-up. " - "Setting IgnoreCarrierLoss=true.", network->filename); - network->ignore_carrier_loss = true; + if (network->ignore_carrier_loss_set && network->ignore_carrier_loss_usec < USEC_INFINITY) + log_warning("%s: IgnoreCarrierLoss=no or finite timespan conflicts with ActivationPolicy=always-up. " + "Setting IgnoreCarrierLoss=yes.", network->filename); + network->ignore_carrier_loss_set = true; + network->ignore_carrier_loss_usec = USEC_INFINITY; } - if (network->ignore_carrier_loss < 0) - network->ignore_carrier_loss = network->configure_without_carrier; + if (!network->ignore_carrier_loss_set) { + network->ignore_carrier_loss_set = true; + network->ignore_carrier_loss_usec = network->configure_without_carrier ? USEC_INFINITY : 0; + } if (IN_SET(network->activation_policy, ACTIVATION_POLICY_DOWN, ACTIVATION_POLICY_ALWAYS_DOWN, ACTIVATION_POLICY_MANUAL)) { if (network->required_for_online < 0 || @@ -379,7 +382,6 @@ int network_load_one(Manager *manager, OrderedHashmap **networks, const char *fi .allmulticast = -1, .promiscuous = -1, - .ignore_carrier_loss = -1, .keep_configuration = _KEEP_CONFIGURATION_INVALID, .dhcp_duid.type = _DUID_TYPE_INVALID, @@ -1285,6 +1287,51 @@ int config_parse_link_group( return 0; } +int config_parse_ignore_carrier_loss( + const char *unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { + + Network *network = userdata; + usec_t usec; + int r; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(network); + + if (isempty(rvalue)) { + network->ignore_carrier_loss_set = false; + return 0; + } + + r = parse_boolean(rvalue); + if (r >= 0) { + network->ignore_carrier_loss_set = true; + network->ignore_carrier_loss_usec = r > 0 ? USEC_INFINITY : 0; + return 0; + } + + r = parse_sec(rvalue, &usec); + if (r < 0) { + log_syntax(unit, LOG_WARNING, filename, line, r, + "Failed to parse %s=, ignoring assignment: %s", lvalue, rvalue); + return 0; + } + + network->ignore_carrier_loss_set = true; + network->ignore_carrier_loss_usec = usec; + return 0; +} + DEFINE_CONFIG_PARSE_ENUM(config_parse_required_family_for_online, link_required_address_family, AddressFamily, "Failed to parse RequiredFamilyForOnline= setting"); diff --git a/src/network/networkd-network.h b/src/network/networkd-network.h index fb79ee8509..626b7710f0 100644 --- a/src/network/networkd-network.h +++ b/src/network/networkd-network.h @@ -109,7 +109,8 @@ struct Network { /* misc settings */ bool configure_without_carrier; - int ignore_carrier_loss; + bool ignore_carrier_loss_set; + usec_t ignore_carrier_loss_usec; /* timespan */ KeepConfiguration keep_configuration; char **bind_carrier; bool default_route_on_device; @@ -383,6 +384,7 @@ CONFIG_PARSER_PROTOTYPE(config_parse_keep_configuration); CONFIG_PARSER_PROTOTYPE(config_parse_ipv6_link_local_address_gen_mode); CONFIG_PARSER_PROTOTYPE(config_parse_activation_policy); CONFIG_PARSER_PROTOTYPE(config_parse_link_group); +CONFIG_PARSER_PROTOTYPE(config_parse_ignore_carrier_loss); const struct ConfigPerfItem* network_network_gperf_lookup(const char *key, GPERF_LEN_TYPE length); diff --git a/src/network/networkd-wifi.c b/src/network/networkd-wifi.c index 1475218286..f1d5c7d8d4 100644 --- a/src/network/networkd-wifi.c +++ b/src/network/networkd-wifi.c @@ -273,7 +273,7 @@ int manager_genl_process_nl80211_mlme(sd_netlink *genl, sd_netlink_message *mess strna(nl80211_cmd_to_string(cmd)), cmd); link->bssid = ETHER_ADDR_NULL; - link->ssid = mfree(link->ssid); + free_and_replace(link->previous_ssid, link->ssid); break; default: |