diff options
author | LetzteInstanz <faust6@inbox.ru> | 2021-04-11 23:29:11 +0300 |
---|---|---|
committer | Yu Watanabe <watanabe.yu+github@gmail.com> | 2021-04-14 08:51:02 +0900 |
commit | 8430841b5e2140b01ad3e3db5929f77f3e8cc585 (patch) | |
tree | 45267415041fbbe43f41fc33d0912d5310bcbacc | |
parent | 86ae2d69a3b07de23f0c4ddb1fa3e5ec8bc85c1b (diff) | |
download | systemd-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.xml | 12 | ||||
-rw-r--r-- | src/libsystemd/sd-network/network-util.c | 9 | ||||
-rw-r--r-- | src/libsystemd/sd-network/network-util.h | 3 | ||||
-rw-r--r-- | src/network/networkd-link-bus.c | 2 | ||||
-rw-r--r-- | src/network/networkd-link.c | 60 | ||||
-rw-r--r-- | src/network/networkd-link.h | 2 | ||||
-rw-r--r-- | src/network/networkd-manager-bus.c | 2 | ||||
-rw-r--r-- | src/network/networkd-manager.h | 2 | ||||
-rw-r--r-- | src/network/networkd-network-gperf.gperf | 1 | ||||
-rw-r--r-- | src/network/networkd-network.c | 3 | ||||
-rw-r--r-- | src/network/networkd-network.h | 2 | ||||
-rw-r--r-- | src/network/networkd-state-file.c | 52 | ||||
-rw-r--r-- | test/fuzz/fuzz-network-parser/directives.network | 1 | ||||
-rw-r--r-- | test/fuzz/fuzz-unit-file/directives-all.service | 1 |
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= |