From bcdcc59648dabefaed4267a2432a9e7928f93cb5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alvin=20=C5=A0ipraga?= Date: Tue, 30 Mar 2021 21:39:18 +0200 Subject: [PATCH 1/7] 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. --- src/libsystemd/sd-network/network-util.c | 8 +++++ src/libsystemd/sd-network/network-util.h | 11 +++++++ src/libsystemd/sd-network/sd-network.c | 8 +++++ src/network/networkd-json.c | 3 +- src/network/networkd-link-bus.c | 2 ++ src/network/networkd-link-bus.h | 1 + src/network/networkd-link.c | 42 ++++++++++++++++++++++++ src/network/networkd-link.h | 1 + src/network/networkd-manager-bus.c | 1 + src/network/networkd-manager.c | 1 + src/network/networkd-manager.h | 1 + src/network/networkd-state-file.c | 31 +++++++++++++++-- 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 45700983882f0..b01f88366693c 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 d33f42cfb0595..3a2e4a7f6c6d3 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 b190e8f881081..552ec381b6743 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 7a7fc24ea62c4..c78e653c0b052 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 f2f47c52b086f..7be333eac6294 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 ddc3fcb39df7a..e8fa84b4e52ec 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 d493afda4c845..0c2e759180b16 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 fbc593f124ee0..f6317d4cb3540 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 f66d7d1612778..23c1fb57c6805 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 fd576169a94cd..2b066575906d6 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 3f8f81b865789..ef98c519d6271 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 f8243cc3eef1b..b9dab9b211f50 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 3f4ccf19087ab..776f6b5243ee8 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: From 84a257ab65b0ce866e818cea202e13118056c370 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alvin=20=C5=A0ipraga?= Date: Tue, 30 Mar 2021 23:18:08 +0200 Subject: [PATCH 2/7] network: use the overall online state in network_is_online() Since networkd advertises a reliable online state, use it in network_is_online(). If for some reason networkd does not know the online state (e.g. it does not manage any of the network interfaces), fall back to the original best-guess logic. --- src/libsystemd/sd-network/network-util.c | 32 +++++++++++++++++------- 1 file changed, 23 insertions(+), 9 deletions(-) diff --git a/src/libsystemd/sd-network/network-util.c b/src/libsystemd/sd-network/network-util.c index b01f88366693c..4a648caa5daac 100644 --- a/src/libsystemd/sd-network/network-util.c +++ b/src/libsystemd/sd-network/network-util.c @@ -13,20 +13,34 @@ #include "strv.h" bool network_is_online(void) { - _cleanup_free_ char *carrier_state = NULL, *addr_state = NULL; + _cleanup_free_ char *online_state = NULL; + LinkOnlineState state; int r; - r = sd_network_get_carrier_state(&carrier_state); - if (r < 0) /* if we don't know anything, we consider the system online */ - return true; + r = sd_network_get_online_state(&online_state); + if (r < 0) + state = _LINK_ONLINE_STATE_INVALID; + else + state = link_online_state_from_string(online_state); - r = sd_network_get_address_state(&addr_state); - if (r < 0) /* if we don't know anything, we consider the system online */ + if (state >= LINK_ONLINE_STATE_PARTIAL) return true; + else if (state < 0) { + _cleanup_free_ char *carrier_state = NULL, *addr_state = NULL; - if (STR_IN_SET(carrier_state, "degraded-carrier", "carrier") && - STR_IN_SET(addr_state, "routable", "degraded")) - return true; + r = sd_network_get_carrier_state(&carrier_state); + if (r < 0) /* if we don't know anything, we consider the system online */ + return true; + + r = sd_network_get_address_state(&addr_state); + if (r < 0) /* if we don't know anything, we consider the system online */ + return true; + + /* we don't know the online state for certain, so make an educated guess */ + if (STR_IN_SET(carrier_state, "degraded-carrier", "carrier") && + STR_IN_SET(addr_state, "routable", "degraded")) + return true; + } return false; } From 6c95e09388a527ec053efb631f93188458dd95e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alvin=20=C5=A0ipraga?= Date: Tue, 6 Apr 2021 15:56:05 +0200 Subject: [PATCH 3/7] man: clarify RequiredForOnline= behaviour for online state With new "online state" semantics in networkd, make the description of RequiredForOnline= a little more broad. --- man/systemd.network.xml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/man/systemd.network.xml b/man/systemd.network.xml index 02e464b193db3..d1c823789ff6e 100644 --- a/man/systemd.network.xml +++ b/man/systemd.network.xml @@ -215,9 +215,9 @@ Takes a boolean or a minimum operational state and an optional maximum operational state. Please see networkctl1 for possible operational states. When yes, the network is deemed required when - determining whether the system is online when running - systemd-networkd-wait-online. When no, the network is ignored - when checking for online state. When a minimum operational state and an optional maximum operational + determining whether the system is online (including when running + systemd-networkd-wait-online). When no, the network is ignored + when determining the online state. When a minimum operational state and an optional maximum operational state are set, yes is implied, and this controls the minimum and maximum operational state required for the network interface to be considered online. Defaults to yes. From 553022c4af6d50cc9439867b3dae3b2f751b004a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alvin=20=C5=A0ipraga?= Date: Fri, 16 Apr 2021 15:04:24 +0200 Subject: [PATCH 4/7] man: clarify RequiredFamilyForOnline= behaviour for online state With new "online state" semantics in networkd, make the description of RequiredFamilyForOnline= a little more broad. Some rewording has been done to make the passage easier to understand. --- man/systemd.network.xml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/man/systemd.network.xml b/man/systemd.network.xml index d1c823789ff6e..64bd036e0c89b 100644 --- a/man/systemd.network.xml +++ b/man/systemd.network.xml @@ -232,13 +232,13 @@ RequiredFamilyForOnline= - Specifies an address family. When specified, - systemd-networkd-wait-online waits for at least one routable or link-local - IP address in the family should be configured on the link. Takes one of - ipv4, ipv6, both, or - any. Defaults to any. Note that this will be used only - when RequiredForOnline= is true, or its minimum operational state is - degraded or above. Otherwise, it will be ignored. + Takes an address family. When specified, an IP address in the given family is deemed required + when determining whether the link is online (including when running + systemd-networkd-wait-online). Takes one of ipv4, + ipv6, both, or any. Defaults to + any. Note that this option has no effect if + RequiredForOnline=no, or if RequiredForOnline= specifies a + minimum operational state below degraded. From 4a481ec4ae2137db1b294c8ff2ce7d2d1ebdc37e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alvin=20=C5=A0ipraga?= Date: Tue, 6 Apr 2021 15:40:46 +0200 Subject: [PATCH 5/7] network: show online state in networkctl status output MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In case the link online state is invalid, networkctl will print "unknown", which is sufficiently neutral. The same goes for the overall manager online state if there are no managed links, or if RequiredForOnline=no for all managed links. Example output: $ networkctl status ● State: routable Online state: partial Address: 172.22.0.130 on wlan0 ... $ networkctl status wlan0 ● 3: wlan0 Link File: /lib/systemd/network/99-default.link Network File: /etc/systemd/network/50-wlan0.network Type: wlan State: routable (configured) Online state: online ... --- src/network/networkctl.c | 47 +++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/src/network/networkctl.c b/src/network/networkctl.c index 7953a52b9d557..f36d725d7d7b4 100644 --- a/src/network/networkctl.c +++ b/src/network/networkctl.c @@ -225,6 +225,25 @@ static void setup_state_to_color(const char *state, const char **on, const char } } +static void online_state_to_color(const char *state, const char **on, const char **off) { + if (streq_ptr(state, "online")) { + if (on) + *on = ansi_highlight_green(); + if (off) + *off = ansi_normal(); + } else if (streq_ptr(state, "partial")) { + if (on) + *on = ansi_highlight_yellow(); + if (off) + *off = ansi_normal(); + } else { + if (on) + *on = ""; + if (off) + *off = ""; + } +} + typedef struct VxLanInfo { uint32_t vni; uint32_t link; @@ -1514,9 +1533,9 @@ static int link_status_one( _cleanup_strv_free_ char **dns = NULL, **ntp = NULL, **sip = NULL, **search_domains = NULL, **route_domains = NULL; _cleanup_free_ char *t = NULL, *network = NULL, *iaid = NULL, *duid = NULL, - *setup_state = NULL, *operational_state = NULL, *lease_file = NULL, *activation_policy = NULL; + *setup_state = NULL, *operational_state = NULL, *online_state = NULL, *lease_file = NULL, *activation_policy = NULL; const char *driver = NULL, *path = NULL, *vendor = NULL, *model = NULL, *link = NULL, - *on_color_operational, *off_color_operational, *on_color_setup, *off_color_setup; + *on_color_operational, *off_color_operational, *on_color_setup, *off_color_setup, *on_color_online; _cleanup_free_ int *carrier_bound_to = NULL, *carrier_bound_by = NULL; _cleanup_(sd_dhcp_lease_unrefp) sd_dhcp_lease *lease = NULL; _cleanup_(table_unrefp) Table *table = NULL; @@ -1529,6 +1548,9 @@ static int link_status_one( (void) sd_network_link_get_operational_state(info->ifindex, &operational_state); operational_state_to_color(info->name, operational_state, &on_color_operational, &off_color_operational); + (void) sd_network_link_get_online_state(info->ifindex, &online_state); + online_state_to_color(online_state, &on_color_online, NULL); + r = sd_network_link_get_setup_state(info->ifindex, &setup_state); if (r == -ENODATA) /* If there's no info available about this iface, it's unmanaged by networkd */ setup_state = strdup("unmanaged"); @@ -1613,6 +1635,14 @@ static int link_status_one( if (r < 0) return table_log_add_error(r); + r = table_add_many(table, + TABLE_EMPTY, + TABLE_STRING, "Online state:", + TABLE_STRING, online_state ?: "unknown", + TABLE_SET_COLOR, on_color_online); + if (r < 0) + return table_log_add_error(r); + strv_sort(info->alternative_names); r = dump_list(table, "Alternative Names:", info->alternative_names); if (r < 0) @@ -2272,9 +2302,9 @@ static int link_status_one( } static int system_status(sd_netlink *rtnl, sd_hwdb *hwdb) { - _cleanup_free_ char *operational_state = NULL; + _cleanup_free_ char *operational_state = NULL, *online_state = NULL; _cleanup_strv_free_ char **dns = NULL, **ntp = NULL, **search_domains = NULL, **route_domains = NULL; - const char *on_color_operational; + const char *on_color_operational, *on_color_online; _cleanup_(table_unrefp) Table *table = NULL; TableCell *cell; int r; @@ -2284,6 +2314,9 @@ static int system_status(sd_netlink *rtnl, sd_hwdb *hwdb) { (void) sd_network_get_operational_state(&operational_state); operational_state_to_color(NULL, operational_state, &on_color_operational, NULL); + (void) sd_network_get_online_state(&online_state); + online_state_to_color(online_state, &on_color_online, NULL); + table = table_new("dot", "key", "value"); if (!table) return log_oom(); @@ -2305,7 +2338,11 @@ static int system_status(sd_netlink *rtnl, sd_hwdb *hwdb) { TABLE_SET_COLOR, on_color_operational, TABLE_STRING, "State:", TABLE_STRING, strna(operational_state), - TABLE_SET_COLOR, on_color_operational); + TABLE_SET_COLOR, on_color_operational, + TABLE_EMPTY, + TABLE_STRING, "Online state:", + TABLE_STRING, online_state ?: "unknown", + TABLE_SET_COLOR, on_color_online); if (r < 0) return table_log_add_error(r); From 1940b3a7cd277daea7f5d776033d8a596a73e01b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alvin=20=C5=A0ipraga?= Date: Fri, 23 Apr 2021 14:19:56 +0200 Subject: [PATCH 6/7] networkd-test: support online state in networkctl status output networkctl status now outputs an online state. Fix up the tests to account for this. --- test/networkd-test.py | 1 + 1 file changed, 1 insertion(+) diff --git a/test/networkd-test.py b/test/networkd-test.py index 726cc2e0e1b61..c13a20dd7f029 100755 --- a/test/networkd-test.py +++ b/test/networkd-test.py @@ -412,6 +412,7 @@ def do_test(self, coldplug=True, ipv6=False, extra_opts='', out = subprocess.check_output(['networkctl', '-n', '0', 'status', self.iface]) self.assertRegex(out, br'Type:\s+ether') self.assertRegex(out, br'State:\s+routable.*configured') + self.assertRegex(out, br'Online state:\s+online') self.assertRegex(out, br'Address:\s+192.168.5.\d+') if ipv6: self.assertRegex(out, br'2600::') From 7e59cfe9516722ac8a00adef5d01575c45a0ba2f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alvin=20=C5=A0ipraga?= Date: Tue, 27 Apr 2021 10:58:18 +0200 Subject: [PATCH 7/7] man: describe overall online status in networkctl(1) --- man/networkctl.xml | 48 ++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 40 insertions(+), 8 deletions(-) diff --git a/man/networkctl.xml b/man/networkctl.xml index 19095164ce3be..2f7e9d7f4686e 100644 --- a/man/networkctl.xml +++ b/man/networkctl.xml @@ -187,14 +187,46 @@ Produces output similar to: -● State: routable - Address: 10.193.76.5 on eth0 - 192.168.122.1 on virbr0 - 169.254.190.105 on eth0 - fe80::5054:aa:bbbb:cccc on eth0 - Gateway: 10.193.11.1 (CISCO SYSTEMS, INC.) on eth0 - DNS: 8.8.8.8 - 8.8.4.4 +● State: routable + Online state: online + Address: 10.193.76.5 on eth0 + 192.168.122.1 on virbr0 + 169.254.190.105 on eth0 + fe80::5054:aa:bbbb:cccc on eth0 + Gateway: 10.193.11.1 (CISCO SYSTEMS, INC.) on eth0 + DNS: 8.8.8.8 + 8.8.4.4 + + In the overall network status, the online state depends on the individual online state of all + required links. Managed links are required for online by default. In this case, the online state is + one of the following: + + + unknown + + all links have unknown online status (i.e. there are no required links) + + + + offline + + all required links are offline + + + + partial + + some, but not all, required links are online + + + + online + + all required links are online + + + +