diff --git a/man/networkctl.xml b/man/networkctl.xml
index 497d88a15f8..7d461786d75 100644
--- a/man/networkctl.xml
+++ b/man/networkctl.xml
@@ -96,8 +96,7 @@
degraded-carrier
- for bond or bridge master, one of the bonding or bridge slave network interfaces is
- in off, no-carrier, or dormant state
+ one of the bonding or bridge slave network interfaces is in off, no-carrier, or dormant state, and the master interface has no address.
@@ -110,7 +109,9 @@
degraded
- the link has carrier and addresses valid on the local link configured
+ the link has carrier and addresses valid on the local link configured. For bond or
+ bridge master this means that not all slave network interfaces have carrier but at least
+ one does.
@@ -122,7 +123,8 @@
routable
- the link has carrier and routable address configured
+ the link has carrier and routable address configured. For bond or bridge master it is
+ not necessary for all slave network interfaces to have carrier, but at least one must.
diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c
index d16090dbcd2..62dd892afaa 100644
--- a/src/network/networkd-link.c
+++ b/src/network/networkd-link.c
@@ -1775,11 +1775,15 @@ void link_update_operstate(Link *link, bool also_update_master) {
* | 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
+ * address_state degraded | off | no-carrier | dormant | degraded | degraded | enslaved
+ * routable | off | no-carrier | dormant | routable | routable | routable
*/
- if (carrier_state < LINK_CARRIER_STATE_CARRIER || address_state == LINK_ADDRESS_STATE_OFF)
+ if (carrier_state == LINK_CARRIER_STATE_DEGRADED_CARRIER && address_state == LINK_ADDRESS_STATE_ROUTABLE)
+ operstate = LINK_OPERSTATE_ROUTABLE;
+ else if (carrier_state == LINK_CARRIER_STATE_DEGRADED_CARRIER && address_state == LINK_ADDRESS_STATE_DEGRADED)
+ operstate = LINK_OPERSTATE_DEGRADED;
+ else 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;
diff --git a/test/test-network/systemd-networkd-tests.py b/test/test-network/systemd-networkd-tests.py
index 5658433bca8..b5ef83a9c08 100755
--- a/test/test-network/systemd-networkd-tests.py
+++ b/test/test-network/systemd-networkd-tests.py
@@ -3950,7 +3950,7 @@ class NetworkdBondTests(unittest.TestCase, Utilities):
self.wait_operstate('dummy98', 'off')
self.wait_operstate('test1', 'enslaved')
- self.wait_operstate('bond99', 'degraded-carrier')
+ self.wait_operstate('bond99', 'routable')
check_output('ip link set dummy98 up')
@@ -4121,7 +4121,7 @@ class NetworkdBridgeTests(unittest.TestCase, Utilities):
self.assertRegex(output, 'ff00::/8 table local (proto kernel )?metric 256 (linkdown )?pref medium')
remove_link('test1')
- self.wait_operstate('bridge99', 'degraded-carrier')
+ self.wait_operstate('bridge99', 'routable')
output = check_output('ip -d link show bridge99')
print(output)