aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/macvlan.c
diff options
context:
space:
mode:
authordingtianhong <dingtianhong@huawei.com>2014-05-30 02:32:49 -0400
committerDavid S. Miller <davem@davemloft.net>2014-06-02 18:57:34 -0400
commite289fd28176b78de7e54bf6c8e2b558afefaf6df (patch)
treeadccd7d6821425bdb7aae3662b0444161bc9b885 /drivers/net/macvlan.c
parentd7ec858413612ebb53c539541d6a0c7927db0bcd (diff)
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 <dingtianhong@huawei.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/macvlan.c')
-rw-r--r--drivers/net/macvlan.c50
1 files changed, 38 insertions, 12 deletions
diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c
index a665e902b989..d2dbcfc68ee4 100644
--- a/drivers/net/macvlan.c
+++ b/drivers/net/macvlan.c
@@ -494,35 +494,49 @@ hash_del:
494 return 0; 494 return 0;
495} 495}
496 496
497static int macvlan_set_mac_address(struct net_device *dev, void *p) 497static int macvlan_sync_address(struct net_device *dev, unsigned char *addr)
498{ 498{
499 struct macvlan_dev *vlan = netdev_priv(dev); 499 struct macvlan_dev *vlan = netdev_priv(dev);
500 struct net_device *lowerdev = vlan->lowerdev; 500 struct net_device *lowerdev = vlan->lowerdev;
501 struct sockaddr *addr = p;
502 int err; 501 int err;
503 502
504 if (!is_valid_ether_addr(addr->sa_data))
505 return -EADDRNOTAVAIL;
506
507 if (!(dev->flags & IFF_UP)) { 503 if (!(dev->flags & IFF_UP)) {
508 /* Just copy in the new address */ 504 /* Just copy in the new address */
509 memcpy(dev->dev_addr, addr->sa_data, ETH_ALEN); 505 ether_addr_copy(dev->dev_addr, addr);
510 } else { 506 } else {
511 /* Rehash and update the device filters */ 507 /* Rehash and update the device filters */
512 if (macvlan_addr_busy(vlan->port, addr->sa_data)) 508 if (macvlan_addr_busy(vlan->port, addr))
513 return -EBUSY; 509 return -EBUSY;
514 510
515 err = dev_uc_add(lowerdev, addr->sa_data); 511 if (!vlan->port->passthru) {
516 if (err) 512 err = dev_uc_add(lowerdev, addr);
517 return err; 513 if (err)
514 return err;
518 515
519 dev_uc_del(lowerdev, dev->dev_addr); 516 dev_uc_del(lowerdev, dev->dev_addr);
517 }
520 518
521 macvlan_hash_change_addr(vlan, addr->sa_data); 519 macvlan_hash_change_addr(vlan, addr);
522 } 520 }
523 return 0; 521 return 0;
524} 522}
525 523
524static 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
526static void macvlan_change_rx_flags(struct net_device *dev, int change) 540static void macvlan_change_rx_flags(struct net_device *dev, int change)
527{ 541{
528 struct macvlan_dev *vlan = netdev_priv(dev); 542 struct macvlan_dev *vlan = netdev_priv(dev);
@@ -1106,6 +1120,18 @@ static int macvlan_device_event(struct notifier_block *unused,
1106 dev_set_mtu(vlan->dev, dev->mtu); 1120 dev_set_mtu(vlan->dev, dev->mtu);
1107 } 1121 }
1108 break; 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
1134 break;
1109 case NETDEV_UNREGISTER: 1135 case NETDEV_UNREGISTER:
1110 /* twiddle thumbs on netns device moves */ 1136 /* twiddle thumbs on netns device moves */
1111 if (dev->reg_state != NETREG_UNREGISTERING) 1137 if (dev->reg_state != NETREG_UNREGISTERING)