summaryrefslogtreecommitdiff
path: root/src/network/networkd-link.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/network/networkd-link.c')
-rw-r--r--src/network/networkd-link.c100
1 files changed, 61 insertions, 39 deletions
diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c
index 56e36b7d6b..46ebc2b597 100644
--- a/src/network/networkd-link.c
+++ b/src/network/networkd-link.c
@@ -360,63 +360,85 @@ 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;
+ uint8_t scope = RT_SCOPE_NOWHERE;
+ 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;
+
+ link->carrier_state = carrier_state;
+ link->address_state = address_state;
+
if (link->operstate != operstate) {
link->operstate = operstate;
link_send_changed(link, "OperationalState", NULL);