From patchwork Fri Jun 16 13:36:49 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Vladislav Yasevich X-Patchwork-Id: 776748 X-Patchwork-Delegate: davem@davemloft.net Return-Path: X-Original-To: patchwork-incoming@ozlabs.org Delivered-To: patchwork-incoming@ozlabs.org Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 3wq1d05sKpz9s7M for ; Fri, 16 Jun 2017 23:37:08 +1000 (AEST) Authentication-Results: ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b="S/5VLaiw"; dkim-atps=neutral Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753806AbdFPNhH (ORCPT ); Fri, 16 Jun 2017 09:37:07 -0400 Received: from mail-qt0-f196.google.com ([209.85.216.196]:36304 "EHLO mail-qt0-f196.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753767AbdFPNhD (ORCPT ); Fri, 16 Jun 2017 09:37:03 -0400 Received: by mail-qt0-f196.google.com with SMTP id s33so10245499qtg.3 for ; Fri, 16 Jun 2017 06:37:03 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=tA4thsPhMWYC0kMG/SHmBwGRPCx2D43+mHNEv5ZovME=; b=S/5VLaiw3e8lrr4Jo/qczlGKKXWVV2Utq8E6Eng6Kc5WAVSh8Wqf5Kqxl11xiZzKmC dSrnrlvJ1DksLfH7RxdwvlxrXBYopKAsSK+D/9R4ctClfn15vNfyqfbCYm1Xv/8fHFvQ Hr4D+wGYlLlhTw8Yz4m1+/dnx9aXMO3h1i1cLePOODSNG8ABw/zo04bX0EtuECFwoA45 ZIL5xmWcMCfvJXdgpACjxMr2HtFwgmK/Uu36uRpOqSegD48DqRh9ClJZkiy+0a0koJ7j zuQfUCjvrcbH+BzumpECuc0sNUMF37W/y36Gxf20+bgVSJ+I1V9PSNSrZd+OdOUxQm9j ab9A== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=tA4thsPhMWYC0kMG/SHmBwGRPCx2D43+mHNEv5ZovME=; b=C6oVi5DJEcWe/c6F5VLR8WNsm/fxi+0AIY/LTdZAdLz0KRqjzb5cQSKIWh6r49VxlM TWPaClrg2K95zUfOluMOUPnKD105qCGP6vtPh0ZZjF8faWYyJyjjbsZivCPOLOzydPwg hwiywv2liaaEeGxG6oBnB4gzDJR6gcj06eCNfZMyqzb6NRpM6MSWXmlQXZhFbgbJRc5J vZLC2WL3juxVo2vGCU27B9kQuv5p1lyaByplptoEXIXUB7HyppDE51Y0DtSSMvLjQppK NjrLJi7Y3FJ6kYFd+5g53N1XqN+88o+MLKthP7MWzTBcBgB6Fz1uXBE9eoHLu7/Q2hIQ Bq7w== X-Gm-Message-State: AKS2vOyRzHP2gGAI9HiUSjBo5087BRE/6m0gC55oed5kWVdQ430TCHEJ SQFDDOKFuG/8V6WJ X-Received: by 10.55.27.96 with SMTP id b93mr12223445qkb.235.1497620222501; Fri, 16 Jun 2017 06:37:02 -0700 (PDT) Received: from flash.redhat.com (c-75-68-54-224.hsd1.nh.comcast.net. [75.68.54.224]) by smtp.gmail.com with ESMTPSA id i28sm1647889qta.52.2017.06.16.06.37.01 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Fri, 16 Jun 2017 06:37:01 -0700 (PDT) From: Vladislav Yasevich X-Google-Original-From: Vladislav Yasevich To: netdev@vger.kernel.org Cc: Vladislav Yasevich Subject: [PATCH net 4/4] macvlan: Let passthru macvlan correctly restore lower mac address Date: Fri, 16 Jun 2017 09:36:49 -0400 Message-Id: <20170616133649.24622-5-vyasevic@redhat.com> X-Mailer: git-send-email 2.9.4 In-Reply-To: <20170616133649.24622-1-vyasevic@redhat.com> References: <20170616133649.24622-1-vyasevic@redhat.com> Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org 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 changes done directly to the lower device mac address will be kept. Signed-off-by: Vladislav Yasevich --- drivers/net/macvlan.c | 47 ++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 44 insertions(+), 3 deletions(-) diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c index eb956ff..c551165 100644 --- a/drivers/net/macvlan.c +++ b/drivers/net/macvlan.c @@ -40,6 +40,7 @@ #define MACVLAN_BC_QUEUE_LEN 1000 #define MACVLAN_F_PASSTHRU 1 +#define MACVLAN_F_ADDRCHANGE 2 struct macvlan_port { struct net_device *dev; @@ -51,6 +52,7 @@ struct macvlan_port { int count; struct hlist_head vlan_source_hash[MACVLAN_HASH_SIZE]; DECLARE_BITMAP(mc_filter, MACVLAN_MC_FILTER_SZ); + unsigned char perm_addr[ETH_ALEN]; }; struct macvlan_source_entry { @@ -78,6 +80,21 @@ static inline void macvlan_set_passthru(struct macvlan_port *port) port->flags |= MACVLAN_F_PASSTHRU; } +static inline bool macvlan_addr_change(const struct macvlan_port *port) +{ + return port->flags & MACVLAN_F_ADDRCHANGE; +} + +static inline void macvlan_set_addr_change(struct macvlan_port *port) +{ + port->flags |= MACVLAN_F_ADDRCHANGE; +} + +static inline void macvlan_clear_addr_change(struct macvlan_port *port) +{ + port->flags &= ~MACVLAN_F_ADDRCHANGE; +} + /* Hash Ethernet address */ static u32 macvlan_eth_hash(const unsigned char *addr) { @@ -193,11 +210,11 @@ static void macvlan_hash_change_addr(struct macvlan_dev *vlan, static bool macvlan_addr_busy(const struct macvlan_port *port, const unsigned char *addr) { - /* Test to see if the specified multicast address is + /* Test to see if the specified address is * currently in use by the underlying device or * another macvlan. */ - if (!macvlan_passthru(port) && + if (!macvlan_passthru(port) && !macvlan_addr_change(port) && ether_addr_equal_64bits(port->dev->dev_addr, addr)) return true; @@ -685,6 +702,7 @@ static int macvlan_sync_address(struct net_device *dev, unsigned char *addr) { struct macvlan_dev *vlan = netdev_priv(dev); struct net_device *lowerdev = vlan->lowerdev; + struct macvlan_port *port = vlan->port; int err; if (!(dev->flags & IFF_UP)) { @@ -695,7 +713,7 @@ static int macvlan_sync_address(struct net_device *dev, unsigned char *addr) if (macvlan_addr_busy(vlan->port, addr)) return -EBUSY; - if (!macvlan_passthru(vlan->port)) { + if (!macvlan_passthru(port)) { err = dev_uc_add(lowerdev, addr); if (err) return err; @@ -705,6 +723,15 @@ static int macvlan_sync_address(struct net_device *dev, unsigned char *addr) macvlan_hash_change_addr(vlan, addr); } + if (macvlan_passthru(port) && !macvlan_addr_change(port)) { + /* Since addr_change isn't set, we are here due to lower + * device change. Save the lower-dev address so we can + * restore it later. + */ + ether_addr_copy(vlan->port->perm_addr, + dev->dev_addr); + } + macvlan_clear_addr_change(port); return 0; } @@ -721,6 +748,7 @@ static int macvlan_set_mac_address(struct net_device *dev, void *p) return 0; if (vlan->mode == MACVLAN_MODE_PASSTHRU) { + macvlan_set_addr_change(vlan->port); dev_set_mac_address(vlan->lowerdev, addr); return 0; } @@ -1138,6 +1166,7 @@ static int macvlan_port_create(struct net_device *dev) return -ENOMEM; port->dev = dev; + ether_addr_copy(port->perm_addr, dev->dev_addr); INIT_LIST_HEAD(&port->vlans); for (i = 0; i < MACVLAN_HASH_SIZE; i++) INIT_HLIST_HEAD(&port->vlan_hash[i]); @@ -1177,6 +1206,18 @@ static void macvlan_port_destroy(struct net_device *dev) kfree_skb(skb); } + /* If the lower device address has been changed by passthru + * macvlan, put it back. + */ + if (macvlan_passthru(port) && + !ether_addr_equal(port->dev->dev_addr, port->perm_addr)) { + struct sockaddr sa; + + sa.sa_family = port->dev->type; + memcpy(&sa.sa_data, port->perm_addr, port->dev->addr_len); + dev_set_mac_address(port->dev, &sa); + } + kfree(port); }