From patchwork Tue Sep 5 11:47:18 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Johannes Nixdorf X-Patchwork-Id: 13374446 X-Patchwork-Delegate: kuba@kernel.org Received: from lindbergh.monkeyblade.net (lindbergh.monkeyblade.net [23.128.96.19]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 2B58BCA6B for ; Tue, 5 Sep 2023 11:55:20 +0000 (UTC) X-Greylist: delayed 327 seconds by postgrey-1.37 at lindbergh.monkeyblade.net; Tue, 05 Sep 2023 04:55:19 PDT Received: from mail.avm.de (mail.avm.de [212.42.244.119]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 431281AD; Tue, 5 Sep 2023 04:55:19 -0700 (PDT) Received: from mail-auth.avm.de (unknown [IPv6:2001:bf0:244:244::71]) by mail.avm.de (Postfix) with ESMTPS; Tue, 5 Sep 2023 13:49:50 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=avm.de; s=mail; t=1693914590; bh=ZsQ3D/ai0dRwVx5veqLcaOVIYyHU7UzerQkt4HdacU8=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=skhnokKEXI2ReIgvIaFyFEG+VfAeKi9lHdzEVsZBtJBfyyMskG1mUbtBurTx05A84 Jl0yBczRuZ2WRti3zyHLR+bV0QV7NObaJVE+XmmncW97TI1MJUQgBh8NLHFt3Dnen/ NMqzCKmOFYwx+DsYLjEkBBeMz8Ws+WabDPQmipvc= Received: from localhost (unknown [172.17.88.63]) by mail-auth.avm.de (Postfix) with ESMTPSA id 0668B82160; Tue, 5 Sep 2023 13:49:50 +0200 (CEST) From: Johannes Nixdorf Date: Tue, 05 Sep 2023 13:47:18 +0200 Subject: [PATCH net-next v3 1/6] net: bridge: Set BR_FDB_ADDED_BY_USER early in fdb_add_entry Precedence: bulk X-Mailing-List: netdev@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Message-Id: <20230905-fdb_limit-v3-1-7597cd500a82@avm.de> References: <20230905-fdb_limit-v3-0-7597cd500a82@avm.de> In-Reply-To: <20230905-fdb_limit-v3-0-7597cd500a82@avm.de> To: "David S. Miller" , Andrew Lunn , David Ahern , Eric Dumazet , Florian Fainelli , Ido Schimmel , Jakub Kicinski , Nikolay Aleksandrov , Oleksij Rempel , Paolo Abeni , Roopa Prabhu , Shuah Khan , Vladimir Oltean Cc: bridge@lists.linux-foundation.org, netdev@vger.kernel.org, linux-kernel@vger.kernel.org, linux-kselftest@vger.kernel.org, Johannes Nixdorf X-Mailer: b4 0.12.3 X-purgate-ID: 149429::1693914590-864E198B-EF077B6C/0/0 X-purgate-type: clean X-purgate-size: 1370 X-purgate-Ad: Categorized by eleven eXpurgate (R) http://www.eleven.de X-purgate: This mail is considered clean (visit http://www.eleven.de for further information) X-purgate: clean X-Spam-Status: No, score=-2.1 required=5.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF, RCVD_IN_DNSWL_BLOCKED,SPF_HELO_NONE,SPF_PASS autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net X-Patchwork-Delegate: kuba@kernel.org In preparation of the following fdb limit for dynamically learned entries, allow fdb_create to detect that the entry was added by the user. This way it can skip applying the limit in this case. Signed-off-by: Johannes Nixdorf --- net/bridge/br_fdb.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/net/bridge/br_fdb.c b/net/bridge/br_fdb.c index e69a872bfc1d..06e28ef8d9ff 100644 --- a/net/bridge/br_fdb.c +++ b/net/bridge/br_fdb.c @@ -1056,7 +1056,7 @@ static int fdb_add_entry(struct net_bridge *br, struct net_bridge_port *source, if (!(flags & NLM_F_CREATE)) return -ENOENT; - fdb = fdb_create(br, source, addr, vid, 0); + fdb = fdb_create(br, source, addr, vid, BIT(BR_FDB_ADDED_BY_USER)); if (!fdb) return -ENOMEM; @@ -1069,6 +1069,8 @@ static int fdb_add_entry(struct net_bridge *br, struct net_bridge_port *source, WRITE_ONCE(fdb->dst, source); modified = true; } + + set_bit(BR_FDB_ADDED_BY_USER, &fdb->flags); } if (fdb_to_nud(br, fdb) != state) { @@ -1100,8 +1102,6 @@ static int fdb_add_entry(struct net_bridge *br, struct net_bridge_port *source, if (fdb_handle_notify(fdb, notify)) modified = true; - set_bit(BR_FDB_ADDED_BY_USER, &fdb->flags); - fdb->used = jiffies; if (modified) { if (refresh) From patchwork Tue Sep 5 11:47:19 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Johannes Nixdorf X-Patchwork-Id: 13374448 X-Patchwork-Delegate: kuba@kernel.org Received: from lindbergh.monkeyblade.net (lindbergh.monkeyblade.net [23.128.96.19]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id E28E6D2FF for ; Tue, 5 Sep 2023 11:55:21 +0000 (UTC) X-Greylist: delayed 328 seconds by postgrey-1.37 at lindbergh.monkeyblade.net; Tue, 05 Sep 2023 04:55:20 PDT Received: from mail.avm.de (mail.avm.de [IPv6:2001:bf0:244:244::94]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 608231B6; Tue, 5 Sep 2023 04:55:20 -0700 (PDT) Received: from mail-auth.avm.de (unknown [IPv6:2001:bf0:244:244::71]) by mail.avm.de (Postfix) with ESMTPS; Tue, 5 Sep 2023 13:49:50 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=avm.de; s=mail; t=1693914590; bh=FxjzhMsEXbd2V05at0TDRKWZ5Vs57RGKp/5uaokS04U=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=aKkOEyu7ZG4ESRwHolf1wmfg4si8EhEKSvRdsiddd2RKSwSkqfZ21ligIa6FVby40 hNADXAi7bMf63zPagSchspJJooyd9G+yZpzsUOcIhFUNcqD4r1M3o3v8ImP7Cd4GeZ f/iR48dmT81T0zRq2c8X3QAapgo29Ac6FUo9Af+8= Received: from localhost (unknown [172.17.88.63]) by mail-auth.avm.de (Postfix) with ESMTPSA id 31DB382158; Tue, 5 Sep 2023 13:49:50 +0200 (CEST) From: Johannes Nixdorf Date: Tue, 05 Sep 2023 13:47:19 +0200 Subject: [PATCH net-next v3 2/6] net: bridge: Set strict_start_type for br_policy Precedence: bulk X-Mailing-List: netdev@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Message-Id: <20230905-fdb_limit-v3-2-7597cd500a82@avm.de> References: <20230905-fdb_limit-v3-0-7597cd500a82@avm.de> In-Reply-To: <20230905-fdb_limit-v3-0-7597cd500a82@avm.de> To: "David S. Miller" , Andrew Lunn , David Ahern , Eric Dumazet , Florian Fainelli , Ido Schimmel , Jakub Kicinski , Nikolay Aleksandrov , Oleksij Rempel , Paolo Abeni , Roopa Prabhu , Shuah Khan , Vladimir Oltean Cc: bridge@lists.linux-foundation.org, netdev@vger.kernel.org, linux-kernel@vger.kernel.org, linux-kselftest@vger.kernel.org, Johannes Nixdorf X-Mailer: b4 0.12.3 X-purgate-ID: 149429::1693914590-4C48745F-8F184E4A/0/0 X-purgate-type: clean X-purgate-size: 807 X-purgate-Ad: Categorized by eleven eXpurgate (R) http://www.eleven.de X-purgate: This mail is considered clean (visit http://www.eleven.de for further information) X-purgate: clean X-Spam-Status: No, score=-2.1 required=5.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF, RCVD_IN_DNSWL_BLOCKED,SPF_HELO_NONE,SPF_PASS autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net X-Patchwork-Delegate: kuba@kernel.org Set any new attributes added to br_policy to be parsed strictly, to prevent userspace from passing garbage. Signed-off-by: Johannes Nixdorf --- net/bridge/br_netlink.c | 1 + 1 file changed, 1 insertion(+) diff --git a/net/bridge/br_netlink.c b/net/bridge/br_netlink.c index 05c5863d2e20..1dc4e1bce740 100644 --- a/net/bridge/br_netlink.c +++ b/net/bridge/br_netlink.c @@ -1217,6 +1217,7 @@ static size_t br_port_get_slave_size(const struct net_device *brdev, } static const struct nla_policy br_policy[IFLA_BR_MAX + 1] = { + [IFLA_BR_UNSPEC] = { .strict_start_type = IFLA_BR_MCAST_QUERIER_STATE + 1 }, [IFLA_BR_FORWARD_DELAY] = { .type = NLA_U32 }, [IFLA_BR_HELLO_TIME] = { .type = NLA_U32 }, [IFLA_BR_MAX_AGE] = { .type = NLA_U32 }, From patchwork Tue Sep 5 11:47:20 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Johannes Nixdorf X-Patchwork-Id: 13374451 X-Patchwork-Delegate: kuba@kernel.org Received: from lindbergh.monkeyblade.net (lindbergh.monkeyblade.net [23.128.96.19]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 7DDFFD512 for ; Tue, 5 Sep 2023 11:55:22 +0000 (UTC) Received: from mail.avm.de (mail.avm.de [IPv6:2001:bf0:244:244::119]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id DF5A51BE; Tue, 5 Sep 2023 04:55:20 -0700 (PDT) Received: from mail-auth.avm.de (unknown [IPv6:2001:bf0:244:244::71]) by mail.avm.de (Postfix) with ESMTPS; Tue, 5 Sep 2023 13:49:50 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=avm.de; s=mail; t=1693914590; bh=9CzF9wwiQ2iiDMYvUIonfLdBdIiRKAnlIBWP9H0gNS0=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=w0g7TxUzuvW16z0e/fQ7D7kb18uJDzxO4+kNBeJBmBvXGsgCsLbnYkzLPCjEM3wUl LFnQQq/1LKMI9fy7LaG0EYxVthTtqA73awAqhb3ike696Q7G+7vSsLzHMlGlBFhFQy GqAo25J+kI2CLKl2DPMPlk9xii36Z079Oi6br7YA= Received: from localhost (unknown [172.17.88.63]) by mail-auth.avm.de (Postfix) with ESMTPSA id 539ED82160; Tue, 5 Sep 2023 13:49:50 +0200 (CEST) From: Johannes Nixdorf Date: Tue, 05 Sep 2023 13:47:20 +0200 Subject: [PATCH net-next v3 3/6] net: bridge: Track and limit dynamically learned FDB entries Precedence: bulk X-Mailing-List: netdev@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Message-Id: <20230905-fdb_limit-v3-3-7597cd500a82@avm.de> References: <20230905-fdb_limit-v3-0-7597cd500a82@avm.de> In-Reply-To: <20230905-fdb_limit-v3-0-7597cd500a82@avm.de> To: "David S. Miller" , Andrew Lunn , David Ahern , Eric Dumazet , Florian Fainelli , Ido Schimmel , Jakub Kicinski , Nikolay Aleksandrov , Oleksij Rempel , Paolo Abeni , Roopa Prabhu , Shuah Khan , Vladimir Oltean Cc: bridge@lists.linux-foundation.org, netdev@vger.kernel.org, linux-kernel@vger.kernel.org, linux-kselftest@vger.kernel.org, Johannes Nixdorf X-Mailer: b4 0.12.3 X-purgate-ID: 149429::1693914590-B34BF98B-EB37643D/0/0 X-purgate-type: clean X-purgate-size: 5689 X-purgate-Ad: Categorized by eleven eXpurgate (R) http://www.eleven.de X-purgate: This mail is considered clean (visit http://www.eleven.de for further information) X-purgate: clean X-Spam-Status: No, score=-2.1 required=5.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF, RCVD_IN_DNSWL_BLOCKED,SPF_HELO_NONE,SPF_PASS autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net X-Patchwork-Delegate: kuba@kernel.org A malicious actor behind one bridge port may spam the kernel with packets with a random source MAC address, each of which will create an FDB entry, each of which is a dynamic allocation in the kernel. There are roughly 2^48 different MAC addresses, further limited by the rhashtable they are stored in to 2^31. Each entry is of the type struct net_bridge_fdb_entry, which is currently 128 bytes big. This means the maximum amount of memory allocated for FDB entries is 2^31 * 128B = 256GiB, which is too much for most computers. Mitigate this by maintaining a per bridge count of those automatically generated entries in fdb_n_learned_entries, and a limit in fdb_max_learned_entries. If the limit is hit new entries are not learned anymore. For backwards compatibility the default setting of 0 disables the limit. User-added entries by netlink or from bridge or bridge port addresses are never blocked and do not count towards that limit. Introduce a new fdb entry flag BR_FDB_DYNAMIC_LEARNED to keep track of whether an FDB entry is included in the count. The flag is enabled for dynamically learned entries, and disabled for all other entries. This should be equivalent to BR_FDB_ADDED_BY_USER and BR_FDB_LOCAL being unset, but contrary to the two flags it can be toggled atomically. Atomicity is required here, as there are multiple callers that modify the flags, but are not under a common lock (br_fdb_update is the exception for br->hash_lock, br_fdb_external_learn_add for RTNL). Signed-off-by: Johannes Nixdorf --- net/bridge/br_fdb.c | 34 ++++++++++++++++++++++++++++++++-- net/bridge/br_private.h | 4 ++++ 2 files changed, 36 insertions(+), 2 deletions(-) diff --git a/net/bridge/br_fdb.c b/net/bridge/br_fdb.c index 06e28ef8d9ff..f8a96ed9a338 100644 --- a/net/bridge/br_fdb.c +++ b/net/bridge/br_fdb.c @@ -329,11 +329,18 @@ static void fdb_delete(struct net_bridge *br, struct net_bridge_fdb_entry *f, hlist_del_init_rcu(&f->fdb_node); rhashtable_remove_fast(&br->fdb_hash_tbl, &f->rhnode, br_fdb_rht_params); + if (test_bit(BR_FDB_DYNAMIC_LEARNED, &f->flags)) + atomic_dec(&br->fdb_n_learned_entries); fdb_notify(br, f, RTM_DELNEIGH, swdev_notify); call_rcu(&f->rcu, fdb_rcu_free); } -/* Delete a local entry if no other port had the same address. */ +/* Delete a local entry if no other port had the same address. + * + * This function should only be called on entries with BR_FDB_LOCAL set, + * so even with BR_FDB_ADDED_BY_USER cleared we never need to increase + * the accounting for dynamically learned entries again. + */ static void fdb_delete_local(struct net_bridge *br, const struct net_bridge_port *p, struct net_bridge_fdb_entry *f) @@ -388,9 +395,20 @@ static struct net_bridge_fdb_entry *fdb_create(struct net_bridge *br, __u16 vid, unsigned long flags) { + bool learned = !test_bit(BR_FDB_ADDED_BY_USER, &flags) && + !test_bit(BR_FDB_LOCAL, &flags); + u32 max_learned = READ_ONCE(br->fdb_max_learned_entries); struct net_bridge_fdb_entry *fdb; int err; + if (likely(learned)) { + int n_learned = atomic_read(&br->fdb_n_learned_entries); + + if (unlikely(max_learned && n_learned >= max_learned)) + return NULL; + __set_bit(BR_FDB_DYNAMIC_LEARNED, &flags); + } + fdb = kmem_cache_alloc(br_fdb_cache, GFP_ATOMIC); if (!fdb) return NULL; @@ -407,6 +425,9 @@ static struct net_bridge_fdb_entry *fdb_create(struct net_bridge *br, return NULL; } + if (likely(learned)) + atomic_inc(&br->fdb_n_learned_entries); + hlist_add_head_rcu(&fdb->fdb_node, &br->fdb_list); return fdb; @@ -893,8 +914,11 @@ void br_fdb_update(struct net_bridge *br, struct net_bridge_port *source, clear_bit(BR_FDB_LOCKED, &fdb->flags); } - if (unlikely(test_bit(BR_FDB_ADDED_BY_USER, &flags))) + if (unlikely(test_bit(BR_FDB_ADDED_BY_USER, &flags))) { set_bit(BR_FDB_ADDED_BY_USER, &fdb->flags); + if (test_and_clear_bit(BR_FDB_DYNAMIC_LEARNED, &fdb->flags)) + atomic_dec(&br->fdb_n_learned_entries); + } if (unlikely(fdb_modified)) { trace_br_fdb_update(br, source, addr, vid, flags); fdb_notify(br, fdb, RTM_NEWNEIGH, true); @@ -1071,6 +1095,8 @@ static int fdb_add_entry(struct net_bridge *br, struct net_bridge_port *source, } set_bit(BR_FDB_ADDED_BY_USER, &fdb->flags); + if (test_and_clear_bit(BR_FDB_DYNAMIC_LEARNED, &fdb->flags)) + atomic_dec(&br->fdb_n_learned_entries); } if (fdb_to_nud(br, fdb) != state) { @@ -1445,6 +1471,10 @@ int br_fdb_external_learn_add(struct net_bridge *br, struct net_bridge_port *p, if (!p) set_bit(BR_FDB_LOCAL, &fdb->flags); + if ((swdev_notify || !p) && + test_and_clear_bit(BR_FDB_DYNAMIC_LEARNED, &fdb->flags)) + atomic_dec(&br->fdb_n_learned_entries); + if (modified) fdb_notify(br, fdb, RTM_NEWNEIGH, swdev_notify); } diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h index a63b32c1638e..675cc40ae1dc 100644 --- a/net/bridge/br_private.h +++ b/net/bridge/br_private.h @@ -274,6 +274,7 @@ enum { BR_FDB_NOTIFY, BR_FDB_NOTIFY_INACTIVE, BR_FDB_LOCKED, + BR_FDB_DYNAMIC_LEARNED, }; struct net_bridge_fdb_key { @@ -554,6 +555,9 @@ struct net_bridge { struct kobject *ifobj; u32 auto_cnt; + atomic_t fdb_n_learned_entries; + u32 fdb_max_learned_entries; + #ifdef CONFIG_NET_SWITCHDEV /* Counter used to make sure that hardware domains get unique * identifiers in case a bridge spans multiple switchdev instances. From patchwork Tue Sep 5 11:47:21 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Johannes Nixdorf X-Patchwork-Id: 13374449 X-Patchwork-Delegate: kuba@kernel.org Received: from lindbergh.monkeyblade.net (lindbergh.monkeyblade.net [23.128.96.19]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id E937CD301 for ; Tue, 5 Sep 2023 11:55:21 +0000 (UTC) Received: from mail.avm.de (mail.avm.de [212.42.244.94]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 526281B3; Tue, 5 Sep 2023 04:55:20 -0700 (PDT) Received: from mail-auth.avm.de (dovecot-mx-01.avm.de [212.42.244.71]) by mail.avm.de (Postfix) with ESMTPS; Tue, 5 Sep 2023 13:49:50 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=avm.de; s=mail; t=1693914590; bh=FPvR5S0dzh9pzA8i7ZAlkvgvOnkftZUu19pNgPk7n8s=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=HDBeSAuHZ/4fkrzgwKx/s+KTaIHBGX4CbvwyqIVPxdAwJYmYoHwHC/UwZsCMQBCtp /7lB/8fhFBc/xn15uNMgEhoHgSjoL0M7/2eTLXllwPn3O05e4Z62+7lMcIMAa7naTR 12KAp/7xX2bfTu/a09ZFtVyFjp/zUlBqzcTNP0gc= Received: from localhost (unknown [172.17.88.63]) by mail-auth.avm.de (Postfix) with ESMTPSA id 7BDBC82158; Tue, 5 Sep 2023 13:49:50 +0200 (CEST) From: Johannes Nixdorf Date: Tue, 05 Sep 2023 13:47:21 +0200 Subject: [PATCH net-next v3 4/6] net: bridge: Add netlink knobs for number / max learned FDB entries Precedence: bulk X-Mailing-List: netdev@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Message-Id: <20230905-fdb_limit-v3-4-7597cd500a82@avm.de> References: <20230905-fdb_limit-v3-0-7597cd500a82@avm.de> In-Reply-To: <20230905-fdb_limit-v3-0-7597cd500a82@avm.de> To: "David S. Miller" , Andrew Lunn , David Ahern , Eric Dumazet , Florian Fainelli , Ido Schimmel , Jakub Kicinski , Nikolay Aleksandrov , Oleksij Rempel , Paolo Abeni , Roopa Prabhu , Shuah Khan , Vladimir Oltean Cc: bridge@lists.linux-foundation.org, netdev@vger.kernel.org, linux-kernel@vger.kernel.org, linux-kselftest@vger.kernel.org, Johannes Nixdorf X-Mailer: b4 0.12.3 X-purgate-ID: 149429::1693914590-4349545F-0B38AFC6/0/0 X-purgate-type: clean X-purgate-size: 3821 X-purgate-Ad: Categorized by eleven eXpurgate (R) http://www.eleven.de X-purgate: This mail is considered clean (visit http://www.eleven.de for further information) X-purgate: clean X-Spam-Status: No, score=-2.1 required=5.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF, RCVD_IN_DNSWL_BLOCKED,SPF_HELO_NONE,SPF_PASS autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net X-Patchwork-Delegate: kuba@kernel.org The previous patch added accounting and a limit for the number of dynamically learned FDB entries per bridge. However it did not provide means to actually configure those bounds or read back the count. This patch does that. Two new netlink attributes are added for the accounting and limit of dynamically learned FDB entries: - IFLA_BR_FDB_N_LEARNED_ENTRIES (RO) for the number of entries accounted for a single bridge. - IFLA_BR_FDB_MAX_LEARNED_ENTRIES (RW) for the configured limit of entries for the bridge. The new attributes are used like this: # ip link add name br up type bridge fdb_max_learned_entries 256 # ip link add name v1 up master br type veth peer v2 # ip link set up dev v2 # mausezahn -a rand -c 1024 v2 0.01 seconds (90877 packets per second # bridge fdb | grep -v permanent | wc -l 256 # ip -d link show dev br 13: br: mtu 1500 [...] [...] fdb_n_learned_entries 256 fdb_max_learned_entries 256 Signed-off-by: Johannes Nixdorf --- include/uapi/linux/if_link.h | 2 ++ net/bridge/br_netlink.c | 15 ++++++++++++++- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/include/uapi/linux/if_link.h b/include/uapi/linux/if_link.h index 0f6a0fe09bdb..bcdf728cfe98 100644 --- a/include/uapi/linux/if_link.h +++ b/include/uapi/linux/if_link.h @@ -510,6 +510,8 @@ enum { IFLA_BR_VLAN_STATS_PER_PORT, IFLA_BR_MULTI_BOOLOPT, IFLA_BR_MCAST_QUERIER_STATE, + IFLA_BR_FDB_N_LEARNED_ENTRIES, + IFLA_BR_FDB_MAX_LEARNED_ENTRIES, __IFLA_BR_MAX, }; diff --git a/net/bridge/br_netlink.c b/net/bridge/br_netlink.c index 1dc4e1bce740..d8595274879d 100644 --- a/net/bridge/br_netlink.c +++ b/net/bridge/br_netlink.c @@ -1254,6 +1254,8 @@ static const struct nla_policy br_policy[IFLA_BR_MAX + 1] = { [IFLA_BR_VLAN_STATS_PER_PORT] = { .type = NLA_U8 }, [IFLA_BR_MULTI_BOOLOPT] = NLA_POLICY_EXACT_LEN(sizeof(struct br_boolopt_multi)), + [IFLA_BR_FDB_N_LEARNED_ENTRIES] = { .type = NLA_U32 }, + [IFLA_BR_FDB_MAX_LEARNED_ENTRIES] = { .type = NLA_U32 }, }; static int br_changelink(struct net_device *brdev, struct nlattr *tb[], @@ -1528,6 +1530,12 @@ static int br_changelink(struct net_device *brdev, struct nlattr *tb[], return err; } + if (data[IFLA_BR_FDB_MAX_LEARNED_ENTRIES]) { + u32 val = nla_get_u32(data[IFLA_BR_FDB_MAX_LEARNED_ENTRIES]); + + WRITE_ONCE(br->fdb_max_learned_entries, val); + } + return 0; } @@ -1582,6 +1590,8 @@ static size_t br_get_size(const struct net_device *brdev) nla_total_size_64bit(sizeof(u64)) + /* IFLA_BR_TOPOLOGY_CHANGE_TIMER */ nla_total_size_64bit(sizeof(u64)) + /* IFLA_BR_GC_TIMER */ nla_total_size(ETH_ALEN) + /* IFLA_BR_GROUP_ADDR */ + nla_total_size(sizeof(u32)) + /* IFLA_BR_FDB_N_LEARNED_ENTRIES */ + nla_total_size(sizeof(u32)) + /* IFLA_BR_FDB_MAX_LEARNED_ENTRIES */ #ifdef CONFIG_BRIDGE_IGMP_SNOOPING nla_total_size(sizeof(u8)) + /* IFLA_BR_MCAST_ROUTER */ nla_total_size(sizeof(u8)) + /* IFLA_BR_MCAST_SNOOPING */ @@ -1657,7 +1667,10 @@ static int br_fill_info(struct sk_buff *skb, const struct net_device *brdev) nla_put_u8(skb, IFLA_BR_TOPOLOGY_CHANGE_DETECTED, br->topology_change_detected) || nla_put(skb, IFLA_BR_GROUP_ADDR, ETH_ALEN, br->group_addr) || - nla_put(skb, IFLA_BR_MULTI_BOOLOPT, sizeof(bm), &bm)) + nla_put(skb, IFLA_BR_MULTI_BOOLOPT, sizeof(bm), &bm) || + nla_put_u32(skb, IFLA_BR_FDB_N_LEARNED_ENTRIES, + atomic_read(&br->fdb_n_learned_entries)) || + nla_put_u32(skb, IFLA_BR_FDB_MAX_LEARNED_ENTRIES, br->fdb_max_learned_entries)) return -EMSGSIZE; #ifdef CONFIG_BRIDGE_VLAN_FILTERING From patchwork Tue Sep 5 11:47:22 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Johannes Nixdorf X-Patchwork-Id: 13374450 X-Patchwork-Delegate: kuba@kernel.org Received: from lindbergh.monkeyblade.net (lindbergh.monkeyblade.net [23.128.96.19]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 7DF1BD513 for ; Tue, 5 Sep 2023 11:55:22 +0000 (UTC) Received: from mail.avm.de (mail.avm.de [IPv6:2001:bf0:244:244::119]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 8CD631B7; Tue, 5 Sep 2023 04:55:20 -0700 (PDT) Received: from mail-auth.avm.de (unknown [IPv6:2001:bf0:244:244::71]) by mail.avm.de (Postfix) with ESMTPS; Tue, 5 Sep 2023 13:49:50 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=avm.de; s=mail; t=1693914590; bh=LJulS2PK41xRqIXVFIJDhKz2cjHftcib9uFS9jUkoNI=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=hmNsuVZhXkEP6JEYy9rESDP5Oi/VLaKuZ6KoL9sPKoT6vLkBJEXMMA2ZLNoAcFWCE YIA1aTzardwKQdIWGmUaJTRxJaS4X1webWJlKnq1DiuM3DsDfSgr1yyQwrz9ik1lqS M494uUBroXgVsNWfJ3VPhPzTdtQi35T8KPzGIoFk= Received: from localhost (unknown [172.17.88.63]) by mail-auth.avm.de (Postfix) with ESMTPSA id A478982160; Tue, 5 Sep 2023 13:49:50 +0200 (CEST) From: Johannes Nixdorf Date: Tue, 05 Sep 2023 13:47:22 +0200 Subject: [PATCH net-next v3 5/6] net: bridge: Add a configurable default FDB learning limit Precedence: bulk X-Mailing-List: netdev@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Message-Id: <20230905-fdb_limit-v3-5-7597cd500a82@avm.de> References: <20230905-fdb_limit-v3-0-7597cd500a82@avm.de> In-Reply-To: <20230905-fdb_limit-v3-0-7597cd500a82@avm.de> To: "David S. Miller" , Andrew Lunn , David Ahern , Eric Dumazet , Florian Fainelli , Ido Schimmel , Jakub Kicinski , Nikolay Aleksandrov , Oleksij Rempel , Paolo Abeni , Roopa Prabhu , Shuah Khan , Vladimir Oltean Cc: bridge@lists.linux-foundation.org, netdev@vger.kernel.org, linux-kernel@vger.kernel.org, linux-kselftest@vger.kernel.org, Johannes Nixdorf X-Mailer: b4 0.12.3 X-purgate-ID: 149429::1693914590-F0CB498B-0A36A1DE/0/0 X-purgate-type: clean X-purgate-size: 1575 X-purgate-Ad: Categorized by eleven eXpurgate (R) http://www.eleven.de X-purgate: This mail is considered clean (visit http://www.eleven.de for further information) X-purgate: clean X-Spam-Status: No, score=-2.1 required=5.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF, RCVD_IN_DNSWL_BLOCKED,SPF_HELO_NONE,SPF_PASS autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net X-Patchwork-Delegate: kuba@kernel.org Add a Kconfig option to configure a default FDB learning limit system wide, so a distributor building a special purpose kernel can limit all created bridges by default. The limit is only a soft default setting and overrideable on a per bridge basis using netlink. Signed-off-by: Johannes Nixdorf --- net/bridge/Kconfig | 13 +++++++++++++ net/bridge/br_device.c | 2 ++ 2 files changed, 15 insertions(+) diff --git a/net/bridge/Kconfig b/net/bridge/Kconfig index 3c8ded7d3e84..c0d9c08088c4 100644 --- a/net/bridge/Kconfig +++ b/net/bridge/Kconfig @@ -84,3 +84,16 @@ config BRIDGE_CFM Say N to exclude this support and reduce the binary size. If unsure, say N. + +config BRIDGE_DEFAULT_FDB_MAX_LEARNED + int "Default FDB learning limit" + default 0 + depends on BRIDGE + help + Sets a default limit on the number of learned FDB entries on + new bridges. This limit can be overwritten via netlink on a + per bridge basis. + + The default of 0 disables the limit. + + If unsure, say 0. diff --git a/net/bridge/br_device.c b/net/bridge/br_device.c index 9a5ea06236bd..8d4221fc5a6c 100644 --- a/net/bridge/br_device.c +++ b/net/bridge/br_device.c @@ -531,6 +531,8 @@ void br_dev_setup(struct net_device *dev) br->bridge_ageing_time = br->ageing_time = BR_DEFAULT_AGEING_TIME; dev->max_mtu = ETH_MAX_MTU; + br->fdb_max_learned_entries = CONFIG_BRIDGE_DEFAULT_FDB_MAX_LEARNED; + br_netfilter_rtable_init(br); br_stp_timer_init(br); br_multicast_init(br); From patchwork Tue Sep 5 11:47:23 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Johannes Nixdorf X-Patchwork-Id: 13374452 X-Patchwork-Delegate: kuba@kernel.org Received: from lindbergh.monkeyblade.net (lindbergh.monkeyblade.net [23.128.96.19]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id C4FD2D523 for ; Tue, 5 Sep 2023 11:55:22 +0000 (UTC) Received: from mail.avm.de (mail.avm.de [212.42.244.94]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 598B91B4; Tue, 5 Sep 2023 04:55:20 -0700 (PDT) Received: from mail-auth.avm.de (dovecot-mx-01.avm.de [212.42.244.71]) by mail.avm.de (Postfix) with ESMTPS; Tue, 5 Sep 2023 13:49:51 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=avm.de; s=mail; t=1693914591; bh=kosZK5ws2xLosd0JTolym7WL9xE6UdyuEKk7TSJ0nDg=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=h5auX9XjUHuBNnLuRq3JaVBpo+OG07KL0XreDYKZ1UE9dQTGIj7dhmQdUwIzEZ632 I24EbXgOR2jzbFPOggL/jco52PrEJbY1HtcJVTme3HOcVHN8HmCsbqbqy1fBbkgj63 5wWPJMYjmI+JMdMOswhL+ielvIIFGqUxbvBFXnb4= Received: from localhost (unknown [172.17.88.63]) by mail-auth.avm.de (Postfix) with ESMTPSA id CD28A82158; Tue, 5 Sep 2023 13:49:50 +0200 (CEST) From: Johannes Nixdorf Date: Tue, 05 Sep 2023 13:47:23 +0200 Subject: [PATCH net-next v3 6/6] selftests: forwarding: bridge_fdb_learning_limit: Add a new selftest Precedence: bulk X-Mailing-List: netdev@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Message-Id: <20230905-fdb_limit-v3-6-7597cd500a82@avm.de> References: <20230905-fdb_limit-v3-0-7597cd500a82@avm.de> In-Reply-To: <20230905-fdb_limit-v3-0-7597cd500a82@avm.de> To: "David S. Miller" , Andrew Lunn , David Ahern , Eric Dumazet , Florian Fainelli , Ido Schimmel , Jakub Kicinski , Nikolay Aleksandrov , Oleksij Rempel , Paolo Abeni , Roopa Prabhu , Shuah Khan , Vladimir Oltean Cc: bridge@lists.linux-foundation.org, netdev@vger.kernel.org, linux-kernel@vger.kernel.org, linux-kselftest@vger.kernel.org, Johannes Nixdorf X-Mailer: b4 0.12.3 X-purgate-ID: 149429::1693914591-40CAE7EF-9EC1E11A/0/0 X-purgate-type: clean X-purgate-size: 6746 X-purgate-Ad: Categorized by eleven eXpurgate (R) http://www.eleven.de X-purgate: This mail is considered clean (visit http://www.eleven.de for further information) X-purgate: clean X-Spam-Status: No, score=-2.1 required=5.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF, RCVD_IN_DNSWL_BLOCKED,SPF_HELO_NONE,SPF_PASS autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net X-Patchwork-Delegate: kuba@kernel.org Add a suite covering the fdb_n_learned_entries and fdb_max_learned_entries bridge features, touching all special cases in accounting at least once. Signed-off-by: Johannes Nixdorf --- .../net/forwarding/bridge_fdb_learning_limit.sh | 283 +++++++++++++++++++++ 1 file changed, 283 insertions(+) diff --git a/tools/testing/selftests/net/forwarding/bridge_fdb_learning_limit.sh b/tools/testing/selftests/net/forwarding/bridge_fdb_learning_limit.sh new file mode 100755 index 000000000000..4da17ac65357 --- /dev/null +++ b/tools/testing/selftests/net/forwarding/bridge_fdb_learning_limit.sh @@ -0,0 +1,283 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-2.0 + +# ShellCheck incorrectly believes that most of the code here is unreachable +# because it's invoked by variable name following ALL_TESTS. +# +# shellcheck disable=SC2317 + +ALL_TESTS="check_accounting check_limit" +NUM_NETIFS=6 +source lib.sh + +TEST_MAC_BASE=de:ad:be:ef:42: + +NUM_PKTS=16 +FDB_LIMIT=8 + +FDB_TYPES=( + # name is counted? overrides learned? + 'learned 1 0' + 'static 0 1' + 'user 0 1' + 'extern_learn 0 1' + 'local 0 1' +) + +mac() +{ + printf "${TEST_MAC_BASE}%02x" "$1" +} + +H1_DEFAULT_MAC=$(mac 42) + +switch_create() +{ + ip link add dev br0 type bridge + + ip link set dev "$swp1" master br0 + ip link set dev "$swp2" master br0 + # swp3 is used to add local MACs, so do not add it to the bridge yet. + + # swp2 is only used for replying when learning on swp1, its MAC should not be learned. + ip link set dev "$swp2" type bridge_slave learning off + + ip link set dev br0 up + + ip link set dev "$swp1" up + ip link set dev "$swp2" up + ip link set dev "$swp3" up +} + +switch_destroy() +{ + ip link set dev "$swp3" down + ip link set dev "$swp2" down + ip link set dev "$swp1" down + + ip link del dev br0 +} + +h_create() +{ + ip link set "$h1" addr "$H1_DEFAULT_MAC" + + simple_if_init "$h1" 192.0.2.1/24 + simple_if_init "$h2" 192.0.2.2/24 +} + +h_destroy() +{ + simple_if_fini "$h1" 192.0.2.1/24 + simple_if_fini "$h2" 192.0.2.2/24 +} + +setup_prepare() +{ + h1=${NETIFS[p1]} + swp1=${NETIFS[p2]} + + h2=${NETIFS[p3]} + swp2=${NETIFS[p4]} + + swp3=${NETIFS[p6]} + + vrf_prepare + + h_create + + switch_create +} + +cleanup() +{ + pre_cleanup + + switch_destroy + + h_destroy + + vrf_cleanup +} + +fdb_get_n_learned() +{ + ip -d -j link show dev br0 type bridge | \ + jq '.[]["linkinfo"]["info_data"]["fdb_n_learned_entries"]' +} + +fdb_get_n_mac() +{ + local mac=${1} + + bridge -j fdb show br br0 | \ + jq "map(select(.mac == \"${mac}\" and (has(\"vlan\") | not))) | length" +} + +fdb_fill_learned() +{ + local i + + for i in $(seq 1 "$NUM_PKTS"); do + fdb_add learned "$(mac "$i")" + done +} + +fdb_reset() +{ + bridge fdb flush dev br0 + + # Keep the default MAC address of h1 in the table. We set it to a different one when + # testing dynamic learning. + bridge fdb add "$H1_DEFAULT_MAC" dev "$swp1" master static use +} + +fdb_add() +{ + local type=$1 mac=$2 + + case "$type" in + learned) + ip link set "$h1" addr "$mac" + # Wait for a reply so we implicitly wait until after the forwarding + # code finished and the FDB entry was created. + PING_COUNT=1 ping_do "$h1" 192.0.2.2 + check_err $? "Failed to ping another bridge port" + ip link set "$h1" addr "$H1_DEFAULT_MAC" + ;; + local) + ip link set dev "$swp3" addr "$mac" && ip link set "$swp3" master br0 + ;; + static) + bridge fdb replace "$mac" dev "$swp1" master static + ;; + user) + bridge fdb replace "$mac" dev "$swp1" master static use + ;; + extern_learn) + bridge fdb replace "$mac" dev "$swp1" master extern_learn + ;; + esac + + check_err $? "Failed to add a FDB entry of type ${type}" +} + +fdb_del() +{ + local type=$1 mac=$2 + + case "$type" in + local) + ip link set "$swp3" nomaster + ;; + *) + bridge fdb del "$mac" dev "$swp1" master + ;; + esac + + check_err $? "Failed to remove a FDB entry of type ${type}" +} + +check_accounting_one_type() +{ + local type=$1 is_counted=$2 overrides_learned=$3 + shift 3 + RET=0 + + fdb_reset + fdb_add "$type" "$(mac 0)" + learned=$(fdb_get_n_learned) + [ "$learned" -ne "$is_counted" ] + check_fail $? "Inserted FDB type ${type}: Expected the count ${is_counted}, but got ${learned}" + + fdb_del "$type" "$(mac 0)" + learned=$(fdb_get_n_learned) + [ "$learned" -ne 0 ] + check_fail $? "Removed FDB type ${type}: Expected the count 0, but got ${learned}" + + if [ "$overrides_learned" -eq 1 ]; then + fdb_reset + fdb_add learned "$(mac 0)" + fdb_add "$type" "$(mac 0)" + learned=$(fdb_get_n_learned) + [ "$learned" -ne "$is_counted" ] + check_fail $? "Set a learned entry to FDB type ${type}: Expected the count ${is_counted}, but got ${learned}" + fdb_del "$type" "$(mac 0)" + fi + + log_test "FDB accounting interacting with FDB type ${type}" +} + +check_accounting() +{ + local type_args learned + RET=0 + + fdb_reset + learned=$(fdb_get_n_learned) + [ "$learned" -ne 0 ] + check_fail $? "Flushed the FDB table: Expected the count 0, but got ${learned}" + + fdb_fill_learned + sleep 1 + + learned=$(fdb_get_n_learned) + [ "$learned" -ne "$NUM_PKTS" ] + check_fail $? "Filled the FDB table: Expected the count ${NUM_PKTS}, but got ${learned}" + + log_test "FDB accounting" + + for type_args in "${FDB_TYPES[@]}"; do + # This is intentional use of word splitting. + # shellcheck disable=SC2086 + check_accounting_one_type $type_args + done +} + +check_limit_one_type() +{ + local type=$1 is_counted=$2 + local n_mac expected=$((1 - is_counted)) + RET=0 + + fdb_reset + fdb_fill_learned + + fdb_add "$type" "$(mac 0)" + n_mac=$(fdb_get_n_mac "$(mac 0)") + [ "$n_mac" -ne "$expected" ] + check_fail $? "Inserted FDB type ${type} at limit: Expected the count ${expected}, but got ${n_mac}" + + log_test "FDB limits interacting with FDB type ${type}" +} + +check_limit() +{ + local learned + RET=0 + + ip link set br0 type bridge fdb_max_learned_entries "$FDB_LIMIT" + + fdb_reset + fdb_fill_learned + + learned=$(fdb_get_n_learned) + [ "$learned" -ne "$FDB_LIMIT" ] + check_fail $? "Filled the limited FDB table: Expected the count ${FDB_LIMIT}, but got ${learned}" + + log_test "FDB limits" + + for type_args in "${FDB_TYPES[@]}"; do + # This is intentional use of word splitting. + # shellcheck disable=SC2086 + check_limit_one_type $type_args + done +} + +trap cleanup EXIT + +setup_prepare + +tests_run + +exit $EXIT_STATUS