The protodown functionality allows user space to turn off the carrier of a net device: # ip link add name dummy1 up type dummy # ip link add name macvlan1 up link dummy1 type macvlan mode bridge # ip link set dev macvlan1 protodown on $ ip -br link show dev macvlan1 macvlan1@dummy1 DOWN 0a:5c:a3:05:c7:86 Different applications can set different protodown reasons, which prevents an application from turning on the carrier of a net device as long as others want it down: # ip link set dev macvlan1 protodown_reason 1 on # ip link set dev macvlan1 protodown_reason 2 on # ip link set dev macvlan1 protodown off Error: Cannot clear protodown, active reasons. # ip link set dev macvlan1 protodown_reason 2 off # ip link set dev macvlan1 protodown off Error: Cannot clear protodown, active reasons. # ip link set dev macvlan1 protodown_reason 1 off # ip link set dev macvlan1 protodown off $ ip -br link show dev macvlan1 macvlan1@dummy1 UP 0a:5c:a3:05:c7:86 Unfortunately, this mechanism is not very useful when the carrier of a net device can be toggled by toggling the carrier of its lower device: # ip link set dev macvlan1 protodown on $ ip -br link show dev macvlan1 macvlan1@dummy1 DOWN 0a:5c:a3:05:c7:86 # ip link set dev dummy1 carrier off # ip link set dev dummy1 carrier on $ ip -br link show dev macvlan1 macvlan1@dummy1 UP 0a:5c:a3:05:c7:86 Obviously, this is not the intended behavior and it is unlikely to be relied on by anyone. In fact, it is a problem for applications like FRR that use protodown with macvlan on top of a bridge as part of Virtual Router Redundancy Protocol (VRRP). Solve this by preventing a net device configured with protodown on from inheriting the operational state of its lower device. Note that READ_ONCE() is not needed as RTNL is held. Output with the patch: # ip link add name dummy1 up type dummy # ip link add name macvlan1 up link dummy1 type macvlan mode bridge # ip link set dev macvlan1 protodown on $ ip -br link show dev macvlan1 macvlan1@dummy1 DOWN 0a:5c:a3:05:c7:86 # ip link set dev dummy1 carrier off # ip link set dev dummy1 carrier on $ ip -br link show dev macvlan1 macvlan1@dummy1 DOWN 0a:5c:a3:05:c7:86 # ip link set dev macvlan1 protodown off $ ip -br link show dev macvlan1 macvlan1@dummy1 UP 0a:5c:a3:05:c7:86 Signed-off-by: Ido Schimmel --- net/core/dev.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/net/core/dev.c b/net/core/dev.c index 06c195906231..bfb0f297b234 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -11113,6 +11113,9 @@ EXPORT_SYMBOL(netdev_change_features); void netif_stacked_transfer_operstate(const struct net_device *rootdev, struct net_device *dev) { + if (dev->proto_down) + return; + if (rootdev->operstate == IF_OPER_DORMANT) netif_dormant_on(dev); else -- 2.54.0