summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLetzteInstanz <faust6@inbox.ru>2021-04-11 23:29:11 +0300
committerYu Watanabe <watanabe.yu+github@gmail.com>2021-04-14 08:51:02 +0900
commit8430841b5e2140b01ad3e3db5929f77f3e8cc585 (patch)
tree45267415041fbbe43f41fc33d0912d5310bcbacc
parent86ae2d69a3b07de23f0c4ddb1fa3e5ec8bc85c1b (diff)
downloadsystemd-8430841b5e2140b01ad3e3db5929f77f3e8cc585.tar.gz
network: save IPv4/IPv6 address states into state file
This also introduces RequiredFamilyForOnline= setting to .network file, and IPv4AddressState/IPv6AddressState DBus properties.
-rw-r--r--man/systemd.network.xml12
-rw-r--r--src/libsystemd/sd-network/network-util.c9
-rw-r--r--src/libsystemd/sd-network/network-util.h3
-rw-r--r--src/network/networkd-link-bus.c2
-rw-r--r--src/network/networkd-link.c60
-rw-r--r--src/network/networkd-link.h2
-rw-r--r--src/network/networkd-manager-bus.c2
-rw-r--r--src/network/networkd-manager.h2
-rw-r--r--src/network/networkd-network-gperf.gperf1
-rw-r--r--src/network/networkd-network.c3
-rw-r--r--src/network/networkd-network.h2
-rw-r--r--src/network/networkd-state-file.c52
-rw-r--r--test/fuzz/fuzz-network-parser/directives.network1
-rw-r--r--test/fuzz/fuzz-unit-file/directives-all.service1
14 files changed, 130 insertions, 22 deletions
diff --git a/man/systemd.network.xml b/man/systemd.network.xml
index a49e6011e3..5ab1e9f0a8 100644
--- a/man/systemd.network.xml
+++ b/man/systemd.network.xml
@@ -230,6 +230,18 @@
</listitem>
</varlistentry>
<varlistentry>
+ <term><varname>RequiredFamilyForOnline=</varname></term>
+ <listitem>
+ <para>Specifies an address family. When specified,
+ <command>systemd-networkd-wait-online</command> waits for at least one routable or link-local
+ IP address in the family should be configured on the link. Takes one of
+ <literal>ipv4</literal>, <literal>ipv6</literal>, <literal>both</literal>, or
+ <literal>any</literal>. Defaults to <literal>any</literal>. Note that this will be used only
+ when <varname>RequiredForOnline=</varname> is true, or its minimum operational state is
+ <literal>degraded</literal> or above. Otherwise, it will be ignored.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
<term><varname>ActivationPolicy=</varname></term>
<listitem>
<para>Specifies the policy for <command>systemd-networkd</command> managing the link
diff --git a/src/libsystemd/sd-network/network-util.c b/src/libsystemd/sd-network/network-util.c
index acf7500970..c1d3a9f6a2 100644
--- a/src/libsystemd/sd-network/network-util.c
+++ b/src/libsystemd/sd-network/network-util.c
@@ -56,6 +56,15 @@ static const char* const link_carrier_state_table[_LINK_CARRIER_STATE_MAX] = {
DEFINE_STRING_TABLE_LOOKUP(link_carrier_state, LinkCarrierState);
+static const char* const link_required_address_family_table[_ADDRESS_FAMILY_MAX] = {
+ [ADDRESS_FAMILY_NO] = "any",
+ [ADDRESS_FAMILY_IPV4] = "ipv4",
+ [ADDRESS_FAMILY_IPV6] = "ipv6",
+ [ADDRESS_FAMILY_YES] = "both",
+};
+
+DEFINE_STRING_TABLE_LOOKUP(link_required_address_family, AddressFamily);
+
static const char* const link_address_state_table[_LINK_ADDRESS_STATE_MAX] = {
[LINK_ADDRESS_STATE_OFF] = "off",
[LINK_ADDRESS_STATE_DEGRADED] = "degraded",
diff --git a/src/libsystemd/sd-network/network-util.h b/src/libsystemd/sd-network/network-util.h
index ad8632d012..3bd10c42de 100644
--- a/src/libsystemd/sd-network/network-util.h
+++ b/src/libsystemd/sd-network/network-util.h
@@ -60,6 +60,9 @@ LinkOperationalState link_operstate_from_string(const char *s) _pure_;
const char* link_carrier_state_to_string(LinkCarrierState s) _const_;
LinkCarrierState link_carrier_state_from_string(const char *s) _pure_;
+const char* link_required_address_family_to_string(AddressFamily s) _const_;
+AddressFamily link_required_address_family_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_;
diff --git a/src/network/networkd-link-bus.c b/src/network/networkd-link-bus.c
index 16058c6fcf..a999b05845 100644
--- a/src/network/networkd-link-bus.c
+++ b/src/network/networkd-link-bus.c
@@ -684,6 +684,8 @@ const sd_bus_vtable link_vtable[] = {
SD_BUS_PROPERTY("OperationalState", "s", property_get_operational_state, offsetof(Link, operstate), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_PROPERTY("CarrierState", "s", property_get_carrier_state, offsetof(Link, carrier_state), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_PROPERTY("AddressState", "s", property_get_address_state, offsetof(Link, address_state), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
+ SD_BUS_PROPERTY("IPv4AddressState", "s", property_get_address_state, offsetof(Link, ipv4_address_state), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
+ SD_BUS_PROPERTY("IPv6AddressState", "s", property_get_address_state, offsetof(Link, ipv6_address_state), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_PROPERTY("AdministrativeState", "s", property_get_administrative_state, offsetof(Link, state), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_PROPERTY("BitRates", "(tt)", property_get_bit_rates, 0, 0),
diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c
index 6c08203c54..65a6410a5a 100644
--- a/src/network/networkd-link.c
+++ b/src/network/networkd-link.c
@@ -4,6 +4,7 @@
#include <linux/if.h>
#include <linux/if_arp.h>
#include <linux/if_link.h>
+#include <sys/socket.h>
#include <unistd.h>
#include "alloc-util.h"
@@ -163,12 +164,25 @@ static void link_update_master_operstate(Link *link, NetDev *netdev) {
link_update_operstate(master, true);
}
+static LinkAddressState address_state_from_scope(uint8_t scope) {
+ if (scope < RT_SCOPE_SITE)
+ /* universally accessible addresses found */
+ return LINK_ADDRESS_STATE_ROUTABLE;
+
+ if (scope < RT_SCOPE_HOST)
+ /* only link or site local addresses found */
+ return LINK_ADDRESS_STATE_DEGRADED;
+
+ /* no useful addresses found */
+ return LINK_ADDRESS_STATE_OFF;
+}
+
void link_update_operstate(Link *link, bool also_update_master) {
LinkOperationalState operstate;
LinkCarrierState carrier_state;
- LinkAddressState address_state;
+ LinkAddressState ipv4_address_state, ipv6_address_state, address_state;
_cleanup_strv_free_ char **p = NULL;
- uint8_t scope = RT_SCOPE_NOWHERE;
+ uint8_t ipv4_scope = RT_SCOPE_NOWHERE, ipv6_scope = RT_SCOPE_NOWHERE, scope;
bool changed = false;
Address *address;
@@ -201,8 +215,11 @@ void link_update_operstate(Link *link, bool also_update_master) {
if (!address_is_ready(address))
continue;
- if (address->scope < scope)
- scope = address->scope;
+ if (address->family == AF_INET && address->scope < ipv4_scope)
+ ipv4_scope = address->scope;
+
+ if (address->family == AF_INET6 && address->scope < ipv6_scope)
+ ipv6_scope = address->scope;
}
/* for operstate we also take foreign addresses into account */
@@ -210,19 +227,18 @@ void link_update_operstate(Link *link, bool also_update_master) {
if (!address_is_ready(address))
continue;
- if (address->scope < scope)
- scope = address->scope;
+ if (address->family == AF_INET && address->scope < ipv4_scope)
+ ipv4_scope = address->scope;
+
+ if (address->family == AF_INET6 && address->scope < ipv6_scope)
+ ipv6_scope = address->scope;
}
- if (scope < RT_SCOPE_SITE)
- /* universally accessible addresses found */
- address_state = LINK_ADDRESS_STATE_ROUTABLE;
- else if (scope < RT_SCOPE_HOST)
- /* only link or site local addresses found */
- address_state = LINK_ADDRESS_STATE_DEGRADED;
- else
- /* no useful addresses found */
- address_state = LINK_ADDRESS_STATE_OFF;
+ ipv4_address_state = address_state_from_scope(ipv4_scope);
+ ipv6_address_state = address_state_from_scope(ipv6_scope);
+
+ scope = MIN(ipv4_scope, ipv6_scope);
+ address_state = address_state_from_scope(scope);
/* Mapping of address and carrier state vs operational state
* carrier state
@@ -256,6 +272,20 @@ void link_update_operstate(Link *link, bool also_update_master) {
log_oom();
}
+ if (link->ipv4_address_state != ipv4_address_state) {
+ link->ipv4_address_state = ipv4_address_state;
+ changed = true;
+ if (strv_extend(&p, "IPv4AddressState") < 0)
+ log_oom();
+ }
+
+ if (link->ipv6_address_state != ipv6_address_state) {
+ link->ipv6_address_state = ipv6_address_state;
+ changed = true;
+ if (strv_extend(&p, "IPv6AddressState") < 0)
+ log_oom();
+ }
+
if (link->operstate != operstate) {
link->operstate = operstate;
changed = true;
diff --git a/src/network/networkd-link.h b/src/network/networkd-link.h
index d3353a1c4f..a8bdd971f5 100644
--- a/src/network/networkd-link.h
+++ b/src/network/networkd-link.h
@@ -75,6 +75,8 @@ typedef struct Link {
LinkOperationalState operstate;
LinkCarrierState carrier_state;
LinkAddressState address_state;
+ LinkAddressState ipv4_address_state;
+ LinkAddressState ipv6_address_state;
unsigned address_messages;
unsigned address_remove_messages;
diff --git a/src/network/networkd-manager-bus.c b/src/network/networkd-manager-bus.c
index 138d765414..0acaeb2bed 100644
--- a/src/network/networkd-manager-bus.c
+++ b/src/network/networkd-manager-bus.c
@@ -235,6 +235,8 @@ const sd_bus_vtable manager_vtable[] = {
SD_BUS_PROPERTY("OperationalState", "s", property_get_operational_state, offsetof(Manager, operational_state), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_PROPERTY("CarrierState", "s", property_get_carrier_state, offsetof(Manager, carrier_state), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_PROPERTY("AddressState", "s", property_get_address_state, offsetof(Manager, address_state), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
+ SD_BUS_PROPERTY("IPv4AddressState", "s", property_get_address_state, offsetof(Manager, ipv4_address_state), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
+ SD_BUS_PROPERTY("IPv6AddressState", "s", property_get_address_state, offsetof(Manager, ipv6_address_state), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_METHOD_WITH_ARGS("ListLinks",
SD_BUS_NO_ARGS,
diff --git a/src/network/networkd-manager.h b/src/network/networkd-manager.h
index 7f630fccc7..e78b57b936 100644
--- a/src/network/networkd-manager.h
+++ b/src/network/networkd-manager.h
@@ -39,6 +39,8 @@ struct Manager {
LinkOperationalState operational_state;
LinkCarrierState carrier_state;
LinkAddressState address_state;
+ LinkAddressState ipv4_address_state;
+ LinkAddressState ipv6_address_state;
Hashmap *links;
Hashmap *netdevs;
diff --git a/src/network/networkd-network-gperf.gperf b/src/network/networkd-network-gperf.gperf
index 8ebeec8640..6c37e32453 100644
--- a/src/network/networkd-network-gperf.gperf
+++ b/src/network/networkd-network-gperf.gperf
@@ -67,6 +67,7 @@ Link.Promiscuous, config_parse_tristate,
Link.Unmanaged, config_parse_bool, 0, offsetof(Network, unmanaged)
Link.ActivationPolicy, config_parse_activation_policy, 0, offsetof(Network, activation_policy)
Link.RequiredForOnline, config_parse_required_for_online, 0, 0
+Link.RequiredFamilyForOnline, config_parse_required_family_for_online, 0, offsetof(Network, required_family_for_online)
SR-IOV.VirtualFunction, config_parse_sr_iov_uint32, 0, 0
SR-IOV.VLANId, config_parse_sr_iov_uint32, 0, 0
SR-IOV.QualityOfService, config_parse_sr_iov_uint32, 0, 0
diff --git a/src/network/networkd-network.c b/src/network/networkd-network.c
index 8ae2315f1b..7f086ceae2 100644
--- a/src/network/networkd-network.c
+++ b/src/network/networkd-network.c
@@ -1196,6 +1196,9 @@ int config_parse_required_for_online(
return 0;
}
+DEFINE_CONFIG_PARSE_ENUM(config_parse_required_family_for_online, link_required_address_family, AddressFamily,
+ "Failed to parse RequiredFamilyForOnline= setting");
+
DEFINE_CONFIG_PARSE_ENUM(config_parse_keep_configuration, keep_configuration, KeepConfiguration,
"Failed to parse KeepConfiguration= setting");
diff --git a/src/network/networkd-network.h b/src/network/networkd-network.h
index 44b1d0205f..df77b42619 100644
--- a/src/network/networkd-network.h
+++ b/src/network/networkd-network.h
@@ -104,6 +104,7 @@ struct Network {
bool unmanaged;
bool required_for_online; /* Is this network required to be considered online? */
LinkOperationalStateRange required_operstate_for_online;
+ AddressFamily required_family_for_online;
ActivationPolicy activation_policy;
/* misc settings */
@@ -348,6 +349,7 @@ CONFIG_PARSER_PROTOTYPE(config_parse_timezone);
CONFIG_PARSER_PROTOTYPE(config_parse_dnssec_negative_trust_anchors);
CONFIG_PARSER_PROTOTYPE(config_parse_ntp);
CONFIG_PARSER_PROTOTYPE(config_parse_required_for_online);
+CONFIG_PARSER_PROTOTYPE(config_parse_required_family_for_online);
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);
diff --git a/src/network/networkd-state-file.c b/src/network/networkd-state-file.c
index 96232018dd..34613697d6 100644
--- a/src/network/networkd-state-file.c
+++ b/src/network/networkd-state-file.c
@@ -105,10 +105,11 @@ static int ordered_set_put_in4_addrv(
int manager_save(Manager *m) {
_cleanup_ordered_set_free_ OrderedSet *dns = NULL, *ntp = NULL, *sip = NULL, *search_domains = NULL, *route_domains = NULL;
- const char *operstate_str, *carrier_state_str, *address_state_str;
+ const char *operstate_str, *carrier_state_str, *address_state_str, *ipv4_address_state_str, *ipv6_address_state_str;
LinkOperationalState operstate = LINK_OPERSTATE_OFF;
LinkCarrierState carrier_state = LINK_CARRIER_STATE_OFF;
- LinkAddressState address_state = LINK_ADDRESS_STATE_OFF;
+ LinkAddressState ipv4_address_state = LINK_ADDRESS_STATE_OFF, ipv6_address_state = LINK_ADDRESS_STATE_OFF,
+ address_state = LINK_ADDRESS_STATE_OFF;
_cleanup_(unlink_and_freep) char *temp_path = NULL;
_cleanup_strv_free_ char **p = NULL;
_cleanup_fclose_ FILE *f = NULL;
@@ -133,6 +134,12 @@ int manager_save(Manager *m) {
if (link->address_state > address_state)
address_state = link->address_state;
+ if (link->ipv4_address_state > ipv4_address_state)
+ ipv4_address_state = link->ipv4_address_state;
+
+ if (link->ipv6_address_state > ipv6_address_state)
+ ipv6_address_state = link->ipv6_address_state;
+
if (!link->network)
continue;
@@ -226,6 +233,12 @@ int manager_save(Manager *m) {
address_state_str = link_address_state_to_string(address_state);
assert(address_state_str);
+ ipv4_address_state_str = link_address_state_to_string(ipv4_address_state);
+ assert(ipv4_address_state_str);
+
+ ipv6_address_state_str = link_address_state_to_string(ipv6_address_state);
+ assert(ipv6_address_state_str);
+
r = fopen_temporary(m->state_file, &f, &temp_path);
if (r < 0)
return r;
@@ -236,8 +249,10 @@ int manager_save(Manager *m) {
"# This is private data. Do not parse.\n"
"OPER_STATE=%s\n"
"CARRIER_STATE=%s\n"
- "ADDRESS_STATE=%s\n",
- operstate_str, carrier_state_str, address_state_str);
+ "ADDRESS_STATE=%s\n"
+ "IPV4_ADDRESS_STATE=%s\n"
+ "IPV6_ADDRESS_STATE=%s\n",
+ operstate_str, carrier_state_str, address_state_str, ipv4_address_state_str, ipv6_address_state_str);
ordered_set_print(f, "DNS=", dns);
ordered_set_print(f, "NTP=", ntp);
@@ -273,6 +288,18 @@ int manager_save(Manager *m) {
log_oom();
}
+ if (m->ipv4_address_state != ipv4_address_state) {
+ m->ipv4_address_state = ipv4_address_state;
+ if (strv_extend(&p, "IPv4AddressState") < 0)
+ log_oom();
+ }
+
+ if (m->ipv6_address_state != ipv6_address_state) {
+ m->ipv6_address_state = ipv6_address_state;
+ if (strv_extend(&p, "IPv6AddressState") < 0)
+ log_oom();
+ }
+
if (p) {
r = manager_send_changed_strv(m, p);
if (r < 0)
@@ -376,7 +403,7 @@ static void serialize_addresses(
}
int link_save(Link *link) {
- const char *admin_state, *oper_state, *carrier_state, *address_state;
+ const char *admin_state, *oper_state, *carrier_state, *address_state, *ipv4_address_state, *ipv6_address_state;
_cleanup_(unlink_and_freep) char *temp_path = NULL;
_cleanup_fclose_ FILE *f = NULL;
int r;
@@ -403,6 +430,12 @@ int link_save(Link *link) {
address_state = link_address_state_to_string(link->address_state);
assert(address_state);
+ ipv4_address_state = link_address_state_to_string(link->ipv4_address_state);
+ assert(ipv4_address_state);
+
+ ipv6_address_state = link_address_state_to_string(link->ipv6_address_state);
+ assert(ipv6_address_state);
+
r = fopen_temporary(link->state_file, &f, &temp_path);
if (r < 0)
return r;
@@ -414,8 +447,10 @@ int link_save(Link *link) {
"ADMIN_STATE=%s\n"
"OPER_STATE=%s\n"
"CARRIER_STATE=%s\n"
- "ADDRESS_STATE=%s\n",
- admin_state, oper_state, carrier_state, address_state);
+ "ADDRESS_STATE=%s\n"
+ "IPV4_ADDRESS_STATE=%s\n"
+ "IPV6_ADDRESS_STATE=%s\n",
+ admin_state, oper_state, carrier_state, address_state, ipv4_address_state, ipv6_address_state);
if (link->network) {
char **dhcp6_domains = NULL, **dhcp_domains = NULL;
@@ -431,6 +466,9 @@ int link_save(Link *link) {
st.max != LINK_OPERSTATE_RANGE_DEFAULT.max ? ":" : "",
st.max != LINK_OPERSTATE_RANGE_DEFAULT.max ? strempty(link_operstate_to_string(st.max)) : "");
+ fprintf(f, "REQUIRED_FAMILY_FOR_ONLINE=%s\n",
+ link_required_address_family_to_string(link->network->required_family_for_online));
+
fprintf(f, "ACTIVATION_POLICY=%s\n",
activation_policy_to_string(link->network->activation_policy));
diff --git a/test/fuzz/fuzz-network-parser/directives.network b/test/fuzz/fuzz-network-parser/directives.network
index 399eeafa98..016be501ed 100644
--- a/test/fuzz/fuzz-network-parser/directives.network
+++ b/test/fuzz/fuzz-network-parser/directives.network
@@ -32,6 +32,7 @@ PermanentMACAddress=
[Link]
ActivationPolicy=
RequiredForOnline=
+RequiredFamilyForOnline=
ARP=
AllMulticast=
Unmanaged=
diff --git a/test/fuzz/fuzz-unit-file/directives-all.service b/test/fuzz/fuzz-unit-file/directives-all.service
index 310dbd6add..a152bebd73 100644
--- a/test/fuzz/fuzz-unit-file/directives-all.service
+++ b/test/fuzz/fuzz-unit-file/directives-all.service
@@ -545,6 +545,7 @@ RemoteChecksumRx=
RemoteChecksumTx=
ReorderHeader=
RequestBroadcast=
+RequiredFamilyForOnline=
RequiredForOnline=
ResendIGMP=
RootDistanceMaxSec=