From patchwork Tue Oct 16 18:20:32 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ivan Khoronzhuk X-Patchwork-Id: 148982 Delivered-To: patch@linaro.org Received: by 2002:a2e:8595:0:0:0:0:0 with SMTP id b21-v6csp5435509lji; Tue, 16 Oct 2018 11:21:13 -0700 (PDT) X-Google-Smtp-Source: ACcGV62UiNs+fX9JDYoPoaGQMVB5qcqRDUdYVVEAwJTlAyv3uI+bcOyglgJl4Lp5PwvapiKOvNia X-Received: by 2002:a63:3c46:: with SMTP id i6-v6mr21048013pgn.286.1539714073282; Tue, 16 Oct 2018 11:21:13 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1539714073; cv=none; d=google.com; s=arc-20160816; b=wFXkfBd8SZy+6zFDR2MZvK6qqiQ5PgRNIYgSFo8N2cjU2l7iWMR4hUfvl1h8BIYwlQ VVpdZFigL1wKYMHngnMtbfYIgp44SUjAj2J7HwzH3XVgYhBgIUbZ9JWZ0ouaWuwuO74Q WSSzqnRBCVIrkDYgrpAyO38lriJRJlzzVskeLndak55f3yzPn0zqSd0NEjrk1SZcqJAH hWtucxrgqhY2y8df8v7V0y5B+mnTGhNpRVwkVb0m3fUK5daSi22aOnW8njIGeg0xVCnL Ku+pRpS9FGACXsIX2Q+MAcIFz/F2y+5AQrl1O8S1nx3RIFkYsAyFsNFlfpxt40RRbox+ YuOQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:references:in-reply-to:message-id:date :subject:cc:to:from:dkim-signature; bh=UY3go5N1XkoYGbYQ+I2v/woXzZQofslDCysYUjuM+2c=; b=deda4KbPNp2GsQbjhEJKnV9k/0nQIZZSFc/Hc7AAKmaFbh24tJVRBeafFIYre/TKgy QL8nGO9Yc2iagoLQmA7OMSokb8VuNtsJl8c/ZvxKUa220hhf3SOm5BzS2r/EG4xj5wi/ bB7cd4O+BV97B83OBJEO73WpVsJ2gX8lzeeqoCIs5HN+ofdS2v80mdPKZVU8hiza23BE 2dWYGs33VtnHPzqvmHj8ALpmDfhJ5mU7yC0tTKcUAQ8hmhRH751BY7gFgEmxqfZcdlYk rHGHdDdvD2Q7PTk/S1GcwVtFWyTae95VkslDkspYkZiZWd9QzxL+SKuHJC3AB/RDNnFB UvJQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=dJH8U1PJ; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id a127-v6si15813314pfb.24.2018.10.16.11.21.12; Tue, 16 Oct 2018 11:21:13 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=dJH8U1PJ; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727703AbeJQCMw (ORCPT + 32 others); Tue, 16 Oct 2018 22:12:52 -0400 Received: from mail-lf1-f68.google.com ([209.85.167.68]:43387 "EHLO mail-lf1-f68.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727348AbeJQCMW (ORCPT ); Tue, 16 Oct 2018 22:12:22 -0400 Received: by mail-lf1-f68.google.com with SMTP id p34-v6so17729167lfg.10 for ; Tue, 16 Oct 2018 11:20:40 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=UY3go5N1XkoYGbYQ+I2v/woXzZQofslDCysYUjuM+2c=; b=dJH8U1PJ/BNay3RDFioWP26l0qJrNM9u6DCNd1A5aZhrVn5sRESYG4A9S8nG4bHRmR dTGIx9Pt0AEHZ1awjb/erEJo9BxfvPZN/oOY1iAgiFZSYLLkEe2S6Ey+YUFWlNpcsZpC zL8a95KcAvI9rathAbiZ9TYbzYnA5ZCn0CMPI= 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=UY3go5N1XkoYGbYQ+I2v/woXzZQofslDCysYUjuM+2c=; b=AoOIdz+TXuaULTG4b2wS2ZPnJhUs8XpInCmfk+tWbQiTn9PapN1cFRpHpLTpGnSX0x 3RSqgYHYxfSBu6GkXc4eLdd0ISKu6pQoEjgPRqfGVcyhC2KbwhAE3IHhZ9MSTfv/OIL9 VQ742lwpieLT16ee/IcrPzFlpmznWKaHgUGIO2ntd8kmg+cV9e6iRW57UO9JcgykPs8y YbEOv6tLf4REy8YhomjTXqQh3bIrq1sL4oOyFwjUVq+33cpFmXf+vLv+A0Imyqlt+lkm JQIzK7ZHI30lKDklyISa5gEIu3Fgtc7TTcOzbLfwAIaZ3n9t24TCgcioPzbw7zpFlSvi RJnA== X-Gm-Message-State: ABuFfohIlIFPLDhP1dBkameAf3+xHCOb9MHsEEkU2HUA4pUsYBSMfLzr xvKCBv1Y4ifUsw7iu0/AAq275Q== X-Received: by 2002:a19:db84:: with SMTP id t4-v6mr7532859lfi.74.1539714039774; Tue, 16 Oct 2018 11:20:39 -0700 (PDT) Received: from localhost.localdomain (59-201-94-178.pool.ukrtel.net. [178.94.201.59]) by smtp.gmail.com with ESMTPSA id i27-v6sm3207844lfc.22.2018.10.16.11.20.38 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Tue, 16 Oct 2018 11:20:38 -0700 (PDT) From: Ivan Khoronzhuk To: grygorii.strashko@ti.com, davem@davemloft.net Cc: linux-omap@vger.kernel.org, netdev@vger.kernel.org, linux-kernel@vger.kernel.org, alexander.h.duyck@intel.com, Ivan Khoronzhuk Subject: [RFC PATCH net-next 1/4] net: core: dev_addr_lists: add auxiliary func to handle reference address updates Date: Tue, 16 Oct 2018 21:20:32 +0300 Message-Id: <20181016182035.18234-2-ivan.khoronzhuk@linaro.org> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20181016182035.18234-1-ivan.khoronzhuk@linaro.org> References: <20181016182035.18234-1-ivan.khoronzhuk@linaro.org> Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org In order to avoid all table update, and only remove or add new address, the auxiliary function exists, named __hw_addr_sync_dev(). It allows end driver do nothing when nothing changed and add/rm when concrete address is firstly added or lastly removed. But it doesn't include cases when an address of real device or vlan was reused by other vlans or vlan/macval devices. For handaling events when address was reused/unreused the patch adds new auxiliary routine - __hw_addr_ref_sync_dev(). It allows to do nothing when nothing was changed and do updates only for an address being added/reused/deleted/unreused. Thus, clone address changes for vlans can be mirrored in the table. The function is exclusive with __hw_addr_sync_dev(). It's responsibility of the end driver to identify address vlan device, if it needs so. Signed-off-by: Ivan Khoronzhuk --- include/linux/netdevice.h | 10 ++++ net/core/dev_addr_lists.c | 97 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 107 insertions(+) -- 2.17.1 diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index dc1d9ed33b31..de95f96a6352 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -4048,6 +4048,16 @@ int __hw_addr_sync_dev(struct netdev_hw_addr_list *list, int (*sync)(struct net_device *, const unsigned char *), int (*unsync)(struct net_device *, const unsigned char *)); +int __hw_addr_ref_sync_dev(struct netdev_hw_addr_list *list, + struct net_device *dev, + int (*sync)(struct net_device *, + const unsigned char *, int), + int (*unsync)(struct net_device *, + const unsigned char *, int)); +void __hw_addr_ref_unsync_dev(struct netdev_hw_addr_list *list, + struct net_device *dev, + int (*unsync)(struct net_device *, + const unsigned char *, int)); void __hw_addr_unsync_dev(struct netdev_hw_addr_list *list, struct net_device *dev, int (*unsync)(struct net_device *, diff --git a/net/core/dev_addr_lists.c b/net/core/dev_addr_lists.c index d884d8f5f0e5..1385d75fe5ea 100644 --- a/net/core/dev_addr_lists.c +++ b/net/core/dev_addr_lists.c @@ -277,6 +277,103 @@ int __hw_addr_sync_dev(struct netdev_hw_addr_list *list, } EXPORT_SYMBOL(__hw_addr_sync_dev); +/** + * __hw_addr_ref_sync_dev - Synchronize device's multicast address list taking + * into account references + * @list: address list to synchronize + * @dev: device to sync + * @sync: function to call if address or reference on it should be added + * @unsync: function to call if address or some reference on it should removed + * + * This function is intended to be called from the ndo_set_rx_mode + * function of devices that require explicit address or references on it + * add/remove notifications. The unsync function may be NULL in which case + * the addresses or references on it requiring removal will simply be + * removed without any notification to the device. That is responsibility of + * the driver to identify and distribute address or references on it between + * internal address tables. + **/ +int __hw_addr_ref_sync_dev(struct netdev_hw_addr_list *list, + struct net_device *dev, + int (*sync)(struct net_device *, + const unsigned char *, int), + int (*unsync)(struct net_device *, + const unsigned char *, int)) +{ + struct netdev_hw_addr *ha, *tmp; + int err, keep_sync; + + /* first go through and flush out any unsynced/stale entries */ + list_for_each_entry_safe(ha, tmp, &list->list, list) { + /* sync if address is not used */ + if ((ha->sync_cnt << 1) <= ha->refcount) + continue; + + /* if fails defer unsyncing address */ + keep_sync = ha->refcount - ha->sync_cnt; + if (unsync && unsync(dev, ha->addr, keep_sync)) + continue; + + ha->refcount = (keep_sync << 1) + 1; + ha->sync_cnt = keep_sync; + __hw_addr_del_entry(list, ha, false, false); + } + + /* go through and sync updated/new entries to the list */ + list_for_each_entry_safe(ha, tmp, &list->list, list) { + /* sync if address added or reused */ + if ((ha->sync_cnt << 1) >= ha->refcount) + continue; + + keep_sync = ha->refcount - ha->sync_cnt; + err = sync(dev, ha->addr, keep_sync); + if (err) + return err; + + ha->refcount = keep_sync << 1; + ha->sync_cnt = keep_sync; + } + + return 0; +} +EXPORT_SYMBOL(__hw_addr_ref_sync_dev); + +/** + * __hw_addr_ref_unsync_dev - Remove synchronized addresses and references on + * it from device + * @list: address list to remove synchronized addresses (references on it) from + * @dev: device to sync + * @unsync: function to call if address and references on it should be removed + * + * Remove all addresses that were added to the device by + * __hw_addr_ref_sync_dev(). This function is intended to be called from the + * ndo_stop or ndo_open functions on devices that require explicit address (or + * references on it) add/remove notifications. If the unsync function pointer + * is NULL then this function can be used to just reset the sync_cnt for the + * addresses in the list. + **/ +void __hw_addr_ref_unsync_dev(struct netdev_hw_addr_list *list, + struct net_device *dev, + int (*unsync)(struct net_device *, + const unsigned char *, int)) +{ + struct netdev_hw_addr *ha, *tmp; + + list_for_each_entry_safe(ha, tmp, &list->list, list) { + if (!ha->sync_cnt) + continue; + + /* if fails defer unsyncing address */ + if (unsync && unsync(dev, ha->addr, ha->sync_cnt)) + continue; + + ha->refcount -= ha->sync_cnt - 1; + ha->sync_cnt = 0; + __hw_addr_del_entry(list, ha, false, false); + } +} +EXPORT_SYMBOL(__hw_addr_ref_unsync_dev); + /** * __hw_addr_unsync_dev - Remove synchronized addresses from device * @list: address list to remove synchronized addresses from