diff options
author | Alvin Šipraga <alsi@bang-olufsen.dk> | 2021-03-30 21:39:18 +0200 |
---|---|---|
committer | Yu Watanabe <watanabe.yu+github@gmail.com> | 2021-05-19 03:33:55 +0200 |
commit | bcdcc59648dabefaed4267a2432a9e7928f93cb5 (patch) | |
tree | 97653a2cd0da13178b6c0dae7d7204e8ae7c4ff8 | |
parent | Merge pull request #19611 from yuwata/network-dhcp-server-introduce-server-ad... (diff) | |
download | systemd-bcdcc59648dabefaed4267a2432a9e7928f93cb5.tar.xz systemd-bcdcc59648dabefaed4267a2432a9e7928f93cb5.zip |
network: add an online state for links and manager
Add a new state of type LinkOnlineState which indicates whether a link
is online or not. The state is also used by networkd's manager to expose
the overall online state of the system.
The possible states are:
offline the link (or system) is offline
partial at least one required link is online (see below)
online all required links are online
For links, a link is defined to be "online" if:
- it is managed; and
- its operational state is within the range defined by
RequiredForOnline=; and
- it has an IPv4 address if RequiredFamilyForOnline=ipv4 or =both; and
- it has an IPv6 address if RequiredFamilyForOnline=ipv6 or =both.
A link is defined to be "offline" if:
- it is managed; and
- it is not online, i.e. its operational state is not within the range
defined by RequiredForOnline=, and/or it is missing an IP address in
a required address family.
Otherwise, the link online state is undefined (represented internally as
_LINK_ONLINE_STATUS_INVALID or -EINVAL). Put another way, networkd will
only offer a meaningful online state for managed links where
RequiredForOnline=yes.
For the manager, the online state is a function of the online state of
all links which are requried for online, i.e. RequiredForOnline=yes. If
all required links are online, then the manager online state is defined
to be "online". If at least one of the required links is online, then
the manager online state is defined to be "partial". If none of
the required links are online, then the manager online state is defined
to be "offline". If there are no managed links, or RequiredForOnline=no
for all managed links, then the manager online state is undefined as
above.
The purpose of the "partial" state is analogous to the --any switch in
systemd-networkd-wait-online.service(8). For example, a required link
which lacks a carrier on boot will not force the overall (manager)
online state to "offline" if there is an alternative link available.
-rw-r--r-- | src/libsystemd/sd-network/network-util.c | 8 | ||||
-rw-r--r-- | src/libsystemd/sd-network/network-util.h | 11 | ||||
-rw-r--r-- | src/libsystemd/sd-network/sd-network.c | 8 | ||||
-rw-r--r-- | src/network/networkd-json.c | 3 | ||||
-rw-r--r-- | src/network/networkd-link-bus.c | 2 | ||||
-rw-r--r-- | src/network/networkd-link-bus.h | 1 | ||||
-rw-r--r-- | src/network/networkd-link.c | 42 | ||||
-rw-r--r-- | src/network/networkd-link.h | 1 | ||||
-rw-r--r-- | src/network/networkd-manager-bus.c | 1 | ||||
-rw-r--r-- | src/network/networkd-manager.c | 1 | ||||
-rw-r--r-- | src/network/networkd-manager.h | 1 | ||||
-rw-r--r-- | src/network/networkd-state-file.c | 31 | ||||
-rw-r--r-- | src/systemd/sd-network.h | 2 |
13 files changed, 109 insertions, 3 deletions
diff --git a/src/libsystemd/sd-network/network-util.c b/src/libsystemd/sd-network/network-util.c index 4570098388..b01f883666 100644 --- a/src/libsystemd/sd-network/network-util.c +++ b/src/libsystemd/sd-network/network-util.c @@ -73,6 +73,14 @@ static const char* const link_address_state_table[_LINK_ADDRESS_STATE_MAX] = { DEFINE_STRING_TABLE_LOOKUP(link_address_state, LinkAddressState); +static const char *const link_online_state_table[_LINK_ONLINE_STATE_MAX] = { + [LINK_ONLINE_STATE_OFFLINE] = "offline", + [LINK_ONLINE_STATE_PARTIAL] = "partial", + [LINK_ONLINE_STATE_ONLINE] = "online", +}; + +DEFINE_STRING_TABLE_LOOKUP(link_online_state, LinkOnlineState); + int parse_operational_state_range(const char *str, LinkOperationalStateRange *out) { LinkOperationalStateRange range = { _LINK_OPERSTATE_INVALID, _LINK_OPERSTATE_INVALID }; _cleanup_free_ const char *min = NULL; diff --git a/src/libsystemd/sd-network/network-util.h b/src/libsystemd/sd-network/network-util.h index d33f42cfb0..3a2e4a7f6c 100644 --- a/src/libsystemd/sd-network/network-util.h +++ b/src/libsystemd/sd-network/network-util.h @@ -54,6 +54,14 @@ typedef enum LinkAddressState { _LINK_ADDRESS_STATE_INVALID = -EINVAL, } LinkAddressState; +typedef enum LinkOnlineState { + LINK_ONLINE_STATE_OFFLINE, + LINK_ONLINE_STATE_PARTIAL, + LINK_ONLINE_STATE_ONLINE, + _LINK_ONLINE_STATE_MAX, + _LINK_ONLINE_STATE_INVALID = -EINVAL, +} LinkOnlineState; + const char* link_operstate_to_string(LinkOperationalState s) _const_; LinkOperationalState link_operstate_from_string(const char *s) _pure_; @@ -66,6 +74,9 @@ 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_; +const char* link_online_state_to_string(LinkOnlineState s) _const_; +LinkOnlineState link_online_state_from_string(const char *s) _pure_; + typedef struct LinkOperationalStateRange { LinkOperationalState min; LinkOperationalState max; diff --git a/src/libsystemd/sd-network/sd-network.c b/src/libsystemd/sd-network/sd-network.c index b190e8f881..552ec381b6 100644 --- a/src/libsystemd/sd-network/sd-network.c +++ b/src/libsystemd/sd-network/sd-network.c @@ -56,6 +56,10 @@ _public_ int sd_network_get_ipv6_address_state(char **state) { return network_get_string("IPV6_ADDRESS_STATE", state); } +_public_ int sd_network_get_online_state(char **state) { + return network_get_string("ONLINE_STATE", state); +} + static int network_get_strv(const char *key, char ***ret) { _cleanup_strv_free_ char **a = NULL; _cleanup_free_ char *s = NULL; @@ -204,6 +208,10 @@ _public_ int sd_network_link_get_ipv6_address_state(int ifindex, char **state) { return network_link_get_string(ifindex, "IPV6_ADDRESS_STATE", state); } +_public_ int sd_network_link_get_online_state(int ifindex, char **state) { + return network_link_get_string(ifindex, "ONLINE_STATE", state); +} + _public_ int sd_network_link_get_dhcp6_client_iaid_string(int ifindex, char **iaid) { return network_link_get_string(ifindex, "DHCP6_CLIENT_IAID", iaid); } diff --git a/src/network/networkd-json.c b/src/network/networkd-json.c index 7a7fc24ea6..c78e653c0b 100644 --- a/src/network/networkd-json.c +++ b/src/network/networkd-json.c @@ -60,7 +60,8 @@ int link_build_json(Link *link, JsonVariant **ret) { JSON_BUILD_PAIR("CarrierState", JSON_BUILD_STRING(link_carrier_state_to_string(link->carrier_state))), JSON_BUILD_PAIR("AddressState", JSON_BUILD_STRING(link_address_state_to_string(link->address_state))), JSON_BUILD_PAIR("IPv4AddressState", JSON_BUILD_STRING(link_address_state_to_string(link->ipv4_address_state))), - JSON_BUILD_PAIR("IPv6AddressState", JSON_BUILD_STRING(link_address_state_to_string(link->ipv6_address_state))))); + JSON_BUILD_PAIR("IPv6AddressState", JSON_BUILD_STRING(link_address_state_to_string(link->ipv6_address_state))), + JSON_BUILD_PAIR("OnlineState", JSON_BUILD_STRING(link_online_state_to_string(link->online_state))))); if (r < 0) return r; diff --git a/src/network/networkd-link-bus.c b/src/network/networkd-link-bus.c index f2f47c52b0..7be333eac6 100644 --- a/src/network/networkd-link-bus.c +++ b/src/network/networkd-link-bus.c @@ -24,6 +24,7 @@ BUS_DEFINE_PROPERTY_GET_ENUM(property_get_operational_state, link_operstate, LinkOperationalState); BUS_DEFINE_PROPERTY_GET_ENUM(property_get_carrier_state, link_carrier_state, LinkCarrierState); BUS_DEFINE_PROPERTY_GET_ENUM(property_get_address_state, link_address_state, LinkAddressState); +BUS_DEFINE_PROPERTY_GET_ENUM(property_get_online_state, link_online_state, LinkOnlineState); static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_administrative_state, link_state, LinkState); static int property_get_bit_rates( @@ -716,6 +717,7 @@ const sd_bus_vtable link_vtable[] = { 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("OnlineState", "s", property_get_online_state, offsetof(Link, online_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-bus.h b/src/network/networkd-link-bus.h index ddc3fcb39d..e8fa84b4e5 100644 --- a/src/network/networkd-link-bus.h +++ b/src/network/networkd-link-bus.h @@ -18,6 +18,7 @@ int link_send_changed(Link *link, const char *property, ...) _sentinel_; int property_get_operational_state(sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *reply, void *userdata, sd_bus_error *error); int property_get_carrier_state(sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *reply, void *userdata, sd_bus_error *error); int property_get_address_state(sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *reply, void *userdata, sd_bus_error *error); +int property_get_online_state(sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *reply, void *userdata, sd_bus_error *error); int bus_link_method_set_ntp_servers(sd_bus_message *message, void *userdata, sd_bus_error *error); int bus_link_method_set_dns_servers(sd_bus_message *message, void *userdata, sd_bus_error *error); diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c index d493afda4c..0c2e759180 100644 --- a/src/network/networkd-link.c +++ b/src/network/networkd-link.c @@ -202,6 +202,7 @@ void link_update_operstate(Link *link, bool also_update_master) { LinkOperationalState operstate; LinkCarrierState carrier_state; LinkAddressState ipv4_address_state, ipv6_address_state, address_state; + LinkOnlineState online_state; _cleanup_strv_free_ char **p = NULL; uint8_t ipv4_scope = RT_SCOPE_NOWHERE, ipv6_scope = RT_SCOPE_NOWHERE; bool changed = false; @@ -277,6 +278,38 @@ void link_update_operstate(Link *link, bool also_update_master) { else operstate = LINK_OPERSTATE_ENSLAVED; + /* Only determine online state for managed links with RequiredForOnline=yes */ + if (!link->network || !link->network->required_for_online) + online_state = _LINK_ONLINE_STATE_INVALID; + else if (operstate < link->network->required_operstate_for_online.min || + operstate > link->network->required_operstate_for_online.max) + online_state = LINK_ONLINE_STATE_OFFLINE; + else { + AddressFamily required_family = link->network->required_family_for_online; + bool needs_ipv4 = required_family & ADDRESS_FAMILY_IPV4; + bool needs_ipv6 = required_family & ADDRESS_FAMILY_IPV6; + + /* The operational state is within the range required for online. + * If a particular address family is also required, we might revert + * to offline in the blocks below. + */ + online_state = LINK_ONLINE_STATE_ONLINE; + + if (link->network->required_operstate_for_online.min >= LINK_OPERSTATE_DEGRADED) { + if (needs_ipv4 && ipv4_address_state < LINK_ADDRESS_STATE_DEGRADED) + online_state = LINK_ONLINE_STATE_OFFLINE; + if (needs_ipv6 && ipv6_address_state < LINK_ADDRESS_STATE_DEGRADED) + online_state = LINK_ONLINE_STATE_OFFLINE; + } + + if (link->network->required_operstate_for_online.min >= LINK_OPERSTATE_ROUTABLE) { + if (needs_ipv4 && ipv4_address_state < LINK_ADDRESS_STATE_ROUTABLE) + online_state = LINK_ONLINE_STATE_OFFLINE; + if (needs_ipv6 && ipv6_address_state < LINK_ADDRESS_STATE_ROUTABLE) + online_state = LINK_ONLINE_STATE_OFFLINE; + } + } + if (link->carrier_state != carrier_state) { link->carrier_state = carrier_state; changed = true; @@ -312,6 +345,13 @@ void link_update_operstate(Link *link, bool also_update_master) { log_oom(); } + if (link->online_state != online_state) { + link->online_state = online_state; + changed = true; + if (strv_extend(&p, "OnlineState") < 0) + log_oom(); + } + if (p) link_send_changed_strv(link, p); if (changed) @@ -2330,6 +2370,7 @@ static int link_initialized_and_synced(Link *link) { } link->network = network_ref(network); + link_update_operstate(link, false); link_dirty(link); } @@ -2466,6 +2507,7 @@ static int link_new(Manager *manager, sd_netlink_message *message, Link **ret) { *link = (Link) { .n_ref = 1, .state = LINK_STATE_PENDING, + .online_state = _LINK_ONLINE_STATE_INVALID, .ifindex = ifindex, .iftype = iftype, .ifname = TAKE_PTR(ifname), diff --git a/src/network/networkd-link.h b/src/network/networkd-link.h index fbc593f124..f6317d4cb3 100644 --- a/src/network/networkd-link.h +++ b/src/network/networkd-link.h @@ -77,6 +77,7 @@ typedef struct Link { LinkAddressState address_state; LinkAddressState ipv4_address_state; LinkAddressState ipv6_address_state; + LinkOnlineState online_state; unsigned address_label_messages; unsigned static_address_messages; diff --git a/src/network/networkd-manager-bus.c b/src/network/networkd-manager-bus.c index f66d7d1612..23c1fb57c6 100644 --- a/src/network/networkd-manager-bus.c +++ b/src/network/networkd-manager-bus.c @@ -271,6 +271,7 @@ const sd_bus_vtable manager_vtable[] = { 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_PROPERTY("OnlineState", "s", property_get_online_state, offsetof(Manager, online_state), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), SD_BUS_METHOD_WITH_ARGS("ListLinks", SD_BUS_NO_ARGS, diff --git a/src/network/networkd-manager.c b/src/network/networkd-manager.c index fd576169a9..2b06657590 100644 --- a/src/network/networkd-manager.c +++ b/src/network/networkd-manager.c @@ -380,6 +380,7 @@ int manager_new(Manager **ret) { *m = (Manager) { .speed_meter_interval_usec = SPEED_METER_DEFAULT_TIME_INTERVAL, + .online_state = _LINK_ONLINE_STATE_INVALID, .manage_foreign_routes = true, .manage_foreign_rules = true, .ethtool_fd = -1, diff --git a/src/network/networkd-manager.h b/src/network/networkd-manager.h index 3f8f81b865..ef98c519d6 100644 --- a/src/network/networkd-manager.h +++ b/src/network/networkd-manager.h @@ -42,6 +42,7 @@ struct Manager { LinkAddressState address_state; LinkAddressState ipv4_address_state; LinkAddressState ipv6_address_state; + LinkOnlineState online_state; Hashmap *links; Hashmap *netdevs; diff --git a/src/network/networkd-state-file.c b/src/network/networkd-state-file.c index f8243cc3ee..b9dab9b211 100644 --- a/src/network/networkd-state-file.c +++ b/src/network/networkd-state-file.c @@ -105,11 +105,13 @@ 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, *ipv4_address_state_str, *ipv6_address_state_str; + const char *operstate_str, *carrier_state_str, *address_state_str, *ipv4_address_state_str, *ipv6_address_state_str, *online_state_str; LinkOperationalState operstate = LINK_OPERSTATE_OFF; LinkCarrierState carrier_state = LINK_CARRIER_STATE_OFF; LinkAddressState ipv4_address_state = LINK_ADDRESS_STATE_OFF, ipv6_address_state = LINK_ADDRESS_STATE_OFF, address_state = LINK_ADDRESS_STATE_OFF; + LinkOnlineState online_state; + size_t links_offline = 0, links_online = 0; _cleanup_(unlink_and_freep) char *temp_path = NULL; _cleanup_strv_free_ char **p = NULL; _cleanup_fclose_ FILE *f = NULL; @@ -134,6 +136,13 @@ int manager_save(Manager *m) { if (!link->network) continue; + if (link->network->required_for_online) { + if (link->online_state == LINK_ONLINE_STATE_OFFLINE) + links_offline++; + else if (link->online_state == LINK_ONLINE_STATE_ONLINE) + links_online++; + } + /* First add the static configured entries */ if (link->n_dns != UINT_MAX) r = ordered_set_put_dns_servers(&dns, link->ifindex, link->dns, link->n_dns); @@ -215,6 +224,10 @@ int manager_save(Manager *m) { if (carrier_state >= LINK_CARRIER_STATE_ENSLAVED) carrier_state = LINK_CARRIER_STATE_CARRIER; + online_state = links_online > 0 ? + (links_offline > 0 ? LINK_ONLINE_STATE_PARTIAL : LINK_ONLINE_STATE_ONLINE) : + (links_offline > 0 ? LINK_ONLINE_STATE_OFFLINE : _LINK_ONLINE_STATE_INVALID); + operstate_str = link_operstate_to_string(operstate); assert(operstate_str); @@ -245,6 +258,10 @@ int manager_save(Manager *m) { "IPV6_ADDRESS_STATE=%s\n", operstate_str, carrier_state_str, address_state_str, ipv4_address_state_str, ipv6_address_state_str); + online_state_str = link_online_state_to_string(online_state); + if (online_state_str) + fprintf(f, "ONLINE_STATE=%s\n", online_state_str); + ordered_set_print(f, "DNS=", dns); ordered_set_print(f, "NTP=", ntp); ordered_set_print(f, "SIP=", sip); @@ -291,6 +308,12 @@ int manager_save(Manager *m) { log_oom(); } + if (m->online_state != online_state) { + m->online_state = online_state; + if (strv_extend(&p, "OnlineState") < 0) + log_oom(); + } + if (p) { r = manager_send_changed_strv(m, p); if (r < 0) @@ -445,9 +468,13 @@ int link_save(Link *link) { if (link->network) { char **dhcp6_domains = NULL, **dhcp_domains = NULL; - const char *dhcp_domainname = NULL, *p; + const char *dhcp_domainname = NULL, *online_state, *p; bool space; + online_state = link_online_state_to_string(link->online_state); + if (online_state) + fprintf(f, "ONLINE_STATE=%s\n", online_state); + fprintf(f, "REQUIRED_FOR_ONLINE=%s\n", yes_no(link->network->required_for_online)); diff --git a/src/systemd/sd-network.h b/src/systemd/sd-network.h index 3f4ccf1908..776f6b5243 100644 --- a/src/systemd/sd-network.h +++ b/src/systemd/sd-network.h @@ -53,6 +53,7 @@ int sd_network_get_carrier_state(char **state); int sd_network_get_address_state(char **state); int sd_network_get_ipv4_address_state(char **state); int sd_network_get_ipv6_address_state(char **state); +int sd_network_get_online_state(char **state); /* Get DNS entries for all links. These are string representations of * IP addresses */ @@ -99,6 +100,7 @@ int sd_network_link_get_carrier_state(int ifindex, char **state); int sd_network_link_get_address_state(int ifindex, char **state); int sd_network_link_get_ipv4_address_state(int ifindex, char **state); int sd_network_link_get_ipv6_address_state(int ifindex, char **state); +int sd_network_link_get_online_state(int ifindex, char **state); /* Indicates whether the network is relevant to being online. * Possible return codes: |