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;
_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_;
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;
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;
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);
}
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;
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(
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),
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);
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;
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;
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)
}
link->network = network_ref(network);
+ link_update_operstate(link, false);
link_dirty(link);
}
*link = (Link) {
.n_ref = 1,
.state = LINK_STATE_PENDING,
+ .online_state = _LINK_ONLINE_STATE_INVALID,
.ifindex = ifindex,
.iftype = iftype,
.ifname = TAKE_PTR(ifname),
LinkAddressState address_state;
LinkAddressState ipv4_address_state;
LinkAddressState ipv6_address_state;
+ LinkOnlineState online_state;
unsigned address_label_messages;
unsigned static_address_messages;
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,
*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,
LinkAddressState address_state;
LinkAddressState ipv4_address_state;
LinkAddressState ipv6_address_state;
+ LinkOnlineState online_state;
Hashmap *links;
Hashmap *netdevs;
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;
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);
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);
"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);
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)
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));
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 */
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: