1
0
mirror of https://github.com/systemd/systemd synced 2024-07-09 04:26:06 +00:00

Merge pull request #12762 from yuwata/network-introduce-carrier-and-network-state-12752

network: introduce carrier and address state to fix network_is_online()
This commit is contained in:
Lennart Poettering 2019-06-20 13:36:30 +02:00 committed by GitHub
commit 762267cdc1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 271 additions and 79 deletions

View File

@ -7,14 +7,19 @@
#include "strv.h"
bool network_is_online(void) {
_cleanup_free_ char *state = NULL;
_cleanup_free_ char *carrier_state = NULL, *addr_state = NULL;
int r;
r = sd_network_get_operational_state(&state);
r = sd_network_get_carrier_state(&carrier_state);
if (r < 0) /* if we don't know anything, we consider the system online */
return true;
if (STR_IN_SET(state, "routable", "degraded"))
r = sd_network_get_address_state(&addr_state);
if (r < 0) /* if we don't know anything, we consider the system online */
return true;
if (STR_IN_SET(carrier_state, "degraded-carrier", "carrier") &&
STR_IN_SET(addr_state, "routable", "degraded"))
return true;
return false;
@ -32,3 +37,22 @@ static const char* const link_operstate_table[_LINK_OPERSTATE_MAX] = {
};
DEFINE_STRING_TABLE_LOOKUP(link_operstate, LinkOperationalState);
static const char* const link_carrier_state_table[_LINK_CARRIER_STATE_MAX] = {
[LINK_CARRIER_STATE_OFF] = "off",
[LINK_CARRIER_STATE_NO_CARRIER] = "no-carrier",
[LINK_CARRIER_STATE_DORMANT] = "dormant",
[LINK_CARRIER_STATE_DEGRADED_CARRIER] = "degraded-carrier",
[LINK_CARRIER_STATE_CARRIER] = "carrier",
[LINK_CARRIER_STATE_ENSLAVED] = "enslaved",
};
DEFINE_STRING_TABLE_LOOKUP(link_carrier_state, LinkCarrierState);
static const char* const link_address_state_table[_LINK_ADDRESS_STATE_MAX] = {
[LINK_ADDRESS_STATE_OFF] = "off",
[LINK_ADDRESS_STATE_DEGRADED] = "degraded",
[LINK_ADDRESS_STATE_ROUTABLE] = "routable",
};
DEFINE_STRING_TABLE_LOOKUP(link_address_state, LinkAddressState);

View File

@ -20,5 +20,30 @@ typedef enum LinkOperationalState {
_LINK_OPERSTATE_INVALID = -1
} LinkOperationalState;
typedef enum LinkCarrierState {
LINK_CARRIER_STATE_OFF = LINK_OPERSTATE_OFF,
LINK_CARRIER_STATE_NO_CARRIER = LINK_OPERSTATE_NO_CARRIER,
LINK_CARRIER_STATE_DORMANT = LINK_OPERSTATE_DORMANT,
LINK_CARRIER_STATE_DEGRADED_CARRIER = LINK_OPERSTATE_DEGRADED_CARRIER,
LINK_CARRIER_STATE_CARRIER = LINK_OPERSTATE_CARRIER,
LINK_CARRIER_STATE_ENSLAVED = LINK_OPERSTATE_ENSLAVED,
_LINK_CARRIER_STATE_MAX,
_LINK_CARRIER_STATE_INVALID = -1
} LinkCarrierState;
typedef enum LinkAddressState {
LINK_ADDRESS_STATE_OFF,
LINK_ADDRESS_STATE_DEGRADED,
LINK_ADDRESS_STATE_ROUTABLE,
_LINK_ADDRESS_STATE_MAX,
_LINK_ADDRESS_STATE_INVALID = -1
} LinkAddressState;
const char* link_operstate_to_string(LinkOperationalState s) _const_;
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_address_state_to_string(LinkAddressState s) _const_;
LinkAddressState link_address_state_from_string(const char *s) _pure_;

View File

@ -18,13 +18,13 @@
#include "strv.h"
#include "util.h"
_public_ int sd_network_get_operational_state(char **state) {
static int network_get_string(const char *field, char **ret) {
_cleanup_free_ char *s = NULL;
int r;
assert_return(state, -EINVAL);
assert_return(ret, -EINVAL);
r = parse_env_file(NULL, "/run/systemd/netif/state", "OPER_STATE", &s);
r = parse_env_file(NULL, "/run/systemd/netif/state", field, &s);
if (r == -ENOENT)
return -ENODATA;
if (r < 0)
@ -32,11 +32,23 @@ _public_ int sd_network_get_operational_state(char **state) {
if (isempty(s))
return -ENODATA;
*state = TAKE_PTR(s);
*ret = TAKE_PTR(s);
return 0;
}
_public_ int sd_network_get_operational_state(char **state) {
return network_get_string("OPER_STATE", state);
}
_public_ int sd_network_get_carrier_state(char **state) {
return network_get_string("CARRIER_STATE", state);
}
_public_ int sd_network_get_address_state(char **state) {
return network_get_string("ADDRESS_STATE", state);
}
static int network_get_strv(const char *key, char ***ret) {
_cleanup_strv_free_ char **a = NULL;
_cleanup_free_ char *s = NULL;
@ -149,6 +161,14 @@ _public_ int sd_network_link_get_operational_state(int ifindex, char **state) {
return network_link_get_string(ifindex, "OPER_STATE", state);
}
_public_ int sd_network_link_get_carrier_state(int ifindex, char **state) {
return network_link_get_string(ifindex, "CARRIER_STATE", state);
}
_public_ int sd_network_link_get_address_state(int ifindex, char **state) {
return network_link_get_string(ifindex, "ADDRESS_STATE", state);
}
_public_ int sd_network_link_get_required_for_online(int ifindex) {
_cleanup_free_ char *s = NULL;
int r;

View File

@ -63,6 +63,7 @@ sources = files('''
networkd-ipv6-proxy-ndp.c
networkd-ipv6-proxy-ndp.h
networkd-link-bus.c
networkd-link-bus.h
networkd-link.c
networkd-link.h
networkd-lldp-rx.c

View File

@ -3,12 +3,15 @@
#include "alloc-util.h"
#include "bus-common-errors.h"
#include "bus-util.h"
#include "networkd-link-bus.h"
#include "networkd-link.h"
#include "networkd-manager.h"
#include "parse-util.h"
#include "strv.h"
static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_operational_state, link_operstate, LinkOperationalState);
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);
static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_administrative_state, link_state, LinkState);
static int property_get_bit_rates(
@ -60,13 +63,15 @@ const sd_bus_vtable link_vtable[] = {
SD_BUS_VTABLE_START(0),
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("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),
SD_BUS_VTABLE_END
};
static char *link_bus_path(Link *link) {
char *link_bus_path(Link *link) {
_cleanup_free_ char *ifindex = NULL;
char *p;
int r;
@ -145,17 +150,15 @@ int link_object_find(sd_bus *bus, const char *path, const char *interface, void
return 1;
}
int link_send_changed(Link *link, const char *property, ...) {
int link_send_changed_strv(Link *link, char **properties) {
_cleanup_free_ char *p = NULL;
char **l;
assert(link);
assert(link->manager);
assert(properties);
if (!link->manager->bus)
return 0; /* replace with assert when we have kdbus */
l = strv_from_stdarg_alloca(property);
return 0;
p = link_bus_path(link);
if (!p)
@ -165,5 +168,13 @@ int link_send_changed(Link *link, const char *property, ...) {
link->manager->bus,
p,
"org.freedesktop.network1.Link",
l);
properties);
}
int link_send_changed(Link *link, const char *property, ...) {
char **properties;
properties = strv_from_stdarg_alloca(property);
return link_send_changed_strv(link, properties);
}

View File

@ -0,0 +1,20 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once
#include "sd-bus.h"
#include "macro.h"
typedef struct Link Link;
extern const sd_bus_vtable link_vtable[];
char *link_bus_path(Link *link);
int link_node_enumerator(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error);
int link_object_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error);
int link_send_changed_strv(Link *link, char **properties);
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);

View File

@ -20,6 +20,8 @@
#include "network-internal.h"
#include "networkd-can.h"
#include "networkd-ipv6-proxy-ndp.h"
#include "networkd-link-bus.h"
#include "networkd-link.h"
#include "networkd-lldp-tx.h"
#include "networkd-manager.h"
#include "networkd-ndisc.h"
@ -358,69 +360,110 @@ static void link_update_master_operstate(Link *link, NetDev *netdev) {
void link_update_operstate(Link *link, bool also_update_master) {
LinkOperationalState operstate;
LinkCarrierState carrier_state;
LinkAddressState address_state;
_cleanup_strv_free_ char **p = NULL;
uint8_t scope = RT_SCOPE_NOWHERE;
bool changed = false;
Address *address;
Iterator i;
assert(link);
if (link->kernel_operstate == IF_OPER_DORMANT)
operstate = LINK_OPERSTATE_DORMANT;
carrier_state = LINK_CARRIER_STATE_DORMANT;
else if (link_has_carrier(link)) {
Address *address;
uint8_t scope = RT_SCOPE_NOWHERE;
/* if we have carrier, check what addresses we have */
SET_FOREACH(address, link->addresses, i) {
if (!address_is_ready(address))
continue;
if (address->scope < scope)
scope = address->scope;
}
/* for operstate we also take foreign addresses into account */
SET_FOREACH(address, link->addresses_foreign, i) {
if (!address_is_ready(address))
continue;
if (address->scope < scope)
scope = address->scope;
}
if (scope < RT_SCOPE_SITE)
/* universally accessible addresses found */
operstate = LINK_OPERSTATE_ROUTABLE;
else if (scope < RT_SCOPE_HOST)
/* only link or site local addresses found */
operstate = LINK_OPERSTATE_DEGRADED;
if (link_is_enslaved(link))
carrier_state = LINK_CARRIER_STATE_ENSLAVED;
else
/* no useful addresses found */
operstate = LINK_OPERSTATE_CARRIER;
carrier_state = LINK_CARRIER_STATE_CARRIER;
} else if (link->flags & IFF_UP)
operstate = LINK_OPERSTATE_NO_CARRIER;
carrier_state = LINK_CARRIER_STATE_NO_CARRIER;
else
operstate = LINK_OPERSTATE_OFF;
carrier_state = LINK_CARRIER_STATE_OFF;
if (IN_SET(operstate, LINK_OPERSTATE_DEGRADED, LINK_OPERSTATE_CARRIER) &&
link_is_enslaved(link))
operstate = LINK_OPERSTATE_ENSLAVED;
if (operstate >= LINK_OPERSTATE_CARRIER) {
if (carrier_state >= LINK_CARRIER_STATE_CARRIER) {
Link *slave;
SET_FOREACH(slave, link->slaves, i) {
link_update_operstate(slave, false);
if (slave->operstate < LINK_OPERSTATE_CARRIER)
operstate = LINK_OPERSTATE_DEGRADED_CARRIER;
if (slave->carrier_state < LINK_CARRIER_STATE_CARRIER)
carrier_state = LINK_CARRIER_STATE_DEGRADED_CARRIER;
}
}
SET_FOREACH(address, link->addresses, i) {
if (!address_is_ready(address))
continue;
if (address->scope < scope)
scope = address->scope;
}
/* for operstate we also take foreign addresses into account */
SET_FOREACH(address, link->addresses_foreign, i) {
if (!address_is_ready(address))
continue;
if (address->scope < scope)
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;
/* Mapping of address and carrier state vs operational state
* carrier state
* | off | no-carrier | dormant | degraded-carrier | carrier | enslaved
* ------------------------------------------------------------------------------
* off | off | no-carrier | dormant | degraded-carrier | carrier | enslaved
* address_state degraded | off | no-carrier | dormant | degraded-carrier | degraded | enslaved
* routable | off | no-carrier | dormant | degraded-carrier | routable | routable
*/
if (carrier_state < LINK_CARRIER_STATE_CARRIER || address_state == LINK_ADDRESS_STATE_OFF)
operstate = (LinkOperationalState) carrier_state;
else if (address_state == LINK_ADDRESS_STATE_ROUTABLE)
operstate = LINK_OPERSTATE_ROUTABLE;
else if (carrier_state == LINK_CARRIER_STATE_CARRIER)
operstate = LINK_OPERSTATE_DEGRADED;
else
operstate = LINK_OPERSTATE_ENSLAVED;
if (link->carrier_state != carrier_state) {
link->carrier_state = carrier_state;
changed = true;
if (strv_extend(&p, "CarrierState") < 0)
log_oom();
}
if (link->address_state != address_state) {
link->address_state = address_state;
changed = true;
if (strv_extend(&p, "AddressState") < 0)
log_oom();
}
if (link->operstate != operstate) {
link->operstate = operstate;
link_send_changed(link, "OperationalState", NULL);
link_dirty(link);
changed = true;
if (strv_extend(&p, "OperationalState") < 0)
log_oom();
}
if (p)
link_send_changed_strv(link, p);
if (changed)
link_dirty(link);
if (also_update_master && link->network) {
link_update_master_operstate(link, link->network->bond);
link_update_master_operstate(link, link->network->bridge);
@ -3563,7 +3606,7 @@ static void print_link_hashmap(FILE *f, const char *prefix, Hashmap* h) {
int link_save(Link *link) {
_cleanup_free_ char *temp_path = NULL;
_cleanup_fclose_ FILE *f = NULL;
const char *admin_state, *oper_state;
const char *admin_state, *oper_state, *carrier_state, *address_state;
Address *a;
Route *route;
Iterator i;
@ -3587,6 +3630,12 @@ int link_save(Link *link) {
oper_state = link_operstate_to_string(link->operstate);
assert(oper_state);
carrier_state = link_carrier_state_to_string(link->carrier_state);
assert(carrier_state);
address_state = link_address_state_to_string(link->address_state);
assert(address_state);
r = fopen_temporary(link->state_file, &f, &temp_path);
if (r < 0)
goto fail;
@ -3596,8 +3645,10 @@ int link_save(Link *link) {
fprintf(f,
"# This is private data. Do not parse.\n"
"ADMIN_STATE=%s\n"
"OPER_STATE=%s\n",
admin_state, oper_state);
"OPER_STATE=%s\n"
"CARRIER_STATE=%s\n"
"ADDRESS_STATE=%s\n",
admin_state, oper_state, carrier_state, address_state);
if (link->network) {
char **dhcp6_domains = NULL, **dhcp_domains = NULL;

View File

@ -60,6 +60,8 @@ typedef struct Link {
LinkState state;
LinkOperationalState operstate;
LinkCarrierState carrier_state;
LinkAddressState address_state;
unsigned address_messages;
unsigned address_label_messages;
@ -183,12 +185,6 @@ int link_stop_clients(Link *link, bool may_keep_dhcp);
const char* link_state_to_string(LinkState s) _const_;
LinkState link_state_from_string(const char *s) _pure_;
extern const sd_bus_vtable link_vtable[];
int link_node_enumerator(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error);
int link_object_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error);
int link_send_changed(Link *link, const char *property, ...) _sentinel_;
uint32_t link_get_vrf_table(Link *link);
uint32_t link_get_dhcp_route_table(Link *link);
uint32_t link_get_ipv6_accept_ra_route_table(Link *link);

View File

@ -2,32 +2,30 @@
#include "alloc-util.h"
#include "bus-util.h"
#include "networkd-link-bus.h"
#include "networkd-manager.h"
#include "strv.h"
static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_operational_state, link_operstate, LinkOperationalState);
const sd_bus_vtable manager_vtable[] = {
SD_BUS_VTABLE_START(0),
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_VTABLE_END
};
int manager_send_changed(Manager *manager, const char *property, ...) {
char **l;
int manager_send_changed_strv(Manager *manager, char **properties) {
assert(manager);
assert(properties);
if (!manager->bus)
return 0; /* replace by assert when we have kdbus */
l = strv_from_stdarg_alloca(property);
return 0;
return sd_bus_emit_properties_changed_strv(
manager->bus,
"/org/freedesktop/network1",
"org.freedesktop.network1.Manager",
l);
properties);
}

View File

@ -21,6 +21,7 @@
#include "local-addresses.h"
#include "netlink-util.h"
#include "network-internal.h"
#include "networkd-link-bus.h"
#include "networkd-manager.h"
#include "networkd-speed-meter.h"
#include "ordered-set.h"
@ -1105,9 +1106,12 @@ static int manager_save(Manager *m) {
Link *link;
Iterator i;
_cleanup_free_ char *temp_path = NULL;
_cleanup_strv_free_ char **p = NULL;
_cleanup_fclose_ FILE *f = NULL;
LinkOperationalState operstate = LINK_OPERSTATE_OFF;
const char *operstate_str;
LinkCarrierState carrier_state = LINK_CARRIER_STATE_OFF;
LinkAddressState address_state = LINK_ADDRESS_STATE_OFF;
const char *operstate_str, *carrier_state_str, *address_state_str;
int r;
assert(m);
@ -1137,6 +1141,12 @@ static int manager_save(Manager *m) {
if (link->operstate > operstate)
operstate = link->operstate;
if (link->carrier_state > carrier_state)
carrier_state = link->carrier_state;
if (link->address_state > address_state)
address_state = link->address_state;
if (!link->network)
continue;
@ -1208,9 +1218,18 @@ static int manager_save(Manager *m) {
}
}
if (carrier_state >= LINK_CARRIER_STATE_ENSLAVED)
carrier_state = LINK_CARRIER_STATE_CARRIER;
operstate_str = link_operstate_to_string(operstate);
assert(operstate_str);
carrier_state_str = link_carrier_state_to_string(carrier_state);
assert(carrier_state_str);
address_state_str = link_address_state_to_string(address_state);
assert(address_state_str);
r = fopen_temporary(m->state_file, &f, &temp_path);
if (r < 0)
return r;
@ -1219,7 +1238,10 @@ static int manager_save(Manager *m) {
fprintf(f,
"# This is private data. Do not parse.\n"
"OPER_STATE=%s\n", operstate_str);
"OPER_STATE=%s\n"
"CARRIER_STATE=%s\n"
"ADDRESS_STATE=%s\n",
operstate_str, carrier_state_str, address_state_str);
ordered_set_print(f, "DNS=", dns);
ordered_set_print(f, "NTP=", ntp);
@ -1241,9 +1263,26 @@ static int manager_save(Manager *m) {
if (m->operational_state != operstate) {
m->operational_state = operstate;
r = manager_send_changed(m, "OperationalState", NULL);
if (strv_extend(&p, "OperationalState") < 0)
log_oom();
}
if (m->carrier_state != carrier_state) {
m->carrier_state = carrier_state;
if (strv_extend(&p, "CarrierState") < 0)
log_oom();
}
if (m->address_state != address_state) {
m->address_state = address_state;
if (strv_extend(&p, "AddressState") < 0)
log_oom();
}
if (p) {
r = manager_send_changed_strv(m, p);
if (r < 0)
log_error_errno(r, "Could not emit changed OperationalState: %m");
log_error_errno(r, "Could not emit changed properties: %m");
}
m->dirty = false;

View File

@ -33,6 +33,8 @@ struct Manager {
char *state_file;
LinkOperationalState operational_state;
LinkCarrierState carrier_state;
LinkAddressState address_state;
Hashmap *links;
Hashmap *netdevs;
@ -83,7 +85,7 @@ int manager_rtnl_process_address(sd_netlink *nl, sd_netlink_message *message, vo
int manager_rtnl_process_route(sd_netlink *nl, sd_netlink_message *message, void *userdata);
int manager_rtnl_process_rule(sd_netlink *nl, sd_netlink_message *message, void *userdata);
int manager_send_changed(Manager *m, const char *property, ...) _sentinel_;
int manager_send_changed_strv(Manager *m, char **properties);
void manager_dirty(Manager *m);
int manager_address_pool_acquire(Manager *m, int family, unsigned prefixlen, union in_addr_union *found);

View File

@ -5,6 +5,7 @@
#include "sd-event.h"
#include "sd-netlink.h"
#include "networkd-link-bus.h"
#include "networkd-link.h"
#include "networkd-manager.h"
#include "networkd-speed-meter.h"

View File

@ -49,6 +49,8 @@ _SD_BEGIN_DECLARATIONS;
* -ENODATA: networkd is not aware of any links
*/
int sd_network_get_operational_state(char **state);
int sd_network_get_carrier_state(char **state);
int sd_network_get_address_state(char **state);
/* Get DNS entries for all links. These are string representations of
* IP addresses */
@ -90,6 +92,8 @@ int sd_network_link_get_setup_state(int ifindex, char **state);
*/
int sd_network_link_get_operational_state(int ifindex, char **state);
int sd_network_link_get_required_operstate_for_online(int ifindex, char **state);
int sd_network_link_get_carrier_state(int ifindex, char **state);
int sd_network_link_get_address_state(int ifindex, char **state);
/* Indicates whether the network is relevant to being online.
* Possible return codes: