X Tutup
Skip to content

Commit 6706ce2

Browse files
committed
network: make IgnoreCarrierLoss= also take timespan
Fixes systemd#18738 and systemd#20887. Replaces systemd#18746.
1 parent b7ac128 commit 6706ce2

File tree

7 files changed

+146
-25
lines changed

7 files changed

+146
-25
lines changed

man/systemd.network.xml

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -952,18 +952,21 @@ Table=1234</programlisting></para>
952952
<term><varname>ConfigureWithoutCarrier=</varname></term>
953953
<listitem>
954954
<para>Takes a boolean. Allows networkd to configure a specific link even if it has no carrier.
955-
Defaults to false. If <option>IgnoreCarrierLoss=</option> is not explicitly set, it will
956-
default to this value.
955+
Defaults to false. If enabled, and the <varname>IgnoreCarrierLoss=</varname> setting is not
956+
explicitly set, then it is enabled as well.
957957
</para>
958958
</listitem>
959959
</varlistentry>
960960
<varlistentry>
961961
<term><varname>IgnoreCarrierLoss=</varname></term>
962962
<listitem>
963-
<para>Takes a boolean. Allows networkd to retain both the static and dynamic configuration
964-
of the interface even if its carrier is lost. When unset, the value specified with
965-
<option>ConfigureWithoutCarrier=</option> is used.
966-
</para>
963+
<para>Takes a boolean or a timespan. When true, networkd retains both the static and dynamic
964+
configuration of the interface even if its carrier is lost. When a timespan is specified,
965+
networkd waits for the specified timespan, and ignores the carrier loss if the link regain
966+
its carrier within the timespan. Setting a finite timespan may be useful for a wireless
967+
interface connecting to a network which has multiple access points with the same SSID, or an
968+
interface which is reset on changing MTU. When unset, the value specified with
969+
<varname>ConfigureWithoutCarrier=</varname> is used.</para>
967970

968971
<para>When <varname>ActivationPolicy=</varname> is set to <literal>always-up</literal>, this
969972
is forced to <literal>true</literal>.
@@ -1805,6 +1808,9 @@ Table=1234</programlisting></para>
18051808
<para>When true, the interface maximum transmission unit from the DHCP server will be used on the
18061809
current link. If <varname>MTUBytes=</varname> is set, then this setting is ignored. Defaults to
18071810
false.</para>
1811+
<para>Note, some drivers will reset the interfaces if the MTU is changed. For such
1812+
interfaces, please try to use <varname>IgnoreCarrierLoss=</varname> with a short timespan,
1813+
e.g. <literal>3 seconds</literal>.</para>
18081814
</listitem>
18091815
</varlistentry>
18101816

src/network/networkd-link.c

Lines changed: 72 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include "dhcp-lease-internal.h"
2121
#include "env-file.h"
2222
#include "ethtool-util.h"
23+
#include "event-util.h"
2324
#include "fd-util.h"
2425
#include "fileio.h"
2526
#include "format-util.h"
@@ -243,6 +244,7 @@ static Link *link_free(Link *link) {
243244
strv_free(link->alternative_names);
244245
free(link->kind);
245246
free(link->ssid);
247+
free(link->previous_ssid);
246248
free(link->driver);
247249

248250
unlink_and_free(link->lease_file);
@@ -258,6 +260,8 @@ static Link *link_free(Link *link) {
258260

259261
network_unref(link->network);
260262

263+
sd_event_source_disable_unref(link->carrier_lost_timer);
264+
261265
return mfree(link);
262266
}
263267

@@ -1580,16 +1584,30 @@ int manager_udev_process_link(sd_device_monitor *monitor, sd_device *device, voi
15801584
}
15811585

15821586
static int link_carrier_gained(Link *link) {
1587+
bool force_reconfigure;
15831588
int r;
15841589

15851590
assert(link);
15861591

1592+
r = event_source_disable(link->carrier_lost_timer);
1593+
if (r < 0)
1594+
log_link_warning_errno(link, r, "Failed to disable carrier lost timer, ignoring: %m");
1595+
1596+
/* If the SSID is changed, then the connected wireless network could be changed. So, always
1597+
* reconfigure the link. Which means e.g. the DHCP client will be restarted, and the correct
1598+
* network information will be gained.
1599+
* For non-wireless interfaces, we have no way to detect the connected network change. So,
1600+
* setting force_reconfigure = false. Note, both ssid and previous_ssid should be NULL for
1601+
* non-wireless interfaces, and streq_ptr() returns true. */
1602+
force_reconfigure = !streq_ptr(link->previous_ssid, link->ssid);
1603+
link->previous_ssid = mfree(link->previous_ssid);
1604+
15871605
if (IN_SET(link->state, LINK_STATE_CONFIGURING, LINK_STATE_CONFIGURED)) {
15881606
/* At this stage, both wlan and link information should be up-to-date. Hence,
15891607
* it is not necessary to call RTM_GETLINK, NL80211_CMD_GET_INTERFACE, or
15901608
* NL80211_CMD_GET_STATION commands, and simply call link_reconfigure_impl().
15911609
* Note, link_reconfigure_impl() returns 1 when the link is reconfigured. */
1592-
r = link_reconfigure_impl(link, /* force = */ false);
1610+
r = link_reconfigure_impl(link, force_reconfigure);
15931611
if (r != 0)
15941612
return r;
15951613
}
@@ -1615,6 +1633,45 @@ static int link_carrier_gained(Link *link) {
16151633
return 0;
16161634
}
16171635

1636+
static int link_carrier_lost_impl(Link *link) {
1637+
int r, ret = 0;
1638+
1639+
assert(link);
1640+
1641+
link->previous_ssid = mfree(link->previous_ssid);
1642+
1643+
if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
1644+
return 0;
1645+
1646+
if (!link->network)
1647+
return 0;
1648+
1649+
r = link_stop_engines(link, false);
1650+
if (r < 0)
1651+
ret = r;
1652+
1653+
r = link_drop_config(link);
1654+
if (r < 0 && ret >= 0)
1655+
ret = r;
1656+
1657+
return ret;
1658+
}
1659+
1660+
static int link_carrier_lost_handler(sd_event_source *s, uint64_t usec, void *userdata) {
1661+
Link *link = userdata;
1662+
int r;
1663+
1664+
assert(link);
1665+
1666+
r = link_carrier_lost_impl(link);
1667+
if (r < 0) {
1668+
log_link_warning_errno(link, r, "Failed to process carrier lost event: %m");
1669+
link_enter_failed(link);
1670+
}
1671+
1672+
return 0;
1673+
}
1674+
16181675
static int link_carrier_lost(Link *link) {
16191676
int r;
16201677

@@ -1631,16 +1688,22 @@ static int link_carrier_lost(Link *link) {
16311688
if (!link->network)
16321689
return 0;
16331690

1634-
if (link->network->ignore_carrier_loss)
1691+
if (link->network->ignore_carrier_loss_usec == USEC_INFINITY)
16351692
return 0;
16361693

1637-
r = link_stop_engines(link, false);
1638-
if (r < 0) {
1639-
link_enter_failed(link);
1640-
return r;
1641-
}
1642-
1643-
return link_drop_config(link);
1694+
if (link->network->ignore_carrier_loss_usec == 0)
1695+
return link_carrier_lost_impl(link);
1696+
1697+
return event_reset_time_relative(link->manager->event,
1698+
&link->carrier_lost_timer,
1699+
clock_boottime_or_monotonic(),
1700+
link->network->ignore_carrier_loss_usec,
1701+
0,
1702+
link_carrier_lost_handler,
1703+
link,
1704+
0,
1705+
"link-carrier-loss",
1706+
true);
16441707
}
16451708

16461709
static int link_admin_state_up(Link *link) {

src/network/networkd-link.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,11 +67,14 @@ typedef struct Link {
6767
/* wlan */
6868
enum nl80211_iftype wlan_iftype;
6969
char *ssid;
70+
char *previous_ssid;
7071
struct ether_addr bssid;
7172

7273
unsigned flags;
7374
uint8_t kernel_operstate;
7475

76+
sd_event_source *carrier_lost_timer;
77+
7578
Network *network;
7679

7780
LinkState state;

src/network/networkd-network-gperf.gperf

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,7 @@ Network.ProxyARP, config_parse_tristate,
135135
Network.IPv6ProxyNDPAddress, config_parse_ipv6_proxy_ndp_address, 0, 0
136136
Network.BindCarrier, config_parse_strv, 0, offsetof(Network, bind_carrier)
137137
Network.ConfigureWithoutCarrier, config_parse_bool, 0, offsetof(Network, configure_without_carrier)
138-
Network.IgnoreCarrierLoss, config_parse_tristate, 0, offsetof(Network, ignore_carrier_loss)
138+
Network.IgnoreCarrierLoss, config_parse_ignore_carrier_loss, 0, 0
139139
Network.KeepConfiguration, config_parse_keep_configuration, 0, offsetof(Network, keep_configuration)
140140
Network.IPv6SendRA, config_parse_router_prefix_delegation, 0, offsetof(Network, router_prefix_delegation)
141141
Network.DHCPv6PrefixDelegation, config_parse_tristate, 0, offsetof(Network, dhcp6_pd)

src/network/networkd-network.c

Lines changed: 54 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -271,14 +271,17 @@ int network_verify(Network *network) {
271271
network->activation_policy = ACTIVATION_POLICY_UP;
272272

273273
if (network->activation_policy == ACTIVATION_POLICY_ALWAYS_UP) {
274-
if (network->ignore_carrier_loss == false)
275-
log_warning("%s: IgnoreCarrierLoss=false conflicts with ActivationPolicy=always-up. "
276-
"Setting IgnoreCarrierLoss=true.", network->filename);
277-
network->ignore_carrier_loss = true;
274+
if (network->ignore_carrier_loss_set && network->ignore_carrier_loss_usec < USEC_INFINITY)
275+
log_warning("%s: IgnoreCarrierLoss=no or finite timespan conflicts with ActivationPolicy=always-up. "
276+
"Setting IgnoreCarrierLoss=yes.", network->filename);
277+
network->ignore_carrier_loss_set = true;
278+
network->ignore_carrier_loss_usec = USEC_INFINITY;
278279
}
279280

280-
if (network->ignore_carrier_loss < 0)
281-
network->ignore_carrier_loss = network->configure_without_carrier;
281+
if (!network->ignore_carrier_loss_set) {
282+
network->ignore_carrier_loss_set = true;
283+
network->ignore_carrier_loss_usec = network->configure_without_carrier ? USEC_INFINITY : 0;
284+
}
282285

283286
if (IN_SET(network->activation_policy, ACTIVATION_POLICY_DOWN, ACTIVATION_POLICY_ALWAYS_DOWN, ACTIVATION_POLICY_MANUAL)) {
284287
if (network->required_for_online < 0 ||
@@ -379,7 +382,6 @@ int network_load_one(Manager *manager, OrderedHashmap **networks, const char *fi
379382
.allmulticast = -1,
380383
.promiscuous = -1,
381384

382-
.ignore_carrier_loss = -1,
383385
.keep_configuration = _KEEP_CONFIGURATION_INVALID,
384386

385387
.dhcp_duid.type = _DUID_TYPE_INVALID,
@@ -1279,6 +1281,51 @@ int config_parse_link_group(
12791281
return 0;
12801282
}
12811283

1284+
int config_parse_ignore_carrier_loss(
1285+
const char *unit,
1286+
const char *filename,
1287+
unsigned line,
1288+
const char *section,
1289+
unsigned section_line,
1290+
const char *lvalue,
1291+
int ltype,
1292+
const char *rvalue,
1293+
void *data,
1294+
void *userdata) {
1295+
1296+
Network *network = userdata;
1297+
usec_t usec;
1298+
int r;
1299+
1300+
assert(filename);
1301+
assert(lvalue);
1302+
assert(rvalue);
1303+
assert(network);
1304+
1305+
if (isempty(rvalue)) {
1306+
network->ignore_carrier_loss_set = false;
1307+
return 0;
1308+
}
1309+
1310+
r = parse_boolean(rvalue);
1311+
if (r >= 0) {
1312+
network->ignore_carrier_loss_set = true;
1313+
network->ignore_carrier_loss_usec = r > 0 ? USEC_INFINITY : 0;
1314+
return 0;
1315+
}
1316+
1317+
r = parse_sec(rvalue, &usec);
1318+
if (r < 0) {
1319+
log_syntax(unit, LOG_WARNING, filename, line, r,
1320+
"Failed to parse %s=, ignoring assignment: %s", lvalue, rvalue);
1321+
return 0;
1322+
}
1323+
1324+
network->ignore_carrier_loss_set = true;
1325+
network->ignore_carrier_loss_usec = usec;
1326+
return 0;
1327+
}
1328+
12821329
DEFINE_CONFIG_PARSE_ENUM(config_parse_required_family_for_online, link_required_address_family, AddressFamily,
12831330
"Failed to parse RequiredFamilyForOnline= setting");
12841331

src/network/networkd-network.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,8 @@ struct Network {
110110

111111
/* misc settings */
112112
bool configure_without_carrier;
113-
int ignore_carrier_loss;
113+
bool ignore_carrier_loss_set;
114+
usec_t ignore_carrier_loss_usec; /* timespan */
114115
KeepConfiguration keep_configuration;
115116
char **bind_carrier;
116117
bool default_route_on_device;
@@ -384,6 +385,7 @@ CONFIG_PARSER_PROTOTYPE(config_parse_keep_configuration);
384385
CONFIG_PARSER_PROTOTYPE(config_parse_ipv6_link_local_address_gen_mode);
385386
CONFIG_PARSER_PROTOTYPE(config_parse_activation_policy);
386387
CONFIG_PARSER_PROTOTYPE(config_parse_link_group);
388+
CONFIG_PARSER_PROTOTYPE(config_parse_ignore_carrier_loss);
387389

388390
const struct ConfigPerfItem* network_network_gperf_lookup(const char *key, GPERF_LEN_TYPE length);
389391

src/network/networkd-wifi.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -273,7 +273,7 @@ int manager_genl_process_nl80211_mlme(sd_netlink *genl, sd_netlink_message *mess
273273
strna(nl80211_cmd_to_string(cmd)), cmd);
274274

275275
link->bssid = ETHER_ADDR_NULL;
276-
link->ssid = mfree(link->ssid);
276+
free_and_replace(link->previous_ssid, link->ssid);
277277
break;
278278

279279
default:

0 commit comments

Comments
 (0)
X Tutup