aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVlad Yasevich <vyasevich@gmail.com>2017-06-21 07:59:19 -0400
committerDavid S. Miller <davem@davemloft.net>2017-06-22 11:17:42 -0400
commit18c8c54de9a619ba5533419e0170433e20c0ee3e (patch)
tree031f1ab28985f41043c067c9481c55cedac30365
parent43c2d578a0ce0d6067a02b46461811aced551425 (diff)
macvlan: Let passthru macvlan correctly restore lower mac address
Passthru macvlans directly change the mac address of the lower level device. That's OK, but after the macvlan is deleted, the lower device is left with changed address and one needs to reboot to bring back the origina HW addresses. This scenario is actually quite common with passthru macvtap devices. This patch attempts to solve this, by storing the mac address of the lower device in macvlan_port structure and keeping track of it through the changes. After this patch, any changes to the lower device mac address done trough the macvlan device, will be reverted back. Any changs done directly to the lower device mac address will be kept. Signed-off-by: Vladislav Yasevich <vyasevic@redhat.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--drivers/net/macvlan.c47
1 files changed, 44 insertions, 3 deletions
diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c
index 4d013ca79dae..72b801803aa4 100644
--- a/drivers/net/macvlan.c
+++ b/drivers/net/macvlan.c
@@ -40,6 +40,7 @@
40#define MACVLAN_BC_QUEUE_LEN 1000 40#define MACVLAN_BC_QUEUE_LEN 1000
41 41
42#define MACVLAN_F_PASSTHRU 1 42#define MACVLAN_F_PASSTHRU 1
43#define MACVLAN_F_ADDRCHANGE 2
43 44
44struct macvlan_port { 45struct macvlan_port {
45 struct net_device *dev; 46 struct net_device *dev;
@@ -51,6 +52,7 @@ struct macvlan_port {
51 int count; 52 int count;
52 struct hlist_head vlan_source_hash[MACVLAN_HASH_SIZE]; 53 struct hlist_head vlan_source_hash[MACVLAN_HASH_SIZE];
53 DECLARE_BITMAP(mc_filter, MACVLAN_MC_FILTER_SZ); 54 DECLARE_BITMAP(mc_filter, MACVLAN_MC_FILTER_SZ);
55 unsigned char perm_addr[ETH_ALEN];
54}; 56};
55 57
56struct macvlan_source_entry { 58struct macvlan_source_entry {
@@ -78,6 +80,21 @@ static inline void macvlan_set_passthru(struct macvlan_port *port)
78 port->flags |= MACVLAN_F_PASSTHRU; 80 port->flags |= MACVLAN_F_PASSTHRU;
79} 81}
80 82
83static inline bool macvlan_addr_change(const struct macvlan_port *port)
84{
85 return port->flags & MACVLAN_F_ADDRCHANGE;
86}
87
88static inline void macvlan_set_addr_change(struct macvlan_port *port)
89{
90 port->flags |= MACVLAN_F_ADDRCHANGE;
91}
92
93static inline void macvlan_clear_addr_change(struct macvlan_port *port)
94{
95 port->flags &= ~MACVLAN_F_ADDRCHANGE;
96}
97
81/* Hash Ethernet address */ 98/* Hash Ethernet address */
82static u32 macvlan_eth_hash(const unsigned char *addr) 99static u32 macvlan_eth_hash(const unsigned char *addr)
83{ 100{
@@ -193,11 +210,11 @@ static void macvlan_hash_change_addr(struct macvlan_dev *vlan,
193static bool macvlan_addr_busy(const struct macvlan_port *port, 210static bool macvlan_addr_busy(const struct macvlan_port *port,
194 const unsigned char *addr) 211 const unsigned char *addr)
195{ 212{
196 /* Test to see if the specified multicast address is 213 /* Test to see if the specified address is
197 * currently in use by the underlying device or 214 * currently in use by the underlying device or
198 * another macvlan. 215 * another macvlan.
199 */ 216 */
200 if (!macvlan_passthru(port) && 217 if (!macvlan_passthru(port) && !macvlan_addr_change(port) &&
201 ether_addr_equal_64bits(port->dev->dev_addr, addr)) 218 ether_addr_equal_64bits(port->dev->dev_addr, addr))
202 return true; 219 return true;
203 220
@@ -685,6 +702,7 @@ static int macvlan_sync_address(struct net_device *dev, unsigned char *addr)
685{ 702{
686 struct macvlan_dev *vlan = netdev_priv(dev); 703 struct macvlan_dev *vlan = netdev_priv(dev);
687 struct net_device *lowerdev = vlan->lowerdev; 704 struct net_device *lowerdev = vlan->lowerdev;
705 struct macvlan_port *port = vlan->port;
688 int err; 706 int err;
689 707
690 if (!(dev->flags & IFF_UP)) { 708 if (!(dev->flags & IFF_UP)) {
@@ -695,7 +713,7 @@ static int macvlan_sync_address(struct net_device *dev, unsigned char *addr)
695 if (macvlan_addr_busy(vlan->port, addr)) 713 if (macvlan_addr_busy(vlan->port, addr))
696 return -EBUSY; 714 return -EBUSY;
697 715
698 if (!macvlan_passthru(vlan->port)) { 716 if (!macvlan_passthru(port)) {
699 err = dev_uc_add(lowerdev, addr); 717 err = dev_uc_add(lowerdev, addr);
700 if (err) 718 if (err)
701 return err; 719 return err;
@@ -705,6 +723,15 @@ static int macvlan_sync_address(struct net_device *dev, unsigned char *addr)
705 723
706 macvlan_hash_change_addr(vlan, addr); 724 macvlan_hash_change_addr(vlan, addr);
707 } 725 }
726 if (macvlan_passthru(port) && !macvlan_addr_change(port)) {
727 /* Since addr_change isn't set, we are here due to lower
728 * device change. Save the lower-dev address so we can
729 * restore it later.
730 */
731 ether_addr_copy(vlan->port->perm_addr,
732 lowerdev->dev_addr);
733 }
734 macvlan_clear_addr_change(port);
708 return 0; 735 return 0;
709} 736}
710 737
@@ -721,6 +748,7 @@ static int macvlan_set_mac_address(struct net_device *dev, void *p)
721 return 0; 748 return 0;
722 749
723 if (vlan->mode == MACVLAN_MODE_PASSTHRU) { 750 if (vlan->mode == MACVLAN_MODE_PASSTHRU) {
751 macvlan_set_addr_change(vlan->port);
724 dev_set_mac_address(vlan->lowerdev, addr); 752 dev_set_mac_address(vlan->lowerdev, addr);
725 return 0; 753 return 0;
726 } 754 }
@@ -1138,6 +1166,7 @@ static int macvlan_port_create(struct net_device *dev)
1138 return -ENOMEM; 1166 return -ENOMEM;
1139 1167
1140 port->dev = dev; 1168 port->dev = dev;
1169 ether_addr_copy(port->perm_addr, dev->dev_addr);
1141 INIT_LIST_HEAD(&port->vlans); 1170 INIT_LIST_HEAD(&port->vlans);
1142 for (i = 0; i < MACVLAN_HASH_SIZE; i++) 1171 for (i = 0; i < MACVLAN_HASH_SIZE; i++)
1143 INIT_HLIST_HEAD(&port->vlan_hash[i]); 1172 INIT_HLIST_HEAD(&port->vlan_hash[i]);
@@ -1177,6 +1206,18 @@ static void macvlan_port_destroy(struct net_device *dev)
1177 kfree_skb(skb); 1206 kfree_skb(skb);
1178 } 1207 }
1179 1208
1209 /* If the lower device address has been changed by passthru
1210 * macvlan, put it back.
1211 */
1212 if (macvlan_passthru(port) &&
1213 !ether_addr_equal(port->dev->dev_addr, port->perm_addr)) {
1214 struct sockaddr sa;
1215
1216 sa.sa_family = port->dev->type;
1217 memcpy(&sa.sa_data, port->perm_addr, port->dev->addr_len);
1218 dev_set_mac_address(port->dev, &sa);
1219 }
1220
1180 kfree(port); 1221 kfree(port);
1181} 1222}
1182 1223