diff mbox series

[net,2/3] macvlan: fix NETDEV_UP/NETDEV_DOWN event handling

Message ID 20250403085857.17868-3-liuhangbin@gmail.com (mailing list archive)
State New
Headers show
Series fix ipvlan/macvlan link event handing | expand

Commit Message

Hangbin Liu April 3, 2025, 8:58 a.m. UTC
Setting the link down does not necessarily change the carrier state for
virtual interfaces like bonding. Therefore, handling the device up/down
event via netif_stacked_transfer_operstate() is not sufficient.

If the lower link and macvlan are in different namespaces, the upper link
state may become out of sync. Fix this by updating the handling logic to be
similar to VLAN.

Fixes: de7d244d0a35 ("macvlan: make operstate and carrier more accurate")
Fixes: 80fd2d6ca546 ("macvlan: Change status when lower device goes down")
Signed-off-by: Hangbin Liu <liuhangbin@gmail.com>
---
 drivers/net/macvlan.c | 20 ++++++++++++++++++++
 1 file changed, 20 insertions(+)
diff mbox series

Patch

diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c
index d0dfa6bca6cc..f254cda14dac 100644
--- a/drivers/net/macvlan.c
+++ b/drivers/net/macvlan.c
@@ -1781,10 +1781,12 @@  static void update_port_bc_queue_len(struct macvlan_port *port)
 static int macvlan_device_event(struct notifier_block *unused,
 				unsigned long event, void *ptr)
 {
+	struct netlink_ext_ack *extack = netdev_notifier_info_to_extack(ptr);
 	struct net_device *dev = netdev_notifier_info_to_dev(ptr);
 	struct macvlan_dev *vlan, *next;
 	struct macvlan_port *port;
 	LIST_HEAD(list_kill);
+	int flags;
 
 	if (!netif_is_macvlan_port(dev))
 		return NOTIFY_DONE;
@@ -1793,7 +1795,25 @@  static int macvlan_device_event(struct notifier_block *unused,
 
 	switch (event) {
 	case NETDEV_UP:
+		list_for_each_entry(vlan, &port->vlans, list) {
+			flags = vlan->dev->flags;
+			if (flags & IFF_UP)
+				continue;
+			dev_change_flags(vlan->dev, flags | IFF_UP, extack);
+			netif_stacked_transfer_operstate(vlan->lowerdev,
+							 vlan->dev);
+		}
+		break;
 	case NETDEV_DOWN:
+		list_for_each_entry(vlan, &port->vlans, list) {
+			flags = vlan->dev->flags;
+			if (!(flags & IFF_UP))
+				continue;
+			dev_close(vlan->dev);
+			netif_stacked_transfer_operstate(vlan->lowerdev,
+							 vlan->dev);
+		}
+		break;
 	case NETDEV_CHANGE:
 		list_for_each_entry(vlan, &port->vlans, list)
 			netif_stacked_transfer_operstate(vlan->lowerdev,