From patchwork Mon May 15 10:26:40 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Qingfang Deng X-Patchwork-Id: 1781306 X-Patchwork-Delegate: hauke@hauke-m.de Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; spf=none (no SPF record) smtp.mailfrom=lists.openwrt.org (client-ip=2607:7c80:54:3::133; helo=bombadil.infradead.org; envelope-from=openwrt-devel-bounces+incoming=patchwork.ozlabs.org@lists.openwrt.org; receiver=) Authentication-Results: legolas.ozlabs.org; dkim=pass (2048-bit key; secure) header.d=lists.infradead.org header.i=@lists.infradead.org header.a=rsa-sha256 header.s=bombadil.20210309 header.b=EwHgG6Gl; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.a=rsa-sha256 header.s=20221208 header.b=JzHzcfvH; dkim-atps=neutral Received: from bombadil.infradead.org (bombadil.infradead.org [IPv6:2607:7c80:54:3::133]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-384) server-digest SHA384) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4QKbFD0Cdpz20db for ; Mon, 15 May 2023 20:28:47 +1000 (AEST) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20210309; h=Sender: Content-Transfer-Encoding:Content-Type:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To: Message-Id:Date:Subject:Cc:To:From:Reply-To:Content-ID:Content-Description: Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: List-Owner; bh=VjYWnYgUwlE2i5rcDA/tqPs4HUtygoKb7iCFJuZ+hzE=; b=EwHgG6GlAgwGdg OWg5mAdkNc8xTzR0VXuHckMC28qhZwSrh6s+7KqFC9z2fBwPhXNqwrtiQEhp1CqUd5ONWCm+M5KPo WihDm0lyL3JylhJ6Grn/zWadJo11eVXA3hPxvaudB6DiJ5EqQRGswrp6k16mVd7uv/KcQ+oFlS7dX Ptm1ubw4+AbTm5WT0y7c82sV2KQ65DBEGuJNjKPgCjfxeEkOakJH3RyQSeXIpf5oGauI1ZDknRHqV x1E+UB2J886XiaxePcNAwXVil9DtfAn97mUt195sShnIifgPr8NAv3OWl0JAUZBu1AWV81/RhXiXt OccC0OktxY+7wlo9AkeQ==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.96 #2 (Red Hat Linux)) id 1pyVPU-001jCe-0l; Mon, 15 May 2023 10:26:32 +0000 Received: from mail-pl1-x629.google.com ([2607:f8b0:4864:20::629]) by bombadil.infradead.org with esmtps (Exim 4.96 #2 (Red Hat Linux)) id 1pyVPR-001jBY-1O for openwrt-devel@lists.openwrt.org; Mon, 15 May 2023 10:26:31 +0000 Received: by mail-pl1-x629.google.com with SMTP id d9443c01a7336-1addac3de73so27853845ad.1 for ; Mon, 15 May 2023 03:26:26 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20221208; t=1684146386; x=1686738386; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=t2l0d9ndfCSMJZdVMJIRvIxEWGwG3lnQi/YQ8UlGNFE=; b=JzHzcfvHhuyEKnWqn+vD8ab9zh9SRm6SIdmY3ccpWdwySDVIjrY0ShidcjrlvNUUn7 7cDDk/W0s1t5n0LpWBudxvrzgx/FyvWTCxWnNisyUnZEjp74kjlsh9hE0jpXfsP1+FXJ 7PS8zaUsAIY/7Hg2fzx/iHSifVVBfEPu+ne6At04f+zZnaaqTkUzwhnUTHWCp6tJxNen OMWi+8hLXp/0sVePJF+woGugdgCkCESe0di4tays9pD7/7YBOflHMLykSdffARn48ioz cHV2Y2WTh19Sf3SafPjegbIp5AFKzgqRD0b46EwYfB3kq7wFEmTWRNhj+etjF1fqhAwL 1PiA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20221208; t=1684146386; x=1686738386; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=t2l0d9ndfCSMJZdVMJIRvIxEWGwG3lnQi/YQ8UlGNFE=; b=gDl4fPI8E+4FMXB839d2dHB8aTCiYDbBxuqAwQKSGhsVcDqfd1viNAEJwNpO3eRUwE WFFfkedDRDCzaECyiVjELbYCaK0Pxpav7CkmfBhU7VDVUEU5xVc++0biAY6+aM4PAD+n ycKpvBk26yViBMP3LHWgSNJKKmuu7DelXTD12TKM+h+iU/JYmRUoDTxZnCBNa6PHT/W8 us3Zja6IvIZAlSw5i4xH3CUtaf8GkHoYXiwMmQIDQtIYvaXj9lmUUUS0d9PD9fC39VsE us6rOG+HV+jka1Ng54OQE8KxSl86mmf2uATi3X3ox4hZrvXzUb6+BO26aUphHO+jOT1y lLUQ== X-Gm-Message-State: AC+VfDwqUdYSbmwX8HTylP24g9V6w+bRTotqsv+Uc4YzlYnBHe9Mrh2V lXH5sswg93uD83CXf2zp54Zwt2nYHNSM+SHHEb0= X-Google-Smtp-Source: ACHHUZ4eKRmgjpSqi710ZYxdS42WQluJAoCrerFrUEEkI5PoyWWk0/Va42gYE7Dx367uHr/74mQaaA== X-Received: by 2002:a17:902:f682:b0:1a9:6dfb:4b09 with SMTP id l2-20020a170902f68200b001a96dfb4b09mr42735306plg.67.1684146385582; Mon, 15 May 2023 03:26:25 -0700 (PDT) Received: from DESKTOP-4R0U3NR.siflower.com ([222.65.110.68]) by smtp.gmail.com with ESMTPSA id o11-20020a170902d4cb00b001a076025715sm13137080plg.117.2023.05.15.03.26.23 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 15 May 2023 03:26:25 -0700 (PDT) From: Qingfang DENG To: openwrt-devel@lists.openwrt.org Cc: Felix Fietkau , Qingfang DENG Subject: [PATCH v3] kernel: fix scheduling while atomic in bridge offload Date: Mon, 15 May 2023 18:26:40 +0800 Message-Id: <20230515102640.1321685-1-dqfext@gmail.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20230511015620.1027-1-dqfext@gmail.com> References: <20230511015620.1027-1-dqfext@gmail.com> MIME-Version: 1.0 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20230515_032629_469229_D2501E56 X-CRM114-Status: GOOD ( 14.58 ) X-Spam-Score: -0.2 (/) X-Spam-Report: Spam detection software, running on the system "bombadil.infradead.org", has NOT identified this incoming email as spam. The original message has been attached to this so you can view it or label similar future email. If you have any questions, see the administrator of that system for details. Content preview: From: Qingfang DENG br_offload_port_state is in a spinlock's critical section (&br->lock), but rhashtable_init/rhashtable_free_and_destroy/flush_work may sleep, causing scheduling while atomic bug. Content analysis details: (-0.2 points, 5.0 required) pts rule name description ---- ---------------------- -------------------------------------------------- -0.0 RCVD_IN_DNSWL_NONE RBL: Sender listed at https://www.dnswl.org/, no trust [2607:f8b0:4864:20:0:0:0:629 listed in] [list.dnswl.org] -0.0 SPF_PASS SPF: sender matches SPF record 0.0 SPF_HELO_NONE SPF: HELO does not publish an SPF Record 0.0 FREEMAIL_FROM Sender email is commonly abused enduser mail provider [dqfext[at]gmail.com] -0.1 DKIM_VALID_AU Message has a valid DKIM or DK signature from author's domain -0.1 DKIM_VALID Message has at least one valid DKIM or DK signature 0.1 DKIM_SIGNED Message has a DKIM or DK signature, not necessarily valid -0.1 DKIM_VALID_EF Message has a valid DKIM or DK signature from envelope-from domain X-BeenThere: openwrt-devel@lists.openwrt.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: OpenWrt Development List List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "openwrt-devel" Errors-To: openwrt-devel-bounces+incoming=patchwork.ozlabs.org@lists.openwrt.org From: Qingfang DENG br_offload_port_state is in a spinlock's critical section (&br->lock), but rhashtable_init/rhashtable_free_and_destroy/flush_work may sleep, causing scheduling while atomic bug. To fix this, use workqueues to defer the init/destroy operations. To synchronize between rhashtable insert/destroy, synchronize_rcu is used to ensure all writers have left the RCU critical section before calling rhashtable_free_and_destroy. While at it, check for null pointers at the flow allocation. Fixes: 94b4da9b4aad ("kernel: add a fast path for the bridge code") Signed-off-by: Qingfang DENG --- v3: fix race conditions and optimize code .../hack-5.15/600-bridge_offload.patch | 97 +++++++++++++------ 1 file changed, 69 insertions(+), 28 deletions(-) diff --git a/target/linux/generic/hack-5.15/600-bridge_offload.patch b/target/linux/generic/hack-5.15/600-bridge_offload.patch index 9d71a741b2..87396611bd 100644 --- a/target/linux/generic/hack-5.15/600-bridge_offload.patch +++ b/target/linux/generic/hack-5.15/600-bridge_offload.patch @@ -150,16 +150,25 @@ Subject: [PATCH] net/bridge: add bridge offload /* * Determine initial path cost based on speed. -@@ -428,7 +429,7 @@ static struct net_bridge_port *new_nbp(s +@@ -362,6 +363,7 @@ static void del_nbp(struct net_bridge_po + kobject_del(&p->kobj); + + br_netpoll_disable(p); ++ flush_work(&p->offload.deferred_work); + + call_rcu(&p->rcu, destroy_nbp_rcu); + } +@@ -428,7 +430,8 @@ static struct net_bridge_port *new_nbp(s p->path_cost = port_cost(dev); p->priority = 0x8000 >> BR_PORT_BITS; p->port_no = index; - p->flags = BR_LEARNING | BR_FLOOD | BR_MCAST_FLOOD | BR_BCAST_FLOOD; + p->flags = BR_LEARNING | BR_FLOOD | BR_MCAST_FLOOD | BR_BCAST_FLOOD | BR_OFFLOAD; ++ br_offload_init_work(p); br_init_port(p); br_set_state(p, BR_STATE_DISABLED); br_stp_port_timer_init(p); -@@ -771,6 +772,9 @@ void br_port_flags_change(struct net_bri +@@ -771,6 +774,9 @@ void br_port_flags_change(struct net_bri if (mask & BR_NEIGH_SUPPRESS) br_recalculate_neigh_suppress_enabled(br); @@ -199,7 +208,7 @@ Subject: [PATCH] net/bridge: add bridge offload --- /dev/null +++ b/net/bridge/br_offload.c -@@ -0,0 +1,438 @@ +@@ -0,0 +1,458 @@ +// SPDX-License-Identifier: GPL-2.0-only +#include +#include @@ -306,7 +315,7 @@ Subject: [PATCH] net/bridge: add bridge offload + p->br->offload_cache_reserved) >= p->br->offload_cache_size; +} + -+static void ++void +br_offload_gc_work(struct work_struct *work) +{ + struct rhashtable_iter hti; @@ -354,36 +363,53 @@ Subject: [PATCH] net/bridge: add bridge offload + +} + -+void br_offload_port_state(struct net_bridge_port *p) ++void br_offload_deferred_work(struct work_struct *work) +{ -+ struct net_bridge_port_offload *o = &p->offload; -+ bool enabled = true; -+ bool flush = false; ++ struct net_bridge_port_offload *o; ++ struct net_bridge_port *p; ++ bool enabling, enabled; + -+ if (p->state != BR_STATE_FORWARDING || -+ !(p->flags & BR_OFFLOAD)) -+ enabled = false; ++ p = container_of(work, struct net_bridge_port, offload.deferred_work); ++ o = &p->offload; + -+ spin_lock_bh(&offload_lock); -+ if (o->enabled == enabled) -+ goto out; ++ spin_lock_bh(&p->br->lock); ++ enabling = o->enabling; ++ enabled = o->enabled; ++ spin_unlock_bh(&p->br->lock); ++ ++ if (enabling == enabled) ++ return; + -+ if (enabled) { -+ if (!o->gc_work.func) -+ INIT_WORK(&o->gc_work, br_offload_gc_work); ++ if (enabling) { + rhashtable_init(&o->rht, &flow_params); ++ spin_lock_bh(&offload_lock); ++ o->enabled = true; ++ spin_unlock_bh(&offload_lock); + } else { -+ flush = true; ++ spin_lock_bh(&offload_lock); ++ o->enabled = false; ++ spin_unlock_bh(&offload_lock); ++ /* Ensure all rht users have finished */ ++ synchronize_rcu(); ++ cancel_work_sync(&o->gc_work); + rhashtable_free_and_destroy(&o->rht, br_offload_destroy_cb, o); + } ++} + -+ o->enabled = enabled; ++void br_offload_port_state(struct net_bridge_port *p) ++{ ++ struct net_bridge_port_offload *o = &p->offload; ++ bool enabling = true; + -+out: -+ spin_unlock_bh(&offload_lock); ++ if (p->state != BR_STATE_FORWARDING || ++ !(p->flags & BR_OFFLOAD)) ++ enabling = false; ++ ++ if (o->enabling == enabling) ++ return; + -+ if (flush) -+ flush_work(&o->gc_work); ++ o->enabling = enabling; ++ schedule_work(&o->deferred_work); +} + +void br_offload_fdb_update(const struct net_bridge_fdb_entry *fdb) @@ -475,6 +501,9 @@ Subject: [PATCH] net/bridge: add bridge offload +#endif + + flow = kmem_cache_alloc(offload_cache, GFP_ATOMIC); ++ if (unlikely(!flow)) ++ goto out; ++ + flow->port = inp; + memcpy(&flow->key, &key, sizeof(key)); + @@ -655,20 +684,22 @@ Subject: [PATCH] net/bridge: add bridge offload }; #define MDB_PG_FLAGS_PERMANENT BIT(0) -@@ -343,6 +349,12 @@ struct net_bridge_mdb_entry { +@@ -343,6 +349,14 @@ struct net_bridge_mdb_entry { struct rcu_head rcu; }; +struct net_bridge_port_offload { + struct rhashtable rht; + struct work_struct gc_work; ++ struct work_struct deferred_work; + bool enabled; ++ bool enabling; +}; + struct net_bridge_port { struct net_bridge *br; struct net_device *dev; -@@ -403,6 +415,7 @@ struct net_bridge_port { +@@ -403,6 +417,7 @@ struct net_bridge_port { u16 backup_redirected_cnt; struct bridge_stp_xstats stp_xstats; @@ -676,7 +707,7 @@ Subject: [PATCH] net/bridge: add bridge offload }; #define kobj_to_brport(obj) container_of(obj, struct net_bridge_port, kobj) -@@ -519,6 +532,9 @@ struct net_bridge { +@@ -519,6 +534,9 @@ struct net_bridge { struct kobject *ifobj; u32 auto_cnt; @@ -686,7 +717,7 @@ Subject: [PATCH] net/bridge: add bridge offload #ifdef CONFIG_NET_SWITCHDEV /* Counter used to make sure that hardware domains get unique * identifiers in case a bridge spans multiple switchdev instances. -@@ -553,6 +569,10 @@ struct br_input_skb_cb { +@@ -553,6 +571,10 @@ struct br_input_skb_cb { #ifdef CONFIG_NETFILTER_FAMILY_BRIDGE u8 br_netfilter_broute:1; #endif @@ -699,7 +730,7 @@ Subject: [PATCH] net/bridge: add bridge offload /* Set if TX data plane offloading is used towards at least one --- /dev/null +++ b/net/bridge/br_private_offload.h -@@ -0,0 +1,23 @@ +@@ -0,0 +1,33 @@ +#ifndef __BR_OFFLOAD_H +#define __BR_OFFLOAD_H + @@ -713,6 +744,16 @@ Subject: [PATCH] net/bridge: add bridge offload + struct netlink_ext_ack *extack); +int br_offload_set_cache_reserved(struct net_bridge *br, unsigned long val, + struct netlink_ext_ack *extack); ++void br_offload_deferred_work(struct work_struct *work); ++void br_offload_gc_work(struct work_struct *work); ++ ++static inline void br_offload_init_work(struct net_bridge_port *p) ++{ ++ struct net_bridge_port_offload *o = &p->offload; ++ ++ INIT_WORK(&o->deferred_work, br_offload_deferred_work); ++ INIT_WORK(&o->gc_work, br_offload_gc_work); ++} + +static inline void br_offload_skb_disable(struct sk_buff *skb) +{