summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--man/networkctl.xml6
-rw-r--r--man/systemd-networkd-wait-online.service.xml16
-rw-r--r--man/systemd.network.xml9
-rw-r--r--src/libsystemd/sd-network/network-util.c47
-rw-r--r--src/libsystemd/sd-network/network-util.h11
-rw-r--r--src/network/networkd-link.c10
-rw-r--r--src/network/networkd-network.c14
-rw-r--r--src/network/networkd-network.h2
-rw-r--r--src/network/wait-online/link.c13
-rw-r--r--src/network/wait-online/link.h2
-rw-r--r--src/network/wait-online/manager.c32
-rw-r--r--src/network/wait-online/manager.h4
-rw-r--r--src/network/wait-online/wait-online.c46
13 files changed, 148 insertions, 64 deletions
diff --git a/man/networkctl.xml b/man/networkctl.xml
index e34778ac21..52876f3776 100644
--- a/man/networkctl.xml
+++ b/man/networkctl.xml
@@ -70,6 +70,12 @@
<para>The operational status is one of the following:
<variablelist>
<varlistentry>
+ <term>missing</term>
+ <listitem>
+ <para>the device is missing</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
<term>off</term>
<listitem>
<para>the device is powered down</para>
diff --git a/man/systemd-networkd-wait-online.service.xml b/man/systemd-networkd-wait-online.service.xml
index 96fcb5fb48..e2f1eb0e83 100644
--- a/man/systemd-networkd-wait-online.service.xml
+++ b/man/systemd-networkd-wait-online.service.xml
@@ -47,16 +47,16 @@
<variablelist>
<varlistentry>
- <term><option>-i</option> <replaceable>INTERFACE</replaceable><optional>:<replaceable>OPERSTATE</replaceable></optional></term>
- <term><option>--interface=</option><replaceable>INTERFACE</replaceable><optional>:<replaceable>OPERSTATE</replaceable></optional></term>
+ <term><option>-i</option> <replaceable>INTERFACE</replaceable><optional>:<replaceable>MIN_OPERSTATE</replaceable><optional>:<replaceable>MAX_OPERSTATE</replaceable></optional></optional></term>
+ <term><option>--interface=</option><replaceable>INTERFACE</replaceable><optional>:<replaceable>MIN_OPERSTATE</replaceable><optional>:<replaceable>MAX_OPERSTATE</replaceable></optional></optional></term>
<listitem><para>Network interface to wait for before deciding if the system is online. This
is useful when a system has several interfaces which will be configured, but a particular
one is necessary to access some network resources. When used, all other interfaces are ignored.
This option may be used more than once to wait for multiple network interfaces. When this
option is specified multiple times, then <command>systemd-networkd-wait-online</command> waits
- for all specified interfaces to be online. Optionally, required minimum operational state can be
- specified after a colon <literal>:</literal>. Please see
+ for all specified interfaces to be online. Optionally, required minimum and maximum operational
+ states can be specified after a colon <literal>:</literal>. Please see
<citerefentry><refentrytitle>networkctl</refentrytitle><manvolnum>1</manvolnum></citerefentry>
for possible operational states. If the operational state is not specified here, then
the value from <varname>RequiredForOnline=</varname> in the corresponding
@@ -74,11 +74,11 @@
</varlistentry>
<varlistentry>
- <term><option>-o</option> <replaceable>OPERSTATE</replaceable></term>
- <term><option>--operational-state=</option><replaceable>OPERSTATE</replaceable></term>
+ <term><option>-o</option> <replaceable>MIN_OPERSTATE</replaceable><optional>:<replaceable>MAX_OPERSTATE</replaceable></optional></term>
+ <term><option>--operational-state=</option><replaceable>MIN_OPERSTATE</replaceable><optional>:<replaceable>MAX_OPERSTATE</replaceable></optional></term>
- <listitem><para>Takes an operational state. Please see
- <citerefentry><refentrytitle>networkctl</refentrytitle><manvolnum>1</manvolnum></citerefentry>
+ <listitem><para>Takes a minimum operational state and an optional maximum operational state.
+ Please see <citerefentry><refentrytitle>networkctl</refentrytitle><manvolnum>1</manvolnum></citerefentry>
for possible operational states. If set, the specified value overrides
<varname>RequiredForOnline=</varname> settings in <filename>.network</filename> files.
But this does not override operational states specified in <option>--interface=</option> option.
diff --git a/man/systemd.network.xml b/man/systemd.network.xml
index 9e0bf69a35..87fd83c067 100644
--- a/man/systemd.network.xml
+++ b/man/systemd.network.xml
@@ -206,13 +206,14 @@
<varlistentry>
<term><varname>RequiredForOnline=</varname></term>
<listitem>
- <para>Takes a boolean or operational state. Please see
- <citerefentry><refentrytitle>networkctl</refentrytitle><manvolnum>1</manvolnum></citerefentry>
+ <para>Takes a boolean or a minimum operational state and an optional maximum operational state.
+ Please see <citerefentry><refentrytitle>networkctl</refentrytitle><manvolnum>1</manvolnum></citerefentry>
for possible operational states. When <literal>yes</literal>, the network is deemed required when
determining whether the system is online when running
<command>systemd-networkd-wait-online</command>. When <literal>no</literal>, the network is ignored
- when checking for online state. When an operational state is set, <literal>yes</literal> is implied,
- and this controls the operational state required for the network interface to be considered online.
+ when checking for online state. When a minimum operational state and an optional maximum operational
+ state are set, <literal>yes</literal> is implied, and this controls the minimum and maximum
+ operational state required for the network interface to be considered online.
Defaults to <literal>yes</literal>.</para>
<para>The network will be brought up normally in all cases, but in
diff --git a/src/libsystemd/sd-network/network-util.c b/src/libsystemd/sd-network/network-util.c
index 08ed942638..0addabe10a 100644
--- a/src/libsystemd/sd-network/network-util.c
+++ b/src/libsystemd/sd-network/network-util.c
@@ -26,6 +26,7 @@ bool network_is_online(void) {
}
static const char* const link_operstate_table[_LINK_OPERSTATE_MAX] = {
+ [LINK_OPERSTATE_MISSING] = "missing",
[LINK_OPERSTATE_OFF] = "off",
[LINK_OPERSTATE_NO_CARRIER] = "no-carrier",
[LINK_OPERSTATE_DORMANT] = "dormant",
@@ -56,3 +57,49 @@ static const char* const link_address_state_table[_LINK_ADDRESS_STATE_MAX] = {
};
DEFINE_STRING_TABLE_LOOKUP(link_address_state, LinkAddressState);
+
+int parse_operational_state_range(const char *str, LinkOperationalStateRange *out) {
+ LinkOperationalStateRange range = { _LINK_OPERSTATE_INVALID, _LINK_OPERSTATE_INVALID };
+ _cleanup_free_ const char *min = NULL;
+ const char *p;
+
+ assert(str);
+ assert(out);
+
+ p = strchr(str, ':');
+ if (p) {
+ min = strndup(str, p - str);
+
+ if (!isempty(p + 1)) {
+ range.max = link_operstate_from_string(p + 1);
+ if (range.max < 0)
+ return -EINVAL;
+ }
+ } else
+ min = strdup(str);
+
+ if (!min)
+ return -ENOMEM;
+
+ if (!isempty(min)) {
+ range.min = link_operstate_from_string(min);
+ if (range.min < 0)
+ return -EINVAL;
+ }
+
+ /* Fail on empty strings. */
+ if (range.min == _LINK_OPERSTATE_INVALID && range.max == _LINK_OPERSTATE_INVALID)
+ return -EINVAL;
+
+ if (range.min == _LINK_OPERSTATE_INVALID)
+ range.min = LINK_OPERSTATE_MISSING;
+ if (range.max == _LINK_OPERSTATE_INVALID)
+ range.max = LINK_OPERSTATE_ROUTABLE;
+
+ if (range.min > range.max)
+ return -EINVAL;
+
+ *out = range;
+
+ return 0;
+}
diff --git a/src/libsystemd/sd-network/network-util.h b/src/libsystemd/sd-network/network-util.h
index a19435393d..425d192f64 100644
--- a/src/libsystemd/sd-network/network-util.h
+++ b/src/libsystemd/sd-network/network-util.h
@@ -8,6 +8,7 @@
bool network_is_online(void);
typedef enum LinkOperationalState {
+ LINK_OPERSTATE_MISSING,
LINK_OPERSTATE_OFF,
LINK_OPERSTATE_NO_CARRIER,
LINK_OPERSTATE_DORMANT,
@@ -47,3 +48,13 @@ LinkCarrierState link_carrier_state_from_string(const char *s) _pure_;
const char* link_address_state_to_string(LinkAddressState s) _const_;
LinkAddressState link_address_state_from_string(const char *s) _pure_;
+
+typedef struct LinkOperationalStateRange {
+ LinkOperationalState min;
+ LinkOperationalState max;
+} LinkOperationalStateRange;
+
+#define LINK_OPERSTATE_RANGE_DEFAULT (LinkOperationalStateRange) { LINK_OPERSTATE_DEGRADED, \
+ LINK_OPERSTATE_ROUTABLE }
+
+int parse_operational_state_range(const char *str, LinkOperationalStateRange *out);
diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c
index cfecf76a79..7f37a8648b 100644
--- a/src/network/networkd-link.c
+++ b/src/network/networkd-link.c
@@ -3957,8 +3957,14 @@ int link_save(Link *link) {
fprintf(f, "REQUIRED_FOR_ONLINE=%s\n",
yes_no(link->network->required_for_online));
- fprintf(f, "REQUIRED_OPER_STATE_FOR_ONLINE=%s\n",
- strempty(link_operstate_to_string(link->network->required_operstate_for_online)));
+ fprintf(f, "REQUIRED_OPER_STATE_FOR_ONLINE=%s",
+ strempty(link_operstate_to_string(link->network->required_operstate_for_online.min)));
+
+ if (link->network->required_operstate_for_online.max != LINK_OPERSTATE_RANGE_DEFAULT.max)
+ fprintf(f, ":%s",
+ strempty(link_operstate_to_string(link->network->required_operstate_for_online.max)));
+
+ fprintf(f, "\n");
if (link->dhcp6_client) {
r = sd_dhcp6_client_get_lease(link->dhcp6_client, &dhcp6_lease);
diff --git a/src/network/networkd-network.c b/src/network/networkd-network.c
index e7ff9ae54f..ff09e3daad 100644
--- a/src/network/networkd-network.c
+++ b/src/network/networkd-network.c
@@ -375,7 +375,7 @@ int network_load_one(Manager *manager, OrderedHashmap **networks, const char *fi
.n_ref = 1,
.required_for_online = true,
- .required_operstate_for_online = LINK_OPERSTATE_DEGRADED,
+ .required_operstate_for_online = LINK_OPERSTATE_RANGE_DEFAULT,
.dhcp = ADDRESS_FAMILY_NO,
.dhcp_critical = -1,
.dhcp_use_ntp = true,
@@ -1306,18 +1306,18 @@ int config_parse_required_for_online(
void *userdata) {
Network *network = data;
- LinkOperationalState s;
+ LinkOperationalStateRange range;
bool required = true;
int r;
if (isempty(rvalue)) {
network->required_for_online = true;
- network->required_operstate_for_online = LINK_OPERSTATE_DEGRADED;
+ network->required_operstate_for_online = LINK_OPERSTATE_RANGE_DEFAULT;
return 0;
}
- s = link_operstate_from_string(rvalue);
- if (s < 0) {
+ r = parse_operational_state_range(rvalue, &range);
+ if (r < 0) {
r = parse_boolean(rvalue);
if (r < 0) {
log_syntax(unit, LOG_ERR, filename, line, r,
@@ -1327,11 +1327,11 @@ int config_parse_required_for_online(
}
required = r;
- s = LINK_OPERSTATE_DEGRADED;
+ range = LINK_OPERSTATE_RANGE_DEFAULT;
}
network->required_for_online = required;
- network->required_operstate_for_online = s;
+ network->required_operstate_for_online = range;
return 0;
}
diff --git a/src/network/networkd-network.h b/src/network/networkd-network.h
index 1cfbd0b6b6..c1f37e707a 100644
--- a/src/network/networkd-network.h
+++ b/src/network/networkd-network.h
@@ -237,7 +237,7 @@ struct Network {
bool iaid_set;
bool required_for_online; /* Is this network required to be considered online? */
- LinkOperationalState required_operstate_for_online;
+ LinkOperationalStateRange required_operstate_for_online;
LLDPMode lldp_mode; /* LLDP reception */
LLDPEmit lldp_emit; /* LLDP transmission */
diff --git a/src/network/wait-online/link.c b/src/network/wait-online/link.c
index a13373f7d7..69b0057707 100644
--- a/src/network/wait-online/link.c
+++ b/src/network/wait-online/link.c
@@ -36,7 +36,7 @@ int link_new(Manager *m, Link **ret, int ifindex, const char *ifname) {
.manager = m,
.ifname = TAKE_PTR(n),
.ifindex = ifindex,
- .required_operstate = LINK_OPERSTATE_DEGRADED,
+ .required_operstate = LINK_OPERSTATE_RANGE_DEFAULT,
};
r = hashmap_put(m->links_by_name, l->ifname, l);
@@ -105,7 +105,6 @@ int link_update_rtnl(Link *l, sd_netlink_message *m) {
int link_update_monitor(Link *l) {
_cleanup_free_ char *operstate = NULL, *required_operstate = NULL, *state = NULL;
- LinkOperationalState s;
int r, ret = 0;
assert(l);
@@ -121,19 +120,21 @@ int link_update_monitor(Link *l) {
r = sd_network_link_get_required_operstate_for_online(l->ifindex, &required_operstate);
if (r < 0)
ret = log_link_debug_errno(l, r, "Failed to get required operational state, ignoring: %m");
+ else if (isempty(required_operstate))
+ l->required_operstate = LINK_OPERSTATE_RANGE_DEFAULT;
else {
- s = link_operstate_from_string(required_operstate);
- if (s < 0)
+ r = parse_operational_state_range(required_operstate, &l->required_operstate);
+ if (r < 0)
ret = log_link_debug_errno(l, SYNTHETIC_ERRNO(EINVAL),
"Failed to parse required operational state, ignoring: %m");
- else
- l->required_operstate = s;
}
r = sd_network_link_get_operational_state(l->ifindex, &operstate);
if (r < 0)
ret = log_link_debug_errno(l, r, "Failed to get operational state, ignoring: %m");
else {
+ LinkOperationalState s;
+
s = link_operstate_from_string(operstate);
if (s < 0)
ret = log_link_debug_errno(l, SYNTHETIC_ERRNO(EINVAL),
diff --git a/src/network/wait-online/link.h b/src/network/wait-online/link.h
index d58129dfe8..73d9f9cc3e 100644
--- a/src/network/wait-online/link.h
+++ b/src/network/wait-online/link.h
@@ -17,7 +17,7 @@ struct Link {
unsigned flags;
bool required_for_online;
- LinkOperationalState required_operstate;
+ LinkOperationalStateRange required_operstate;
LinkOperationalState operational_state;
char *state;
};
diff --git a/src/network/wait-online/manager.c b/src/network/wait-online/manager.c
index 0e6a284da2..40a29f19aa 100644
--- a/src/network/wait-online/manager.c
+++ b/src/network/wait-online/manager.c
@@ -32,7 +32,7 @@ static bool manager_ignore_link(Manager *m, Link *link) {
return strv_fnmatch(m->ignore, link->ifname);
}
-static int manager_link_is_online(Manager *m, Link *l, LinkOperationalState s) {
+static int manager_link_is_online(Manager *m, Link *l, LinkOperationalStateRange s) {
/* This returns the following:
* -EAGAIN: not processed by udev or networkd
* 0: operstate is not enough
@@ -46,13 +46,18 @@ static int manager_link_is_online(Manager *m, Link *l, LinkOperationalState s) {
return log_link_debug_errno(l, SYNTHETIC_ERRNO(EAGAIN),
"link is being processed by networkd");
- if (s < 0)
- s = m->required_operstate >= 0 ? m->required_operstate : l->required_operstate;
+ if (s.min < 0)
+ s.min = m->required_operstate.min >= 0 ? m->required_operstate.min
+ : l->required_operstate.min;
- if (l->operational_state < s) {
- log_link_debug(l, "Operational state '%s' is below '%s'",
+ if (s.max < 0)
+ s.max = m->required_operstate.max >= 0 ? m->required_operstate.max
+ : l->required_operstate.max;
+
+ if (l->operational_state < s.min || l->operational_state > s.max) {
+ log_link_debug(l, "Operational state '%s' is not in range ['%s':'%s']",
link_operstate_to_string(l->operational_state),
- link_operstate_to_string(s));
+ link_operstate_to_string(s.min), link_operstate_to_string(s.max));
return 0;
}
@@ -70,9 +75,14 @@ bool manager_configured(Manager *m) {
if (!hashmap_isempty(m->interfaces)) {
/* wait for all the links given on the command line to appear */
HASHMAP_FOREACH_KEY(p, ifname, m->interfaces, i) {
- LinkOperationalState s = PTR_TO_INT(p);
+ LinkOperationalStateRange *range = p;
l = hashmap_get(m->links_by_name, ifname);
+ if (!l && range->min == LINK_OPERSTATE_MISSING) {
+ one_ready = true;
+ continue;
+ }
+
if (!l) {
log_debug("still waiting for %s", ifname);
if (!m->any)
@@ -80,7 +90,7 @@ bool manager_configured(Manager *m) {
continue;
}
- if (manager_link_is_online(m, l, s) <= 0) {
+ if (manager_link_is_online(m, l, *range) <= 0) {
if (!m->any)
return false;
continue;
@@ -102,7 +112,9 @@ bool manager_configured(Manager *m) {
continue;
}
- r = manager_link_is_online(m, l, _LINK_OPERSTATE_INVALID);
+ r = manager_link_is_online(m, l,
+ (LinkOperationalStateRange) { _LINK_OPERSTATE_INVALID,
+ _LINK_OPERSTATE_INVALID });
if (r < 0 && !m->any)
return false;
if (r > 0)
@@ -289,7 +301,7 @@ static int manager_network_monitor_listen(Manager *m) {
}
int manager_new(Manager **ret, Hashmap *interfaces, char **ignore,
- LinkOperationalState required_operstate,
+ LinkOperationalStateRange required_operstate,
bool any, usec_t timeout) {
_cleanup_(manager_freep) Manager *m = NULL;
int r;
diff --git a/src/network/wait-online/manager.h b/src/network/wait-online/manager.h
index dd7d847dd3..7398783df7 100644
--- a/src/network/wait-online/manager.h
+++ b/src/network/wait-online/manager.h
@@ -20,7 +20,7 @@ struct Manager {
Hashmap *interfaces;
char **ignore;
- LinkOperationalState required_operstate;
+ LinkOperationalStateRange required_operstate;
bool any;
sd_netlink *rtnl;
@@ -34,7 +34,7 @@ struct Manager {
void manager_free(Manager *m);
int manager_new(Manager **ret, Hashmap *interfaces, char **ignore,
- LinkOperationalState required_operstate,
+ LinkOperationalStateRange required_operstate,
bool any, usec_t timeout);
DEFINE_TRIVIAL_CLEANUP_FUNC(Manager*, manager_free);
diff --git a/src/network/wait-online/wait-online.c b/src/network/wait-online/wait-online.c
index 4ce2ac31b2..17ed5d38cf 100644
--- a/src/network/wait-online/wait-online.c
+++ b/src/network/wait-online/wait-online.c
@@ -18,10 +18,10 @@ static bool arg_quiet = false;
static usec_t arg_timeout = 120 * USEC_PER_SEC;
static Hashmap *arg_interfaces = NULL;
static char **arg_ignore = NULL;
-static LinkOperationalState arg_required_operstate = _LINK_OPERSTATE_INVALID;
+static LinkOperationalStateRange arg_required_operstate = { _LINK_OPERSTATE_INVALID, _LINK_OPERSTATE_INVALID };
static bool arg_any = false;
-STATIC_DESTRUCTOR_REGISTER(arg_interfaces, hashmap_free_free_keyp);
+STATIC_DESTRUCTOR_REGISTER(arg_interfaces, hashmap_free_free_freep);
STATIC_DESTRUCTOR_REGISTER(arg_ignore, strv_freep);
static int help(void) {
@@ -37,10 +37,10 @@ static int help(void) {
" -h --help Show this help\n"
" --version Print version string\n"
" -q --quiet Do not show status information\n"
- " -i --interface=INTERFACE[:OPERSTATE]\n"
+ " -i --interface=INTERFACE[:MIN_OPERSTATE[:MAX_OPERSTATE]]\n"
" Block until at least these interfaces have appeared\n"
" --ignore=INTERFACE Don't take these interfaces into account\n"
- " -o --operational-state=OPERSTATE\n"
+ " -o --operational-state=MIN_OPERSTATE[:MAX_OPERSTATE]\n"
" Required operational state\n"
" --any Wait until at least one of the interfaces is online\n"
" --timeout=SECS Maximum time to wait for network connectivity\n"
@@ -52,28 +52,28 @@ static int help(void) {
return 0;
}
-static int parse_interface_with_operstate(const char *str) {
+static int parse_interface_with_operstate_range(const char *str) {
_cleanup_free_ char *ifname = NULL;
- LinkOperationalState s;
+ _cleanup_free_ LinkOperationalStateRange *range;
const char *p;
int r;
assert(str);
+ range = new(LinkOperationalStateRange, 1);
+ if (!range)
+ return log_oom();
+
p = strchr(str, ':');
if (p) {
- if (isempty(p + 1))
- return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
- "Operational state is empty.");
-
- s = link_operstate_from_string(p + 1);
- if (s < 0)
- return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
- "Invalid operational state '%s'", p + 1);
+ r = parse_operational_state_range(p + 1, range);
+ if (r < 0)
+ log_error_errno(r, "Invalid operational state range '%s'", p + 1);
ifname = strndup(optarg, p - optarg);
} else {
- s = _LINK_OPERSTATE_INVALID;
+ range->min = _LINK_OPERSTATE_INVALID;
+ range->max = _LINK_OPERSTATE_INVALID;
ifname = strdup(str);
}
if (!ifname)
@@ -87,7 +87,7 @@ static int parse_interface_with_operstate(const char *str) {
if (r < 0)
return log_oom();
- r = hashmap_put(arg_interfaces, ifname, INT_TO_PTR(s));
+ r = hashmap_put(arg_interfaces, ifname, TAKE_PTR(range));
if (r < 0)
return log_error_errno(r, "Failed to store interface name: %m");
if (r == 0)
@@ -140,7 +140,7 @@ static int parse_argv(int argc, char *argv[]) {
return version();
case 'i':
- r = parse_interface_with_operstate(optarg);
+ r = parse_interface_with_operstate_range(optarg);
if (r < 0)
return r;
break;
@@ -152,14 +152,14 @@ static int parse_argv(int argc, char *argv[]) {
break;
case 'o': {
- LinkOperationalState s;
+ LinkOperationalStateRange range;
+
+ r = parse_operational_state_range(optarg, &range);
+ if (r < 0)
+ return log_error_errno(r, "Invalid operational state range '%s'", optarg);
- s = link_operstate_from_string(optarg);
- if (s < 0)
- return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
- "Invalid operational state '%s'", optarg);
+ arg_required_operstate = range;
- arg_required_operstate = s;
break;
}
case ARG_ANY: