diff --git a/man/networkctl.xml b/man/networkctl.xml index 19095164ce..2f7e9d7f46 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 + + + + diff --git a/man/systemd.network.xml b/man/systemd.network.xml index 02e464b193..64bd036e0c 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. @@ -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. diff --git a/src/libsystemd/sd-network/network-util.c b/src/libsystemd/sd-network/network-util.c index 4570098388..4a648caa5d 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; } @@ -73,6 +87,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/networkctl.c b/src/network/networkctl.c index 7953a52b9d..f36d725d7d 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); 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: diff --git a/test/networkd-test.py b/test/networkd-test.py index 726cc2e0e1..c13a20dd7f 100755 --- a/test/networkd-test.py +++ b/test/networkd-test.py @@ -412,6 +412,7 @@ DHCP={dhcp_mode} 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::')