From patchwork Wed Feb 24 11:43:34 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Vladimir Oltean X-Patchwork-Id: 387608 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-15.7 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,FREEMAIL_FORGED_FROMDOMAIN,FREEMAIL_FROM, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI, SPF_HELO_NONE, SPF_PASS, URIBL_BLOCKED, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 1DFECC433DB for ; Wed, 24 Feb 2021 11:45:07 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id B92D164E90 for ; Wed, 24 Feb 2021 11:45:06 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S234997AbhBXLoz (ORCPT ); Wed, 24 Feb 2021 06:44:55 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:48242 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S233674AbhBXLoo (ORCPT ); Wed, 24 Feb 2021 06:44:44 -0500 Received: from mail-ej1-x635.google.com (mail-ej1-x635.google.com [IPv6:2a00:1450:4864:20::635]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id DA4FEC061786 for ; Wed, 24 Feb 2021 03:44:03 -0800 (PST) Received: by mail-ej1-x635.google.com with SMTP id lr13so2504178ejb.8 for ; Wed, 24 Feb 2021 03:44:03 -0800 (PST) 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 :mime-version:content-transfer-encoding; bh=39AoPWg2e/Xohh7EIpTv1jo8INkgLVqn1Wa/Oa/tSow=; b=pXE8InlNhHCx3LBMvzn/lV06dq7hx4zLaEi0a0eaObTqSGqR50HYNBV793PUJkOIjC ApoUpuoS/TYB2FSBH96TcYXjd1Zfjk/aaLf5b5eqOBS/sTsgWd2SurL5qEu842L8p3JE kLlOLkwilzoBpPFzERXtoeC5mVYvfMTwIiMg8LjRTXCY2WZyakboTt/M8JaSIMMR3Lki KUI9iOVCesivHXQN759Inr1dIMRzD57mh0ICdG1rowr9QbDlQ232OQxUCNFANJXzsVVZ NgLs2SmiiiDkEdCSBT9ag/DVDqzEOTqcFBf3MY6PMD6wnIOIhFGmxmtCwZT9K8tGjsMm nnug== 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:mime-version:content-transfer-encoding; bh=39AoPWg2e/Xohh7EIpTv1jo8INkgLVqn1Wa/Oa/tSow=; b=Nb7Z9+ymuPjb/6WW3VLg0iJpK3JCgXLNCP5tJYQYZDFswyzEIAJi9bk33ipFtfvcNI 8kPEgiEfVuw6wIaaew7Ch2KExyZ6UAhac0aIgG4AWQWNhv0/D0CoRWyzHEzfEtHEcRyc IxXNnkBDdci2+Vx0Y1VFx/sOF4N9kS7Ps/PKRxDLscdAw3xaKM8Y85waBLpLGo0gIDcu iCGAoXvL0ZFL0z/SAGFZbTmCObd6zzoeTCMmZTyWH/FdPkbmCt8IEEPKRr7ZKEevHhu3 zmLOQVJr6feQ1hs2n4pE5h0QiBm1lFX73zumnay5jqKgGq3SLALg5EU0GNMZh/VsTfiS v21Q== X-Gm-Message-State: AOAM5317jVsqcxqKATBG0kW7j58is8UL7eyxRMERypkG0Tm3csYSG7Qr o/8GpPJoX15B1Z/WgVR78XQVTeDnuI4= X-Google-Smtp-Source: ABdhPJxgncgBke+MptxEyuC8mQhnWktq4E9Mr8K1v6heyqU44xwy6OwQIc5PqZqr3RkaqOqUB1VpDg== X-Received: by 2002:a17:906:758:: with SMTP id z24mr29726775ejb.406.1614167042165; Wed, 24 Feb 2021 03:44:02 -0800 (PST) Received: from localhost.localdomain ([188.25.217.13]) by smtp.gmail.com with ESMTPSA id r5sm1203921ejx.96.2021.02.24.03.44.01 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 24 Feb 2021 03:44:01 -0800 (PST) From: Vladimir Oltean To: netdev@vger.kernel.org Cc: Andrew Lunn , Florian Fainelli , Vivien Didelot , Jiri Pirko , Ido Schimmel , DENG Qingfang , Tobias Waldekranz , George McCollister , Vlad Yasevich , Roopa Prabhu , Nikolay Aleksandrov Subject: [RFC PATCH v2 net-next 01/17] net: dsa: reference count the host mdb addresses Date: Wed, 24 Feb 2021 13:43:34 +0200 Message-Id: <20210224114350.2791260-2-olteanv@gmail.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210224114350.2791260-1-olteanv@gmail.com> References: <20210224114350.2791260-1-olteanv@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org From: Vladimir Oltean Currently any DSA switch that is strict when implementing the mdb operations prints these benign errors after the addresses expire, with at least 2 ports bridged: [ 286.013814] mscc_felix 0000:00:00.5 swp3: failed (err=-2) to del object (id=3) The reason has to do with this piece of code: netdev_for_each_lower_dev(dev, lower_dev, iter) br_mdb_switchdev_host_port(dev, lower_dev, mp, type); called from: br_multicast_group_expired -> br_multicast_host_leave -> br_mdb_notify -> br_mdb_switchdev_host Basically, the bridge code is correct. It tells each switchdev port that the host can leave that multicast group. But in the case of DSA, all user ports are connected to the host through the same pipe. So, because DSA blindly translates a host MDB to a normal MDB on the CPU port, this means that when all user ports leave a multicast group, DSA tries to remove it N times from the CPU port. We should be reference-counting these addresses. Otherwise, the first port on which the MDB expires will cause an entry removal from the CPU port, which will break the host MDB for the remaining ports. There is more. In expectation of future support for multiple CPUs, the addresses filtered towards the host should be kept in a list per CPU port. And cross-chip setups with multiple CPU ports can be really unconventional, nobody says that the switches must be cascaded. Consider just this example: +-------------------------+ | Host system | | | | eth0 eth1 | +-------------------------+ CPU port | | CPU port +-----------+ +-----------+ | | DSA | | | |-----| | | | link| | +-----------+ +-----------+ | | | | | | | | sw0pN user sw1pN user ports ports It is clear that the host addresses of sw0 should not interfere with the host addresses of sw1, and one switch should not even respond to the notifiers emitted for the other's host addresses. An entirely different thing can be said about the typical cross-chip setup that DSA works with today: +-----------------+ | Host system | | | | eth0 | +-----------------+ CPU | port +-----------+ sw0pN -| | user -| | ports -| | -| | +-----------+ DSA | link +-----------+ sw1pN -| | user -| | ports -| | -| | +-----------+ where a host MDB entry installed on a user port of sw1pN should be installed both on its upstream DSA link as well as on the CPU port (but not on the downstream DSA link of sw0pN). Basically this calls for the introduction of a separate notifier for host addresses, which matches on all upstream ports of the targeted user port (be they CPU ports or DSA links). This means we can simplify the normal MDB notifiers to be identical to the FDB notifiers now. Note that for switches which don't implement .port_mdb_add and .port_mdb_del, we don't even attempt to keep the address lists, only to fail at install time. Signed-off-by: Vladimir Oltean --- include/net/dsa.h | 34 ++++++++++++++++++ net/dsa/dsa2.c | 24 +++++++++++-- net/dsa/dsa_priv.h | 6 ++++ net/dsa/port.c | 24 +++++++++++++ net/dsa/slave.c | 89 +++++++++++++++++++++++++++++++++++++++++----- net/dsa/switch.c | 73 +++++++++++++++++++++++++++++-------- 6 files changed, 226 insertions(+), 24 deletions(-) diff --git a/include/net/dsa.h b/include/net/dsa.h index 83a933e563fe..31381bfcf35c 100644 --- a/include/net/dsa.h +++ b/include/net/dsa.h @@ -290,6 +290,11 @@ struct dsa_port { */ const struct dsa_netdevice_ops *netdev_ops; + /* List of MAC addresses that must be extracted from the fabric + * through this CPU port. Valid only for DSA_PORT_TYPE_CPU. + */ + struct list_head host_mdb; + bool setup; }; @@ -304,6 +309,13 @@ struct dsa_link { struct list_head list; }; +struct dsa_host_addr { + unsigned char addr[ETH_ALEN]; + u16 vid; + refcount_t refcount; + struct list_head list; +}; + struct dsa_switch { bool setup; @@ -481,6 +493,28 @@ static inline unsigned int dsa_upstream_port(struct dsa_switch *ds, int port) return dsa_towards_port(ds, cpu_dp->ds->index, cpu_dp->index); } +static inline bool dsa_is_upstream_port(struct dsa_switch *ds, int port) +{ + if (dsa_is_unused_port(ds, port)) + return false; + + return port == dsa_upstream_port(ds, port); +} + +/* Return true if @upstream_ds is an upstream switch of @downstream_ds. */ +static inline bool dsa_switch_is_upstream_of(struct dsa_switch *upstream_ds, + struct dsa_switch *downstream_ds) +{ + int routing_port; + + if (upstream_ds == downstream_ds) + return true; + + routing_port = dsa_routing_port(downstream_ds, upstream_ds->index); + + return dsa_is_upstream_port(downstream_ds, routing_port); +} + static inline bool dsa_port_is_vlan_filtering(const struct dsa_port *dp) { const struct dsa_switch *ds = dp->ds; diff --git a/net/dsa/dsa2.c b/net/dsa/dsa2.c index 4d4956ed303b..d64f1287625d 100644 --- a/net/dsa/dsa2.c +++ b/net/dsa/dsa2.c @@ -326,6 +326,11 @@ static struct dsa_port *dsa_tree_find_first_cpu(struct dsa_switch_tree *dst) return NULL; } +static void dsa_setup_cpu_port(struct dsa_port *cpu_dp) +{ + INIT_LIST_HEAD(&cpu_dp->host_mdb); +} + static int dsa_tree_setup_default_cpu(struct dsa_switch_tree *dst) { struct dsa_port *cpu_dp, *dp; @@ -336,6 +341,8 @@ static int dsa_tree_setup_default_cpu(struct dsa_switch_tree *dst) return -EINVAL; } + dsa_setup_cpu_port(cpu_dp); + /* Assign the default CPU port to all ports of the fabric */ list_for_each_entry(dp, &dst->ports, list) if (dsa_port_is_user(dp) || dsa_port_is_dsa(dp)) @@ -344,13 +351,26 @@ static int dsa_tree_setup_default_cpu(struct dsa_switch_tree *dst) return 0; } +static void dsa_teardown_cpu_port(struct dsa_port *cpu_dp) +{ + struct dsa_host_addr *a, *tmp; + + list_for_each_entry_safe(a, tmp, &cpu_dp->host_mdb, list) { + list_del(&a->list); + kfree(a); + } +} + static void dsa_tree_teardown_default_cpu(struct dsa_switch_tree *dst) { struct dsa_port *dp; - list_for_each_entry(dp, &dst->ports, list) - if (dsa_port_is_user(dp) || dsa_port_is_dsa(dp)) + list_for_each_entry(dp, &dst->ports, list) { + if (dsa_port_is_user(dp) || dsa_port_is_dsa(dp)) { + dsa_teardown_cpu_port(dp->cpu_dp); dp->cpu_dp = NULL; + } + } } static int dsa_port_setup(struct dsa_port *dp) diff --git a/net/dsa/dsa_priv.h b/net/dsa/dsa_priv.h index 2eeaa42f2e08..c730d40b81b9 100644 --- a/net/dsa/dsa_priv.h +++ b/net/dsa/dsa_priv.h @@ -27,6 +27,8 @@ enum { DSA_NOTIFIER_LAG_LEAVE, DSA_NOTIFIER_MDB_ADD, DSA_NOTIFIER_MDB_DEL, + DSA_NOTIFIER_HOST_MDB_ADD, + DSA_NOTIFIER_HOST_MDB_DEL, DSA_NOTIFIER_VLAN_ADD, DSA_NOTIFIER_VLAN_DEL, DSA_NOTIFIER_MTU, @@ -203,6 +205,10 @@ int dsa_port_mdb_add(const struct dsa_port *dp, const struct switchdev_obj_port_mdb *mdb); int dsa_port_mdb_del(const struct dsa_port *dp, const struct switchdev_obj_port_mdb *mdb); +int dsa_port_host_mdb_add(const struct dsa_port *dp, + const struct switchdev_obj_port_mdb *mdb); +int dsa_port_host_mdb_del(const struct dsa_port *dp, + const struct switchdev_obj_port_mdb *mdb); int dsa_port_pre_bridge_flags(const struct dsa_port *dp, struct switchdev_brport_flags flags, struct netlink_ext_ack *extack); diff --git a/net/dsa/port.c b/net/dsa/port.c index c9c6d7ab3f47..df9ba9b67675 100644 --- a/net/dsa/port.c +++ b/net/dsa/port.c @@ -538,6 +538,30 @@ int dsa_port_mdb_del(const struct dsa_port *dp, return dsa_port_notify(dp, DSA_NOTIFIER_MDB_DEL, &info); } +int dsa_port_host_mdb_add(const struct dsa_port *dp, + const struct switchdev_obj_port_mdb *mdb) +{ + struct dsa_notifier_mdb_info info = { + .sw_index = dp->ds->index, + .port = dp->index, + .mdb = mdb, + }; + + return dsa_port_notify(dp, DSA_NOTIFIER_HOST_MDB_ADD, &info); +} + +int dsa_port_host_mdb_del(const struct dsa_port *dp, + const struct switchdev_obj_port_mdb *mdb) +{ + struct dsa_notifier_mdb_info info = { + .sw_index = dp->ds->index, + .port = dp->index, + .mdb = mdb, + }; + + return dsa_port_notify(dp, DSA_NOTIFIER_HOST_MDB_DEL, &info); +} + int dsa_port_vlan_add(struct dsa_port *dp, const struct switchdev_obj_port_vlan *vlan, struct netlink_ext_ack *extack) diff --git a/net/dsa/slave.c b/net/dsa/slave.c index 491e3761b5f4..14a51503efe0 100644 --- a/net/dsa/slave.c +++ b/net/dsa/slave.c @@ -23,6 +23,85 @@ #include "dsa_priv.h" +static struct dsa_host_addr *dsa_host_addr_find(struct list_head *addr_list, + const unsigned char *addr, + u16 vid) +{ + struct dsa_host_addr *a; + + list_for_each_entry(a, addr_list, list) + if (ether_addr_equal(a->addr, addr) && a->vid == vid) + return a; + + return NULL; +} + +/* DSA can directly translate this to a normal MDB add, but on the CPU port. + * But because multiple user ports can join the same multicast group and the + * bridge will emit a notification for each port, we need to add/delete the + * entry towards the host only once, so we reference count it. + */ +static int dsa_host_mdb_add(struct dsa_port *dp, + const struct switchdev_obj_port_mdb *mdb) +{ + struct dsa_port *cpu_dp = dp->cpu_dp; + struct dsa_host_addr *a; + int err; + + if (!dp->ds->ops->port_mdb_add || !dp->ds->ops->port_mdb_del) + return -EOPNOTSUPP; + + a = dsa_host_addr_find(&cpu_dp->host_mdb, mdb->addr, mdb->vid); + if (a) { + refcount_inc(&a->refcount); + return 0; + } + + a = kzalloc(sizeof(*a), GFP_KERNEL); + if (!a) + return -ENOMEM; + + err = dsa_port_host_mdb_add(dp, mdb); + if (err) { + kfree(a); + return err; + } + + ether_addr_copy(a->addr, mdb->addr); + a->vid = mdb->vid; + refcount_set(&a->refcount, 1); + list_add_tail(&a->list, &cpu_dp->host_mdb); + + return 0; +} + +static int dsa_host_mdb_del(struct dsa_port *dp, + const struct switchdev_obj_port_mdb *mdb) +{ + struct dsa_port *cpu_dp = dp->cpu_dp; + struct dsa_host_addr *a; + int err; + + if (!dp->ds->ops->port_mdb_add || !dp->ds->ops->port_mdb_del) + return -EOPNOTSUPP; + + a = dsa_host_addr_find(&cpu_dp->host_mdb, mdb->addr, mdb->vid); + if (!a) + return -ENOENT; + + if (!refcount_dec_and_test(&a->refcount)) + return 0; + + err = dsa_port_host_mdb_del(dp, mdb); + if (err) + return err; + + list_del(&a->list); + kfree(a); + + return 0; +} + /* slave mii_bus handling ***************************************************/ static int dsa_slave_phy_read(struct mii_bus *bus, int addr, int reg) { @@ -396,10 +475,7 @@ static int dsa_slave_port_obj_add(struct net_device *dev, err = dsa_port_mdb_add(dp, SWITCHDEV_OBJ_PORT_MDB(obj)); break; case SWITCHDEV_OBJ_ID_HOST_MDB: - /* DSA can directly translate this to a normal MDB add, - * but on the CPU port. - */ - err = dsa_port_mdb_add(dp->cpu_dp, SWITCHDEV_OBJ_PORT_MDB(obj)); + err = dsa_host_mdb_add(dp, SWITCHDEV_OBJ_PORT_MDB(obj)); break; case SWITCHDEV_OBJ_ID_PORT_VLAN: err = dsa_slave_vlan_add(dev, obj, extack); @@ -464,10 +540,7 @@ static int dsa_slave_port_obj_del(struct net_device *dev, err = dsa_port_mdb_del(dp, SWITCHDEV_OBJ_PORT_MDB(obj)); break; case SWITCHDEV_OBJ_ID_HOST_MDB: - /* DSA can directly translate this to a normal MDB add, - * but on the CPU port. - */ - err = dsa_port_mdb_del(dp->cpu_dp, SWITCHDEV_OBJ_PORT_MDB(obj)); + err = dsa_host_mdb_del(dp, SWITCHDEV_OBJ_PORT_MDB(obj)); break; case SWITCHDEV_OBJ_ID_PORT_VLAN: err = dsa_slave_vlan_del(dev, obj); diff --git a/net/dsa/switch.c b/net/dsa/switch.c index 4b5da89dc27a..94996e213469 100644 --- a/net/dsa/switch.c +++ b/net/dsa/switch.c @@ -148,6 +148,25 @@ static int dsa_switch_bridge_leave(struct dsa_switch *ds, return 0; } +/* Matches for all upstream-facing ports (the CPU port and all upstream-facing + * DSA links) that sit between the port that emitted the notification and the + * DSA master. + */ +static bool dsa_switch_host_address_match(struct dsa_switch *ds, int port, + int info_sw_index, int info_port) +{ + struct dsa_switch *downstream_ds; + + downstream_ds = dsa_switch_find(ds->dst->index, info_sw_index); + if (WARN_ON(!downstream_ds)) + return false; + + if (dsa_switch_is_upstream_of(ds, downstream_ds)) + return dsa_is_upstream_port(ds, port); + + return false; +} + static int dsa_switch_fdb_add(struct dsa_switch *ds, struct dsa_notifier_fdb_info *info) { @@ -229,20 +248,30 @@ static int dsa_switch_lag_leave(struct dsa_switch *ds, return 0; } -static bool dsa_switch_mdb_match(struct dsa_switch *ds, int port, - struct dsa_notifier_mdb_info *info) +static int dsa_switch_mdb_add(struct dsa_switch *ds, + struct dsa_notifier_mdb_info *info) { - if (ds->index == info->sw_index && port == info->port) - return true; + int port = dsa_towards_port(ds, info->sw_index, info->port); - if (dsa_is_dsa_port(ds, port)) - return true; + if (!ds->ops->port_mdb_add) + return -EOPNOTSUPP; - return false; + return ds->ops->port_mdb_add(ds, port, info->mdb); } -static int dsa_switch_mdb_add(struct dsa_switch *ds, +static int dsa_switch_mdb_del(struct dsa_switch *ds, struct dsa_notifier_mdb_info *info) +{ + int port = dsa_towards_port(ds, info->sw_index, info->port); + + if (!ds->ops->port_mdb_del) + return -EOPNOTSUPP; + + return ds->ops->port_mdb_del(ds, port, info->mdb); +} + +static int dsa_switch_host_mdb_add(struct dsa_switch *ds, + struct dsa_notifier_mdb_info *info) { int err = 0; int port; @@ -251,7 +280,8 @@ static int dsa_switch_mdb_add(struct dsa_switch *ds, return -EOPNOTSUPP; for (port = 0; port < ds->num_ports; port++) { - if (dsa_switch_mdb_match(ds, port, info)) { + if (dsa_switch_host_address_match(ds, port, info->sw_index, + info->port)) { err = ds->ops->port_mdb_add(ds, port, info->mdb); if (err) break; @@ -261,16 +291,25 @@ static int dsa_switch_mdb_add(struct dsa_switch *ds, return err; } -static int dsa_switch_mdb_del(struct dsa_switch *ds, - struct dsa_notifier_mdb_info *info) +static int dsa_switch_host_mdb_del(struct dsa_switch *ds, + struct dsa_notifier_mdb_info *info) { + int err = 0; + int port; + if (!ds->ops->port_mdb_del) return -EOPNOTSUPP; - if (ds->index == info->sw_index) - return ds->ops->port_mdb_del(ds, info->port, info->mdb); + for (port = 0; port < ds->num_ports; port++) { + if (dsa_switch_host_address_match(ds, port, info->sw_index, + info->port)) { + err = ds->ops->port_mdb_del(ds, info->port, info->mdb); + if (err) + break; + } + } - return 0; + return err; } static bool dsa_switch_vlan_match(struct dsa_switch *ds, int port, @@ -508,6 +547,12 @@ static int dsa_switch_event(struct notifier_block *nb, case DSA_NOTIFIER_MDB_DEL: err = dsa_switch_mdb_del(ds, info); break; + case DSA_NOTIFIER_HOST_MDB_ADD: + err = dsa_switch_host_mdb_add(ds, info); + break; + case DSA_NOTIFIER_HOST_MDB_DEL: + err = dsa_switch_host_mdb_del(ds, info); + break; case DSA_NOTIFIER_VLAN_ADD: err = dsa_switch_vlan_add(ds, info); break; From patchwork Wed Feb 24 11:43:35 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Vladimir Oltean X-Patchwork-Id: 387104 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-15.7 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,FREEMAIL_FORGED_FROMDOMAIN,FREEMAIL_FROM, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI, SPF_HELO_NONE, SPF_PASS, URIBL_BLOCKED, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 7BEA3C433DB for ; Wed, 24 Feb 2021 11:45:13 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 2976564E90 for ; Wed, 24 Feb 2021 11:45:13 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S235000AbhBXLpH (ORCPT ); Wed, 24 Feb 2021 06:45:07 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:48248 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S234255AbhBXLop (ORCPT ); Wed, 24 Feb 2021 06:44:45 -0500 Received: from mail-ej1-x62a.google.com (mail-ej1-x62a.google.com [IPv6:2a00:1450:4864:20::62a]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id D6756C06178A for ; Wed, 24 Feb 2021 03:44:04 -0800 (PST) Received: by mail-ej1-x62a.google.com with SMTP id do6so2540656ejc.3 for ; Wed, 24 Feb 2021 03:44:04 -0800 (PST) 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 :mime-version:content-transfer-encoding; bh=KWneYLD92B29Pm4MbtcfzLvL38NMVW53l3jrfht4vLQ=; b=XYLK2JlnY2C/rvYN0IIR69tZ2IuiXLZ8tUNaJBTmrHEXaJwLGxf5IBCVtqEnkuHNbq 6QtiOEuRQur+LRwlGbLxr9DaDBzJ0MkOAaOhVPduMvDKO/GBr06Gps2mpeAHiZ/6DphZ oEANipBB3It1kYR86gInXBBSi+5FzhqiWINhs6l1Z+9x3oUx7BYFAuKm7Deu2Iq0Rg4q 1R1mNTetHTA5jmyffSdBBQsmIZ2kUSbspEcsgN7yO64LbGOBVG41fxEmuf6foU2pH+rB j57Qbup90DOSxB0Mj8JYR+DQfEEZF0saY1yGGjS11uRI3lZR6ZU6tV7gSFxdsL6lkE5Y zxyw== 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:mime-version:content-transfer-encoding; bh=KWneYLD92B29Pm4MbtcfzLvL38NMVW53l3jrfht4vLQ=; b=dLk3BssWv585H2XnAbH60xnlGTxU6v1TXPr/5GUZd5JqweptBTZBfadS4uzqfGe+g6 zHnc/LdQeYKjO43N1FksTvFBdxs+rCnn1wtOR+2eHNPElE71h9Szyxcvk5IX4PfzhpVV /GOpmYW3eUrv8Zc/YSei6X0XVy/Nat/tlGYa6V3ycNH0+ElrY3Bqbuf0aiaHLkOgtoRF 9j5JuBfkxpgm+hVTtkiYiFpGMEuMl6DsDN9KKKJQjDCgtGr+rnXXC0J9FpzALSzy/4dI nBm5fJ0U1Y1F/IklZpZ9icAQaxkQV4G/Ejtajn9YlDs3UnhPS+LlfixDD2xGGLEaN5Mv 0+0A== X-Gm-Message-State: AOAM533rvrDXHB0OqDHOYgpLUknpH1sypxRrYUsDLOBjWJjCFVUFKa7I i/3zHs1ugZElkjPIsR0SZPMyaVen1Do= X-Google-Smtp-Source: ABdhPJyphBuIWf/7ls//YBaQeTfr2HYSLjKvPfyuhVJfMAvX66CGN+pcLCFW/GYKg6YYgfbaGohBfQ== X-Received: by 2002:a17:907:3e8d:: with SMTP id hs13mr4813522ejc.36.1614167043287; Wed, 24 Feb 2021 03:44:03 -0800 (PST) Received: from localhost.localdomain ([188.25.217.13]) by smtp.gmail.com with ESMTPSA id r5sm1203921ejx.96.2021.02.24.03.44.02 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 24 Feb 2021 03:44:02 -0800 (PST) From: Vladimir Oltean To: netdev@vger.kernel.org Cc: Andrew Lunn , Florian Fainelli , Vivien Didelot , Jiri Pirko , Ido Schimmel , DENG Qingfang , Tobias Waldekranz , George McCollister , Vlad Yasevich , Roopa Prabhu , Nikolay Aleksandrov Subject: [RFC PATCH v2 net-next 02/17] net: dsa: reference count the host fdb addresses Date: Wed, 24 Feb 2021 13:43:35 +0200 Message-Id: <20210224114350.2791260-3-olteanv@gmail.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210224114350.2791260-1-olteanv@gmail.com> References: <20210224114350.2791260-1-olteanv@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org From: Vladimir Oltean In preparation of unicast filtering towards the CPU, DSA will need to send to the CPU several classes of addresses: - local FDB entries from the bridge - FDB entries pointing to the software bridge itself - the MAC addresses used for termination in standalone mode - the MAC addresses of various upper interfaces (8021q, macvlan) that DSA ports might have So it will no longer be sufficient to gather the address list from a single source such as the bridge. Consider the fact that the bridge currently records the MAC address of every bridge port as a local ('permanent') address placed in the FDB. Sure we could use that as an indication that the address must be sent to the CPU, but that address needs to be sent to the CPU anyway, even if we're operating in standalone mode. So the bridge can't dictate anything, we must keep more addresses, and if we do that, there is a risk that we might delete an address when it was still used, if we just listen to the deletion event emitted by the bridge through switchdev. And that is where the requirement for reference counting comes from. Similar to host MDB entries, we should create a new notifier in DSA, and keep the existing one for out-facing FDB entries untouched. We can also simplify dsa_slave_switchdev_event_work a little bit now, since we always schedule the work item for a user port now, we can unconditionally take the refcount on a net_device. Signed-off-by: Vladimir Oltean --- include/net/dsa.h | 1 + net/dsa/dsa2.c | 6 ++++ net/dsa/dsa_priv.h | 7 ++++ net/dsa/port.c | 27 ++++++++++++++ net/dsa/slave.c | 88 +++++++++++++++++++++++++++++++++++++++++----- net/dsa/switch.c | 50 ++++++++++++++++++++++++++ 6 files changed, 170 insertions(+), 9 deletions(-) diff --git a/include/net/dsa.h b/include/net/dsa.h index 31381bfcf35c..0210b49f291e 100644 --- a/include/net/dsa.h +++ b/include/net/dsa.h @@ -293,6 +293,7 @@ struct dsa_port { /* List of MAC addresses that must be extracted from the fabric * through this CPU port. Valid only for DSA_PORT_TYPE_CPU. */ + struct list_head host_fdb; struct list_head host_mdb; bool setup; diff --git a/net/dsa/dsa2.c b/net/dsa/dsa2.c index d64f1287625d..27654cac1c61 100644 --- a/net/dsa/dsa2.c +++ b/net/dsa/dsa2.c @@ -328,6 +328,7 @@ static struct dsa_port *dsa_tree_find_first_cpu(struct dsa_switch_tree *dst) static void dsa_setup_cpu_port(struct dsa_port *cpu_dp) { + INIT_LIST_HEAD(&cpu_dp->host_fdb); INIT_LIST_HEAD(&cpu_dp->host_mdb); } @@ -355,6 +356,11 @@ static void dsa_teardown_cpu_port(struct dsa_port *cpu_dp) { struct dsa_host_addr *a, *tmp; + list_for_each_entry_safe(a, tmp, &cpu_dp->host_fdb, list) { + list_del(&a->list); + kfree(a); + } + list_for_each_entry_safe(a, tmp, &cpu_dp->host_mdb, list) { list_del(&a->list); kfree(a); diff --git a/net/dsa/dsa_priv.h b/net/dsa/dsa_priv.h index c730d40b81b9..4043da2bacc0 100644 --- a/net/dsa/dsa_priv.h +++ b/net/dsa/dsa_priv.h @@ -20,6 +20,8 @@ enum { DSA_NOTIFIER_BRIDGE_LEAVE, DSA_NOTIFIER_FDB_ADD, DSA_NOTIFIER_FDB_DEL, + DSA_NOTIFIER_HOST_FDB_ADD, + DSA_NOTIFIER_HOST_FDB_DEL, DSA_NOTIFIER_HSR_JOIN, DSA_NOTIFIER_HSR_LEAVE, DSA_NOTIFIER_LAG_CHANGE, @@ -121,6 +123,7 @@ struct dsa_switchdev_event_work { */ unsigned char addr[ETH_ALEN]; u16 vid; + bool host_addr; }; /* DSA_NOTIFIER_HSR_* */ @@ -200,6 +203,10 @@ int dsa_port_fdb_add(struct dsa_port *dp, const unsigned char *addr, u16 vid); int dsa_port_fdb_del(struct dsa_port *dp, const unsigned char *addr, u16 vid); +int dsa_port_host_fdb_add(struct dsa_port *dp, const unsigned char *addr, + u16 vid); +int dsa_port_host_fdb_del(struct dsa_port *dp, const unsigned char *addr, + u16 vid); int dsa_port_fdb_dump(struct dsa_port *dp, dsa_fdb_dump_cb_t *cb, void *data); int dsa_port_mdb_add(const struct dsa_port *dp, const struct switchdev_obj_port_mdb *mdb); diff --git a/net/dsa/port.c b/net/dsa/port.c index df9ba9b67675..d9ff222c041c 100644 --- a/net/dsa/port.c +++ b/net/dsa/port.c @@ -503,6 +503,33 @@ int dsa_port_fdb_del(struct dsa_port *dp, const unsigned char *addr, return dsa_port_notify(dp, DSA_NOTIFIER_FDB_DEL, &info); } +int dsa_port_host_fdb_add(struct dsa_port *dp, const unsigned char *addr, + u16 vid) +{ + struct dsa_notifier_fdb_info info = { + .sw_index = dp->ds->index, + .port = dp->index, + .addr = addr, + .vid = vid, + }; + + return dsa_port_notify(dp, DSA_NOTIFIER_HOST_FDB_ADD, &info); +} + +int dsa_port_host_fdb_del(struct dsa_port *dp, const unsigned char *addr, + u16 vid) +{ + struct dsa_notifier_fdb_info info = { + .sw_index = dp->ds->index, + .port = dp->index, + .addr = addr, + .vid = vid, + + }; + + return dsa_port_notify(dp, DSA_NOTIFIER_HOST_FDB_DEL, &info); +} + int dsa_port_fdb_dump(struct dsa_port *dp, dsa_fdb_dump_cb_t *cb, void *data) { struct dsa_switch *ds = dp->ds; diff --git a/net/dsa/slave.c b/net/dsa/slave.c index 14a51503efe0..12d51bdb5eea 100644 --- a/net/dsa/slave.c +++ b/net/dsa/slave.c @@ -102,6 +102,67 @@ static int dsa_host_mdb_del(struct dsa_port *dp, return 0; } +static int dsa_host_fdb_add(struct dsa_port *dp, const unsigned char *addr, + u16 vid) +{ + struct dsa_port *cpu_dp = dp->cpu_dp; + struct dsa_host_addr *a; + int err; + + if (!dp->ds->ops->port_fdb_add || !dp->ds->ops->port_fdb_del) + return -EOPNOTSUPP; + + a = dsa_host_addr_find(&cpu_dp->host_fdb, addr, vid); + if (a) { + refcount_inc(&a->refcount); + return 0; + } + + a = kzalloc(sizeof(*a), GFP_KERNEL); + if (!a) + return -ENOMEM; + + err = dsa_port_host_fdb_add(dp, addr, vid); + if (err) { + kfree(a); + return err; + } + + ether_addr_copy(a->addr, addr); + a->vid = vid; + refcount_set(&a->refcount, 1); + list_add_tail(&a->list, &cpu_dp->host_fdb); + + return 0; +} + +static int dsa_host_fdb_del(struct dsa_port *dp, const unsigned char *addr, + u16 vid) +{ + struct dsa_port *cpu_dp = dp->cpu_dp; + struct dsa_host_addr *a; + int err; + + if (!dp->ds->ops->port_fdb_add || !dp->ds->ops->port_fdb_del) + return -EOPNOTSUPP; + + a = dsa_host_addr_find(&cpu_dp->host_fdb, addr, vid); + if (!a) + return -ENOENT; + + if (!refcount_dec_and_test(&a->refcount)) + return 0; + + err = dsa_port_host_fdb_del(dp, addr, vid); + if (err) + return err; + + list_del(&a->list); + kfree(a); + + return 0; +} + /* slave mii_bus handling ***************************************************/ static int dsa_slave_phy_read(struct mii_bus *bus, int addr, int reg) { @@ -2264,8 +2325,12 @@ static void dsa_slave_switchdev_event_work(struct work_struct *work) rtnl_lock(); switch (switchdev_work->event) { case SWITCHDEV_FDB_ADD_TO_DEVICE: - err = dsa_port_fdb_add(dp, switchdev_work->addr, - switchdev_work->vid); + if (switchdev_work->host_addr) + err = dsa_host_fdb_add(dp, switchdev_work->addr, + switchdev_work->vid); + else + err = dsa_port_fdb_add(dp, switchdev_work->addr, + switchdev_work->vid); if (err) { dev_err(ds->dev, "port %d failed to add %pM vid %d to fdb: %d\n", @@ -2277,8 +2342,12 @@ static void dsa_slave_switchdev_event_work(struct work_struct *work) break; case SWITCHDEV_FDB_DEL_TO_DEVICE: - err = dsa_port_fdb_del(dp, switchdev_work->addr, - switchdev_work->vid); + if (switchdev_work->host_addr) + err = dsa_host_fdb_del(dp, switchdev_work->addr, + switchdev_work->vid); + else + err = dsa_port_fdb_del(dp, switchdev_work->addr, + switchdev_work->vid); if (err) { dev_err(ds->dev, "port %d failed to delete %pM vid %d from fdb: %d\n", @@ -2291,8 +2360,7 @@ static void dsa_slave_switchdev_event_work(struct work_struct *work) rtnl_unlock(); kfree(switchdev_work); - if (dsa_is_user_port(ds, dp->index)) - dev_put(dp->slave); + dev_put(dp->slave); } static int dsa_lower_dev_walk(struct net_device *lower_dev, @@ -2324,6 +2392,7 @@ static int dsa_slave_switchdev_event(struct notifier_block *unused, struct net_device *dev = switchdev_notifier_info_to_dev(ptr); const struct switchdev_notifier_fdb_info *fdb_info; struct dsa_switchdev_event_work *switchdev_work; + bool host_addr = false; struct dsa_port *dp; int err; @@ -2361,7 +2430,8 @@ static int dsa_slave_switchdev_event(struct notifier_block *unused, if (!p) return NOTIFY_DONE; - dp = p->dp->cpu_dp; + dp = p->dp; + host_addr = true; if (!dp->ds->assisted_learning_on_cpu_port) return NOTIFY_DONE; @@ -2391,10 +2461,10 @@ static int dsa_slave_switchdev_event(struct notifier_block *unused, ether_addr_copy(switchdev_work->addr, fdb_info->addr); switchdev_work->vid = fdb_info->vid; + switchdev_work->host_addr = host_addr; /* Hold a reference on the slave for dsa_fdb_offload_notify */ - if (dsa_is_user_port(dp->ds, dp->index)) - dev_hold(dev); + dev_hold(dev); dsa_schedule_work(&switchdev_work->work); break; default: diff --git a/net/dsa/switch.c b/net/dsa/switch.c index 94996e213469..a89363117f6f 100644 --- a/net/dsa/switch.c +++ b/net/dsa/switch.c @@ -167,6 +167,50 @@ static bool dsa_switch_host_address_match(struct dsa_switch *ds, int port, return false; } +static int dsa_switch_host_fdb_add(struct dsa_switch *ds, + struct dsa_notifier_fdb_info *info) +{ + int err = 0; + int port; + + if (!ds->ops->port_fdb_add) + return -EOPNOTSUPP; + + for (port = 0; port < ds->num_ports; port++) { + if (dsa_switch_host_address_match(ds, port, info->sw_index, + info->port)) { + err = ds->ops->port_fdb_add(ds, port, info->addr, + info->vid); + if (err) + break; + } + } + + return err; +} + +static int dsa_switch_host_fdb_del(struct dsa_switch *ds, + struct dsa_notifier_fdb_info *info) +{ + int err = 0; + int port; + + if (!ds->ops->port_fdb_del) + return -EOPNOTSUPP; + + for (port = 0; port < ds->num_ports; port++) { + if (dsa_switch_host_address_match(ds, port, info->sw_index, + info->port)) { + err = ds->ops->port_fdb_del(ds, info->port, info->addr, + info->vid); + if (err) + break; + } + } + + return err; +} + static int dsa_switch_fdb_add(struct dsa_switch *ds, struct dsa_notifier_fdb_info *info) { @@ -526,6 +570,12 @@ static int dsa_switch_event(struct notifier_block *nb, case DSA_NOTIFIER_FDB_DEL: err = dsa_switch_fdb_del(ds, info); break; + case DSA_NOTIFIER_HOST_FDB_ADD: + err = dsa_switch_host_fdb_add(ds, info); + break; + case DSA_NOTIFIER_HOST_FDB_DEL: + err = dsa_switch_host_fdb_del(ds, info); + break; case DSA_NOTIFIER_HSR_JOIN: err = dsa_switch_hsr_join(ds, info); break; From patchwork Wed Feb 24 11:43:36 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Vladimir Oltean X-Patchwork-Id: 387607 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-15.7 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,FREEMAIL_FORGED_FROMDOMAIN,FREEMAIL_FROM, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI, SPF_HELO_NONE, SPF_PASS, URIBL_BLOCKED, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 617A3C433DB for ; Wed, 24 Feb 2021 11:45:59 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 05AAE60231 for ; Wed, 24 Feb 2021 11:45:58 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S235029AbhBXLpt (ORCPT ); Wed, 24 Feb 2021 06:45:49 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:48254 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S234970AbhBXLoq (ORCPT ); Wed, 24 Feb 2021 06:44:46 -0500 Received: from mail-ej1-x635.google.com (mail-ej1-x635.google.com [IPv6:2a00:1450:4864:20::635]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id BFD0EC06178B for ; Wed, 24 Feb 2021 03:44:05 -0800 (PST) Received: by mail-ej1-x635.google.com with SMTP id u20so2516849ejb.7 for ; Wed, 24 Feb 2021 03:44:05 -0800 (PST) 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 :mime-version:content-transfer-encoding; bh=piGplLjZJEQ7DaXpT0Z5Bw5Z5JllZd0C+8Mir6u6p8Q=; b=iCEUKryz8XWwMY5+zj/5N72y/WBdk/+tkb0u4jHpBPlD9H+Vl38/1ACiSKXYJbxc8y WVeWPurAb/rSLz0uK1iX/SsWGGIqICcJEZJtOI6Bgd/MQOP9n6aEX6kqPDTOVCCmzCU7 vOvOyrCYYGAluKF9Xs8kYewQiE/15qk+4IMMc2F15+daWBjg/Ss5qyEq/pybZbRh7kIL I8l+jzjeAGiesjnpYgBa9mJ1aniajOI45AiOso8yUuK3hcBx59C5Yi5jOfHZAMibxLh8 UAQ2CeXOEgkg0TqJradwx/gata98PpfuFf0TYsbWFNhqDAqQFN1O+oC4AUoq47I3yzQ6 OM8A== 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:mime-version:content-transfer-encoding; bh=piGplLjZJEQ7DaXpT0Z5Bw5Z5JllZd0C+8Mir6u6p8Q=; b=OGCowZw18RXrts7Pg+lfEJvbEdE8p+Hs49fWX6PYOLFs1bxDkgSyVJM2/po/TcS/KZ QZ+hcp61q/6aS64I45+A1l7v2uKcZ7Sd8+G40p17HkZMtPO1jGk8qg5u99KH0GQvfquI C7DRXi4herg5rC7iGtx2tIh7I1mjvwTk7gzX/XcGejn55yKWLjZbwmewBbLhRgPbMXBM aXdCcS/qv3VNJQFXdpSC5UOYjNFFnJM4QbzJt7CsNyoVHoug2Nd5xMPNtHalcBi7LhiB KhvlkJw/EkkwK1g3dJS82ATdXHZ2kIf2FQXwAfiYlpEwAhr5DtB9xq6ffm1Uyn4KxSwb myRQ== X-Gm-Message-State: AOAM533SIcJ686eGEaxvJjy98SxlHAv72M6b0ewAORCfpE3UquOaUSuW AfRo3Kj3RMHjVr9Nb+MDQ59QUZkGM60= X-Google-Smtp-Source: ABdhPJzjr9eGSMD0d5xtuIP8oDmAPJmQlWpWAfQGFlmhJlxjF3YCnDqiwqU46mOPpBHVXtb7J1u1ow== X-Received: by 2002:a17:906:c24b:: with SMTP id bl11mr2339771ejb.80.1614167044311; Wed, 24 Feb 2021 03:44:04 -0800 (PST) Received: from localhost.localdomain ([188.25.217.13]) by smtp.gmail.com with ESMTPSA id r5sm1203921ejx.96.2021.02.24.03.44.03 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 24 Feb 2021 03:44:04 -0800 (PST) From: Vladimir Oltean To: netdev@vger.kernel.org Cc: Andrew Lunn , Florian Fainelli , Vivien Didelot , Jiri Pirko , Ido Schimmel , DENG Qingfang , Tobias Waldekranz , George McCollister , Vlad Yasevich , Roopa Prabhu , Nikolay Aleksandrov Subject: [RFC PATCH v2 net-next 03/17] net: dsa: install the host MDB and FDB entries in the master's RX filter Date: Wed, 24 Feb 2021 13:43:36 +0200 Message-Id: <20210224114350.2791260-4-olteanv@gmail.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210224114350.2791260-1-olteanv@gmail.com> References: <20210224114350.2791260-1-olteanv@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org From: Vladimir Oltean If the DSA master implements strict address filtering, then the unicast and multicast addresses kept by the DSA CPU ports should be synchronized with the address lists of the DSA master. Note that we want the synchronization of the master's address lists even if the DSA switch doesn't support unicast/multicast database operations, on the premises that the packets will be flooded to the CPU in that case, and we should still instruct the master to receive them. Signed-off-by: Vladimir Oltean --- net/dsa/slave.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/net/dsa/slave.c b/net/dsa/slave.c index 12d51bdb5eea..b6ea7e21b3b6 100644 --- a/net/dsa/slave.c +++ b/net/dsa/slave.c @@ -48,6 +48,8 @@ static int dsa_host_mdb_add(struct dsa_port *dp, struct dsa_host_addr *a; int err; + dev_mc_add(cpu_dp->master, mdb->addr); + if (!dp->ds->ops->port_mdb_add || !dp->ds->ops->port_mdb_del) return -EOPNOTSUPP; @@ -82,6 +84,8 @@ static int dsa_host_mdb_del(struct dsa_port *dp, struct dsa_host_addr *a; int err; + dev_mc_del(cpu_dp->master, mdb->addr); + if (!dp->ds->ops->port_mdb_add || !dp->ds->ops->port_mdb_del) return -EOPNOTSUPP; @@ -109,6 +113,8 @@ static int dsa_host_fdb_add(struct dsa_port *dp, const unsigned char *addr, struct dsa_host_addr *a; int err; + dev_uc_add(cpu_dp->master, addr); + if (!dp->ds->ops->port_fdb_add || !dp->ds->ops->port_fdb_del) return -EOPNOTSUPP; @@ -143,6 +149,8 @@ static int dsa_host_fdb_del(struct dsa_port *dp, const unsigned char *addr, struct dsa_host_addr *a; int err; + dev_uc_del(cpu_dp->master, addr); + if (!dp->ds->ops->port_fdb_add || !dp->ds->ops->port_fdb_del) return -EOPNOTSUPP; From patchwork Wed Feb 24 11:43:37 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Vladimir Oltean X-Patchwork-Id: 387103 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-15.7 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,FREEMAIL_FORGED_FROMDOMAIN,FREEMAIL_FROM, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI, SPF_HELO_NONE, SPF_PASS, URIBL_BLOCKED, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 8D009C433E0 for ; Wed, 24 Feb 2021 11:46:22 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 41B5064E90 for ; Wed, 24 Feb 2021 11:46:22 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S235044AbhBXLqS (ORCPT ); Wed, 24 Feb 2021 06:46:18 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:48332 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S234189AbhBXLpI (ORCPT ); Wed, 24 Feb 2021 06:45:08 -0500 Received: from mail-ed1-x52f.google.com (mail-ed1-x52f.google.com [IPv6:2a00:1450:4864:20::52f]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id D120BC06178C for ; Wed, 24 Feb 2021 03:44:06 -0800 (PST) Received: by mail-ed1-x52f.google.com with SMTP id h25so2090815eds.4 for ; Wed, 24 Feb 2021 03:44:06 -0800 (PST) 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 :mime-version:content-transfer-encoding; bh=yoeAVXVVgmxIroT+hw2AkHBtvfntX19xz1hn/RwiUHo=; b=QqBVRTlRH4UmpnUe3vf/XKZfg283KiLXd9GaHYMDaFTz3pbjLSb2/RJBvk5D12xvY3 GM3WsUh/F+2HS7c81WJYiIkqMpdyqlPBQro5KfjqAfohM1l5ZfZCA2DQv2HBjcHzReYV ZPgA7zNzFbSjZQCpi4Yla4WqN2ry5BuTg2WK7boUK0JnHm/oDBHzcOAD89F6atg+flip aju7FaYb1DpEuvTcUBc3VlREH005D6UkzM7Hr1gcamkQFi9SykR51/943rLpFc/G7+e7 KxcCknOQDb5R01WOR7uNmvB6VAMLkMt+ROaeMSlGCe+4YF2Q5wjJ5TuXBVh3BZS3qNh7 5ybQ== 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:mime-version:content-transfer-encoding; bh=yoeAVXVVgmxIroT+hw2AkHBtvfntX19xz1hn/RwiUHo=; b=loHkCBcsOCfZfgSURABvo2BthhPIiQOxBkHX13vRZNxH3PxrVvIKD8kQk36DuNDcRa B75BiWA27a62g0GLc/OlJL58nBioaQRvOei4J9b7c2wSx6NFNrsNEyUXwMndL8754xed q5CcH9eZeKBuK9rKcnvE3CtaH+EjZ/rJ0kKRthEZG6Ov4yWGmIJHcZSRS0WxVWVH7Kao L4ft0s5Y1qe8IL1Ry5MMqOFpAbxSsvD8VkAPEFlTKgMXfzoUSD/44Agz0hI9k4bHfySC 0iKsUGcBhO7z9/ICgSyY7qkT6/LKmtuA8r/9CHmqzrhJsdzv981uZm+jcfLim1iO3IkN 4u2A== X-Gm-Message-State: AOAM531Z0cc0IO77IhskpVQwdWwVaWlCBbMiO8V7BgblMnbnZyqIyedR yW3J39aruRCP6zvTdqatjOfDwXLQPdE= X-Google-Smtp-Source: ABdhPJwHE/yG7le0+dXFw79KdfZeaq/qV/N2rEKvBzipX7VSzGlbidosUeHpY7fjzbZQPNbUUj6jug== X-Received: by 2002:aa7:d2c4:: with SMTP id k4mr15362246edr.237.1614167045449; Wed, 24 Feb 2021 03:44:05 -0800 (PST) Received: from localhost.localdomain ([188.25.217.13]) by smtp.gmail.com with ESMTPSA id r5sm1203921ejx.96.2021.02.24.03.44.04 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 24 Feb 2021 03:44:05 -0800 (PST) From: Vladimir Oltean To: netdev@vger.kernel.org Cc: Andrew Lunn , Florian Fainelli , Vivien Didelot , Jiri Pirko , Ido Schimmel , DENG Qingfang , Tobias Waldekranz , George McCollister , Vlad Yasevich , Roopa Prabhu , Nikolay Aleksandrov Subject: [RFC PATCH v2 net-next 04/17] net: dsa: install the port MAC addresses as host fdb entries Date: Wed, 24 Feb 2021 13:43:37 +0200 Message-Id: <20210224114350.2791260-5-olteanv@gmail.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210224114350.2791260-1-olteanv@gmail.com> References: <20210224114350.2791260-1-olteanv@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org From: Vladimir Oltean In preparation of support for IFF_UNICAST_FLT for DSA standalone ports, the unicast address of the DSA interfaces should always be known to the switch and installed as an FDB entry towards the CPU port associated with that user port. Signed-off-by: Vladimir Oltean --- net/dsa/slave.c | 32 ++++++++++---------------------- 1 file changed, 10 insertions(+), 22 deletions(-) diff --git a/net/dsa/slave.c b/net/dsa/slave.c index b6ea7e21b3b6..6544a4ec69f4 100644 --- a/net/dsa/slave.c +++ b/net/dsa/slave.c @@ -223,11 +223,9 @@ static int dsa_slave_open(struct net_device *dev) goto out; } - if (!ether_addr_equal(dev->dev_addr, master->dev_addr)) { - err = dev_uc_add(master, dev->dev_addr); - if (err < 0) - goto out; - } + err = dsa_host_fdb_add(dp, dev->dev_addr, 0); + if (err && err != -EOPNOTSUPP) + goto out; if (dev->flags & IFF_ALLMULTI) { err = dev_set_allmulti(master, 1); @@ -253,8 +251,7 @@ static int dsa_slave_open(struct net_device *dev) if (dev->flags & IFF_ALLMULTI) dev_set_allmulti(master, -1); del_unicast: - if (!ether_addr_equal(dev->dev_addr, master->dev_addr)) - dev_uc_del(master, dev->dev_addr); + dsa_host_fdb_del(dp, dev->dev_addr, 0); out: return err; } @@ -273,8 +270,7 @@ static int dsa_slave_close(struct net_device *dev) if (dev->flags & IFF_PROMISC) dev_set_promiscuity(master, -1); - if (!ether_addr_equal(dev->dev_addr, master->dev_addr)) - dev_uc_del(master, dev->dev_addr); + dsa_host_fdb_del(dp, dev->dev_addr, 0); return 0; } @@ -302,26 +298,18 @@ static void dsa_slave_set_rx_mode(struct net_device *dev) static int dsa_slave_set_mac_address(struct net_device *dev, void *a) { - struct net_device *master = dsa_slave_to_master(dev); + struct dsa_port *dp = dsa_slave_to_port(dev); struct sockaddr *addr = a; int err; if (!is_valid_ether_addr(addr->sa_data)) return -EADDRNOTAVAIL; - if (!(dev->flags & IFF_UP)) - goto out; - - if (!ether_addr_equal(addr->sa_data, master->dev_addr)) { - err = dev_uc_add(master, addr->sa_data); - if (err < 0) - return err; - } - - if (!ether_addr_equal(dev->dev_addr, master->dev_addr)) - dev_uc_del(master, dev->dev_addr); + err = dsa_host_fdb_add(dp, addr->sa_data, 0); + if (err && err != -EOPNOTSUPP) + return err; -out: + dsa_host_fdb_del(dp, dev->dev_addr, 0); ether_addr_copy(dev->dev_addr, addr->sa_data); return 0; From patchwork Wed Feb 24 11:43:38 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Vladimir Oltean X-Patchwork-Id: 387606 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-15.7 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,FREEMAIL_FORGED_FROMDOMAIN,FREEMAIL_FROM, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI, SPF_HELO_NONE, SPF_PASS, URIBL_BLOCKED, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id EDCE2C433E0 for ; Wed, 24 Feb 2021 11:46:44 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id A03FE64E60 for ; Wed, 24 Feb 2021 11:46:44 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232545AbhBXLq3 (ORCPT ); Wed, 24 Feb 2021 06:46:29 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:48334 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S235007AbhBXLpI (ORCPT ); Wed, 24 Feb 2021 06:45:08 -0500 Received: from mail-ed1-x534.google.com (mail-ed1-x534.google.com [IPv6:2a00:1450:4864:20::534]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 0A1C0C061793 for ; Wed, 24 Feb 2021 03:44:08 -0800 (PST) Received: by mail-ed1-x534.google.com with SMTP id w21so2070883edc.7 for ; Wed, 24 Feb 2021 03:44:07 -0800 (PST) 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 :mime-version:content-transfer-encoding; bh=14IFdbQi7qBTsEbIGGLHwEMAkDriFhkRYedkx1tDDg4=; b=IPBA2dR2qvxBUdw5SMnKg1sJuMP+lCiE8xmw5xZlJgF+2lNlMp3+Njz67+ckWveyc7 XNygFPAyAEc13k+QNn5KDrmnPy/DNwGG94D2ESpM2qarBosfkpInz/SaVbVWy/JZG895 7U6fIGbJiu6ZANAJnZsScYR87Irc7tc/zenU2xoELjaIqYKXQdagcbMo6RVIYPpQ4p3i sT3QYbtX2BrocVKuEPXVsHx00TvAl3qvOgMrVkzfrUy/qCEMksJ/YBXkyfQjuPqKzwCx XHCAzsFrcxO+tjoPF1yOotL5yXgdxnOP+ziz/DEAOX+CnhnaNiKBfBtx2RpFJXOiDlnz nTUQ== 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:mime-version:content-transfer-encoding; bh=14IFdbQi7qBTsEbIGGLHwEMAkDriFhkRYedkx1tDDg4=; b=HkFBaynHjFY8Sl1EFWZtlhXdkN7gtYsS0ToN5BYygKohT+GGEWr4kaLzbSB+jy9Zl6 GIuAKzYhK3OJ8Opg/JLyE02SOuswCNXdRZmd7enHCqNLQVy+X6JGwGVtYMaEETTORW9/ IQKCIr/nF4Bs9qSUtpSBliTAa3oppho0o3FHCaiKgA+C6Mx2bm7lTEzhOX3+0WwIipXp 2tunpcepujJuT0//gtRehC7S38g18y4OyaXVywb57lblwAvBw3XjTRN43OBLdUtHRQVx 6GO4+PcKsGAC2MXF9BCKilC75EirKLwVFVZMPgOSi/28+xrE1r9kp9Sr+NVjWK98Zpcf zc8g== X-Gm-Message-State: AOAM531SMX0zkQ/N7eR1hGtOIoG8tbl8j4LXiGL+WX0U9IO73hIYLq9/ iQCPerxmT8Livv+BHrhU4/3G/tGwUTg= X-Google-Smtp-Source: ABdhPJwPrZEvUdlt0Xowb3g/5EYFsSb/UA3Z6hYh1aybpoAJOtJTlQrTpOfwL/U/uadT5p/uGN7Bvg== X-Received: by 2002:a05:6402:3133:: with SMTP id dd19mr32332904edb.337.1614167046597; Wed, 24 Feb 2021 03:44:06 -0800 (PST) Received: from localhost.localdomain ([188.25.217.13]) by smtp.gmail.com with ESMTPSA id r5sm1203921ejx.96.2021.02.24.03.44.05 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 24 Feb 2021 03:44:06 -0800 (PST) From: Vladimir Oltean To: netdev@vger.kernel.org Cc: Andrew Lunn , Florian Fainelli , Vivien Didelot , Jiri Pirko , Ido Schimmel , DENG Qingfang , Tobias Waldekranz , George McCollister , Vlad Yasevich , Roopa Prabhu , Nikolay Aleksandrov Subject: [RFC PATCH v2 net-next 05/17] net: bridge: implement unicast filtering for the bridge device Date: Wed, 24 Feb 2021 13:43:38 +0200 Message-Id: <20210224114350.2791260-6-olteanv@gmail.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210224114350.2791260-1-olteanv@gmail.com> References: <20210224114350.2791260-1-olteanv@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org From: Vladimir Oltean The bridge device currently goes into promiscuous mode when it has an upper with a different MAC address than itself. But it could do better: it could sync the MAC addresses of its uppers to the software FDB, as local entries pointing to the bridge itself. This is compatible with switchdev, since drivers are now instructed to trap these MAC addresses to the CPU. Note that the dev_uc_add API does not propagate VLAN ID, so this only works for VLAN-unaware bridges. Signed-off-by: Vladimir Oltean --- net/bridge/br_device.c | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/net/bridge/br_device.c b/net/bridge/br_device.c index 3f2f06b4dd27..a7d9d35e70d0 100644 --- a/net/bridge/br_device.c +++ b/net/bridge/br_device.c @@ -179,8 +179,25 @@ static int br_dev_open(struct net_device *dev) return 0; } -static void br_dev_set_multicast_list(struct net_device *dev) +static int br_dev_sync_uc(struct net_device *dev, const unsigned char *addr) { + struct net_bridge *br = netdev_priv(dev); + + return br_fdb_insert(br, NULL, addr, 0); +} + +static int br_dev_unsync_uc(struct net_device *dev, const unsigned char *addr) +{ + struct net_bridge *br = netdev_priv(dev); + + br_fdb_find_delete_local(br, NULL, addr, 0); + + return 0; +} + +static void br_dev_set_rx_mode(struct net_device *dev) +{ + __dev_uc_sync(dev, br_dev_sync_uc, br_dev_unsync_uc); } static void br_dev_change_rx_flags(struct net_device *dev, int change) @@ -399,7 +416,7 @@ static const struct net_device_ops br_netdev_ops = { .ndo_start_xmit = br_dev_xmit, .ndo_get_stats64 = dev_get_tstats64, .ndo_set_mac_address = br_set_mac_address, - .ndo_set_rx_mode = br_dev_set_multicast_list, + .ndo_set_rx_mode = br_dev_set_rx_mode, .ndo_change_rx_flags = br_dev_change_rx_flags, .ndo_change_mtu = br_change_mtu, .ndo_do_ioctl = br_dev_ioctl, @@ -436,7 +453,7 @@ void br_dev_setup(struct net_device *dev) dev->needs_free_netdev = true; dev->ethtool_ops = &br_ethtool_ops; SET_NETDEV_DEVTYPE(dev, &br_type); - dev->priv_flags = IFF_EBRIDGE | IFF_NO_QUEUE; + dev->priv_flags = IFF_EBRIDGE | IFF_NO_QUEUE | IFF_UNICAST_FLT; dev->features = COMMON_FEATURES | NETIF_F_LLTX | NETIF_F_NETNS_LOCAL | NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_STAG_TX; From patchwork Wed Feb 24 11:43:39 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Vladimir Oltean X-Patchwork-Id: 387605 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-15.7 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,FREEMAIL_FORGED_FROMDOMAIN,FREEMAIL_FROM, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI, SPF_HELO_NONE, SPF_PASS, URIBL_BLOCKED, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 5A3DBC433DB for ; Wed, 24 Feb 2021 11:47:06 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id EB0A264E90 for ; Wed, 24 Feb 2021 11:47:05 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S235089AbhBXLrC (ORCPT ); Wed, 24 Feb 2021 06:47:02 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:48392 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S234458AbhBXLp0 (ORCPT ); Wed, 24 Feb 2021 06:45:26 -0500 Received: from mail-ed1-x52f.google.com (mail-ed1-x52f.google.com [IPv6:2a00:1450:4864:20::52f]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 5142EC061794 for ; Wed, 24 Feb 2021 03:44:09 -0800 (PST) Received: by mail-ed1-x52f.google.com with SMTP id h25so2090956eds.4 for ; Wed, 24 Feb 2021 03:44:09 -0800 (PST) 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 :mime-version:content-transfer-encoding; bh=zM0PPFR+CS534MEi0dmiqmCC/cSsNMNZs9q4OHJGGfU=; b=U9FRwdS2NuAhcGva/znwVxqX6bWldErC0cDJq7BGCBsk+YjizWIF8TOChwNJcbODa+ t9v1utuWd5+aU7kt/FmNPbHxxj8wg//kY3W49iK3j11OvKSPR7mMdO5pwy5hYK1ebVBX Pr96NF4fBetOlx2apzXJ4iZyAj17hGENE5DzcDC3lxc4TzRLkNiEwf6XDV63AZyYRt+9 moIuezi9O7DqaOPUCC9f5quaEqXbOqOfpIPvboBHfA0UFCu5+10Mz/nCt/LBCWLHUmha 9lKDAa2SUuOb6c10lT69gBloZC+Tnie8JilQuWENs4ZnCOogKnEijR5mS7xTOl9N5mwL 4+jw== 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:mime-version:content-transfer-encoding; bh=zM0PPFR+CS534MEi0dmiqmCC/cSsNMNZs9q4OHJGGfU=; b=oFsVZUA+OSuBREWFpq9t9u0U2slWi9THi6CRxmYIL0e84ykovjZbJzPcLB0Rh7wg7W 2Wcsv8eNKVUqSpeOiKKRDh+1bZ5CacS+7ogNHs9xGNZTCXXqs47FClN6J00QCTD2f2Wm U8id3itsaNR9htlAeg4rE7HqMXN61ZB6Gy7RnVmzJweUdSAvYGlAZivutRlq7Zaqyu77 fKC0VNeCwXXlG4WxUeQ/ltgg0BXVAMS9CEhAd/FcGq8TFQKf/b0p8ePgBRCa1nfMYNv0 GWaHHqYkw3CLxrWPAS1+JZ45OXIiCp75XeeRjIjnd2K0P6FHRvhBw9wi/ioQMqjPlUJw dYRA== X-Gm-Message-State: AOAM531dxZMabJk42An1O2yEGpJE03uFAnsrGvisZUISmYFYnYOPCI3P YM7Rdwh5z7Q2CNAj21PoIF74M4Dyw9I= X-Google-Smtp-Source: ABdhPJzcz+AkqbOMjB1kzCWIcQBVWC0++fT5pEhHq8s3ge2P6c7KQVL/099XCqVVHSgLdcIEFz3SwQ== X-Received: by 2002:a05:6402:5107:: with SMTP id m7mr4077050edd.155.1614167047669; Wed, 24 Feb 2021 03:44:07 -0800 (PST) Received: from localhost.localdomain ([188.25.217.13]) by smtp.gmail.com with ESMTPSA id r5sm1203921ejx.96.2021.02.24.03.44.06 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 24 Feb 2021 03:44:07 -0800 (PST) From: Vladimir Oltean To: netdev@vger.kernel.org Cc: Andrew Lunn , Florian Fainelli , Vivien Didelot , Jiri Pirko , Ido Schimmel , DENG Qingfang , Tobias Waldekranz , George McCollister , Vlad Yasevich , Roopa Prabhu , Nikolay Aleksandrov Subject: [RFC PATCH v2 net-next 06/17] net: dsa: add addresses obtained from RX filtering to host addresses Date: Wed, 24 Feb 2021 13:43:39 +0200 Message-Id: <20210224114350.2791260-7-olteanv@gmail.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210224114350.2791260-1-olteanv@gmail.com> References: <20210224114350.2791260-1-olteanv@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org From: Vladimir Oltean In case we have ptp4l running on a bridged DSA switch interface, the PTP traffic is classified as link-local (in the default profile, the MAC addresses are 01:1b:19:00:00:00 and 01:80:c2:00:00:0e), which means it isn't the responsibility of the bridge to make sure it gets trapped to the CPU. The solution is to implement the standard callbacks for dev_uc_add and dev_mc_add, and behave just like any other network interface: ensure that the user space program can see those packets. Note that since ndo_set_rx_mode runs in atomic context, we must schedule the dsa_slave_switchdev_event_work in order to install the FDB and MDB entries to a DSA switch that may sleep. But since the DSA switchdev event logic only deals with FDB entries, we must fake some events for MDB ones. Signed-off-by: Vladimir Oltean --- net/dsa/dsa_priv.h | 10 +- net/dsa/slave.c | 329 ++++++++++++++++++++++++++++++++------------- 2 files changed, 239 insertions(+), 100 deletions(-) diff --git a/net/dsa/dsa_priv.h b/net/dsa/dsa_priv.h index 4043da2bacc0..c03c67631e23 100644 --- a/net/dsa/dsa_priv.h +++ b/net/dsa/dsa_priv.h @@ -117,10 +117,12 @@ struct dsa_switchdev_event_work { struct dsa_switch *ds; int port; struct work_struct work; - unsigned long event; - /* Specific for SWITCHDEV_FDB_ADD_TO_DEVICE and - * SWITCHDEV_FDB_DEL_TO_DEVICE - */ + enum dsa_switchdev_event { + DSA_EVENT_FDB_ADD, + DSA_EVENT_FDB_DEL, + DSA_EVENT_MDB_ADD, + DSA_EVENT_MDB_DEL, + } event; unsigned char addr[ETH_ALEN]; u16 vid; bool host_addr; diff --git a/net/dsa/slave.c b/net/dsa/slave.c index 6544a4ec69f4..65b3c1166fe7 100644 --- a/net/dsa/slave.c +++ b/net/dsa/slave.c @@ -171,6 +171,220 @@ static int dsa_host_fdb_del(struct dsa_port *dp, const unsigned char *addr, return 0; } +static void +dsa_fdb_offload_notify(struct dsa_switchdev_event_work *switchdev_work) +{ + struct dsa_switch *ds = switchdev_work->ds; + struct switchdev_notifier_fdb_info info; + struct dsa_port *dp; + + if (!dsa_is_user_port(ds, switchdev_work->port)) + return; + + info.addr = switchdev_work->addr; + info.vid = switchdev_work->vid; + info.offloaded = true; + dp = dsa_to_port(ds, switchdev_work->port); + call_switchdev_notifiers(SWITCHDEV_FDB_OFFLOADED, + dp->slave, &info.info, NULL); +} + +#define work_to_ctx(w) \ + container_of((w), struct dsa_switchdev_event_work, work) + +static void dsa_slave_switchdev_event_work(struct work_struct *work) +{ + struct dsa_switchdev_event_work *switchdev_work = work_to_ctx(work); + struct dsa_switch *ds = switchdev_work->ds; + struct dsa_port *dp; + int err; + + dp = dsa_to_port(ds, switchdev_work->port); + + rtnl_lock(); + switch (switchdev_work->event) { + case DSA_EVENT_FDB_ADD: + if (switchdev_work->host_addr) + err = dsa_host_fdb_add(dp, switchdev_work->addr, + switchdev_work->vid); + else + err = dsa_port_fdb_add(dp, switchdev_work->addr, + switchdev_work->vid); + if (err) { + dev_err(ds->dev, + "port %d failed to add %pM vid %d to fdb: %d\n", + dp->index, switchdev_work->addr, + switchdev_work->vid, err); + break; + } + dsa_fdb_offload_notify(switchdev_work); + break; + + case DSA_EVENT_FDB_DEL: + if (switchdev_work->host_addr) + err = dsa_host_fdb_del(dp, switchdev_work->addr, + switchdev_work->vid); + else + err = dsa_port_fdb_del(dp, switchdev_work->addr, + switchdev_work->vid); + if (err) { + dev_err(ds->dev, + "port %d failed to delete %pM vid %d from fdb: %d\n", + dp->index, switchdev_work->addr, + switchdev_work->vid, err); + } + + break; + + case DSA_EVENT_MDB_ADD: { + struct switchdev_obj_port_mdb mdb; + + ether_addr_copy(mdb.addr, switchdev_work->addr); + mdb.vid = switchdev_work->vid; + + if (switchdev_work->host_addr) + err = dsa_host_mdb_add(dp, &mdb); + else + err = dsa_port_mdb_add(dp, &mdb); + if (err) { + dev_err(ds->dev, + "port %d failed to add %pM vid %d to mdb: %d\n", + dp->index, mdb.addr, mdb.vid, err); + break; + } + dsa_fdb_offload_notify(switchdev_work); + break; + } + case DSA_EVENT_MDB_DEL: { + struct switchdev_obj_port_mdb mdb; + + ether_addr_copy(mdb.addr, switchdev_work->addr); + mdb.vid = switchdev_work->vid; + + if (switchdev_work->host_addr) + err = dsa_host_mdb_del(dp, &mdb); + else + err = dsa_port_mdb_del(dp, &mdb); + if (err) { + dev_err(ds->dev, + "port %d failed to delete %pM vid %d from mdb: %d\n", + dp->index, mdb.addr, mdb.vid, err); + } + break; + } + default: + break; + } + rtnl_unlock(); + + kfree(switchdev_work); + dev_put(dp->slave); +} + + +static int dsa_slave_schedule_switchdev_work(struct net_device *dev, + enum dsa_switchdev_event event, + const unsigned char *addr, u16 vid, + bool host_addr) +{ + struct dsa_switchdev_event_work *switchdev_work; + struct dsa_port *dp = dsa_slave_to_port(dev); + + if (!dp->ds->ops->port_fdb_add || !dp->ds->ops->port_fdb_del) + return -EOPNOTSUPP; + + switchdev_work = kzalloc(sizeof(*switchdev_work), GFP_ATOMIC); + if (!switchdev_work) + return -ENOMEM; + + INIT_WORK(&switchdev_work->work, dsa_slave_switchdev_event_work); + switchdev_work->ds = dp->ds; + switchdev_work->port = dp->index; + switchdev_work->event = event; + + ether_addr_copy(switchdev_work->addr, addr); + switchdev_work->vid = vid; + switchdev_work->host_addr = host_addr; + + /* Hold a reference on the slave for dsa_fdb_offload_notify */ + dev_hold(dev); + dsa_schedule_work(&switchdev_work->work); + + return 0; +} + +static int dsa_slave_sync_uc(struct net_device *dev, + const unsigned char *addr) +{ + int err; + + err = dsa_slave_schedule_switchdev_work(dev, DSA_EVENT_FDB_ADD, + addr, 0, true); + if (err == -EOPNOTSUPP) { + struct dsa_port *dp = dsa_slave_to_port(dev); + + dev_uc_add(dp->cpu_dp->master, addr); + + return 0; + } + + return err; +} + +static int dsa_slave_unsync_uc(struct net_device *dev, + const unsigned char *addr) +{ + int err; + + err = dsa_slave_schedule_switchdev_work(dev, DSA_EVENT_FDB_DEL, + addr, 0, true); + if (err == -EOPNOTSUPP) { + struct dsa_port *dp = dsa_slave_to_port(dev); + + dev_uc_del(dp->cpu_dp->master, addr); + + return 0; + } + + return err; +} + +static int dsa_slave_sync_mc(struct net_device *dev, + const unsigned char *addr) +{ + int err; + + err = dsa_slave_schedule_switchdev_work(dev, DSA_EVENT_MDB_ADD, + addr, 0, true); + if (err == -EOPNOTSUPP) { + struct dsa_port *dp = dsa_slave_to_port(dev); + + dev_mc_add(dp->cpu_dp->master, addr); + + return 0; + } + + return err; +} + +static int dsa_slave_unsync_mc(struct net_device *dev, + const unsigned char *addr) +{ + int err; + + err = dsa_slave_schedule_switchdev_work(dev, DSA_EVENT_MDB_DEL, + addr, 0, true); + if (err == -EOPNOTSUPP) { + struct dsa_port *dp = dsa_slave_to_port(dev); + + dev_mc_del(dp->cpu_dp->master, addr); + + return 0; + } + + return err; +} + /* slave mii_bus handling ***************************************************/ static int dsa_slave_phy_read(struct mii_bus *bus, int addr, int reg) { @@ -263,8 +477,9 @@ static int dsa_slave_close(struct net_device *dev) dsa_port_disable_rt(dp); - dev_mc_unsync(master, dev); - dev_uc_unsync(master, dev); + __dev_uc_sync(dev, dsa_slave_sync_uc, dsa_slave_unsync_uc); + __dev_mc_sync(dev, dsa_slave_sync_mc, dsa_slave_unsync_mc); + if (dev->flags & IFF_ALLMULTI) dev_set_allmulti(master, -1); if (dev->flags & IFF_PROMISC) @@ -290,10 +505,8 @@ static void dsa_slave_change_rx_flags(struct net_device *dev, int change) static void dsa_slave_set_rx_mode(struct net_device *dev) { - struct net_device *master = dsa_slave_to_master(dev); - - dev_mc_sync(master, dev); - dev_uc_sync(master, dev); + __dev_uc_sync(dev, dsa_slave_sync_uc, dsa_slave_unsync_uc); + __dev_mc_sync(dev, dsa_slave_sync_mc, dsa_slave_unsync_mc); } static int dsa_slave_set_mac_address(struct net_device *dev, void *a) @@ -1970,6 +2183,8 @@ int dsa_slave_create(struct dsa_port *port) else eth_hw_addr_inherit(slave_dev, master); slave_dev->priv_flags |= IFF_NO_QUEUE; + if (ds->ops->port_fdb_add && ds->ops->port_fdb_del) + slave_dev->priv_flags |= IFF_UNICAST_FLT; slave_dev->netdev_ops = &dsa_slave_netdev_ops; if (ds->ops->port_max_mtu) slave_dev->max_mtu = ds->ops->port_max_mtu(ds, port->index); @@ -2290,75 +2505,6 @@ static int dsa_slave_netdevice_event(struct notifier_block *nb, return NOTIFY_DONE; } -static void -dsa_fdb_offload_notify(struct dsa_switchdev_event_work *switchdev_work) -{ - struct dsa_switch *ds = switchdev_work->ds; - struct switchdev_notifier_fdb_info info; - struct dsa_port *dp; - - if (!dsa_is_user_port(ds, switchdev_work->port)) - return; - - info.addr = switchdev_work->addr; - info.vid = switchdev_work->vid; - info.offloaded = true; - dp = dsa_to_port(ds, switchdev_work->port); - call_switchdev_notifiers(SWITCHDEV_FDB_OFFLOADED, - dp->slave, &info.info, NULL); -} - -static void dsa_slave_switchdev_event_work(struct work_struct *work) -{ - struct dsa_switchdev_event_work *switchdev_work = - container_of(work, struct dsa_switchdev_event_work, work); - struct dsa_switch *ds = switchdev_work->ds; - struct dsa_port *dp; - int err; - - dp = dsa_to_port(ds, switchdev_work->port); - - rtnl_lock(); - switch (switchdev_work->event) { - case SWITCHDEV_FDB_ADD_TO_DEVICE: - if (switchdev_work->host_addr) - err = dsa_host_fdb_add(dp, switchdev_work->addr, - switchdev_work->vid); - else - err = dsa_port_fdb_add(dp, switchdev_work->addr, - switchdev_work->vid); - if (err) { - dev_err(ds->dev, - "port %d failed to add %pM vid %d to fdb: %d\n", - dp->index, switchdev_work->addr, - switchdev_work->vid, err); - break; - } - dsa_fdb_offload_notify(switchdev_work); - break; - - case SWITCHDEV_FDB_DEL_TO_DEVICE: - if (switchdev_work->host_addr) - err = dsa_host_fdb_del(dp, switchdev_work->addr, - switchdev_work->vid); - else - err = dsa_port_fdb_del(dp, switchdev_work->addr, - switchdev_work->vid); - if (err) { - dev_err(ds->dev, - "port %d failed to delete %pM vid %d from fdb: %d\n", - dp->index, switchdev_work->addr, - switchdev_work->vid, err); - } - - break; - } - rtnl_unlock(); - - kfree(switchdev_work); - dev_put(dp->slave); -} - static int dsa_lower_dev_walk(struct net_device *lower_dev, struct netdev_nested_priv *priv) { @@ -2387,7 +2533,7 @@ static int dsa_slave_switchdev_event(struct notifier_block *unused, { struct net_device *dev = switchdev_notifier_info_to_dev(ptr); const struct switchdev_notifier_fdb_info *fdb_info; - struct dsa_switchdev_event_work *switchdev_work; + enum dsa_switchdev_event dsa_event; bool host_addr = false; struct dsa_port *dp; int err; @@ -2441,28 +2587,19 @@ static int dsa_slave_switchdev_event(struct notifier_block *unused, return NOTIFY_DONE; } - if (!dp->ds->ops->port_fdb_add || !dp->ds->ops->port_fdb_del) - return NOTIFY_DONE; - - switchdev_work = kzalloc(sizeof(*switchdev_work), GFP_ATOMIC); - if (!switchdev_work) - return NOTIFY_BAD; - - INIT_WORK(&switchdev_work->work, - dsa_slave_switchdev_event_work); - switchdev_work->ds = dp->ds; - switchdev_work->port = dp->index; - switchdev_work->event = event; + if (event == SWITCHDEV_FDB_ADD_TO_DEVICE) + dsa_event = DSA_EVENT_FDB_ADD; + else + dsa_event = DSA_EVENT_FDB_DEL; - ether_addr_copy(switchdev_work->addr, - fdb_info->addr); - switchdev_work->vid = fdb_info->vid; - switchdev_work->host_addr = host_addr; + err = dsa_slave_schedule_switchdev_work(dp->slave, dsa_event, + fdb_info->addr, + fdb_info->vid, + host_addr); + if (err == -EOPNOTSUPP) + return NOTIFY_OK; - /* Hold a reference on the slave for dsa_fdb_offload_notify */ - dev_hold(dev); - dsa_schedule_work(&switchdev_work->work); - break; + return notifier_from_errno(err); default: return NOTIFY_DONE; } From patchwork Wed Feb 24 11:43:40 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Vladimir Oltean X-Patchwork-Id: 387102 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-15.7 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,FREEMAIL_FORGED_FROMDOMAIN,FREEMAIL_FROM, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI, SPF_HELO_NONE, SPF_PASS, URIBL_BLOCKED, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 85493C433DB for ; Wed, 24 Feb 2021 11:46:52 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 4522664E90 for ; Wed, 24 Feb 2021 11:46:52 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S235080AbhBXLqs (ORCPT ); Wed, 24 Feb 2021 06:46:48 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:48398 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S235009AbhBXLp0 (ORCPT ); Wed, 24 Feb 2021 06:45:26 -0500 Received: from mail-ed1-x535.google.com (mail-ed1-x535.google.com [IPv6:2a00:1450:4864:20::535]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 33321C061797 for ; Wed, 24 Feb 2021 03:44:10 -0800 (PST) Received: by mail-ed1-x535.google.com with SMTP id d2so2050204edq.10 for ; Wed, 24 Feb 2021 03:44:10 -0800 (PST) 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 :mime-version:content-transfer-encoding; bh=667OGP0Gur8Sq+vHsTVkN4C3tR422yk3lVbW1cl/0Uw=; b=o+6vY7wsB9AQBYTO360K6jEVdDhsIdH3YjnbrCuQz8j9lrGrh7hP/dnaUYwDVegkyb eEnwm8Vo6zEdXwlBWkjIb/pkwy0oYTmOKUxyhCpUTPOQDjaM0y2hPuio++fCIbXyGKm3 25KwVs5Jizedg4ZrCZM3crtcIiefcqBoowDLC1ceZlC2PBxOs6TCh/FiQkZw9eEi+IKy VvVlTaBhnWOcLVjXveDfKlbmeWvlwUSU1FA1SfbmO72Umfr8hmUMrtbSnx4v+XhymYko WjFznW20cpDv+2LLCFmdSGVJ7zlDOsSoPuFHANHSHmISmQPU7rJywCYZTgdxRCXJWG8L wFEQ== 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:mime-version:content-transfer-encoding; bh=667OGP0Gur8Sq+vHsTVkN4C3tR422yk3lVbW1cl/0Uw=; b=fsKM5w8wg8UW/sxbaK2EBT6HmS0FmZPm8QEVKe4woO/hpwH8eslXE1i44j8lUKAMk1 Rd5liUBX0/HlKBaPkNxNCsEr7N3n5eMhKaLACQqjzS5A7+fnYLfjXT3QZwismYd5YavJ KsUQCmq/rqbLoyWdajRlmy13aokJIW5KcZg0k8CKoWjaU3vnwJlWbcyYv77eE9W6R23t RiRxavGJt+TDAOaRamwiHUUUfgf7PfvCePzxzFa1wXpuq4hsfZzSlSa4YvlOAAF9jJT8 Z9xK+RE3IIQXrZfKYDc5CPDKETs5POBhCtuvxJmSPNm2LBH7Den0tT9GYPjST3m5ELI/ CO1Q== X-Gm-Message-State: AOAM5322YGJPNGtWN/NBJ6tTQDvmPRiCZll9z5JMSmdE+p1hyEMpZA74 fkLG0sXYdF1WG9Ri3xglNnISOVPk8zg= X-Google-Smtp-Source: ABdhPJyfut56mhd0R1WD+LbadiL0LDK3gh1OJuqZuwHc8Jru3rynLgOUYTslt6l7wGA1RK1xrDvQvA== X-Received: by 2002:a05:6402:1383:: with SMTP id b3mr31705045edv.131.1614167048745; Wed, 24 Feb 2021 03:44:08 -0800 (PST) Received: from localhost.localdomain ([188.25.217.13]) by smtp.gmail.com with ESMTPSA id r5sm1203921ejx.96.2021.02.24.03.44.07 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 24 Feb 2021 03:44:08 -0800 (PST) From: Vladimir Oltean To: netdev@vger.kernel.org Cc: Andrew Lunn , Florian Fainelli , Vivien Didelot , Jiri Pirko , Ido Schimmel , DENG Qingfang , Tobias Waldekranz , George McCollister , Vlad Yasevich , Roopa Prabhu , Nikolay Aleksandrov Subject: [RFC PATCH v2 net-next 07/17] net: bridge: switchdev: refactor br_switchdev_fdb_notify Date: Wed, 24 Feb 2021 13:43:40 +0200 Message-Id: <20210224114350.2791260-8-olteanv@gmail.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210224114350.2791260-1-olteanv@gmail.com> References: <20210224114350.2791260-1-olteanv@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org From: Tobias Waldekranz Instead of having to add more and more arguments to br_switchdev_fdb_call_notifiers, get rid of it and build the info struct directly in br_switchdev_fdb_notify. Signed-off-by: Tobias Waldekranz Reviewed-by: Vladimir Oltean Signed-off-by: Vladimir Oltean --- net/bridge/br_switchdev.c | 41 +++++++++++---------------------------- 1 file changed, 11 insertions(+), 30 deletions(-) diff --git a/net/bridge/br_switchdev.c b/net/bridge/br_switchdev.c index b89503832fcc..1386677bdaf8 100644 --- a/net/bridge/br_switchdev.c +++ b/net/bridge/br_switchdev.c @@ -107,46 +107,27 @@ int br_switchdev_set_port_flag(struct net_bridge_port *p, return 0; } -static void -br_switchdev_fdb_call_notifiers(bool adding, const unsigned char *mac, - u16 vid, struct net_device *dev, - bool added_by_user, bool offloaded) -{ - struct switchdev_notifier_fdb_info info; - unsigned long notifier_type; - - info.addr = mac; - info.vid = vid; - info.added_by_user = added_by_user; - info.offloaded = offloaded; - notifier_type = adding ? SWITCHDEV_FDB_ADD_TO_DEVICE : SWITCHDEV_FDB_DEL_TO_DEVICE; - call_switchdev_notifiers(notifier_type, dev, &info.info, NULL); -} - void br_switchdev_fdb_notify(const struct net_bridge_fdb_entry *fdb, int type) { + struct switchdev_notifier_fdb_info info = { + .addr = fdb->key.addr.addr, + .vid = fdb->key.vlan_id, + .added_by_user = test_bit(BR_FDB_ADDED_BY_USER, &fdb->flags), + .offloaded = test_bit(BR_FDB_OFFLOADED, &fdb->flags), + }; + if (!fdb->dst) return; switch (type) { case RTM_DELNEIGH: - br_switchdev_fdb_call_notifiers(false, fdb->key.addr.addr, - fdb->key.vlan_id, - fdb->dst->dev, - test_bit(BR_FDB_ADDED_BY_USER, - &fdb->flags), - test_bit(BR_FDB_OFFLOADED, - &fdb->flags)); + call_switchdev_notifiers(SWITCHDEV_FDB_DEL_TO_DEVICE, + fdb->dst->dev, &info.info, NULL); break; case RTM_NEWNEIGH: - br_switchdev_fdb_call_notifiers(true, fdb->key.addr.addr, - fdb->key.vlan_id, - fdb->dst->dev, - test_bit(BR_FDB_ADDED_BY_USER, - &fdb->flags), - test_bit(BR_FDB_OFFLOADED, - &fdb->flags)); + call_switchdev_notifiers(SWITCHDEV_FDB_ADD_TO_DEVICE, + fdb->dst->dev, &info.info, NULL); break; } } From patchwork Wed Feb 24 11:43:41 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Vladimir Oltean X-Patchwork-Id: 387101 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-15.7 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,FREEMAIL_FORGED_FROMDOMAIN,FREEMAIL_FROM, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI, SPF_HELO_NONE, SPF_PASS, URIBL_BLOCKED, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id CA39DC433DB for ; Wed, 24 Feb 2021 11:47:27 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 6F0BF64E90 for ; Wed, 24 Feb 2021 11:47:27 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S234973AbhBXLrR (ORCPT ); Wed, 24 Feb 2021 06:47:17 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:48408 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S234255AbhBXLp2 (ORCPT ); Wed, 24 Feb 2021 06:45:28 -0500 Received: from mail-ed1-x536.google.com (mail-ed1-x536.google.com [IPv6:2a00:1450:4864:20::536]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 60C93C0617A7 for ; Wed, 24 Feb 2021 03:44:11 -0800 (PST) Received: by mail-ed1-x536.google.com with SMTP id d2so2050271edq.10 for ; Wed, 24 Feb 2021 03:44:11 -0800 (PST) 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 :mime-version:content-transfer-encoding; bh=ZhQQzSKu+5RLnYgBeMfX0i3Omf38kuDGLkALtzF7r7Q=; b=Zz9DRj+oV0tqMAIs9xPPagw8m6szTfqRggXu9xVtFT3GasjpxS+0PFa7VgAhE4X550 6rRdldOa3W8pce+pCt73jd0Gos8mrmfSkeqrOSveqLlJB04Wd0lk1R9dM/MpiO+cPEHx Pum9ZEzv8jeGYS9vUth12g9d9Xrblvul4/n5jbLUS9jGbcTsqjxRCrZpaWcu1YqWuvzU Rj5G03qEE7lhUpI3lQmwGG4XcsWQ2ZxwfOyhaaTupU1tjyZiSfSlR6C85FBXwVCz8S48 n6Ey7VyJ7L3ZSvTiiF4Tu333pfpkyi+ZA7ENj+u5BcH2TRAYskDIfhW/RfbXlap85ejE QJiQ== 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:mime-version:content-transfer-encoding; bh=ZhQQzSKu+5RLnYgBeMfX0i3Omf38kuDGLkALtzF7r7Q=; b=TRUr3o2Ele8q5ydrPR5bWJvcuVPFPvM8pt1a0A/cPRSEdhT01brNDApzBYyd2uNABe gp/VJIOnkN7Vhih70kXNUHuCpWFRDIgz4ZFD8iyFaaxfOX0VbE467CVjr1Dg8X05MuGW E2p/WXFmD45w8it5e7EAmOxDdEM4k60vczYb5rdKqp0ohh1nSfLp+xtaHzpgIoBudBhE kozKGNsIRb97dOBjbVSFjStldEYE3c6oIcurSq3E/G64WDLQYq8pcX90gWoIKN5+y+E6 /wnxcTHBhuAgbhhKYapNRcgBppawew4ruaBZUhIJPjnS+/qkJwmIpoKXMLCft36IKgO8 9yDw== X-Gm-Message-State: AOAM53222Qup1TX/4nd7B37AwfbeojT8ui+wsvOHYGhiz0HKih+FSRWu E2KhmkCS+vdIumuSZm2cPbjnyxIgduY= X-Google-Smtp-Source: ABdhPJyJNq5jlf9RaxyPurSjUmWgmYK1IDT89mBLI9IMnecf6hYxtzFN4zieU1yE1OWNTmNBlDHe6w== X-Received: by 2002:a05:6402:95d:: with SMTP id h29mr1467675edz.327.1614167049850; Wed, 24 Feb 2021 03:44:09 -0800 (PST) Received: from localhost.localdomain ([188.25.217.13]) by smtp.gmail.com with ESMTPSA id r5sm1203921ejx.96.2021.02.24.03.44.08 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 24 Feb 2021 03:44:09 -0800 (PST) From: Vladimir Oltean To: netdev@vger.kernel.org Cc: Andrew Lunn , Florian Fainelli , Vivien Didelot , Jiri Pirko , Ido Schimmel , DENG Qingfang , Tobias Waldekranz , George McCollister , Vlad Yasevich , Roopa Prabhu , Nikolay Aleksandrov Subject: [RFC PATCH v2 net-next 08/17] net: bridge: switchdev: include local flag in FDB notifications Date: Wed, 24 Feb 2021 13:43:41 +0200 Message-Id: <20210224114350.2791260-9-olteanv@gmail.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210224114350.2791260-1-olteanv@gmail.com> References: <20210224114350.2791260-1-olteanv@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org From: Vladimir Oltean As explained in the discussion on the initial version of this patch: https://lore.kernel.org/netdev/20210117193009.io3nungdwuzmo5f7@skbuf/ the switchdev notifiers for FDB entries managed to have a zero-day bug. The bridge would not say that this entry is local: ip link add br0 type bridge ip link set swp0 master br0 bridge fdb add dev swp0 00:01:02:03:04:05 master local and the switchdev driver would be more than happy to offload it as a normal static FDB entry. This is despite the fact that 'local' and non-'local' entries have completely opposite directions: a local entry is locally terminated and not forwarded, whereas a static entry is forwarded and not locally terminated. So, for example, DSA would install this entry on swp0 instead of installing it on the CPU port as it should. There is an even sadder part, which is that the 'local' flag is implicit if 'static' is not specified, meaning that this command produces the same result of adding a 'local' entry: bridge fdb add dev swp0 00:01:02:03:04:05 master So this patch is a bugfix which does what should have been done from day one: make the bridge inform switchdev that it's a local entry, and have all drivers ignore local entries (since none of them currently has any logic to deal with host entries). At least we've updated the man pages for 'bridge' now, and we're pretty explicit that the commands above were broken and should have never worked: https://patchwork.kernel.org/project/netdevbpf/cover/20210211104502.2081443-1-olteanv@gmail.com/ But we don't do anything to even attempt to keep backwards compatibility with the broken behavior. If we did that, it would be pretty much game over for any attempt to really deal with host entries in switchdev drivers. Co-developed-by: Tobias Waldekranz Signed-off-by: Tobias Waldekranz Signed-off-by: Vladimir Oltean --- drivers/net/ethernet/marvell/prestera/prestera_switchdev.c | 2 +- drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c | 5 +++-- drivers/net/ethernet/rocker/rocker_main.c | 4 ++-- drivers/net/ethernet/ti/am65-cpsw-switchdev.c | 4 ++-- drivers/net/ethernet/ti/cpsw_switchdev.c | 4 ++-- drivers/staging/fsl-dpaa2/ethsw/ethsw.c | 4 ++-- include/net/switchdev.h | 1 + net/bridge/br_switchdev.c | 1 + net/dsa/slave.c | 2 +- 9 files changed, 15 insertions(+), 12 deletions(-) diff --git a/drivers/net/ethernet/marvell/prestera/prestera_switchdev.c b/drivers/net/ethernet/marvell/prestera/prestera_switchdev.c index 49e052273f30..cb564890a3dc 100644 --- a/drivers/net/ethernet/marvell/prestera/prestera_switchdev.c +++ b/drivers/net/ethernet/marvell/prestera/prestera_switchdev.c @@ -798,7 +798,7 @@ static void prestera_fdb_event_work(struct work_struct *work) switch (swdev_work->event) { case SWITCHDEV_FDB_ADD_TO_DEVICE: fdb_info = &swdev_work->fdb_info; - if (!fdb_info->added_by_user) + if (!fdb_info->added_by_user || fdb_info->is_local) break; err = prestera_port_fdb_set(port, fdb_info, true); diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c index 23b7e8d6386b..9aadc29ad777 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c @@ -2865,7 +2865,8 @@ mlxsw_sp_switchdev_bridge_nve_fdb_event(struct mlxsw_sp_switchdev_event_work * return; if (switchdev_work->event == SWITCHDEV_FDB_ADD_TO_DEVICE && - !switchdev_work->fdb_info.added_by_user) + (!switchdev_work->fdb_info.added_by_user || + switchdev_work->fdb_info.is_local)) return; if (!netif_running(dev)) @@ -2920,7 +2921,7 @@ static void mlxsw_sp_switchdev_bridge_fdb_event_work(struct work_struct *work) switch (switchdev_work->event) { case SWITCHDEV_FDB_ADD_TO_DEVICE: fdb_info = &switchdev_work->fdb_info; - if (!fdb_info->added_by_user) + if (!fdb_info->added_by_user || fdb_info->is_local) break; err = mlxsw_sp_port_fdb_set(mlxsw_sp_port, fdb_info, true); if (err) diff --git a/drivers/net/ethernet/rocker/rocker_main.c b/drivers/net/ethernet/rocker/rocker_main.c index 3473d296b2e2..a46633606cae 100644 --- a/drivers/net/ethernet/rocker/rocker_main.c +++ b/drivers/net/ethernet/rocker/rocker_main.c @@ -2736,7 +2736,7 @@ static void rocker_switchdev_event_work(struct work_struct *work) switch (switchdev_work->event) { case SWITCHDEV_FDB_ADD_TO_DEVICE: fdb_info = &switchdev_work->fdb_info; - if (!fdb_info->added_by_user) + if (!fdb_info->added_by_user || fdb_info->is_local) break; err = rocker_world_port_fdb_add(rocker_port, fdb_info); if (err) { @@ -2747,7 +2747,7 @@ static void rocker_switchdev_event_work(struct work_struct *work) break; case SWITCHDEV_FDB_DEL_TO_DEVICE: fdb_info = &switchdev_work->fdb_info; - if (!fdb_info->added_by_user) + if (!fdb_info->added_by_user || fdb_info->is_local) break; err = rocker_world_port_fdb_del(rocker_port, fdb_info); if (err) diff --git a/drivers/net/ethernet/ti/am65-cpsw-switchdev.c b/drivers/net/ethernet/ti/am65-cpsw-switchdev.c index d93ffd8a08b0..23cfb91e9c4d 100644 --- a/drivers/net/ethernet/ti/am65-cpsw-switchdev.c +++ b/drivers/net/ethernet/ti/am65-cpsw-switchdev.c @@ -385,7 +385,7 @@ static void am65_cpsw_switchdev_event_work(struct work_struct *work) fdb->addr, fdb->vid, fdb->added_by_user, fdb->offloaded, port_id); - if (!fdb->added_by_user) + if (!fdb->added_by_user || fdb->is_local) break; if (memcmp(port->slave.mac_addr, (u8 *)fdb->addr, ETH_ALEN) == 0) port_id = HOST_PORT_NUM; @@ -401,7 +401,7 @@ static void am65_cpsw_switchdev_event_work(struct work_struct *work) fdb->addr, fdb->vid, fdb->added_by_user, fdb->offloaded, port_id); - if (!fdb->added_by_user) + if (!fdb->added_by_user || fdb->is_local) break; if (memcmp(port->slave.mac_addr, (u8 *)fdb->addr, ETH_ALEN) == 0) port_id = HOST_PORT_NUM; diff --git a/drivers/net/ethernet/ti/cpsw_switchdev.c b/drivers/net/ethernet/ti/cpsw_switchdev.c index a72bb570756f..05a64fb7a04f 100644 --- a/drivers/net/ethernet/ti/cpsw_switchdev.c +++ b/drivers/net/ethernet/ti/cpsw_switchdev.c @@ -395,7 +395,7 @@ static void cpsw_switchdev_event_work(struct work_struct *work) fdb->addr, fdb->vid, fdb->added_by_user, fdb->offloaded, port); - if (!fdb->added_by_user) + if (!fdb->added_by_user || fdb->is_local) break; if (memcmp(priv->mac_addr, (u8 *)fdb->addr, ETH_ALEN) == 0) port = HOST_PORT_NUM; @@ -411,7 +411,7 @@ static void cpsw_switchdev_event_work(struct work_struct *work) fdb->addr, fdb->vid, fdb->added_by_user, fdb->offloaded, port); - if (!fdb->added_by_user) + if (!fdb->added_by_user || fdb->is_local) break; if (memcmp(priv->mac_addr, (u8 *)fdb->addr, ETH_ALEN) == 0) port = HOST_PORT_NUM; diff --git a/drivers/staging/fsl-dpaa2/ethsw/ethsw.c b/drivers/staging/fsl-dpaa2/ethsw/ethsw.c index 703055e063ff..aad212b9b97b 100644 --- a/drivers/staging/fsl-dpaa2/ethsw/ethsw.c +++ b/drivers/staging/fsl-dpaa2/ethsw/ethsw.c @@ -1298,7 +1298,7 @@ static void dpaa2_switch_event_work(struct work_struct *work) switch (switchdev_work->event) { case SWITCHDEV_FDB_ADD_TO_DEVICE: - if (!fdb_info->added_by_user) + if (!fdb_info->added_by_user || fdb_info->is_local) break; if (is_unicast_ether_addr(fdb_info->addr)) err = dpaa2_switch_port_fdb_add_uc(netdev_priv(dev), @@ -1313,7 +1313,7 @@ static void dpaa2_switch_event_work(struct work_struct *work) &fdb_info->info, NULL); break; case SWITCHDEV_FDB_DEL_TO_DEVICE: - if (!fdb_info->added_by_user) + if (!fdb_info->added_by_user || fdb_info->is_local) break; if (is_unicast_ether_addr(fdb_info->addr)) dpaa2_switch_port_fdb_del_uc(netdev_priv(dev), fdb_info->addr); diff --git a/include/net/switchdev.h b/include/net/switchdev.h index b7fc7d0f54e2..ca7223a79135 100644 --- a/include/net/switchdev.h +++ b/include/net/switchdev.h @@ -208,6 +208,7 @@ struct switchdev_notifier_fdb_info { const unsigned char *addr; u16 vid; u8 added_by_user:1, + is_local:1, offloaded:1; }; diff --git a/net/bridge/br_switchdev.c b/net/bridge/br_switchdev.c index 1386677bdaf8..a5e601e41cb9 100644 --- a/net/bridge/br_switchdev.c +++ b/net/bridge/br_switchdev.c @@ -114,6 +114,7 @@ br_switchdev_fdb_notify(const struct net_bridge_fdb_entry *fdb, int type) .addr = fdb->key.addr.addr, .vid = fdb->key.vlan_id, .added_by_user = test_bit(BR_FDB_ADDED_BY_USER, &fdb->flags), + .is_local = test_bit(BR_FDB_LOCAL, &fdb->flags), .offloaded = test_bit(BR_FDB_OFFLOADED, &fdb->flags), }; diff --git a/net/dsa/slave.c b/net/dsa/slave.c index 65b3c1166fe7..c4db870b48e5 100644 --- a/net/dsa/slave.c +++ b/net/dsa/slave.c @@ -2549,7 +2549,7 @@ static int dsa_slave_switchdev_event(struct notifier_block *unused, fdb_info = ptr; if (dsa_slave_dev_check(dev)) { - if (!fdb_info->added_by_user) + if (!fdb_info->added_by_user || fdb_info->is_local) return NOTIFY_OK; dp = dsa_slave_to_port(dev); From patchwork Wed Feb 24 11:43:42 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Vladimir Oltean X-Patchwork-Id: 387604 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-15.7 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,FREEMAIL_FORGED_FROMDOMAIN,FREEMAIL_FROM, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI, SPF_HELO_NONE, SPF_PASS, URIBL_BLOCKED, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 0C4EFC433E0 for ; Wed, 24 Feb 2021 11:47:38 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id AB66564E90 for ; Wed, 24 Feb 2021 11:47:37 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S235016AbhBXLre (ORCPT ); Wed, 24 Feb 2021 06:47:34 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:48412 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S235010AbhBXLp2 (ORCPT ); Wed, 24 Feb 2021 06:45:28 -0500 Received: from mail-ed1-x536.google.com (mail-ed1-x536.google.com [IPv6:2a00:1450:4864:20::536]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 8F91EC0617A9 for ; Wed, 24 Feb 2021 03:44:12 -0800 (PST) Received: by mail-ed1-x536.google.com with SMTP id j9so2111121edp.1 for ; Wed, 24 Feb 2021 03:44:12 -0800 (PST) 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 :mime-version:content-transfer-encoding; bh=rdXrHF3RIlZtNN200L/dGI+RQwRa1qmw0c6RA8LNzA8=; b=d6rDMWZ2DGT8dwOrfmdIRj8aHw5c8EDLfBvC/BFWErLThrNaa44qMLwzb0hfOh2AJg fqZDd+Bn77M5aXvypKD/rcn4dcy0hVfq7jpR7RejQj60Ex0/NEv6vw5nGbr+SduCoj/2 L9b3wmtnPo2RHR09G3jAHZ5NNM+DUwp2fCM4KADVA5gjuK3DV6wUf+rU0LKaPGu7YTHO zBxdxuNsMAnVYCae+STLtztKtu31t43bvHsArcq71DXIRt1ha+XXexlDyhjtQN6/b/L1 7T5Bzk1fBvCmxfnOqI8o0OOk8QxmlUYsQ3nRwM8iU5XWAqvkFI7EZ50T82mYzjECdWW5 Jyhg== 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:mime-version:content-transfer-encoding; bh=rdXrHF3RIlZtNN200L/dGI+RQwRa1qmw0c6RA8LNzA8=; b=NtqlPpmu8VWkNu6I9eAiz6j+a2EUuNnRescTrr76eNkk9j33tNlcp7hi5rpEwXPKy8 aLWpzkTbkQyh+SBi7wcf6xiXKeQODrBE+u0rsaT6stGyBkhpz+H8reyIQ30wiv6C6pN3 6A4yQGmqI9OwpqaIvLWtIKFQ7wlk3nxyHUfnQSwkHfZyT8sBAZU0W3uvzNysON9hrYOE xOQcuAjP87Iaro4To+Sh3Mwceiqp/VhRyFNT7+h2esiSeKzGfkXzQtHp5ABSOBE3CmuB RTruwolvrKjXSOKWtnSrAk/Vt9Cia6h1LSli1iuNsSQW50jvl8hSsz9bn+YGeA1NuGbl VeWg== X-Gm-Message-State: AOAM533dX+lq2HlsEwY427fVu2b/UMoHj1nEV5o1bsdKINUj8+pXP0lb MtMvG28gLHBLBd/C7VUhdVPMH8tX0HQ= X-Google-Smtp-Source: ABdhPJw0W02an/0vVWIhl/MikZUw4lX60Ta12Sc4yqG3D2Bc7izcAU+/RoeGaXrNqQFhHjko09Kd8w== X-Received: by 2002:a05:6402:34d2:: with SMTP id w18mr33971761edc.102.1614167051134; Wed, 24 Feb 2021 03:44:11 -0800 (PST) Received: from localhost.localdomain ([188.25.217.13]) by smtp.gmail.com with ESMTPSA id r5sm1203921ejx.96.2021.02.24.03.44.09 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 24 Feb 2021 03:44:10 -0800 (PST) From: Vladimir Oltean To: netdev@vger.kernel.org Cc: Andrew Lunn , Florian Fainelli , Vivien Didelot , Jiri Pirko , Ido Schimmel , DENG Qingfang , Tobias Waldekranz , George McCollister , Vlad Yasevich , Roopa Prabhu , Nikolay Aleksandrov Subject: [RFC PATCH v2 net-next 09/17] net: bridge: switchdev: send FDB notifications for host addresses Date: Wed, 24 Feb 2021 13:43:42 +0200 Message-Id: <20210224114350.2791260-10-olteanv@gmail.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210224114350.2791260-1-olteanv@gmail.com> References: <20210224114350.2791260-1-olteanv@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org From: Tobias Waldekranz Treat addresses added to the bridge itself in the same way as regular ports and send out a notification so that drivers may sync it down to the hardware FDB. Signed-off-by: Tobias Waldekranz Signed-off-by: Vladimir Oltean --- net/bridge/br_fdb.c | 4 ++-- net/bridge/br_private.h | 7 ++++--- net/bridge/br_switchdev.c | 11 +++++------ 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/net/bridge/br_fdb.c b/net/bridge/br_fdb.c index b7490237f3fc..1d54ae0f58fb 100644 --- a/net/bridge/br_fdb.c +++ b/net/bridge/br_fdb.c @@ -602,7 +602,7 @@ void br_fdb_update(struct net_bridge *br, struct net_bridge_port *source, /* fastpath: update of existing entry */ if (unlikely(source != fdb->dst && !test_bit(BR_FDB_STICKY, &fdb->flags))) { - br_switchdev_fdb_notify(fdb, RTM_DELNEIGH); + br_switchdev_fdb_notify(br, fdb, RTM_DELNEIGH); fdb->dst = source; fdb_modified = true; /* Take over HW learned entry */ @@ -735,7 +735,7 @@ static void fdb_notify(struct net_bridge *br, int err = -ENOBUFS; if (swdev_notify) - br_switchdev_fdb_notify(fdb, type); + br_switchdev_fdb_notify(br, fdb, type); skb = nlmsg_new(fdb_nlmsg_size(), GFP_ATOMIC); if (skb == NULL) diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h index d7d167e10b70..4a262dc55e6b 100644 --- a/net/bridge/br_private.h +++ b/net/bridge/br_private.h @@ -1581,8 +1581,8 @@ int br_switchdev_set_port_flag(struct net_bridge_port *p, unsigned long flags, unsigned long mask, struct netlink_ext_ack *extack); -void br_switchdev_fdb_notify(const struct net_bridge_fdb_entry *fdb, - int type); +void br_switchdev_fdb_notify(struct net_bridge *br, + const struct net_bridge_fdb_entry *fdb, int type); int br_switchdev_port_vlan_add(struct net_device *dev, u16 vid, u16 flags, struct netlink_ext_ack *extack); int br_switchdev_port_vlan_del(struct net_device *dev, u16 vid); @@ -1629,7 +1629,8 @@ static inline int br_switchdev_port_vlan_del(struct net_device *dev, u16 vid) } static inline void -br_switchdev_fdb_notify(const struct net_bridge_fdb_entry *fdb, int type) +br_switchdev_fdb_notify(struct net_bridge *br, + const struct net_bridge_fdb_entry *fdb, int type) { } diff --git a/net/bridge/br_switchdev.c b/net/bridge/br_switchdev.c index a5e601e41cb9..9a707da79dfe 100644 --- a/net/bridge/br_switchdev.c +++ b/net/bridge/br_switchdev.c @@ -108,7 +108,8 @@ int br_switchdev_set_port_flag(struct net_bridge_port *p, } void -br_switchdev_fdb_notify(const struct net_bridge_fdb_entry *fdb, int type) +br_switchdev_fdb_notify(struct net_bridge *br, + const struct net_bridge_fdb_entry *fdb, int type) { struct switchdev_notifier_fdb_info info = { .addr = fdb->key.addr.addr, @@ -117,18 +118,16 @@ br_switchdev_fdb_notify(const struct net_bridge_fdb_entry *fdb, int type) .is_local = test_bit(BR_FDB_LOCAL, &fdb->flags), .offloaded = test_bit(BR_FDB_OFFLOADED, &fdb->flags), }; - - if (!fdb->dst) - return; + struct net_device *dev = fdb->dst ? fdb->dst->dev : br->dev; switch (type) { case RTM_DELNEIGH: call_switchdev_notifiers(SWITCHDEV_FDB_DEL_TO_DEVICE, - fdb->dst->dev, &info.info, NULL); + dev, &info.info, NULL); break; case RTM_NEWNEIGH: call_switchdev_notifiers(SWITCHDEV_FDB_ADD_TO_DEVICE, - fdb->dst->dev, &info.info, NULL); + dev, &info.info, NULL); break; } } From patchwork Wed Feb 24 11:43:43 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Vladimir Oltean X-Patchwork-Id: 387100 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-15.7 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,FREEMAIL_FORGED_FROMDOMAIN,FREEMAIL_FROM, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI, SPF_HELO_NONE, SPF_PASS, URIBL_BLOCKED, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 83B3AC433DB for ; Wed, 24 Feb 2021 11:48:03 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 1AE7564E90 for ; Wed, 24 Feb 2021 11:48:03 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S234928AbhBXLrm (ORCPT ); Wed, 24 Feb 2021 06:47:42 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:48422 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S235012AbhBXLpa (ORCPT ); Wed, 24 Feb 2021 06:45:30 -0500 Received: from mail-ej1-x62a.google.com (mail-ej1-x62a.google.com [IPv6:2a00:1450:4864:20::62a]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id A8194C0617AA for ; Wed, 24 Feb 2021 03:44:13 -0800 (PST) Received: by mail-ej1-x62a.google.com with SMTP id u20so2517456ejb.7 for ; Wed, 24 Feb 2021 03:44:13 -0800 (PST) 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 :mime-version:content-transfer-encoding; bh=m0fpouldJeND9lqkQ7yYVxufj/CE6mHLIjl16R1I05k=; b=LUcjNezqDKxSUESHF2E/d4ky7Q2fQFgcafUAaEnSCnilwTESpokIOWphmZaseFwgPy WjGGxGSIaLYXGeKD8gRHKE8epbysUvOOn7d2wCtDoIVThsSEw1G/xWGZoSZinlyelvlr Qkoleyb6RefnrPV5q65H71a3TT68iTHWi+7ZhTSDk2GpXa+FWm2XEpiO0bvmbcvkdS1O lpLIECv8ZNBJYsoXQ7T3cqAPLOyZVHx2zr5tfc8COtKs3GGJljCwJKDe6Io4wUS50JFQ 1ZwSasfcUUNkKWNJ+FPvviasn09goN80mfmMWDxL6iAwb2dNRKjqqWgzTrb6zxMtDn7i ILlg== 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:mime-version:content-transfer-encoding; bh=m0fpouldJeND9lqkQ7yYVxufj/CE6mHLIjl16R1I05k=; b=YX/kMkBg/umdzF+msXHJ93njp/lCMYoq8+fX8WbCK8q+MIMzDoqOAG4kO2oi7X/4wU NsyezECvO5Nd077Uej58nQj4BT7A9GFJ7pJ4VCsicSELFDdfGjAIKkToChd4XD9TtXpI ghAZmzjuhsx0fvAH1YmSf6KTWWfbLmcJ7aZk2gya2XZOHDRz7JcQaDrAf1hEoQfHUIVm F98SSmhuSSsxiVf5liSRtio4aLsJSYXKGOwstWYJt9Zsm2WGmp+/IIvqxsig/etYdSo/ WZRwd7Zz0WeDSj9ayv9fAA34bAOpAOfX6XzcDBDCNw7Rxbp/2vBdBg5B+kL8/VSfK8sM Ksrg== X-Gm-Message-State: AOAM532d87x3C4J5ofg97gQZZeM6LdEJ/Px6xNAPiJKCIcl3KY3+DnG9 aQX0OaAger0uuCAspWd92VLzfs2PmJY= X-Google-Smtp-Source: ABdhPJzt/TKsw75cO8Ibfs4kNuMHWepHCS5/Y7GBg91qaT4Jvgo2RBXMEb0xT15WYrVS2GFWjazb6Q== X-Received: by 2002:a17:906:511:: with SMTP id j17mr19100579eja.143.1614167052191; Wed, 24 Feb 2021 03:44:12 -0800 (PST) Received: from localhost.localdomain ([188.25.217.13]) by smtp.gmail.com with ESMTPSA id r5sm1203921ejx.96.2021.02.24.03.44.11 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 24 Feb 2021 03:44:11 -0800 (PST) From: Vladimir Oltean To: netdev@vger.kernel.org Cc: Andrew Lunn , Florian Fainelli , Vivien Didelot , Jiri Pirko , Ido Schimmel , DENG Qingfang , Tobias Waldekranz , George McCollister , Vlad Yasevich , Roopa Prabhu , Nikolay Aleksandrov Subject: [RFC PATCH v2 net-next 10/17] net: dsa: include bridge addresses which are local in the host fdb list Date: Wed, 24 Feb 2021 13:43:43 +0200 Message-Id: <20210224114350.2791260-11-olteanv@gmail.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210224114350.2791260-1-olteanv@gmail.com> References: <20210224114350.2791260-1-olteanv@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org From: Tobias Waldekranz The bridge automatically creates local (not forwarded) fdb entries pointing towards physical ports with their interface MAC addresses. For switchdev, the significance of these fdb entries is the exact opposite of that of non-local entries: instead of sending these frame outwards, we must send them inwards (towards the host). NOTE: The bridge's own MAC address is also "local". If that address is not shared with any port, the bridge's MAC is not be added by this functionality - but the following commit takes care of that case. NOTE 2: We mark these addresses as host-filtered regardless of the value of ds->assisted_learning_on_cpu_port. This is because, as opposed to the speculative logic done for dynamic address learning on foreign interfaces, the local FDB entries are rather fixed, so there isn't any risk of them migrating from one bridge port to another. Signed-off-by: Tobias Waldekranz Signed-off-by: Vladimir Oltean --- net/dsa/slave.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/net/dsa/slave.c b/net/dsa/slave.c index c4db870b48e5..8d4cd27cc79f 100644 --- a/net/dsa/slave.c +++ b/net/dsa/slave.c @@ -2549,10 +2549,12 @@ static int dsa_slave_switchdev_event(struct notifier_block *unused, fdb_info = ptr; if (dsa_slave_dev_check(dev)) { - if (!fdb_info->added_by_user || fdb_info->is_local) - return NOTIFY_OK; - dp = dsa_slave_to_port(dev); + + if (fdb_info->is_local) + host_addr = true; + else if (!fdb_info->added_by_user) + return NOTIFY_OK; } else { /* Snoop addresses learnt on foreign interfaces * bridged with us, for switches that don't From patchwork Wed Feb 24 11:43:44 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Vladimir Oltean X-Patchwork-Id: 387603 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-15.7 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,FREEMAIL_FORGED_FROMDOMAIN,FREEMAIL_FROM, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI, SPF_HELO_NONE, SPF_PASS, URIBL_BLOCKED, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id BEB63C433DB for ; Wed, 24 Feb 2021 11:48:11 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 6681664E90 for ; Wed, 24 Feb 2021 11:48:11 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S235124AbhBXLsF (ORCPT ); Wed, 24 Feb 2021 06:48:05 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:48424 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S235013AbhBXLpa (ORCPT ); Wed, 24 Feb 2021 06:45:30 -0500 Received: from mail-ej1-x62c.google.com (mail-ej1-x62c.google.com [IPv6:2a00:1450:4864:20::62c]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id C4653C0617AB for ; Wed, 24 Feb 2021 03:44:14 -0800 (PST) Received: by mail-ej1-x62c.google.com with SMTP id g5so2546504ejt.2 for ; Wed, 24 Feb 2021 03:44:14 -0800 (PST) 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 :mime-version:content-transfer-encoding; bh=8Z8RxArzm3Bt6cO5FJ/vajivUciH4I6m9xbaFfaxYxo=; b=ln+4CRnkuL5bFe/atUWdDWcVVGF07mj08wZD5CuSbugk6jAVwn0oFAx2p30OpD4VFj T+tzUkkaERstS/bKaPzfRK9fdtzvMdcGZeUBH/Yi3T9J8XJDWKNswCsXUs8eposRD4E/ QdpiDfGSqUbkzhkyQQ0JmP1Dhbxku7sfkptAmgV5YpYpGik8LDvuiF8xTUKlU8O2aeQw BomNfPe/WUV3Mo4kAEw/8MEMzdnAtvFPmMWzE50U64GSn//FH9AzG+tx5qmHVXFFoqfz BGB+h+PONfVnqjsS4k6N8AWideB66HdSNoQkVE0hGuYVSGOwRC/j7LTXSK+AlSKssrPy TQoA== 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:mime-version:content-transfer-encoding; bh=8Z8RxArzm3Bt6cO5FJ/vajivUciH4I6m9xbaFfaxYxo=; b=YjAbxw2Yzo6fFv+Wj5hXozbLRaJ9i51yHVcSobotA8jqjOqo453B8u5H/87Y9xHx9L Lr7AjtkybiWISVHSBWYvAx9KdibcZguSB2QHHUxsnW1To60OlZImuEx00v64j/ZSAE7m SrFh9km/wvvZT6YPf1w8VJ6+J03CJaIWIYUft53+cruYhFraSK3m5IbfScL4BDSlKtRT H26fWp9yyoZP54nmPKFukw7789M7wDI0FkJb84r/S6QzApWPFjVtnTV7O57hTv/UNrJS ADBw4wOUxEkXNhTz+gbIxrUk12snwr3OV07MWDJWwun3rjHzHt+3RKl8kU7vHHa7tMGS prVw== X-Gm-Message-State: AOAM530UCY0/DY82zCDKNzCzMbhdLRObYiX7aWOWCulTOxzZLqYh067f BzPwESS2w87LyjzhlSIVG0XUa/cfZUM= X-Google-Smtp-Source: ABdhPJwmnVIH1T8E7B2cvJi+KGmmRZu0cH1AqKZe11qE1KkntFOvCmzAJwidk6JgiYb1PR/NSyA9Dg== X-Received: by 2002:a17:907:36e:: with SMTP id rs14mr2313823ejb.42.1614167053296; Wed, 24 Feb 2021 03:44:13 -0800 (PST) Received: from localhost.localdomain ([188.25.217.13]) by smtp.gmail.com with ESMTPSA id r5sm1203921ejx.96.2021.02.24.03.44.12 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 24 Feb 2021 03:44:13 -0800 (PST) From: Vladimir Oltean To: netdev@vger.kernel.org Cc: Andrew Lunn , Florian Fainelli , Vivien Didelot , Jiri Pirko , Ido Schimmel , DENG Qingfang , Tobias Waldekranz , George McCollister , Vlad Yasevich , Roopa Prabhu , Nikolay Aleksandrov Subject: [RFC PATCH v2 net-next 11/17] net: dsa: include fdb entries pointing to bridge in the host fdb list Date: Wed, 24 Feb 2021 13:43:44 +0200 Message-Id: <20210224114350.2791260-12-olteanv@gmail.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210224114350.2791260-1-olteanv@gmail.com> References: <20210224114350.2791260-1-olteanv@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org From: Vladimir Oltean The bridge supports a legacy way of adding local (non-forwarded) FDB entries, which works on an individual port basis: bridge fdb add dev swp0 00:01:02:03:04:05 master local As well as a new way, added by Roopa Prabhu in commit 3741873b4f73 ("bridge: allow adding of fdb entries pointing to the bridge device"): bridge fdb add dev br0 00:01:02:03:04:05 self local The two commands are functionally equivalent, except that the first one produces an entry with fdb->dst == swp0, and the other an entry with fdb->dst == NULL. The confusing part, though, is that even if fdb->dst is swp0 for the 'local on port' entry, that destination is not used. Nonetheless, the idea is that the bridge has reference counting for local entries, and local entries pointing towards the bridge are still 'as local' as local entries for a port. The bridge adds the MAC addresses of the interfaces automatically as FDB entries with is_local=1. For the MAC address of the ports, fdb->dst will be equal to the port, and for the MAC address of the bridge, fdb->dst will point towards the bridge (i.e. be NULL). Therefore, if the MAC address of the bridge is not inherited from either of the physical ports, then we must explicitly catch local FDB entries emitted towards the br0, otherwise we'll miss the MAC address of the bridge (and, of course, any entry with 'bridge add dev br0 ... self local'). Co-developed-by: Tobias Waldekranz Signed-off-by: Tobias Waldekranz Signed-off-by: Vladimir Oltean --- net/dsa/slave.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/net/dsa/slave.c b/net/dsa/slave.c index 8d4cd27cc79f..425b3223b7d1 100644 --- a/net/dsa/slave.c +++ b/net/dsa/slave.c @@ -2563,7 +2563,11 @@ static int dsa_slave_switchdev_event(struct notifier_block *unused, struct net_device *br_dev; struct dsa_slave_priv *p; - br_dev = netdev_master_upper_dev_get_rcu(dev); + if (netif_is_bridge_master(dev)) + br_dev = dev; + else + br_dev = netdev_master_upper_dev_get_rcu(dev); + if (!br_dev) return NOTIFY_DONE; @@ -2584,8 +2588,13 @@ static int dsa_slave_switchdev_event(struct notifier_block *unused, * LAG we don't want to send traffic to the CPU, the * other ports bridged with the LAG should be able to * autonomously forward towards it. + * On the other hand, if the address is local + * (therefore not learned) then we want to trap it to + * the CPU regardless of whether the interface it + * belongs to is offloaded or not. */ - if (dsa_tree_offloads_netdev(dp->ds->dst, dev)) + if (dsa_tree_offloads_netdev(dp->ds->dst, dev) && + !fdb_info->is_local) return NOTIFY_DONE; } From patchwork Wed Feb 24 11:43:45 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Vladimir Oltean X-Patchwork-Id: 387602 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-15.7 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,FREEMAIL_FORGED_FROMDOMAIN,FREEMAIL_FROM, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI, SPF_HELO_NONE, SPF_PASS, URIBL_BLOCKED, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id DDE62C433DB for ; Wed, 24 Feb 2021 11:48:48 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 8F65C64E90 for ; Wed, 24 Feb 2021 11:48:48 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S233674AbhBXLso (ORCPT ); Wed, 24 Feb 2021 06:48:44 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:48614 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S235062AbhBXLqX (ORCPT ); Wed, 24 Feb 2021 06:46:23 -0500 Received: from mail-ej1-x629.google.com (mail-ej1-x629.google.com [IPv6:2a00:1450:4864:20::629]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id D63A6C061356 for ; Wed, 24 Feb 2021 03:44:15 -0800 (PST) Received: by mail-ej1-x629.google.com with SMTP id d8so2531348ejc.4 for ; Wed, 24 Feb 2021 03:44:15 -0800 (PST) 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 :mime-version:content-transfer-encoding; bh=nu59qIPS2kqMtAot2Qj7Ys6cl5ZPPoFdF2Sho0eLISM=; b=Q8ZLhkK1/nGDy61hKoaVp0XrOuKPuybvza0HWYGFuELg8lkPOZFghSLkDCDX3S0pek LJZehVEFN3TEvWWfzgN1X9FnygQFDRx/DFvF2XYKTRpsi2wQpQnGlmqv7I4/vqmPDqgT HdJe56tAwCA9EiFE0ygWraWmK3VCYhCe89APQ4+sqhIE+hR/TJrw2eLyPLHdmDT8RSyN 5giNKS1t6Qj9CPBSqjYnXyXBwUEbvA+49MXWMO2HbTsZShlUEDJ00+orbH0DM/o5L3Np ahgvom2AnBmd8GkKLCEZ0LZOVbTGN7XtA/ViFGx9gCRV3re43pMo7Im1rkdt+gqouiJO AXlw== 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:mime-version:content-transfer-encoding; bh=nu59qIPS2kqMtAot2Qj7Ys6cl5ZPPoFdF2Sho0eLISM=; b=nmvTgmbTDo67qCru4+9zww01ngqpT31GNfXlkWeHvzUW9hCPDXkf9GL9DJ+kWhgYQf 3UirCloHMa1mtARW1k2i2kuQVRpYhzm082N5vSpE7DeAqIsVvcsMqnVtcKl8DlulS90q /9YbaMJfclqQO0tqpzGJP2ybOaspET56IQt3kwZA9P+YZCN4pApInFsyEU7RX21LEPGK EpGpQEG7oY0l/81KdXOPRDkFolZrip2ywHZw+hx0bdvHHXKLFMqYLSm/9aYt7gabyoOe vWXhKdv6mxVSlhZIE6Ml9IPY4u5MLv9a0/AAmJp98eN1NAa+RZt5CLQgO6LSkmXaKOw2 fvuQ== X-Gm-Message-State: AOAM533gOlGZCnOiFS1OUVRkvnxSiDm8vicH3vXP4uHCd+Oy6QURz16z wF8wJIyxrzRqoJnWopTPwwNfFE8B9no= X-Google-Smtp-Source: ABdhPJxAtViWOh8RrNs2tJ0PghNzT+TtxcGwTiCAeks/GyS9UmxB2i99gCNBq8k3f3iyZa7GWPzKTw== X-Received: by 2002:a17:906:25c4:: with SMTP id n4mr30795367ejb.359.1614167054379; Wed, 24 Feb 2021 03:44:14 -0800 (PST) Received: from localhost.localdomain ([188.25.217.13]) by smtp.gmail.com with ESMTPSA id r5sm1203921ejx.96.2021.02.24.03.44.13 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 24 Feb 2021 03:44:14 -0800 (PST) From: Vladimir Oltean To: netdev@vger.kernel.org Cc: Andrew Lunn , Florian Fainelli , Vivien Didelot , Jiri Pirko , Ido Schimmel , DENG Qingfang , Tobias Waldekranz , George McCollister , Vlad Yasevich , Roopa Prabhu , Nikolay Aleksandrov Subject: [RFC PATCH v2 net-next 12/17] net: dsa: sync static FDB entries on foreign interfaces to hardware Date: Wed, 24 Feb 2021 13:43:45 +0200 Message-Id: <20210224114350.2791260-13-olteanv@gmail.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210224114350.2791260-1-olteanv@gmail.com> References: <20210224114350.2791260-1-olteanv@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org From: Tobias Waldekranz Reuse the "assisted_learning_on_cpu_port" functionality to always add entries for user-configured entries on foreign interfaces, even if assisted_learning_on_cpu_port is not enabled. E.g. in this situation: br0 / \ swp0 dummy0 $ bridge fdb add 02:00:de:ad:00:01 dev dummy0 vlan 1 master static Results in DSA adding an entry in the hardware FDB, pointing this address towards the CPU port. The same is true for entries added to the bridge itself, e.g: $ bridge fdb add 02:00:de:ad:00:01 dev br0 vlan 1 self local Signed-off-by: Tobias Waldekranz Signed-off-by: Vladimir Oltean --- net/dsa/slave.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/net/dsa/slave.c b/net/dsa/slave.c index 425b3223b7d1..a32875d3dc5f 100644 --- a/net/dsa/slave.c +++ b/net/dsa/slave.c @@ -2556,9 +2556,12 @@ static int dsa_slave_switchdev_event(struct notifier_block *unused, else if (!fdb_info->added_by_user) return NOTIFY_OK; } else { - /* Snoop addresses learnt on foreign interfaces - * bridged with us, for switches that don't - * automatically learn SA from CPU-injected traffic + /* Snoop addresses added to foreign interfaces + * bridged with us, or the bridge + * itself. Dynamically learned addresses can + * also be added for switches that don't + * automatically learn SA from CPU-injected + * traffic. */ struct net_device *br_dev; struct dsa_slave_priv *p; @@ -2581,7 +2584,8 @@ static int dsa_slave_switchdev_event(struct notifier_block *unused, dp = p->dp; host_addr = true; - if (!dp->ds->assisted_learning_on_cpu_port) + if (!fdb_info->added_by_user && + !dp->ds->assisted_learning_on_cpu_port) return NOTIFY_DONE; /* When the bridge learns an address on an offloaded From patchwork Wed Feb 24 11:43:46 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Vladimir Oltean X-Patchwork-Id: 387098 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-15.7 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,FREEMAIL_FORGED_FROMDOMAIN,FREEMAIL_FROM, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI, SPF_HELO_NONE, SPF_PASS, URIBL_BLOCKED, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 7B33CC433DB for ; Wed, 24 Feb 2021 11:48:56 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 2AB2D64E90 for ; Wed, 24 Feb 2021 11:48:56 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S235072AbhBXLsx (ORCPT ); Wed, 24 Feb 2021 06:48:53 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:48616 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S235063AbhBXLqX (ORCPT ); Wed, 24 Feb 2021 06:46:23 -0500 Received: from mail-ej1-x632.google.com (mail-ej1-x632.google.com [IPv6:2a00:1450:4864:20::632]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id EF892C06121C for ; Wed, 24 Feb 2021 03:44:16 -0800 (PST) Received: by mail-ej1-x632.google.com with SMTP id do6so2541540ejc.3 for ; Wed, 24 Feb 2021 03:44:16 -0800 (PST) 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 :mime-version:content-transfer-encoding; bh=RFOX600Q/Cv3HMjqdBygz+3o5JVjShH9AZxw2X5WKRw=; b=URQTkSxdTb/EYkTMzw+WRm6jFboadm5OLgpBewr/gfseIFX9xK2bDhHr/5Y+uKpOqL qCmolMDNxm0SGeSSDcEdnFoVUlpzC1c3YjbhZBGvKRItYjzw/7wdaNHPYupH5GrL1BYr btpC87faiug6F95F0WScGsCQyc83yUiro3Htw+Hc6td0G6XK9gVR0jeIyfuCui9aq8PV T0ytJiSv4KgEj0Wysy5oj3JIOh7kty6PzRzJQNA3RG2jT2/X9dK9Rgo9vMsR3+OWNePX /2s41fCTe9xk0zW6qAixm70T9pJJuP4Fcbol7gbwQmra/0TNetZemyBOWRTOSSFyF5Ap 3J0Q== 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:mime-version:content-transfer-encoding; bh=RFOX600Q/Cv3HMjqdBygz+3o5JVjShH9AZxw2X5WKRw=; b=VROkbDy2zoUExu2vD1x2dW91aCeTrtBqy242GuAsZCqpFFDXqSSVuX6ga99KKaNHSk sDxkYDo7nZMzCXjttLtS5dO1PIRo6tiEqTdshfBmGkEcdCNYadGNnJPgaZJda2b71c+U 2PBx5vc+HRF4+N5OM00ln32WwLs/9A7nbblrPTtDqmU7fXx3JbkoyMtO0jqeF9paeQDq 2XUEhRLrgcWJvqffheD1XTcPL/Pk/7yg6SKK4ElHDnkOSsqoVsJ7MlexA06CnHQEKyXW se55VXq2Gje/kZCyOZT4oDEhDewPWMwPoESlaKdBMtCyPeJxKGI9zMgOtWbt6V7OxGfk 0WAw== X-Gm-Message-State: AOAM530iu29Fvb8gHD5pwj2cpZZEGJuVNwsxmpvxm9uY+t5eJdtY3Mif 8vwSpsb3kqYWU97mXaFoGwu9gdyAiLE= X-Google-Smtp-Source: ABdhPJxFGplH7866kCEzcIob9wviSgA/CL3xFSxVcmMwq08QniYZgFZ2B6IqlkWThWI4kznuGuL7fQ== X-Received: by 2002:a17:906:4e8f:: with SMTP id v15mr20853013eju.357.1614167055479; Wed, 24 Feb 2021 03:44:15 -0800 (PST) Received: from localhost.localdomain ([188.25.217.13]) by smtp.gmail.com with ESMTPSA id r5sm1203921ejx.96.2021.02.24.03.44.14 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 24 Feb 2021 03:44:15 -0800 (PST) From: Vladimir Oltean To: netdev@vger.kernel.org Cc: Andrew Lunn , Florian Fainelli , Vivien Didelot , Jiri Pirko , Ido Schimmel , DENG Qingfang , Tobias Waldekranz , George McCollister , Vlad Yasevich , Roopa Prabhu , Nikolay Aleksandrov Subject: [RFC PATCH v2 net-next 13/17] net: dsa: mv88e6xxx: Request assisted learning on CPU port Date: Wed, 24 Feb 2021 13:43:46 +0200 Message-Id: <20210224114350.2791260-14-olteanv@gmail.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210224114350.2791260-1-olteanv@gmail.com> References: <20210224114350.2791260-1-olteanv@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org From: Tobias Waldekranz While the hardware is capable of performing learning on the CPU port, it requires alot of additions to the bridge's forwarding path in order to handle multi-destination traffic correctly. Until that is in place, opt for the next best thing and let DSA sync the relevant addresses down to the hardware FDB. Signed-off-by: Tobias Waldekranz Signed-off-by: Vladimir Oltean --- drivers/net/dsa/mv88e6xxx/chip.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c index 903d619e08ed..e25bfcde8324 100644 --- a/drivers/net/dsa/mv88e6xxx/chip.c +++ b/drivers/net/dsa/mv88e6xxx/chip.c @@ -5818,6 +5818,7 @@ static int mv88e6xxx_register_switch(struct mv88e6xxx_chip *chip) ds->ops = &mv88e6xxx_switch_ops; ds->ageing_time_min = chip->info->age_time_coeff; ds->ageing_time_max = chip->info->age_time_coeff * U8_MAX; + ds->assisted_learning_on_cpu_port = true; /* Some chips support up to 32, but that requires enabling the * 5-bit port mode, which we do not support. 640k^W16 ought to From patchwork Wed Feb 24 11:43:47 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Vladimir Oltean X-Patchwork-Id: 387099 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-15.7 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,FREEMAIL_FORGED_FROMDOMAIN,FREEMAIL_FROM, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI, SPF_HELO_NONE, SPF_PASS, URIBL_BLOCKED, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id C16C2C433E0 for ; Wed, 24 Feb 2021 11:48:35 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 6A0E064E90 for ; Wed, 24 Feb 2021 11:48:35 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S235047AbhBXLsS (ORCPT ); Wed, 24 Feb 2021 06:48:18 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:48332 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S235037AbhBXLqO (ORCPT ); Wed, 24 Feb 2021 06:46:14 -0500 Received: from mail-ej1-x62b.google.com (mail-ej1-x62b.google.com [IPv6:2a00:1450:4864:20::62b]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 0CD7AC06121D for ; Wed, 24 Feb 2021 03:44:18 -0800 (PST) Received: by mail-ej1-x62b.google.com with SMTP id mm21so2245732ejb.12 for ; Wed, 24 Feb 2021 03:44:17 -0800 (PST) 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 :mime-version:content-transfer-encoding; bh=EABo2wmdvoZSCpRCQk6mPqSgnBg7SprnKIxoTK9v1D4=; b=tbvCYZ/zIiN7JvdefxIII4/xvgeV5BMidpeNv4UoAU1B/L0s+62Rw2iYKZhn0DeuAI phzrKzAo2uTkmhalZ9G6nKAFZ4czt8XCIInBWEu+62JS4h6ddRCOfAz86f9PJWfn1afU QA3tXA1flQQY5urirscFGEtbEAT4ww7K1mfCgwPwYkBgqJu2q46HizrlxeNKtfICM0Ni X6ICYjTJKIFqjh8yMtJPoK3g5DXPMcmwi35sNxiIz+A8B6ezcpVmqzSa0h0xMsUEC05Z 8yeq8hhtRKZieOJwl+V53N0mROCtZFMx/ndURPaswv/hyQPHBa4lFOuP9YlzXeAvCIN3 Qm3Q== 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:mime-version:content-transfer-encoding; bh=EABo2wmdvoZSCpRCQk6mPqSgnBg7SprnKIxoTK9v1D4=; b=IfwI38w9wyJhYd/cIXs9Eim4DG7LztfM/glqGChdHdfC0XA1Hns7BZSdzfATUbtmV3 cWGbQa2hPbQ8Iu3UdvEZc9s00dZKIPfQJOgMXp21ZvSFg6BGshRfOCtfUAaldV09uf2I vqjBTbvfEgUD6GaK/HM/JrwT+2LI0/uxQ3+QR+FXbwPfqdGMRaypL8NZhhgSf9RJvv26 DrFYf3lnTM9zdmJZfqPUzv6w2Y8TwK2bIHEoFNnoq5PQw1a9WZgNi1XYlC9S4d7l7g36 zdsMpxpDwmAdgmNE8pVU2YXYIydTcs5D9HYGJ22c33qeT0qmSoqlXXip7fomS3W7HhH8 pjgw== X-Gm-Message-State: AOAM533AemrQ80djUWM5t+ixuZ2Yl50svxDwJx0uKfnb6gkC/bLKZfOm 6SNFcwX/WaHrGbFUSGxdeRgp4aT9L7k= X-Google-Smtp-Source: ABdhPJxKSpZCud710deOk/36uWpJF5ejX7gK6d3dCAsdVqMmboSS1XUeXy+SkuSkUDNlNKjWl/jSLg== X-Received: by 2002:a17:907:2da5:: with SMTP id gt37mr29474232ejc.324.1614167056539; Wed, 24 Feb 2021 03:44:16 -0800 (PST) Received: from localhost.localdomain ([188.25.217.13]) by smtp.gmail.com with ESMTPSA id r5sm1203921ejx.96.2021.02.24.03.44.15 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 24 Feb 2021 03:44:16 -0800 (PST) From: Vladimir Oltean To: netdev@vger.kernel.org Cc: Andrew Lunn , Florian Fainelli , Vivien Didelot , Jiri Pirko , Ido Schimmel , DENG Qingfang , Tobias Waldekranz , George McCollister , Vlad Yasevich , Roopa Prabhu , Nikolay Aleksandrov Subject: [RFC PATCH v2 net-next 14/17] net: dsa: replay port and host-joined mdb entries when joining the bridge Date: Wed, 24 Feb 2021 13:43:47 +0200 Message-Id: <20210224114350.2791260-15-olteanv@gmail.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210224114350.2791260-1-olteanv@gmail.com> References: <20210224114350.2791260-1-olteanv@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org From: Vladimir Oltean I have udhcpcd in my system and this is configured to bring interfaces up as soon as they are created. I create a bridge as follows: ip link add br0 type bridge As soon as I create the bridge and udhcpcd brings it up, I have some other crap (avahi) that starts sending some random IPv6 packets to advertise some local services, and from there, the br0 bridge joins the following IPv6 groups: 33:33:ff:6d:c1:9c vid 0 33:33:00:00:00:6a vid 0 33:33:00:00:00:fb vid 0 br_dev_xmit -> br_multicast_rcv -> br_ip6_multicast_add_group -> __br_multicast_add_group -> br_multicast_host_join -> br_mdb_notify This is all fine, but inside br_mdb_notify we have br_mdb_switchdev_host hooked up, and switchdev will attempt to offload the host joined groups to an empty list of ports. Of course nobody offloads them. Then when we add a port to br0: ip link set swp0 master br0 the bridge doesn't replay the host-joined MDB entries from br_add_if, and eventually the host joined addresses expire, and a switchdev notification for deleting it is emitted, but surprise, the original addition was already completely missed. The strategy to address this problem is to replay the MDB entries (both the port ones and the host joined ones) when the new port joins the bridge, similar to what vxlan_fdb_replay does (in that case, its FDB can be populated and only then attached to a bridge that you offload). However there are 2 possibilities: the addresses can be 'pushed' by the bridge into the port, or the port can 'pull' them from the bridge. Considering that in the general case, the new port can be really late to the party, and there may have been many other switchdev ports that already received the initial notification, we would like to avoid delivering duplicate events to them, since they might misbehave. And currently, the bridge calls the entire switchdev notifier chain, whereas for replaying it should just call the notifier block of the new guy. But the bridge doesn't know what is the new guy's notifier block, it just knows where the switchdev notifier chain is. So for simplification, we make this a driver-initiated pull for now, and the notifier block is passed as an argument. To emulate the calling context for mdb objects (deferred and put on the blocking notifier chain), we must iterate under RCU protection through the bridge's mdb entries, queue them, and only call them once we're out of the RCU read-side critical section. Suggested-by: Ido Schimmel Signed-off-by: Vladimir Oltean --- include/linux/if_bridge.h | 8 +++ include/net/switchdev.h | 1 + net/bridge/br_mdb.c | 117 ++++++++++++++++++++++++++++++++++++++ net/dsa/slave.c | 17 +++++- 4 files changed, 141 insertions(+), 2 deletions(-) diff --git a/include/linux/if_bridge.h b/include/linux/if_bridge.h index b979005ea39c..2f0e5713bf39 100644 --- a/include/linux/if_bridge.h +++ b/include/linux/if_bridge.h @@ -69,6 +69,8 @@ bool br_multicast_has_querier_anywhere(struct net_device *dev, int proto); bool br_multicast_has_querier_adjacent(struct net_device *dev, int proto); bool br_multicast_enabled(const struct net_device *dev); bool br_multicast_router(const struct net_device *dev); +int br_mdb_replay(struct net_device *br_dev, struct net_device *dev, + struct notifier_block *nb); #else static inline int br_multicast_list_adjacent(struct net_device *dev, struct list_head *br_ip_list) @@ -93,6 +95,12 @@ static inline bool br_multicast_router(const struct net_device *dev) { return false; } +static inline int br_mdb_replay(struct net_device *br_dev, + struct net_device *dev, + struct notifier_block *nb) +{ + return -EINVAL; +} #endif #if IS_ENABLED(CONFIG_BRIDGE) && IS_ENABLED(CONFIG_BRIDGE_VLAN_FILTERING) diff --git a/include/net/switchdev.h b/include/net/switchdev.h index ca7223a79135..f1a5a9a3634d 100644 --- a/include/net/switchdev.h +++ b/include/net/switchdev.h @@ -68,6 +68,7 @@ enum switchdev_obj_id { }; struct switchdev_obj { + struct list_head list; struct net_device *orig_dev; enum switchdev_obj_id id; u32 flags; diff --git a/net/bridge/br_mdb.c b/net/bridge/br_mdb.c index 8846c5bcd075..170353510c35 100644 --- a/net/bridge/br_mdb.c +++ b/net/bridge/br_mdb.c @@ -506,6 +506,123 @@ static void br_mdb_complete(struct net_device *dev, int err, void *priv) kfree(priv); } +static int br_mdb_replay_one(struct notifier_block *nb, struct net_device *dev, + struct switchdev_obj_port_mdb *mdb) +{ + struct switchdev_notifier_port_obj_info obj_info = { + .info = { + .dev = dev, + }, + .obj = &mdb->obj, + }; + int err; + + err = nb->notifier_call(nb, SWITCHDEV_PORT_OBJ_ADD, &obj_info); + return notifier_to_errno(err); +} + +static int br_mdb_queue_one(struct list_head *mdb_list, + enum switchdev_obj_id id, + struct net_bridge_mdb_entry *mp, + struct net_device *orig_dev) +{ + struct switchdev_obj_port_mdb *mdb; + + mdb = kzalloc(sizeof(*mdb), GFP_ATOMIC); + if (!mdb) + return -ENOMEM; + + mdb->obj.id = id; + mdb->obj.orig_dev = orig_dev; + mdb->vid = mp->addr.vid; + + if (mp->addr.proto == htons(ETH_P_IP)) + ip_eth_mc_map(mp->addr.dst.ip4, mdb->addr); +#if IS_ENABLED(CONFIG_IPV6) + else if (mp->addr.proto == htons(ETH_P_IPV6)) + ipv6_eth_mc_map(&mp->addr.dst.ip6, mdb->addr); +#endif + else + ether_addr_copy(mdb->addr, mp->addr.dst.mac_addr); + + list_add_tail(&mdb->obj.list, mdb_list); + + return 0; +} + +int br_mdb_replay(struct net_device *br_dev, struct net_device *dev, + struct notifier_block *nb) +{ + struct net_bridge_mdb_entry *mp; + struct switchdev_obj *obj, *tmp; + struct list_head mdb_list; + struct net_bridge *br; + int err = 0; + + ASSERT_RTNL(); + + INIT_LIST_HEAD(&mdb_list); + + if (!netif_is_bridge_master(br_dev)) + return -EINVAL; + + if (!netif_is_bridge_port(dev)) + return -EINVAL; + + br = netdev_priv(br_dev); + + if (!br_opt_get(br, BROPT_MULTICAST_ENABLED)) + return 0; + + rcu_read_lock(); + + hlist_for_each_entry_rcu(mp, &br->mdb_list, mdb_node) { + struct net_bridge_port_group __rcu **pp; + struct net_bridge_port_group *p; + + if (mp->host_joined) { + err = br_mdb_queue_one(&mdb_list, + SWITCHDEV_OBJ_ID_HOST_MDB, + mp, br_dev); + if (err) { + rcu_read_unlock(); + goto out_free_mdb; + } + } + + for (pp = &mp->ports; (p = rcu_dereference(*pp)) != NULL; + pp = &p->next) { + if (p->key.port->dev != dev) + continue; + + err = br_mdb_queue_one(&mdb_list, + SWITCHDEV_OBJ_ID_PORT_MDB, + mp, dev); + if (err) { + rcu_read_unlock(); + goto out_free_mdb; + } + } + } + + rcu_read_unlock(); + + list_for_each_entry(obj, &mdb_list, list) { + err = br_mdb_replay_one(nb, dev, SWITCHDEV_OBJ_PORT_MDB(obj)); + if (err) + goto out_free_mdb; + } + +out_free_mdb: + list_for_each_entry_safe(obj, tmp, &mdb_list, list) { + list_del(&obj->list); + kfree(SWITCHDEV_OBJ_PORT_MDB(obj)); + } + + return err; +} +EXPORT_SYMBOL(br_mdb_replay); + static void br_mdb_switchdev_host_port(struct net_device *dev, struct net_device *lower_dev, struct net_bridge_mdb_entry *mp, diff --git a/net/dsa/slave.c b/net/dsa/slave.c index a32875d3dc5f..10b4a0f72dcb 100644 --- a/net/dsa/slave.c +++ b/net/dsa/slave.c @@ -2290,6 +2290,9 @@ bool dsa_slave_dev_check(const struct net_device *dev) } EXPORT_SYMBOL_GPL(dsa_slave_dev_check); +/* Circular reference */ +static struct notifier_block dsa_slave_switchdev_blocking_notifier; + static int dsa_slave_changeupper(struct net_device *dev, struct netdev_notifier_changeupper_info *info) { @@ -2297,10 +2300,15 @@ static int dsa_slave_changeupper(struct net_device *dev, int err = NOTIFY_DONE; if (netif_is_bridge_master(info->upper_dev)) { + struct net_device *bridge_dev = info->upper_dev; + if (info->linking) { - err = dsa_port_bridge_join(dp, info->upper_dev); - if (!err) + err = dsa_port_bridge_join(dp, bridge_dev); + if (!err) { dsa_bridge_mtu_normalization(dp); + br_mdb_replay(bridge_dev, dev, + &dsa_slave_switchdev_blocking_notifier); + } err = notifier_from_errno(err); } else { dsa_port_bridge_leave(dp, info->upper_dev); @@ -2361,6 +2369,11 @@ dsa_slave_lag_changeupper(struct net_device *dev, break; } + if (netif_is_bridge_master(info->upper_dev) && !err) { + br_mdb_replay(info->upper_dev, dev, + &dsa_slave_switchdev_blocking_notifier); + } + return err; } From patchwork Wed Feb 24 11:43:48 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Vladimir Oltean X-Patchwork-Id: 387097 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-15.7 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,FREEMAIL_FORGED_FROMDOMAIN,FREEMAIL_FROM, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI, SPF_HELO_NONE, SPF_PASS, URIBL_BLOCKED, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 5A7A5C433DB for ; Wed, 24 Feb 2021 11:49:40 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 0509D64E90 for ; Wed, 24 Feb 2021 11:49:39 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S234973AbhBXLta (ORCPT ); Wed, 24 Feb 2021 06:49:30 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:48678 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S235073AbhBXLqk (ORCPT ); Wed, 24 Feb 2021 06:46:40 -0500 Received: from mail-ed1-x52d.google.com (mail-ed1-x52d.google.com [IPv6:2a00:1450:4864:20::52d]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 0C2D2C06121E for ; Wed, 24 Feb 2021 03:44:19 -0800 (PST) Received: by mail-ed1-x52d.google.com with SMTP id l12so2094693edt.3 for ; Wed, 24 Feb 2021 03:44:18 -0800 (PST) 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 :mime-version:content-transfer-encoding; bh=FNtyx1iBEYhZqSggSZzDB0DtbFNpszhXmYMTCDWdd5s=; b=gdNxduoY0fIvVxUjggGGpHiewqs8yNLP9Q/NGO6DMcFcwv24g56vE024YdqV8Q/Lue 6TaBHREknUnMdCK1SpGZMzU/jItNm0e2Rg0AkV+giw7+FUTMU28YzgVO7iGih2Z5Pj2R qMQQBhSdcXD+6VDww7IObOWC0STWE4jZHwhdU3UQDaCW1RwTNbyxKzh9ifF2dhU0WqzQ Shu8zPk4R+GSpx2odcAd97s9e4xKubhMR0szmPJt12vf6MddlE7lga1lF6AdxwzN80ak BPaqq3GXBsJ+b//kXBkQW1cacMm3bwXjZHO6jGKHgxmEKBrBf/FP5UUbJepo85WaB4a6 LwSA== 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:mime-version:content-transfer-encoding; bh=FNtyx1iBEYhZqSggSZzDB0DtbFNpszhXmYMTCDWdd5s=; b=Hlk3PLxMmFEFvZhZe0XGshZErNb4SdI3szfaflcMTBu7rqIm/uuhwgsozMGzmJSNvA 2OdOSRmOLdajX14M/5yOb5KwUFx3D8Ee5F+M2szgPdN0W5SWOKg9E19YiTwb+/o5fIWb bQ1Ih0HOtsk4z/h3buNYIdKC6uFujpicID0L9s15VZRUPYlIgE/B21cnQcL70MaeqjPv EcH1fI+0HmRL0Dx3UYejmqPl6cun4Pvld57HVn5NptH69+2ahpW1ydbN7ia1NCzAwahP 1EkhfRWGuw3eqWaQo5Z5lXItqDsikp2lATtCFkoLlz7XRy6EIt7BzsEhZmtGbP4/9o4+ iFtA== X-Gm-Message-State: AOAM5335GQbQdJdfd6YzDnMhOS2ZJUDGgIFf3CS9JjAqT+Qlzw2GpKMD YkHkFfLJK1GKhBOq5GcZvqnsCZ/mQoE= X-Google-Smtp-Source: ABdhPJxxNhFIxG32jfjAuZ1vVOdnkON4glhXRu+TS7usS7wRGgrxYNigRRALQcXGF15lQafBsjmC1g== X-Received: by 2002:a05:6402:1689:: with SMTP id a9mr17261637edv.273.1614167057592; Wed, 24 Feb 2021 03:44:17 -0800 (PST) Received: from localhost.localdomain ([188.25.217.13]) by smtp.gmail.com with ESMTPSA id r5sm1203921ejx.96.2021.02.24.03.44.16 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 24 Feb 2021 03:44:17 -0800 (PST) From: Vladimir Oltean To: netdev@vger.kernel.org Cc: Andrew Lunn , Florian Fainelli , Vivien Didelot , Jiri Pirko , Ido Schimmel , DENG Qingfang , Tobias Waldekranz , George McCollister , Vlad Yasevich , Roopa Prabhu , Nikolay Aleksandrov Subject: [RFC PATCH v2 net-next 15/17] net: dsa: replay port and local fdb entries when joining the bridge Date: Wed, 24 Feb 2021 13:43:48 +0200 Message-Id: <20210224114350.2791260-16-olteanv@gmail.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210224114350.2791260-1-olteanv@gmail.com> References: <20210224114350.2791260-1-olteanv@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org From: Vladimir Oltean When a DSA port joins a LAG that already had an FDB entry pointing to it: ip link set bond0 master br0 bridge fdb add dev bond0 00:01:02:03:04:05 master static ip link set swp0 master bond0 the DSA port will have no idea that this FDB entry is there, because it missed the switchdev event emitted at its creation. Ido Schimmel pointed this out during a discussion about challenges with switchdev offloading of stacked interfaces between the physical port and the bridge, and recommended to just catch that condition and deny the CHANGEUPPER event: https://lore.kernel.org/netdev/20210210105949.GB287766@shredder.lan/ But in fact, we might need to deal with the hard thing anyway, which is to replay all FDB addresses relevant to this port, because it isn't just static FDB entries, but also local addresses (ones that are not forwarded but terminated by the bridge). There, we can't just say 'oh yeah, there was an upper already so I'm not joining that'. So, similar to the logic for replaying MDB entries, add a function that must be called by individual switchdev drivers and replays local FDB entries as well as ones pointing towards a bridge port. This time, we use the atomic switchdev notifier block, since that's what FDB entries expect for some reason. Reported-by: Ido Schimmel Signed-off-by: Vladimir Oltean --- include/linux/if_bridge.h | 10 ++++++++ include/net/switchdev.h | 1 + net/bridge/br_fdb.c | 53 +++++++++++++++++++++++++++++++++++++++ net/dsa/slave.c | 7 +++++- 4 files changed, 70 insertions(+), 1 deletion(-) diff --git a/include/linux/if_bridge.h b/include/linux/if_bridge.h index 2f0e5713bf39..2a90ac638b06 100644 --- a/include/linux/if_bridge.h +++ b/include/linux/if_bridge.h @@ -144,6 +144,8 @@ struct net_device *br_fdb_find_port(const struct net_device *br_dev, __u16 vid); void br_fdb_clear_offload(const struct net_device *dev, u16 vid); bool br_port_flag_is_set(const struct net_device *dev, unsigned long flag); +int br_fdb_replay(struct net_device *br_dev, struct net_device *dev, + struct notifier_block *nb); #else static inline struct net_device * br_fdb_find_port(const struct net_device *br_dev, @@ -162,6 +164,14 @@ br_port_flag_is_set(const struct net_device *dev, unsigned long flag) { return false; } + +static inline int br_fdb_replay(struct net_device *br_dev, + struct net_device *dev, + struct notifier_block *nb) +{ + return -EINVAL; +} + #endif #endif diff --git a/include/net/switchdev.h b/include/net/switchdev.h index f1a5a9a3634d..5b63dfd444c6 100644 --- a/include/net/switchdev.h +++ b/include/net/switchdev.h @@ -206,6 +206,7 @@ struct switchdev_notifier_info { struct switchdev_notifier_fdb_info { struct switchdev_notifier_info info; /* must be first */ + struct list_head list; const unsigned char *addr; u16 vid; u8 added_by_user:1, diff --git a/net/bridge/br_fdb.c b/net/bridge/br_fdb.c index 1d54ae0f58fb..9eb776503b02 100644 --- a/net/bridge/br_fdb.c +++ b/net/bridge/br_fdb.c @@ -726,6 +726,59 @@ static inline size_t fdb_nlmsg_size(void) + nla_total_size(sizeof(u8)); /* NFEA_ACTIVITY_NOTIFY */ } +static int br_fdb_replay_one(struct notifier_block *nb, + struct net_bridge_fdb_entry *fdb, + struct net_device *dev) +{ + struct switchdev_notifier_fdb_info item; + int err; + + item.addr = fdb->key.addr.addr; + item.vid = fdb->key.vlan_id; + item.added_by_user = test_bit(BR_FDB_ADDED_BY_USER, &fdb->flags); + item.offloaded = test_bit(BR_FDB_OFFLOADED, &fdb->flags); + item.is_local = test_bit(BR_FDB_LOCAL, &fdb->flags); + item.info.dev = dev; + + err = nb->notifier_call(nb, SWITCHDEV_FDB_ADD_TO_DEVICE, &item); + return notifier_to_errno(err); +} + +int br_fdb_replay(struct net_device *br_dev, struct net_device *dev, + struct notifier_block *nb) +{ + struct net_bridge_fdb_entry *fdb; + struct net_bridge *br; + int err = 0; + + if (!netif_is_bridge_master(br_dev)) + return -EINVAL; + + if (!netif_is_bridge_port(dev)) + return -EINVAL; + + br = netdev_priv(br_dev); + + rcu_read_lock(); + + hlist_for_each_entry_rcu(fdb, &br->fdb_list, fdb_node) { + struct net_device *dst_dev; + + dst_dev = fdb->dst ? fdb->dst->dev : br->dev; + if (dst_dev != br_dev && dst_dev != dev) + continue; + + err = br_fdb_replay_one(nb, fdb, dst_dev); + if (err) + break; + } + + rcu_read_unlock(); + + return err; +} +EXPORT_SYMBOL(br_fdb_replay); + static void fdb_notify(struct net_bridge *br, const struct net_bridge_fdb_entry *fdb, int type, bool swdev_notify) diff --git a/net/dsa/slave.c b/net/dsa/slave.c index 10b4a0f72dcb..5fa5737e622c 100644 --- a/net/dsa/slave.c +++ b/net/dsa/slave.c @@ -2290,7 +2290,8 @@ bool dsa_slave_dev_check(const struct net_device *dev) } EXPORT_SYMBOL_GPL(dsa_slave_dev_check); -/* Circular reference */ +/* Circular references */ +static struct notifier_block dsa_slave_switchdev_notifier; static struct notifier_block dsa_slave_switchdev_blocking_notifier; static int dsa_slave_changeupper(struct net_device *dev, @@ -2306,6 +2307,8 @@ static int dsa_slave_changeupper(struct net_device *dev, err = dsa_port_bridge_join(dp, bridge_dev); if (!err) { dsa_bridge_mtu_normalization(dp); + br_fdb_replay(bridge_dev, dev, + &dsa_slave_switchdev_notifier); br_mdb_replay(bridge_dev, dev, &dsa_slave_switchdev_blocking_notifier); } @@ -2370,6 +2373,8 @@ dsa_slave_lag_changeupper(struct net_device *dev, } if (netif_is_bridge_master(info->upper_dev) && !err) { + br_fdb_replay(info->upper_dev, dev, + &dsa_slave_switchdev_notifier); br_mdb_replay(info->upper_dev, dev, &dsa_slave_switchdev_blocking_notifier); } From patchwork Wed Feb 24 11:43:49 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Vladimir Oltean X-Patchwork-Id: 387601 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-15.7 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,FREEMAIL_FORGED_FROMDOMAIN,FREEMAIL_FROM, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI, SPF_HELO_NONE, SPF_PASS, URIBL_BLOCKED, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 5E4FDC433DB for ; Wed, 24 Feb 2021 11:49:08 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id EDA0E64EC3 for ; Wed, 24 Feb 2021 11:49:07 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S235095AbhBXLtC (ORCPT ); Wed, 24 Feb 2021 06:49:02 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:48334 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S235050AbhBXLqX (ORCPT ); Wed, 24 Feb 2021 06:46:23 -0500 Received: from mail-ej1-x636.google.com (mail-ej1-x636.google.com [IPv6:2a00:1450:4864:20::636]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 73241C06121F for ; Wed, 24 Feb 2021 03:44:20 -0800 (PST) Received: by mail-ej1-x636.google.com with SMTP id t11so2523866ejx.6 for ; Wed, 24 Feb 2021 03:44:20 -0800 (PST) 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 :mime-version:content-transfer-encoding; bh=nfBDHgnDjcsZES8vXUS8aoIStbEt+fjmkG61Meh+ib4=; b=P47RXwwEdGcmArkX6q8gMYIqMhh1OPQjJmzW0Gwky44DuQd3vXpuBqR0HuRU6d8ccZ IVRZUMYJIOjJY7uqx0nXoSFKLGiViLPwp5vaP0zJfVXtZilkQfUhNvVacM97r8Za/y4m cUSYtiLtcR/trCoZBilqktqNQ2NcgtJ8deE8yxEFLxZgg0mTKzVMGzWVHf2xDCrlrESo Gbu1xMUOugDemR/0IYdeG7pCCjs4MtNssl1vD8tpcb9q/4iNIircm7h2GApOKKlfxizI tk2RU/8WYmNfaU0LYxrY57A7eSB5wasKIwFKXzY4YJJfXQnhIBSGDcNeSEPVePmg8IAs jXzA== 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:mime-version:content-transfer-encoding; bh=nfBDHgnDjcsZES8vXUS8aoIStbEt+fjmkG61Meh+ib4=; b=l0WP8T2Pwb5UdKGdUSEvVYLWLT7KQcPiHNGgGTNWQ5CadC7dg3rN2aZXTXwbLGEZ0q e2c67R+Wt/tyNFH+ccUQY6Ns96GyrgNTqpCCasPGxDHyMVv/kxG0JgP4VoxOMDScEu+r BYFXMNtl/kfNaCCDfHuv+GOgklHT79nz8+WIEvHfJeomghoQSMRtODH08qLHyv1UTHae DHea5M+HyR8TqcY4Da7Lxw1tIn9sObUxPLs4ECENNN0oBaFIJXi3Y05yu2IO8J0bMfWB aE+l1T/Ra8Ypjy0IKLzJvPkjKFgxzmP3tK2OEJhXftkc22l81XHZX/P/PxV1ipcDK58j 4iTg== X-Gm-Message-State: AOAM531oB8URXMF6bQ4uhiD6HfpqkgB6qi49thCmaUR1fl+RRmkrilul ZSsuxogVhjjLuhD9rI6ClJ49wmcLyk8= X-Google-Smtp-Source: ABdhPJzJoUP9gUyS/U5hnpvKUNm9vTUTMe3O04dsV8jOG4JSXFD//9pZGwdxIY3qitBT4ln4EGvBsg== X-Received: by 2002:a17:906:b214:: with SMTP id p20mr22505839ejz.22.1614167058668; Wed, 24 Feb 2021 03:44:18 -0800 (PST) Received: from localhost.localdomain ([188.25.217.13]) by smtp.gmail.com with ESMTPSA id r5sm1203921ejx.96.2021.02.24.03.44.17 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 24 Feb 2021 03:44:18 -0800 (PST) From: Vladimir Oltean To: netdev@vger.kernel.org Cc: Andrew Lunn , Florian Fainelli , Vivien Didelot , Jiri Pirko , Ido Schimmel , DENG Qingfang , Tobias Waldekranz , George McCollister , Vlad Yasevich , Roopa Prabhu , Nikolay Aleksandrov Subject: [RFC PATCH v2 net-next 16/17] net: bridge: switchdev: let drivers inform which bridge ports are offloaded Date: Wed, 24 Feb 2021 13:43:49 +0200 Message-Id: <20210224114350.2791260-17-olteanv@gmail.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210224114350.2791260-1-olteanv@gmail.com> References: <20210224114350.2791260-1-olteanv@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org From: Vladimir Oltean On reception of an skb, the bridge checks if it was marked as 'already forwarded in hardware' (checks if skb->offload_fwd_mark == 1), and if it is, it puts a mark of its own on that skb, with the switchdev mark of the ingress port. Then during forwarding, it enforces that the egress port must have a different switchdev mark than the ingress one (this is done in nbp_switchdev_allowed_egress). Non-switchdev drivers don't report any physical switch id (neither through devlink nor .ndo_get_port_parent_id), therefore the bridge assigns them a switchdev mark of 0, and packets coming from them will always have skb->offload_fwd_mark = 0. So there aren't any restrictions. Problems appear due to the fact that DSA would like to perform software fallback for bonding and team interfaces that the physical switch cannot offload. +-- br0 -+ / / | \ / / | \ / / | \ / / | \ / / | \ / | | bond0 / | | / \ swp0 swp1 swp2 swp3 swp4 There, it is desirable that the presence of swp3 and swp4 under a non-offloaded LAG does not preclude us from doing hardware bridging beteen swp0, swp1 and swp2. The bandwidth of the CPU is often times high enough that software bridging between {swp0,swp1,swp2} and bond0 is not impractical. But this creates an impossible paradox given the current way in which port switchdev marks are assigned. When the driver receives a packet from swp0 (say, due to flooding), it must set skb->offload_fwd_mark to something. - If we set it to 0, then the bridge will forward it towards swp1, swp2 and bond0. But the switch has already forwarded it towards swp1 and swp2 (not to bond0, remember, that isn't offloaded, so as far as the switch is concerned, ports swp3 and swp4 are not looking up the FDB, and the entire bond0 is a destination that is strictly behind the CPU). But we don't want duplicated traffic towards swp1 and swp2, so it's not ok to set skb->offload_fwd_mark = 0. - If we set it to 1, then the bridge will not forward the skb towards the ports with the same switchdev mark, i.e. not to swp1, swp2 and bond0. Towards swp1 and swp2 that's ok, but towards bond0? It should have forwarded the skb there. So the real issue is that bond0 will be assigned the same switchdev mark as {swp0,swp1,swp2}, because the function that assigns switchdev marks to bridge ports, nbp_switchdev_mark_set, recurses through bond0's lower interfaces until it finds something that implements devlink. A solution is to give the bridge explicit hints as to what switchdev mark it should use for each port. Currently, the bridging offload is very 'silent': a driver registers a netdevice notifier, which is put on the netns's notifier chain, and which sniffs around for NETDEV_CHANGEUPPER events where the upper is a bridge, and the lower is an interface it knows about (one registered by this driver, normally). Then, from within that notifier, it does a bunch of stuff behind the bridge's back, without the bridge necessarily knowing that there's somebody offloading that port. It looks like this: ip link set swp0 master br0 | v bridge calls netdev_master_upper_dev_link | v call_netdevice_notifiers | v dsa_slave_netdevice_event | v oh, hey! it's for me! | v .port_bridge_join What we do to solve the conundrum is to be less silent, and emit a notification back. Something like this: ip link set swp0 master br0 | v bridge calls netdev_master_upper_dev_link | v bridge: Aye! I'll use this call_netdevice_notifiers ^ ppid as the | | switchdev mark for v | this port, and zero dsa_slave_netdevice_event | if I got nothing. | | v | oh, hey! it's for me! | | | v | .port_bridge_join | | | +------------------------+ call_switchdev_notifiers(swp0, SWITCHDEV_BRPORT_OFFLOADED, ppid) Then stacked interfaces (like bond0 on top of swp3/swp4) would be treated differently in DSA, depending on whether we can or cannot offload them. The offload case: ip link set bond0 master br0 | v bridge calls netdev_master_upper_dev_link | v bridge: Aye! I'll use this call_netdevice_notifiers ^ ppid as the | | switchdev mark for v | bond0. dsa_slave_netdevice_event | Coincidentally (or not), | | bond0 and swp0, swp1, swp2 v | all have the same switchdev hmm, it's not quite for me, | mark now, since the ASIC but my driver has already | is able to forward towards called .port_lag_join | all these ports in hw. for it, because I have | a port with dp->lag_dev == bond0. | | | v | .port_bridge_join | for swp3 and swp4 | | | +------------------------+ call_switchdev_notifiers(bond0, SWITCHDEV_BRPORT_OFFLOADED, ppid) And the non-offload case: ip link set bond0 master br0 | v bridge calls netdev_master_upper_dev_link | v bridge waiting: call_netdevice_notifiers ^ huh, no SWITCHDEV_BRPORT_OFFLOADED | | event, okay, I'll use a switchdev v | mark of zero for this one. dsa_slave_netdevice_event : Then packets received on swp0 will | : not be forwarded towards swp1, but v : they will towards bond0. it's not for me, but bond0 is an upper of swp3 and swp4, but their dp->lag_dev is NULL because they couldn't offload it. Signed-off-by: Vladimir Oltean --- .../marvell/prestera/prestera_switchdev.c | 2 + .../mellanox/mlxsw/spectrum_switchdev.c | 2 + drivers/net/ethernet/mscc/ocelot_net.c | 43 +++++++++++++++---- drivers/net/ethernet/rocker/rocker_ofdpa.c | 2 + drivers/net/ethernet/ti/am65-cpsw-nuss.c | 2 + drivers/net/ethernet/ti/cpsw_new.c | 1 + drivers/staging/fsl-dpaa2/ethsw/ethsw.c | 2 + include/net/switchdev.h | 16 +++++++ net/bridge/br.c | 8 +++- net/bridge/br_if.c | 11 ++--- net/bridge/br_private.h | 7 +-- net/bridge/br_switchdev.c | 27 +++++------- net/dsa/slave.c | 20 +++++---- net/switchdev/switchdev.c | 18 ++++++++ 14 files changed, 116 insertions(+), 45 deletions(-) diff --git a/drivers/net/ethernet/marvell/prestera/prestera_switchdev.c b/drivers/net/ethernet/marvell/prestera/prestera_switchdev.c index cb564890a3dc..10a6242b7ac1 100644 --- a/drivers/net/ethernet/marvell/prestera/prestera_switchdev.c +++ b/drivers/net/ethernet/marvell/prestera/prestera_switchdev.c @@ -443,6 +443,8 @@ static int prestera_port_bridge_join(struct prestera_port *port, goto err_brport_create; } + switchdev_bridge_port_offload_notify(port->dev); + if (bridge->vlan_enabled) return 0; diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c index 9aadc29ad777..241276dbe876 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c @@ -2326,6 +2326,8 @@ int mlxsw_sp_port_bridge_join(struct mlxsw_sp_port *mlxsw_sp_port, if (err) goto err_port_join; + switchdev_bridge_port_offload_notify(brport_dev); + return 0; err_port_join: diff --git a/drivers/net/ethernet/mscc/ocelot_net.c b/drivers/net/ethernet/mscc/ocelot_net.c index 12cb6867a2d0..b8be69ade1bd 100644 --- a/drivers/net/ethernet/mscc/ocelot_net.c +++ b/drivers/net/ethernet/mscc/ocelot_net.c @@ -1111,10 +1111,14 @@ static int ocelot_port_obj_del(struct net_device *dev, return ret; } -static int ocelot_netdevice_bridge_join(struct ocelot *ocelot, int port, +static int ocelot_netdevice_bridge_join(struct net_device *dev, struct net_device *bridge) { + struct ocelot_port_private *priv = netdev_priv(dev); + struct ocelot_port *ocelot_port = &priv->port; + struct ocelot *ocelot = ocelot_port->ocelot; struct switchdev_brport_flags flags; + int port = priv->chip_port; int err; flags.mask = BR_LEARNING | BR_FLOOD | BR_MCAST_FLOOD | BR_BCAST_FLOOD; @@ -1124,15 +1128,20 @@ static int ocelot_netdevice_bridge_join(struct ocelot *ocelot, int port, if (err) return err; + switchdev_bridge_port_offload_notify(dev); ocelot_port_bridge_flags(ocelot, port, flags); return 0; } -static int ocelot_netdevice_bridge_leave(struct ocelot *ocelot, int port, +static int ocelot_netdevice_bridge_leave(struct net_device *dev, struct net_device *bridge) { + struct ocelot_port_private *priv = netdev_priv(dev); + struct ocelot_port *ocelot_port = &priv->port; + struct ocelot *ocelot = ocelot_port->ocelot; struct switchdev_brport_flags flags; + int port = priv->chip_port; int err; flags.mask = BR_LEARNING | BR_FLOOD | BR_MCAST_FLOOD | BR_BCAST_FLOOD; @@ -1146,7 +1155,8 @@ static int ocelot_netdevice_bridge_leave(struct ocelot *ocelot, int port, } static int ocelot_netdevice_changeupper(struct net_device *dev, - struct netdev_notifier_changeupper_info *info) + struct netdev_notifier_changeupper_info *info, + bool notify) { struct ocelot_port_private *priv = netdev_priv(dev); struct ocelot_port *ocelot_port = &priv->port; @@ -1156,11 +1166,11 @@ static int ocelot_netdevice_changeupper(struct net_device *dev, if (netif_is_bridge_master(info->upper_dev)) { if (info->linking) { - err = ocelot_netdevice_bridge_join(ocelot, port, - info->upper_dev); + err = ocelot_netdevice_bridge_join(dev, info->upper_dev); + if (!err && notify) + switchdev_bridge_port_offload_notify(dev); } else { - err = ocelot_netdevice_bridge_leave(ocelot, port, - info->upper_dev); + err = ocelot_netdevice_bridge_leave(dev, info->upper_dev); } } if (netif_is_lag_master(info->upper_dev)) { @@ -1182,6 +1192,12 @@ static int ocelot_netdevice_changeupper(struct net_device *dev, return notifier_from_errno(err); } +/* Treat CHANGEUPPER events on an offloaded LAG as individual CHANGEUPPER + * events for the lower physical ports of the LAG. + * If the LAG upper isn't offloaded, ignore its CHANGEUPPER events. + * In case the LAG joined a bridge, notify that we are offloading it and can do + * forwarding in hardware towards it. + */ static int ocelot_netdevice_lag_changeupper(struct net_device *dev, struct netdev_notifier_changeupper_info *info) @@ -1191,11 +1207,20 @@ ocelot_netdevice_lag_changeupper(struct net_device *dev, int err = NOTIFY_DONE; netdev_for_each_lower_dev(dev, lower, iter) { - err = ocelot_netdevice_changeupper(lower, info); + struct ocelot_port_private *priv = netdev_priv(lower); + struct ocelot_port *ocelot_port = &priv->port; + + if (ocelot_port->bond != dev) + return NOTIFY_OK; + + err = ocelot_netdevice_changeupper(lower, info, false); if (err) return notifier_from_errno(err); } + if (info->linking && netif_is_bridge_master(info->upper_dev)) + switchdev_bridge_port_offload_notify(dev); + return NOTIFY_DONE; } @@ -1230,7 +1255,7 @@ static int ocelot_netdevice_event(struct notifier_block *unused, struct netdev_notifier_changeupper_info *info = ptr; if (ocelot_netdevice_dev_check(dev)) - return ocelot_netdevice_changeupper(dev, info); + return ocelot_netdevice_changeupper(dev, info, true); if (netif_is_lag_master(dev)) return ocelot_netdevice_lag_changeupper(dev, info); diff --git a/drivers/net/ethernet/rocker/rocker_ofdpa.c b/drivers/net/ethernet/rocker/rocker_ofdpa.c index 967a634ee9ac..f57c26a24924 100644 --- a/drivers/net/ethernet/rocker/rocker_ofdpa.c +++ b/drivers/net/ethernet/rocker/rocker_ofdpa.c @@ -2592,6 +2592,8 @@ static int ofdpa_port_bridge_join(struct ofdpa_port *ofdpa_port, ofdpa_port->bridge_dev = bridge; + switchdev_bridge_port_offload_notify(ofdpa_port->dev); + return ofdpa_port_vlan_add(ofdpa_port, OFDPA_UNTAGGED_VID, 0); } diff --git a/drivers/net/ethernet/ti/am65-cpsw-nuss.c b/drivers/net/ethernet/ti/am65-cpsw-nuss.c index 638d7b03be4b..7bb1b7b83031 100644 --- a/drivers/net/ethernet/ti/am65-cpsw-nuss.c +++ b/drivers/net/ethernet/ti/am65-cpsw-nuss.c @@ -27,6 +27,7 @@ #include #include #include +#include #include "cpsw_ale.h" #include "cpsw_sl.h" @@ -2096,6 +2097,7 @@ static int am65_cpsw_netdevice_port_link(struct net_device *ndev, struct net_dev common->br_members |= BIT(priv->port->port_id); am65_cpsw_port_offload_fwd_mark_update(common); + switchdev_bridge_port_offload_notify(ndev); return NOTIFY_DONE; } diff --git a/drivers/net/ethernet/ti/cpsw_new.c b/drivers/net/ethernet/ti/cpsw_new.c index 58a64313ac00..e246010db5be 100644 --- a/drivers/net/ethernet/ti/cpsw_new.c +++ b/drivers/net/ethernet/ti/cpsw_new.c @@ -1522,6 +1522,7 @@ static int cpsw_netdevice_port_link(struct net_device *ndev, cpsw->br_members |= BIT(priv->emac_port); cpsw_port_offload_fwd_mark_update(cpsw); + switchdev_bridge_port_offload_notify(ndev); return NOTIFY_DONE; } diff --git a/drivers/staging/fsl-dpaa2/ethsw/ethsw.c b/drivers/staging/fsl-dpaa2/ethsw/ethsw.c index aad212b9b97b..535982be5605 100644 --- a/drivers/staging/fsl-dpaa2/ethsw/ethsw.c +++ b/drivers/staging/fsl-dpaa2/ethsw/ethsw.c @@ -1237,6 +1237,8 @@ static int dpaa2_switch_port_bridge_join(struct net_device *netdev, if (!err) port_priv->bridge_dev = upper_dev; + switchdev_bridge_port_offload_notify(netdev); + return err; } diff --git a/include/net/switchdev.h b/include/net/switchdev.h index 5b63dfd444c6..a3b4cf6ade6c 100644 --- a/include/net/switchdev.h +++ b/include/net/switchdev.h @@ -197,6 +197,8 @@ enum switchdev_notifier_type { SWITCHDEV_VXLAN_FDB_ADD_TO_DEVICE, SWITCHDEV_VXLAN_FDB_DEL_TO_DEVICE, SWITCHDEV_VXLAN_FDB_OFFLOADED, + + SWITCHDEV_BRPORT_OFFLOADED, }; struct switchdev_notifier_info { @@ -204,6 +206,11 @@ struct switchdev_notifier_info { struct netlink_ext_ack *extack; }; +struct switchdev_notifier_brport_info { + struct switchdev_notifier_info info; /* must be first */ + struct netdev_phys_item_id ppid; +}; + struct switchdev_notifier_fdb_info { struct switchdev_notifier_info info; /* must be first */ struct list_head list; @@ -284,6 +291,9 @@ int switchdev_handle_port_attr_set(struct net_device *dev, int (*set_cb)(struct net_device *dev, const struct switchdev_attr *attr, struct netlink_ext_ack *extack)); + +int switchdev_bridge_port_offload_notify(struct net_device *dev); + #else static inline void switchdev_deferred_process(void) @@ -380,6 +390,12 @@ switchdev_handle_port_attr_set(struct net_device *dev, { return 0; } + +static inline int switchdev_bridge_port_offload_notify(struct net_device *dev) +{ + return 0; +} + #endif #endif /* _LINUX_SWITCHDEV_H_ */ diff --git a/net/bridge/br.c b/net/bridge/br.c index ef743f94254d..72dcd0bc462a 100644 --- a/net/bridge/br.c +++ b/net/bridge/br.c @@ -151,9 +151,10 @@ static int br_switchdev_event(struct notifier_block *unused, unsigned long event, void *ptr) { struct net_device *dev = switchdev_notifier_info_to_dev(ptr); + struct switchdev_notifier_brport_info *brport_info; + struct switchdev_notifier_fdb_info *fdb_info; struct net_bridge_port *p; struct net_bridge *br; - struct switchdev_notifier_fdb_info *fdb_info; int err = NOTIFY_DONE; p = br_port_get_rtnl_rcu(dev); @@ -191,6 +192,11 @@ static int br_switchdev_event(struct notifier_block *unused, /* Don't delete static entries */ br_fdb_delete_by_port(br, p, fdb_info->vid, 0); break; + case SWITCHDEV_BRPORT_OFFLOADED: + brport_info = ptr; + p->ppid = brport_info->ppid; + p->offloaded = true; + break; } out: diff --git a/net/bridge/br_if.c b/net/bridge/br_if.c index f7d2f472ae24..680fc3bed549 100644 --- a/net/bridge/br_if.c +++ b/net/bridge/br_if.c @@ -643,9 +643,7 @@ int br_add_if(struct net_bridge *br, struct net_device *dev, if (err) goto err5; - err = nbp_switchdev_mark_set(p); - if (err) - goto err6; + nbp_switchdev_mark_set(p); dev_disable_lro(dev); @@ -671,13 +669,13 @@ int br_add_if(struct net_bridge *br, struct net_device *dev, */ err = dev_pre_changeaddr_notify(br->dev, dev->dev_addr, extack); if (err) - goto err7; + goto err6; } err = nbp_vlan_init(p, extack); if (err) { netdev_err(dev, "failed to initialize vlan filtering on this port\n"); - goto err7; + goto err6; } spin_lock_bh(&br->lock); @@ -700,11 +698,10 @@ int br_add_if(struct net_bridge *br, struct net_device *dev, return 0; -err7: +err6: list_del_rcu(&p->list); br_fdb_delete_by_port(br, p, 0, 1); nbp_update_port_count(br); -err6: netdev_upper_dev_unlink(dev, br->dev); err5: dev->priv_flags &= ~IFF_BRIDGE_PORT; diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h index 4a262dc55e6b..484e23e8bb9d 100644 --- a/net/bridge/br_private.h +++ b/net/bridge/br_private.h @@ -328,6 +328,8 @@ struct net_bridge_port { #endif #ifdef CONFIG_NET_SWITCHDEV int offload_fwd_mark; + bool offloaded; + struct netdev_phys_item_id ppid; #endif u16 group_fwd_mask; u16 backup_redirected_cnt; @@ -1572,7 +1574,7 @@ static inline void br_sysfs_delbr(struct net_device *dev) { return; } /* br_switchdev.c */ #ifdef CONFIG_NET_SWITCHDEV -int nbp_switchdev_mark_set(struct net_bridge_port *p); +void nbp_switchdev_mark_set(struct net_bridge_port *p); void nbp_switchdev_frame_mark(const struct net_bridge_port *p, struct sk_buff *skb); bool nbp_switchdev_allowed_egress(const struct net_bridge_port *p, @@ -1592,9 +1594,8 @@ static inline void br_switchdev_frame_unmark(struct sk_buff *skb) skb->offload_fwd_mark = 0; } #else -static inline int nbp_switchdev_mark_set(struct net_bridge_port *p) +static inline void nbp_switchdev_mark_set(struct net_bridge_port *p) { - return 0; } static inline void nbp_switchdev_frame_mark(const struct net_bridge_port *p, diff --git a/net/bridge/br_switchdev.c b/net/bridge/br_switchdev.c index 9a707da79dfe..c700da5c71e0 100644 --- a/net/bridge/br_switchdev.c +++ b/net/bridge/br_switchdev.c @@ -8,36 +8,29 @@ #include "br_private.h" -static int br_switchdev_mark_get(struct net_bridge *br, struct net_device *dev) +static int br_switchdev_mark_get(struct net_bridge *br, + struct net_bridge_port *new_nbp) { struct net_bridge_port *p; /* dev is yet to be added to the port list. */ list_for_each_entry(p, &br->port_list, list) { - if (netdev_port_same_parent_id(dev, p->dev)) + if (!p->offloaded) + continue; + + if (netdev_phys_item_id_same(&p->ppid, &new_nbp->ppid)) return p->offload_fwd_mark; } return ++br->offload_fwd_mark; } -int nbp_switchdev_mark_set(struct net_bridge_port *p) +void nbp_switchdev_mark_set(struct net_bridge_port *p) { - struct netdev_phys_item_id ppid = { }; - int err; - - ASSERT_RTNL(); + if (!p->offloaded) + return; - err = dev_get_port_parent_id(p->dev, &ppid, true); - if (err) { - if (err == -EOPNOTSUPP) - return 0; - return err; - } - - p->offload_fwd_mark = br_switchdev_mark_get(p->br, p->dev); - - return 0; + p->offload_fwd_mark = br_switchdev_mark_get(p->br, p); } void nbp_switchdev_frame_mark(const struct net_bridge_port *p, diff --git a/net/dsa/slave.c b/net/dsa/slave.c index 5fa5737e622c..bbb7846d6022 100644 --- a/net/dsa/slave.c +++ b/net/dsa/slave.c @@ -2295,7 +2295,8 @@ static struct notifier_block dsa_slave_switchdev_notifier; static struct notifier_block dsa_slave_switchdev_blocking_notifier; static int dsa_slave_changeupper(struct net_device *dev, - struct netdev_notifier_changeupper_info *info) + struct netdev_notifier_changeupper_info *info, + bool notify) { struct dsa_port *dp = dsa_slave_to_port(dev); int err = NOTIFY_DONE; @@ -2305,6 +2306,8 @@ static int dsa_slave_changeupper(struct net_device *dev, if (info->linking) { err = dsa_port_bridge_join(dp, bridge_dev); + if (!err && notify) + switchdev_bridge_port_offload_notify(dev); if (!err) { dsa_bridge_mtu_normalization(dp); br_fdb_replay(bridge_dev, dev, @@ -2364,22 +2367,23 @@ dsa_slave_lag_changeupper(struct net_device *dev, dp = dsa_slave_to_port(lower); if (!dp->lag_dev) - /* Software LAG */ - continue; + /* Software LAG, ignore all its CHANGEUPPER events */ + return NOTIFY_DONE; - err = dsa_slave_changeupper(lower, info); + err = dsa_slave_changeupper(lower, info, false); if (notifier_to_errno(err)) - break; + return err; } - if (netif_is_bridge_master(info->upper_dev) && !err) { + if (info->linking && netif_is_bridge_master(info->upper_dev)) { + switchdev_bridge_port_offload_notify(dev); br_fdb_replay(info->upper_dev, dev, &dsa_slave_switchdev_notifier); br_mdb_replay(info->upper_dev, dev, &dsa_slave_switchdev_blocking_notifier); } - return err; + return 0; } static int @@ -2475,7 +2479,7 @@ static int dsa_slave_netdevice_event(struct notifier_block *nb, } case NETDEV_CHANGEUPPER: if (dsa_slave_dev_check(dev)) - return dsa_slave_changeupper(dev, ptr); + return dsa_slave_changeupper(dev, ptr, true); if (netif_is_lag_master(dev)) return dsa_slave_lag_changeupper(dev, ptr); diff --git a/net/switchdev/switchdev.c b/net/switchdev/switchdev.c index 89a36db47ab4..7f48effc1ffb 100644 --- a/net/switchdev/switchdev.c +++ b/net/switchdev/switchdev.c @@ -546,3 +546,21 @@ int switchdev_handle_port_attr_set(struct net_device *dev, return err; } EXPORT_SYMBOL_GPL(switchdev_handle_port_attr_set); + +/* Let the bridge know that this port is offloaded, so that it can use the + * port parent id obtained by recursion to determine the bridge port's + * switchdev mark. + */ +int switchdev_bridge_port_offload_notify(struct net_device *dev) +{ + struct switchdev_notifier_brport_info info; + int err; + + err = dev_get_port_parent_id(dev, &info.ppid, true); + if (err) + return err; + + return call_switchdev_notifiers(SWITCHDEV_BRPORT_OFFLOADED, dev, + &info.info, NULL); +} +EXPORT_SYMBOL(switchdev_bridge_port_offload_notify); From patchwork Wed Feb 24 11:43:50 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Vladimir Oltean X-Patchwork-Id: 387600 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-15.7 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,FREEMAIL_FORGED_FROMDOMAIN,FREEMAIL_FROM, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI, SPF_HELO_NONE, SPF_PASS, URIBL_BLOCKED, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id AFFB4C433DB for ; Wed, 24 Feb 2021 11:50:40 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 4C48664DF2 for ; Wed, 24 Feb 2021 11:50:40 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S235101AbhBXLts (ORCPT ); Wed, 24 Feb 2021 06:49:48 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:48710 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S235079AbhBXLqs (ORCPT ); Wed, 24 Feb 2021 06:46:48 -0500 Received: from mail-ed1-x52c.google.com (mail-ed1-x52c.google.com [IPv6:2a00:1450:4864:20::52c]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 46595C061221 for ; Wed, 24 Feb 2021 03:44:21 -0800 (PST) Received: by mail-ed1-x52c.google.com with SMTP id cf12so1257559edb.8 for ; Wed, 24 Feb 2021 03:44:21 -0800 (PST) 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 :mime-version:content-transfer-encoding; bh=HQkwNThB5BeeMrrVMwihs6Hz2oUsXRz+N8B9BmewocY=; b=RwTlGI862OnKvrf/WOh1L3TWqjal8eCOF0PJN4bV6HspV+Zmy2RqdrmNfrDy/4QXJZ AeqP7urq8/lR7EwhOQOICt/Vypl/rs+QZLQ4rorxSxqaB8xyxNFT8fbsrhpMI+gJRR/4 W9vTaAUtmg8VTLMktWnp7wSELY8UpCMBEv6HdT/V6P+ffFXqBFptF7RB/DrsofoXBLRy HQ7MAHLKm1EkYsEikP62lpwA01q0aW7GliMQsJAjRRuqGiiEFGynOMz6SXO7DN7Y1WBH 4WqC8iX29KC3j+/Ksb/rebf+rnYIR5V04jKST7CJ3x2ZOwEEafjufGJvqVy2e2q3s90p 3PpA== 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:mime-version:content-transfer-encoding; bh=HQkwNThB5BeeMrrVMwihs6Hz2oUsXRz+N8B9BmewocY=; b=UFO8W1rawG7CHORZa/voVvxSEyZmj4iN7INzohGTlScAU3y9gnTcraG3K9olW6iEiR 3RKVV2lYUGDm90L8hiXDHb3oggKKe7Vk2C1bQLn4dZIyDfz2NQPUXeq4CxJ3A+0eD3ln bBi/uuMzbCxmc2ntDWWKiMtQEm8E7JYifLCa2lzWlQpwSjd5K7Fatv+UanSeX/6VjNWO 3SVbVHjp8l5CQuOMX4oFhc1M9tup91B6I0FOzNcidPVxlPRG6EKKVPDHQO6DXzZ2J8Un 8GoTM2lWXWt+6/UIOJh9MRZn/JecPuFou91MbZkaRMvMTDTY78op9BsgF+PeByoBXKrl zLzw== X-Gm-Message-State: AOAM533tC+uQbSl/jfzJidZJ9laK397E4qszhM231gUwRBlw5JoBX6yT UJUdOpc2Bhzplzbsj7fO7Qvn5N0CmWM= X-Google-Smtp-Source: ABdhPJzWQoemeYVM9OuVHp7q+VyYPiPdwYC886tu8eNLCzjQ/p2EBqb9Zf3Lol+Xl4esTlnIS3XQdQ== X-Received: by 2002:aa7:d2c4:: with SMTP id k4mr15363095edr.237.1614167059780; Wed, 24 Feb 2021 03:44:19 -0800 (PST) Received: from localhost.localdomain ([188.25.217.13]) by smtp.gmail.com with ESMTPSA id r5sm1203921ejx.96.2021.02.24.03.44.18 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 24 Feb 2021 03:44:19 -0800 (PST) From: Vladimir Oltean To: netdev@vger.kernel.org Cc: Andrew Lunn , Florian Fainelli , Vivien Didelot , Jiri Pirko , Ido Schimmel , DENG Qingfang , Tobias Waldekranz , George McCollister , Vlad Yasevich , Roopa Prabhu , Nikolay Aleksandrov Subject: [RFC PATCH v2 net-next 17/17] net: bridge: offloaded ports are always promiscuous Date: Wed, 24 Feb 2021 13:43:50 +0200 Message-Id: <20210224114350.2791260-18-olteanv@gmail.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210224114350.2791260-1-olteanv@gmail.com> References: <20210224114350.2791260-1-olteanv@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org From: Vladimir Oltean Automatic bridge ports are ones with source address learning or unicast flooding enabled (corollary: non-automatic ports have learning and flooding disabled). The bridge driver has an optimization which says that if all ports are non-automatic, they don't need to operate in promiscuous mode (i.e. they don't need to receive all packets). Instead, if a non-automatic port supports unicast filtering, it can be made to receive only the packets which have a static FDB entry towards another port in the same forwarding domain. The logic is that, if a packet is received and does not have a static FDB entry for routing, it would be dropped anyway because all the other ports have flooding disabled. So it makes sense to not accept the packet on RX in the first place. When a non-automatic port switches to non-promiscuous mode, the static FDB entries towards the other bridge ports are synced to the RX filtering list of this ingress port using dev_uc_add. However, this optimization doesn't bring any benefit for switchdev ports that offload the bridge. Their hardware data path is promiscuous by its very definition, i.e. they accept packets regardless of destination MAC address, because they need to forward them towards the correct station. Not only is the optimization not necessary, it is also detrimential. The promise of switchdev is that it looks just like a regular interface to user space, and it offers extra offloading functionality for stacked virtual interfaces that can benefit from it. Therefore, it is imaginable that a switchdev driver might want to implement IFF_UNICAST_FLT too. When not offloading the bridge, a switchdev interface should really be indistinguishable from a normal port from user space's perspective, which means that addresses installed with dev_uc_add and dev_mc_add should be accepted, and those which aren't should be dropped. So a switchdev driver might implement dev_uc_add and dev_mc_add by extracting these addresses from the hardware data path and delivering them to the CPU, and drop the rest by disabling flooding to the CPU, and this makes perfect sense when there is no bridge involved on top. However, things get complicated when the bridge ports are non-automatic and enter non-promiscuous mode. The bridge will then panic 'oh no, I need to do something in order for my packets to not get dropped', and will do the dev_uc_add procedure mentioned above. This will result in the undesirable behavior that the switchdev driver will extract those MAC addresses to the CPU, when in fact all that the bridge wanted was for the packets to not be dropped. To avoid this situation, the switchdev driver would need to conditionally accept an address added through dev_uc_add and extract it to the CPU only if it wasn't added by the bridge, which is both complicated, strange and counterproductive. It is already unfortunate enough that the bridge uses its own notification mechanisms for addresses which need to be extracted (SWITCHDEV_OBJ_ID_HOST_MDB, SWITCHDEV_FDB_ADD_TO_DEVICE with dev=br0). It shouldn't monopolize the switchdev driver's functionality and instead it should allow it to offer its services to other layers which are unaware of switchdev. So this patch's premise is that the bridge, which is fully aware of switchdev anyway, is the one that needs to compromise, and must not do something which isn't needed if switchdev is being used to offload a port. This way, dev_uc_add and dev_mc_add can be used as a valid mechanism for address filtering towards the CPU requested by switchdev-unaware layers ('towards the CPU' because switchdev-unaware will not benefit from the hardware offload datapath anyway, that's effectively the only destination which is relevant for them). Signed-off-by: Vladimir Oltean --- net/bridge/br_if.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/net/bridge/br_if.c b/net/bridge/br_if.c index 680fc3bed549..fc32066bbfdc 100644 --- a/net/bridge/br_if.c +++ b/net/bridge/br_if.c @@ -111,9 +111,13 @@ static void br_port_clear_promisc(struct net_bridge_port *p) /* Check if the port is already non-promisc or if it doesn't * support UNICAST filtering. Without unicast filtering support * we'll end up re-enabling promisc mode anyway, so just check for - * it here. + * it here. Also, a switchdev offloading this port needs to be + * promiscuous by definition, so don't even attempt to get it out of + * promiscuous mode or sync unicast FDB entries to it, since that is + * pointless and not necessary. */ - if (!br_promisc_port(p) || !(p->dev->priv_flags & IFF_UNICAST_FLT)) + if (!br_promisc_port(p) || !(p->dev->priv_flags & IFF_UNICAST_FLT) || + p->offloaded) return; /* Since we'll be clearing the promisc mode, program the port