Skip to content

Commit e289fd2

Browse files
dingtianhongdavem330
authored andcommitted
macvlan: fix the problem when mac address changes for passthru mode
The macvlan dev should always have the same mac address like lowerdev when in the passthru mode, change the mac address alone will break the work mechanism, so when the lowerdev or macvlan mac address changes, we should propagate the changes to another dev. v1->v2: Allow macvlan dev to change mac address for passthru mode and propagate to lowerdev. v2->v3: Don't set the mac address to the lower dev's unicast address for passthru mode when mac address changes. Signed-off-by: Ding Tianhong <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent d7ec858 commit e289fd2

File tree

1 file changed

+38
-12
lines changed

1 file changed

+38
-12
lines changed

drivers/net/macvlan.c

Lines changed: 38 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -494,35 +494,49 @@ static int macvlan_stop(struct net_device *dev)
494494
return 0;
495495
}
496496

497-
static int macvlan_set_mac_address(struct net_device *dev, void *p)
497+
static int macvlan_sync_address(struct net_device *dev, unsigned char *addr)
498498
{
499499
struct macvlan_dev *vlan = netdev_priv(dev);
500500
struct net_device *lowerdev = vlan->lowerdev;
501-
struct sockaddr *addr = p;
502501
int err;
503502

504-
if (!is_valid_ether_addr(addr->sa_data))
505-
return -EADDRNOTAVAIL;
506-
507503
if (!(dev->flags & IFF_UP)) {
508504
/* Just copy in the new address */
509-
memcpy(dev->dev_addr, addr->sa_data, ETH_ALEN);
505+
ether_addr_copy(dev->dev_addr, addr);
510506
} else {
511507
/* Rehash and update the device filters */
512-
if (macvlan_addr_busy(vlan->port, addr->sa_data))
508+
if (macvlan_addr_busy(vlan->port, addr))
513509
return -EBUSY;
514510

515-
err = dev_uc_add(lowerdev, addr->sa_data);
516-
if (err)
517-
return err;
511+
if (!vlan->port->passthru) {
512+
err = dev_uc_add(lowerdev, addr);
513+
if (err)
514+
return err;
518515

519-
dev_uc_del(lowerdev, dev->dev_addr);
516+
dev_uc_del(lowerdev, dev->dev_addr);
517+
}
520518

521-
macvlan_hash_change_addr(vlan, addr->sa_data);
519+
macvlan_hash_change_addr(vlan, addr);
522520
}
523521
return 0;
524522
}
525523

524+
static int macvlan_set_mac_address(struct net_device *dev, void *p)
525+
{
526+
struct macvlan_dev *vlan = netdev_priv(dev);
527+
struct sockaddr *addr = p;
528+
529+
if (!is_valid_ether_addr(addr->sa_data))
530+
return -EADDRNOTAVAIL;
531+
532+
if (vlan->mode == MACVLAN_MODE_PASSTHRU) {
533+
dev_set_mac_address(vlan->lowerdev, addr);
534+
return 0;
535+
}
536+
537+
return macvlan_sync_address(dev, addr->sa_data);
538+
}
539+
526540
static void macvlan_change_rx_flags(struct net_device *dev, int change)
527541
{
528542
struct macvlan_dev *vlan = netdev_priv(dev);
@@ -1105,6 +1119,18 @@ static int macvlan_device_event(struct notifier_block *unused,
11051119
continue;
11061120
dev_set_mtu(vlan->dev, dev->mtu);
11071121
}
1122+
break;
1123+
case NETDEV_CHANGEADDR:
1124+
if (!port->passthru)
1125+
return NOTIFY_DONE;
1126+
1127+
vlan = list_first_entry_or_null(&port->vlans,
1128+
struct macvlan_dev,
1129+
list);
1130+
1131+
if (macvlan_sync_address(vlan->dev, dev->dev_addr))
1132+
return NOTIFY_BAD;
1133+
11081134
break;
11091135
case NETDEV_UNREGISTER:
11101136
/* twiddle thumbs on netns device moves */

0 commit comments

Comments
 (0)