From patchwork Fri Nov 10 21:46:15 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Victor Nogueira X-Patchwork-Id: 13452808 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 A414C3C6AB for ; Fri, 10 Nov 2023 21:46:30 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=mojatatu-com.20230601.gappssmtp.com header.i=@mojatatu-com.20230601.gappssmtp.com header.b="fPkvnwm6" Received: from mail-pf1-x432.google.com (mail-pf1-x432.google.com [IPv6:2607:f8b0:4864:20::432]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 2D38B4229 for ; Fri, 10 Nov 2023 13:46:29 -0800 (PST) Received: by mail-pf1-x432.google.com with SMTP id d2e1a72fcca58-6c4cf0aea06so1462893b3a.0 for ; Fri, 10 Nov 2023 13:46:29 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=mojatatu-com.20230601.gappssmtp.com; s=20230601; t=1699652788; x=1700257588; darn=vger.kernel.org; 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=EAJy5fMi2KvlNfU6fLnJux298EZ/LxNeaCzTPAoaOxo=; b=fPkvnwm6wY/y//tFozzUC8LBseFLIOTMxXOI79GSLvZ6SlcSUXVnSw2NH244W/HKfP tQFrY8i6B2Ne5OxlZUGceqtwdgOAxIUekNxvZrImrE0MCo1RX03FM/fzc6eT1A16Bccj j5N/wWy7omxTDKxdXER0xPVgdS387D4n6/+lTwNm6cPlhpRnh/o4ON0JIAtjttR4Usx5 1nTjPLOb7YPZBMg/OOFiAuTkeKQ+n7SCMpyk1e49jIVr5qhasaEd1zHR2fLlJrylm5iC M9GqYriyvGu2Gqvowj0R/asbR/3+2fwQjsy4hAw3SlEaEEHZDdAsmdemAo7PPX8nGWV7 /Mxw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1699652788; x=1700257588; 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=EAJy5fMi2KvlNfU6fLnJux298EZ/LxNeaCzTPAoaOxo=; b=Jb8X/1Ttjgp34erL4bAdzXwa80MvP4eU4N/jeXnpRuwyERqLydqsAoZwQdE08/Rg0n ipG2C6KGabCMF56sJEXO72MLaNTkKCcT12tRPTLi+ceWySKZocbYSeCbzBsbfO4hlQwB ISoJrNeyF3y0qkhE75nWOX+XygPrxbfdxIQ+Z7VkfWYuN4bWbGRS9AujPo/B6AxTOJzB wTT6+Z218MiXMXSIkuCDe/dzVCxTx+06qSqprFdDsLsCM2PNCnA3e++v8R3F0naQT6A+ rSGbWusWTcGn6RxpW+oOoqNgjMvDUhfrLqM5G9eN4HaME7gp0t6MLF5S78kZgLIQ8834 +jZA== X-Gm-Message-State: AOJu0YwN0pnrImjsNYwmo79flcgTOwtsMmd9gpAOFyIE9se16TNVzsYF 9ZersNFAxFULTjsBs74F4xP+vw== X-Google-Smtp-Source: AGHT+IGCCHKznzgksUKVaWlcMJHEkbwI/qUOHtCf6TZYyX0i4lSsWSbWEEPypV+TcGReD0PRAJ+ZKA== X-Received: by 2002:a05:6a21:47ca:b0:181:a230:d3fb with SMTP id as10-20020a056a2147ca00b00181a230d3fbmr444288pzc.17.1699652788568; Fri, 10 Nov 2023 13:46:28 -0800 (PST) Received: from localhost.localdomain ([2804:7f1:e2c3:6a74:a464:c4ff:7a79:ee97]) by smtp.gmail.com with ESMTPSA id d13-20020a056a00244d00b006b90f1706f1sm166343pfj.134.2023.11.10.13.46.25 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 10 Nov 2023 13:46:28 -0800 (PST) From: Victor Nogueira To: jhs@mojatatu.com, davem@davemloft.net, edumazet@google.com, kuba@kernel.org, pabeni@redhat.com, xiyou.wangcong@gmail.com, jiri@resnulli.us Cc: mleitner@redhat.com, vladbu@nvidia.com, paulb@nvidia.com, pctammela@mojatatu.com, netdev@vger.kernel.org, kernel@mojatatu.com Subject: [PATCH net-next RFC v5 1/4] net/sched: act_mirred: Separate mirror and redirect into two distinct functions Date: Fri, 10 Nov 2023 18:46:15 -0300 Message-ID: <20231110214618.1883611-2-victor@mojatatu.com> X-Mailer: git-send-email 2.42.0 In-Reply-To: <20231110214618.1883611-1-victor@mojatatu.com> References: <20231110214618.1883611-1-victor@mojatatu.com> Precedence: bulk X-Mailing-List: netdev@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Patchwork-Delegate: kuba@kernel.org X-Patchwork-State: RFC Separate mirror and redirect code into two into two separate functions (tcf_mirror_act and tcf_redirect_act). This not only cleans up the code and improves both readability and maintainability in addition to reducing the complexity given different expectations for mirroring and redirecting. This patchset has a use case for the mirror part in action "blockcast". Co-developed-by: Jamal Hadi Salim Signed-off-by: Jamal Hadi Salim Co-developed-by: Pedro Tammela Signed-off-by: Pedro Tammela Signed-off-by: Victor Nogueira --- include/net/act_api.h | 85 ++++++++++++++++++++++++++++++++++ net/sched/act_mirred.c | 103 +++++++++++------------------------------ 2 files changed, 113 insertions(+), 75 deletions(-) diff --git a/include/net/act_api.h b/include/net/act_api.h index 4ae0580b63ca..8d288040aeb8 100644 --- a/include/net/act_api.h +++ b/include/net/act_api.h @@ -12,6 +12,7 @@ #include #include #include +#include struct tcf_idrinfo { struct mutex lock; @@ -293,5 +294,89 @@ static inline void tcf_action_stats_update(struct tc_action *a, u64 bytes, #endif } +static inline int tcf_mirred_forward(bool to_ingress, bool nested_call, + struct sk_buff *skb) +{ + int err; + + if (!to_ingress) + err = tcf_dev_queue_xmit(skb, dev_queue_xmit); + else if (nested_call) + err = netif_rx(skb); + else + err = netif_receive_skb(skb); + + return err; +} + +static inline struct sk_buff * +tcf_mirred_common(struct sk_buff *skb, bool want_ingress, bool dont_clone, + bool expects_nh, struct net_device *dest_dev) +{ + struct sk_buff *skb_to_send = skb; + bool at_ingress; + int mac_len; + bool at_nh; + int err; + + if (unlikely(!(dest_dev->flags & IFF_UP)) || + !netif_carrier_ok(dest_dev)) { + net_notice_ratelimited("tc mirred to Houston: device %s is down\n", + dest_dev->name); + err = -ENODEV; + goto err_out; + } + + if (!dont_clone) { + skb_to_send = skb_clone(skb, GFP_ATOMIC); + if (!skb_to_send) { + err = -ENOMEM; + goto err_out; + } + } + + at_ingress = skb_at_tc_ingress(skb); + + /* All mirred/redirected skbs should clear previous ct info */ + nf_reset_ct(skb_to_send); + if (want_ingress && !at_ingress) /* drop dst for egress -> ingress */ + skb_dst_drop(skb_to_send); + + at_nh = skb->data == skb_network_header(skb); + if (at_nh != expects_nh) { + mac_len = at_ingress ? skb->mac_len : + skb_network_offset(skb); + if (expects_nh) { + /* target device/action expect data at nh */ + skb_pull_rcsum(skb_to_send, mac_len); + } else { + /* target device/action expect data at mac */ + skb_push_rcsum(skb_to_send, mac_len); + } + } + + skb_to_send->skb_iif = skb->dev->ifindex; + skb_to_send->dev = dest_dev; + + return skb_to_send; + +err_out: + return ERR_PTR(err); +} + +static inline int +tcf_redirect_act(struct sk_buff *skb, + bool nested_call, bool want_ingress) +{ + skb_set_redirected(skb, skb->tc_at_ingress); + + return tcf_mirred_forward(want_ingress, nested_call, skb); +} + +static inline int +tcf_mirror_act(struct sk_buff *skb, bool nested_call, bool want_ingress) +{ + return tcf_mirred_forward(want_ingress, nested_call, skb); +} #endif diff --git a/net/sched/act_mirred.c b/net/sched/act_mirred.c index 0a711c184c29..95d30cb06e54 100644 --- a/net/sched/act_mirred.c +++ b/net/sched/act_mirred.c @@ -211,38 +211,22 @@ static bool is_mirred_nested(void) return unlikely(__this_cpu_read(mirred_nest_level) > 1); } -static int tcf_mirred_forward(bool want_ingress, struct sk_buff *skb) -{ - int err; - - if (!want_ingress) - err = tcf_dev_queue_xmit(skb, dev_queue_xmit); - else if (is_mirred_nested()) - err = netif_rx(skb); - else - err = netif_receive_skb(skb); - - return err; -} - TC_INDIRECT_SCOPE int tcf_mirred_act(struct sk_buff *skb, const struct tc_action *a, struct tcf_result *res) { struct tcf_mirred *m = to_mirred(a); - struct sk_buff *skb2 = skb; + struct sk_buff *skb_to_send; + unsigned int nest_level; bool m_mac_header_xmit; struct net_device *dev; - unsigned int nest_level; - int retval, err = 0; - bool use_reinsert; bool want_ingress; bool is_redirect; bool expects_nh; - bool at_ingress; + bool dont_clone; int m_eaction; - int mac_len; - bool at_nh; + int err = 0; + int retval; nest_level = __this_cpu_inc_return(mirred_nest_level); if (unlikely(nest_level > MIRRED_NEST_LIMIT)) { @@ -255,80 +239,49 @@ TC_INDIRECT_SCOPE int tcf_mirred_act(struct sk_buff *skb, tcf_lastuse_update(&m->tcf_tm); tcf_action_update_bstats(&m->common, skb); - m_mac_header_xmit = READ_ONCE(m->tcfm_mac_header_xmit); m_eaction = READ_ONCE(m->tcfm_eaction); - retval = READ_ONCE(m->tcf_action); + is_redirect = tcf_mirred_is_act_redirect(m_eaction); + retval = READ_ONCE(a->tcfa_action); dev = rcu_dereference_bh(m->tcfm_dev); if (unlikely(!dev)) { pr_notice_once("tc mirred: target device is gone\n"); + err = -ENODEV; goto out; } - if (unlikely(!(dev->flags & IFF_UP)) || !netif_carrier_ok(dev)) { - net_notice_ratelimited("tc mirred to Houston: device %s is down\n", - dev->name); - goto out; - } + m_mac_header_xmit = READ_ONCE(m->tcfm_mac_header_xmit); + want_ingress = tcf_mirred_act_wants_ingress(m_eaction); + expects_nh = want_ingress || !m_mac_header_xmit; /* we could easily avoid the clone only if called by ingress and clsact; * since we can't easily detect the clsact caller, skip clone only for * ingress - that covers the TC S/W datapath. */ - is_redirect = tcf_mirred_is_act_redirect(m_eaction); - at_ingress = skb_at_tc_ingress(skb); - use_reinsert = at_ingress && is_redirect && - tcf_mirred_can_reinsert(retval); - if (!use_reinsert) { - skb2 = skb_clone(skb, GFP_ATOMIC); - if (!skb2) - goto out; - } - - want_ingress = tcf_mirred_act_wants_ingress(m_eaction); - - /* All mirred/redirected skbs should clear previous ct info */ - nf_reset_ct(skb2); - if (want_ingress && !at_ingress) /* drop dst for egress -> ingress */ - skb_dst_drop(skb2); + dont_clone = skb_at_tc_ingress(skb) && is_redirect && + tcf_mirred_can_reinsert(retval); - expects_nh = want_ingress || !m_mac_header_xmit; - at_nh = skb->data == skb_network_header(skb); - if (at_nh != expects_nh) { - mac_len = skb_at_tc_ingress(skb) ? skb->mac_len : - skb_network_offset(skb); - if (expects_nh) { - /* target device/action expect data at nh */ - skb_pull_rcsum(skb2, mac_len); - } else { - /* target device/action expect data at mac */ - skb_push_rcsum(skb2, mac_len); - } + skb_to_send = tcf_mirred_common(skb, want_ingress, dont_clone, + expects_nh, dev); + if (IS_ERR(skb_to_send)) { + err = PTR_ERR(skb_to_send); + goto out; } - skb2->skb_iif = skb->dev->ifindex; - skb2->dev = dev; - - /* mirror is always swallowed */ if (is_redirect) { - skb_set_redirected(skb2, skb2->tc_at_ingress); - - /* let's the caller reinsert the packet, if possible */ - if (use_reinsert) { - err = tcf_mirred_forward(want_ingress, skb); - if (err) - tcf_action_inc_overlimit_qstats(&m->common); - __this_cpu_dec(mirred_nest_level); - return TC_ACT_CONSUMED; - } + if (skb == skb_to_send) + retval = TC_ACT_CONSUMED; + + err = tcf_redirect_act(skb_to_send, is_mirred_nested(), + want_ingress); + } else { + err = tcf_mirror_act(skb_to_send, is_mirred_nested(), + want_ingress); } - err = tcf_mirred_forward(want_ingress, skb2); - if (err) { out: + if (err) tcf_action_inc_overlimit_qstats(&m->common); - if (tcf_mirred_is_act_redirect(m_eaction)) - retval = TC_ACT_SHOT; - } + __this_cpu_dec(mirred_nest_level); return retval; From patchwork Fri Nov 10 21:46:16 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Victor Nogueira X-Patchwork-Id: 13452809 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 04D203C6BD for ; Fri, 10 Nov 2023 21:46:33 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=mojatatu-com.20230601.gappssmtp.com header.i=@mojatatu-com.20230601.gappssmtp.com header.b="tUZLpby4" Received: from mail-pf1-x42e.google.com (mail-pf1-x42e.google.com [IPv6:2607:f8b0:4864:20::42e]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id A917F131 for ; Fri, 10 Nov 2023 13:46:32 -0800 (PST) Received: by mail-pf1-x42e.google.com with SMTP id d2e1a72fcca58-6b5cac99cfdso2289074b3a.2 for ; Fri, 10 Nov 2023 13:46:32 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=mojatatu-com.20230601.gappssmtp.com; s=20230601; t=1699652792; x=1700257592; darn=vger.kernel.org; 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=eLZ2DL850ho8P3vKfdiUJyV00VKN43aA9i9uJjJoJO0=; b=tUZLpby4TrCMXTkrvyNSPHMPZMz9AhRjsA5yc8eeD20xYIm/9qCrlJLce3dNAKdQNE j6ZeEmRYihBcii5EFs3/7EmDwtQ9JrfOb/EGpjJM8GLGQEpnF2VG+fzNoQ2NRm1T+aJz d1HWyFXJerM47Qt1MmWw5EwHGBeKohW1Pwr0SmCb9g626bsTkOZ0KNvuG/hjZCjHmLL0 XuIIGphd9Lesd+1tttN8f15pFq/X5yGliNRXm2est31I8VoDGhEgM6S5ivgp/FyfxrK+ LWVE4/sG9xTH5rfTEX2ntocIytrueyUL5KvKnGkCB5WytBhWhNurxbb5YRzdHhj3Thv7 SmTQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1699652792; x=1700257592; 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=eLZ2DL850ho8P3vKfdiUJyV00VKN43aA9i9uJjJoJO0=; b=XhYcUpH9JuVPZQl+m1vUNV+iEnbvGosJEPr0tShlzFgdNNLSAitSXJz+r7tnMcc328 hFpbUPkEKESghzqtpfHfzRP1eggex0w+O23E/n8NYOzMSJX2YIY7Vo3asCnCTqnFdF/g J9znMPZQ3dBy/3H9Jh2AnSJ4+cpUwPmfEUbf2v2y798lWUIeAol9Idf3EeHbaWxRYdKV giH9WoPlmBybdFkCTpYXXJUwHkcobLMnPitovLKazei4v0QSXmgrHGVamWKHBFIYas3t RcOhoJKbVBkG0OM32jzPM3lvNf41iok9IuToa9UQO9zjnI9W4dGC4DnGb3HCmcRjIYGC CXoA== X-Gm-Message-State: AOJu0YxSFSoCEdNHeIP9INdfJiN9AlajcA/u6wVW84MqURKp8gnHM2d1 bz7fr9w05p4WEnEWKM1Gn5kGgg== X-Google-Smtp-Source: AGHT+IGRa2YgzXNzT6Asloe1QQbgy6ghk82dyxPbZ8m4ls2ggYLxgOXlN7PvHaCN8WZUdl2dfMXZHw== X-Received: by 2002:a05:6a20:7487:b0:181:1fc8:c5de with SMTP id p7-20020a056a20748700b001811fc8c5demr446914pzd.43.1699652792162; Fri, 10 Nov 2023 13:46:32 -0800 (PST) Received: from localhost.localdomain ([2804:7f1:e2c3:6a74:a464:c4ff:7a79:ee97]) by smtp.gmail.com with ESMTPSA id d13-20020a056a00244d00b006b90f1706f1sm166343pfj.134.2023.11.10.13.46.28 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 10 Nov 2023 13:46:31 -0800 (PST) From: Victor Nogueira To: jhs@mojatatu.com, davem@davemloft.net, edumazet@google.com, kuba@kernel.org, pabeni@redhat.com, xiyou.wangcong@gmail.com, jiri@resnulli.us Cc: mleitner@redhat.com, vladbu@nvidia.com, paulb@nvidia.com, pctammela@mojatatu.com, netdev@vger.kernel.org, kernel@mojatatu.com Subject: [PATCH net-next RFC v5 2/4] net/sched: Introduce tc block netdev tracking infra Date: Fri, 10 Nov 2023 18:46:16 -0300 Message-ID: <20231110214618.1883611-3-victor@mojatatu.com> X-Mailer: git-send-email 2.42.0 In-Reply-To: <20231110214618.1883611-1-victor@mojatatu.com> References: <20231110214618.1883611-1-victor@mojatatu.com> Precedence: bulk X-Mailing-List: netdev@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Patchwork-Delegate: kuba@kernel.org X-Patchwork-State: RFC The tc block is a collection of netdevs/ports which allow qdiscs to share filter block instances (as opposed to the traditional tc filter per port). Example: $ tc qdisc add dev ens7 ingress_block 22 $ tc qdisc add dev ens8 ingress_block 22 Now we can add a filter using the block index: $ tc filter add block 22 protocol ip pref 25 \ flower dst_ip 192.168.0.0/16 action drop Up to this point, the block has been unaware of its ports. This patch makes tc block aware of its ports. Patch 3 exposes tc block to the datapath. Patch 4 shows a use case of the blockcast action which uses the tc block in its datapath and then multicast packets to the tc block ports. Suggested-by: Jiri Pirko Co-developed-by: Jamal Hadi Salim Signed-off-by: Jamal Hadi Salim Co-developed-by: Pedro Tammela Signed-off-by: Pedro Tammela Signed-off-by: Victor Nogueira --- include/net/sch_generic.h | 4 +++ net/sched/cls_api.c | 2 ++ net/sched/sch_api.c | 55 +++++++++++++++++++++++++++++++++++++++ net/sched/sch_generic.c | 31 ++++++++++++++++++++-- 4 files changed, 90 insertions(+), 2 deletions(-) diff --git a/include/net/sch_generic.h b/include/net/sch_generic.h index dcb9160e6467..cefca55dd4f9 100644 --- a/include/net/sch_generic.h +++ b/include/net/sch_generic.h @@ -19,6 +19,7 @@ #include #include #include +#include struct Qdisc_ops; struct qdisc_walker; @@ -126,6 +127,8 @@ struct Qdisc { struct rcu_head rcu; netdevice_tracker dev_tracker; + netdevice_tracker in_block_tracker; + netdevice_tracker eg_block_tracker; /* private data */ long privdata[] ____cacheline_aligned; }; @@ -457,6 +460,7 @@ struct tcf_chain { }; struct tcf_block { + struct xarray ports; /* datapath accessible */ /* Lock protects tcf_block and lifetime-management data of chains * attached to the block (refcnt, action_refcnt, explicitly_created). */ diff --git a/net/sched/cls_api.c b/net/sched/cls_api.c index 1976bd163986..42f760ab7e43 100644 --- a/net/sched/cls_api.c +++ b/net/sched/cls_api.c @@ -531,6 +531,7 @@ static void tcf_block_destroy(struct tcf_block *block) { mutex_destroy(&block->lock); mutex_destroy(&block->proto_destroy_lock); + xa_destroy(&block->ports); kfree_rcu(block, rcu); } @@ -1003,6 +1004,7 @@ static struct tcf_block *tcf_block_create(struct net *net, struct Qdisc *q, refcount_set(&block->refcnt, 1); block->net = net; block->index = block_index; + xa_init(&block->ports); /* Don't store q pointer for blocks which are shared */ if (!tcf_block_shared(block)) diff --git a/net/sched/sch_api.c b/net/sched/sch_api.c index e9eaf637220e..09ec64f2f463 100644 --- a/net/sched/sch_api.c +++ b/net/sched/sch_api.c @@ -1180,6 +1180,57 @@ static int qdisc_graft(struct net_device *dev, struct Qdisc *parent, return 0; } +static int qdisc_block_add_dev(struct Qdisc *sch, struct net_device *dev, + struct nlattr **tca, + struct netlink_ext_ack *extack) +{ + const struct Qdisc_class_ops *cl_ops = sch->ops->cl_ops; + struct tcf_block *in_block = NULL; + struct tcf_block *eg_block = NULL; + int err; + + if (tca[TCA_INGRESS_BLOCK]) { + /* works for both ingress and clsact */ + in_block = cl_ops->tcf_block(sch, TC_H_MIN_INGRESS, NULL); + if (!in_block) { + NL_SET_ERR_MSG(extack, "Shared ingress block missing"); + return -EINVAL; + } + + err = xa_insert(&in_block->ports, dev->ifindex, dev, GFP_KERNEL); + if (err) { + NL_SET_ERR_MSG(extack, "Ingress block dev insert failed"); + return err; + } + + netdev_hold(dev, &sch->in_block_tracker, GFP_KERNEL); + } + + if (tca[TCA_EGRESS_BLOCK]) { + eg_block = cl_ops->tcf_block(sch, TC_H_MIN_EGRESS, NULL); + if (!eg_block) { + NL_SET_ERR_MSG(extack, "Shared egress block missing"); + err = -EINVAL; + goto err_out; + } + + err = xa_insert(&eg_block->ports, dev->ifindex, dev, GFP_KERNEL); + if (err) { + NL_SET_ERR_MSG(extack, "Egress block dev insert failed"); + goto err_out; + } + netdev_hold(dev, &sch->eg_block_tracker, GFP_KERNEL); + } + + return 0; +err_out: + if (in_block) { + xa_erase(&in_block->ports, dev->ifindex); + netdev_put(dev, &sch->in_block_tracker); + } + return err; +} + static int qdisc_block_indexes_set(struct Qdisc *sch, struct nlattr **tca, struct netlink_ext_ack *extack) { @@ -1350,6 +1401,10 @@ static struct Qdisc *qdisc_create(struct net_device *dev, qdisc_hash_add(sch, false); trace_qdisc_create(ops, dev, parent); + err = qdisc_block_add_dev(sch, dev, tca, extack); + if (err) + goto err_out4; + return sch; err_out4: diff --git a/net/sched/sch_generic.c b/net/sched/sch_generic.c index 4195a4bc26ca..83bea257904a 100644 --- a/net/sched/sch_generic.c +++ b/net/sched/sch_generic.c @@ -1049,7 +1049,11 @@ static void qdisc_free_cb(struct rcu_head *head) static void __qdisc_destroy(struct Qdisc *qdisc) { - const struct Qdisc_ops *ops = qdisc->ops; + struct net_device *dev = qdisc_dev(qdisc); + const struct Qdisc_ops *ops = qdisc->ops; + const struct Qdisc_class_ops *cops; + struct tcf_block *block; + u32 block_index; #ifdef CONFIG_NET_SCHED qdisc_hash_del(qdisc); @@ -1060,11 +1064,34 @@ static void __qdisc_destroy(struct Qdisc *qdisc) qdisc_reset(qdisc); + cops = ops->cl_ops; + if (ops->ingress_block_get) { + block_index = ops->ingress_block_get(qdisc); + if (block_index) { + block = cops->tcf_block(qdisc, TC_H_MIN_INGRESS, NULL); + if (block) { + if (xa_erase(&block->ports, dev->ifindex)) + netdev_put(dev, &qdisc->in_block_tracker); + } + } + } + + if (ops->egress_block_get) { + block_index = ops->egress_block_get(qdisc); + if (block_index) { + block = cops->tcf_block(qdisc, TC_H_MIN_EGRESS, NULL); + if (block) { + if (xa_erase(&block->ports, dev->ifindex)) + netdev_put(dev, &qdisc->eg_block_tracker); + } + } + } + if (ops->destroy) ops->destroy(qdisc); module_put(ops->owner); - netdev_put(qdisc_dev(qdisc), &qdisc->dev_tracker); + netdev_put(dev, &qdisc->dev_tracker); trace_qdisc_destroy(qdisc); From patchwork Fri Nov 10 21:46:17 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Victor Nogueira X-Patchwork-Id: 13452810 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 72FDC3D384 for ; Fri, 10 Nov 2023 21:46:37 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=mojatatu-com.20230601.gappssmtp.com header.i=@mojatatu-com.20230601.gappssmtp.com header.b="mIlwY7kY" Received: from mail-ot1-x329.google.com (mail-ot1-x329.google.com [IPv6:2607:f8b0:4864:20::329]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 6C3684205 for ; Fri, 10 Nov 2023 13:46:36 -0800 (PST) Received: by mail-ot1-x329.google.com with SMTP id 46e09a7af769-6d33298f8fdso1333819a34.1 for ; Fri, 10 Nov 2023 13:46:36 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=mojatatu-com.20230601.gappssmtp.com; s=20230601; t=1699652795; x=1700257595; darn=vger.kernel.org; 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=YLe3lb2hGG6BKY8VKxjXOdMwIHzjt2Xzi/SZMN4U9pQ=; b=mIlwY7kY40voni0XCKsCZfCSmoVasPEyO6OLBk86v0DnfaBs8XC/jbfNibO+50a1tk OH5QFW2cD0G3/2NByfOn+o+vi6SclP9eCR73JP3M9FeVx4EqiIqi/JS4QR+dI9xQUXtd UJoZF7BGRRZKkO6OeLzS5BJMNJrCXZFdLTg6PpZ6U8+oqG9n3wu2v6ChG6w5gYQBj7Zy F/V3CEapUzxz9t7mU2SnegWiyayFHviAXSzgJCcjeLia08lp4JQ5Ba9omz7TbM1i2GDc 6sw7uaTC0FmobfUXuuU/86rI1jJFWZ7gdTA20Mbwj8jL73oMhxiDPrr6fqyo9OYdBWIm cv4g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1699652795; x=1700257595; 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=YLe3lb2hGG6BKY8VKxjXOdMwIHzjt2Xzi/SZMN4U9pQ=; b=O5BHpXRxTGRZq+ml+XWiG99ax3yIw+0BKGHizlU2Xm2YDUZIGvtxg80P51qDIV3gft H/DNK2y6GGHdQCe1zBsgCai59+4wIeqhE/J3HLTfp0yNzB+H38wglgl0zDF9/uNP+r0Z PTASd6d3yJBE44rnpKN3Ha1UMyWDS/1sn9LN4gVU5bEKJOuhCTJFw1zG0vvYY1g0DBAF x0bavaNCsXwY4xObE4uV2wlr66ruRPzFUvU0WboTsGGDQFzyR6nNK8XvL142q+yPGPyt xVL+RvnBSP7BkR6dxaDO1Vk9QsK5IBL7v9BkSlQEnirrIdiFQfemfNZR+A3u3vInvytm Osfw== X-Gm-Message-State: AOJu0YwQaZnUEYZ0u4NJrfU19hCZ3TNUJ4mrEqPUeYd1te8PQN9+hBSh aV/0tAYV+WFWr3NEa7Cvh9EOaA== X-Google-Smtp-Source: AGHT+IFfRjqFbhxMzqjNmYZKKCw1hXtiZvt192jOO4FRp+wRuWgKSOzDirk15CUzpjLua1NclYerhg== X-Received: by 2002:a05:6870:9f84:b0:1ea:cdcb:5a2b with SMTP id xm4-20020a0568709f8400b001eacdcb5a2bmr475306oab.54.1699652795754; Fri, 10 Nov 2023 13:46:35 -0800 (PST) Received: from localhost.localdomain ([2804:7f1:e2c3:6a74:a464:c4ff:7a79:ee97]) by smtp.gmail.com with ESMTPSA id d13-20020a056a00244d00b006b90f1706f1sm166343pfj.134.2023.11.10.13.46.32 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 10 Nov 2023 13:46:35 -0800 (PST) From: Victor Nogueira To: jhs@mojatatu.com, davem@davemloft.net, edumazet@google.com, kuba@kernel.org, pabeni@redhat.com, xiyou.wangcong@gmail.com, jiri@resnulli.us Cc: mleitner@redhat.com, vladbu@nvidia.com, paulb@nvidia.com, pctammela@mojatatu.com, netdev@vger.kernel.org, kernel@mojatatu.com Subject: [PATCH net-next RFC v5 3/4] net/sched: cls_api: Expose tc block to the datapath Date: Fri, 10 Nov 2023 18:46:17 -0300 Message-ID: <20231110214618.1883611-4-victor@mojatatu.com> X-Mailer: git-send-email 2.42.0 In-Reply-To: <20231110214618.1883611-1-victor@mojatatu.com> References: <20231110214618.1883611-1-victor@mojatatu.com> Precedence: bulk X-Mailing-List: netdev@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Patchwork-Delegate: kuba@kernel.org X-Patchwork-State: RFC The datapath can now find the block of the port in which the packet arrived at. In the next patch we show a simple action(blockcast) that multicasts to all ports except for the port in which the packet arrived on. Co-developed-by: Jamal Hadi Salim Signed-off-by: Jamal Hadi Salim Co-developed-by: Pedro Tammela Signed-off-by: Pedro Tammela Signed-off-by: Victor Nogueira --- include/net/sch_generic.h | 2 ++ net/sched/cls_api.c | 3 ++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/include/net/sch_generic.h b/include/net/sch_generic.h index cefca55dd4f9..479bc195bb0f 100644 --- a/include/net/sch_generic.h +++ b/include/net/sch_generic.h @@ -487,6 +487,8 @@ struct tcf_block { struct mutex proto_destroy_lock; /* Lock for proto_destroy hashtable. */ }; +struct tcf_block *tcf_block_lookup(struct net *net, u32 block_index); + static inline bool lockdep_tcf_chain_is_locked(struct tcf_chain *chain) { return lockdep_is_held(&chain->filter_chain_lock); diff --git a/net/sched/cls_api.c b/net/sched/cls_api.c index 42f760ab7e43..e7015c2dbbbb 100644 --- a/net/sched/cls_api.c +++ b/net/sched/cls_api.c @@ -1012,12 +1012,13 @@ static struct tcf_block *tcf_block_create(struct net *net, struct Qdisc *q, return block; } -static struct tcf_block *tcf_block_lookup(struct net *net, u32 block_index) +struct tcf_block *tcf_block_lookup(struct net *net, u32 block_index) { struct tcf_net *tn = net_generic(net, tcf_net_id); return idr_find(&tn->idr, block_index); } +EXPORT_SYMBOL(tcf_block_lookup); static struct tcf_block *tcf_block_refcnt_get(struct net *net, u32 block_index) { From patchwork Fri Nov 10 21:46:18 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Victor Nogueira X-Patchwork-Id: 13452811 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 C53D13C68C for ; Fri, 10 Nov 2023 21:46:41 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=mojatatu-com.20230601.gappssmtp.com header.i=@mojatatu-com.20230601.gappssmtp.com header.b="YdENny5+" Received: from mail-pf1-x433.google.com (mail-pf1-x433.google.com [IPv6:2607:f8b0:4864:20::433]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 04206131 for ; Fri, 10 Nov 2023 13:46:40 -0800 (PST) Received: by mail-pf1-x433.google.com with SMTP id d2e1a72fcca58-6c320a821c4so2316487b3a.2 for ; Fri, 10 Nov 2023 13:46:39 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=mojatatu-com.20230601.gappssmtp.com; s=20230601; t=1699652799; x=1700257599; darn=vger.kernel.org; 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=lDjZB/hj6CmjEUlhzRn/Vqn+C70fXR3R3e9xIBFslro=; b=YdENny5+AfvwJT6GXRvUC+4/Ew1emb6+LAIOKZPieDyx//CDrjYgWILO2tMD5w6jHC LeFh3gffm0cUvWA3HVOBfOOuy3KgqZ1DsiZRYAWwXWHghsz24hn2FSCnVM/xctvi2NG9 KcpfvlymCZ/VZqLcCmUMkIfOKVxKSDpYxne4JE5LQrWX36RGRm6lABqgGfll2JLfaxB6 Pd/4+UBh/qeBIMHoTFnaPsT/bXZkiGIhHZUN1rx8eh/s8P1gNLRStxS7AEFLwD4wS7Zc YNDioSNMnQqPg04I82fkNcQkukXbKYKt09tQpk8g44xKrgDetmCasNpGkkjB8YbC+DX1 plxw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1699652799; x=1700257599; 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=lDjZB/hj6CmjEUlhzRn/Vqn+C70fXR3R3e9xIBFslro=; b=UpOzAaFH/kS+DLsT+YGbcwtIGigOJJNGfuWvFgNNrKpeijnvSLr+/F1tiQUe3Xx3su KVr67BUaHmkqFvGABYUQEEVvzKp5OscqMZsaq7vGoqFM+QqaiGIyKRWkQZPmsdln5I9D eai4sbD1ieqRCNhWS06eRwLUjqbWXapM89mePzV1vV+wEiyhTc3h/VcaHlYnm/ePZGPY O0VFpNJSS0rFUcb2xHPWb31itTauVeXad7dnFesGVVTxwB/2o56u8om/o95ZrU16Eh3L 1jfxTz6MrnR9OgZOQNnkz955SPpMcpd5fJPyrThDcCyRF8E16s2U6dPKnw5eFmCc0/Qv k/Iw== X-Gm-Message-State: AOJu0YwwHUIhfv6PUCFguNcLiymlW7aVyS09+ctyF89xqauCAophy3fX RlAkReU5L8dqqaznaSMLtkrNmg== X-Google-Smtp-Source: AGHT+IEXc3+n3ITo1xFARBiXdT63ocMfApbn7Izz3pVb5jSZ+JMEinYmsbkbP/V8YRl5S1E4615FXQ== X-Received: by 2002:a05:6a20:54a1:b0:163:5bfd:ae5b with SMTP id i33-20020a056a2054a100b001635bfdae5bmr485867pzk.15.1699652799394; Fri, 10 Nov 2023 13:46:39 -0800 (PST) Received: from localhost.localdomain ([2804:7f1:e2c3:6a74:a464:c4ff:7a79:ee97]) by smtp.gmail.com with ESMTPSA id d13-20020a056a00244d00b006b90f1706f1sm166343pfj.134.2023.11.10.13.46.36 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 10 Nov 2023 13:46:39 -0800 (PST) From: Victor Nogueira To: jhs@mojatatu.com, davem@davemloft.net, edumazet@google.com, kuba@kernel.org, pabeni@redhat.com, xiyou.wangcong@gmail.com, jiri@resnulli.us Cc: mleitner@redhat.com, vladbu@nvidia.com, paulb@nvidia.com, pctammela@mojatatu.com, netdev@vger.kernel.org, kernel@mojatatu.com Subject: [PATCH net-next RFC v5 4/4] net/sched: act_blockcast: Introduce blockcast tc action Date: Fri, 10 Nov 2023 18:46:18 -0300 Message-ID: <20231110214618.1883611-5-victor@mojatatu.com> X-Mailer: git-send-email 2.42.0 In-Reply-To: <20231110214618.1883611-1-victor@mojatatu.com> References: <20231110214618.1883611-1-victor@mojatatu.com> Precedence: bulk X-Mailing-List: netdev@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Patchwork-Delegate: kuba@kernel.org X-Patchwork-State: RFC This action takes advantage of the presence of tc block ports set in the datapath and multicasts a packet to ports on a block. By default, it will broadcast the packet to a block, that is send to all members of the block except the port in which the packet arrived on. However, the user may specify the option "tx_type all", which will send the packet to all members of the block indiscriminately. Example usage: $ tc qdisc add dev ens7 ingress_block 22 $ tc qdisc add dev ens8 ingress_block 22 Now we can add a filter to broadcast packets to ports on ingress block id 22: $ tc filter add block 22 protocol ip pref 25 \ flower dst_ip 192.168.0.0/16 action blockcast blockid 22 Or if we wish to send to all ports in the block: $ tc filter add block 22 protocol ip pref 25 \ flower dst_ip 192.168.0.0/16 action blockcast blockid 22 tx_type all Co-developed-by: Jamal Hadi Salim Signed-off-by: Jamal Hadi Salim Co-developed-by: Pedro Tammela Signed-off-by: Pedro Tammela Signed-off-by: Victor Nogueira --- include/net/tc_act/tc_blockcast.h | 16 ++ include/net/tc_wrapper.h | 5 + include/uapi/linux/pkt_cls.h | 1 + include/uapi/linux/tc_act/tc_blockcast.h | 32 +++ net/sched/Kconfig | 12 + net/sched/Makefile | 1 + net/sched/act_blockcast.c | 283 +++++++++++++++++++++++ 7 files changed, 350 insertions(+) create mode 100644 include/net/tc_act/tc_blockcast.h create mode 100644 include/uapi/linux/tc_act/tc_blockcast.h create mode 100644 net/sched/act_blockcast.c diff --git a/include/net/tc_act/tc_blockcast.h b/include/net/tc_act/tc_blockcast.h new file mode 100644 index 000000000000..513d6622db66 --- /dev/null +++ b/include/net/tc_act/tc_blockcast.h @@ -0,0 +1,16 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +#ifndef __NET_TC_BLOCKCAST_H +#define __NET_TC_BLOCKCAST_H + +#include +#include + +struct tcf_blockcast_act { + struct tc_action common; + u32 blockid; + enum tc_blockcast_tx_type tx_type; +}; + +#define to_blockcast_act(a) ((struct tcf_blockcast_act *)a) + +#endif /* __NET_TC_BLOCKCAST_H */ diff --git a/include/net/tc_wrapper.h b/include/net/tc_wrapper.h index a6d481b5bcbc..5525544ee6ee 100644 --- a/include/net/tc_wrapper.h +++ b/include/net/tc_wrapper.h @@ -28,6 +28,7 @@ TC_INDIRECT_ACTION_DECLARE(tcf_csum_act); TC_INDIRECT_ACTION_DECLARE(tcf_ct_act); TC_INDIRECT_ACTION_DECLARE(tcf_ctinfo_act); TC_INDIRECT_ACTION_DECLARE(tcf_gact_act); +TC_INDIRECT_ACTION_DECLARE(tcf_blockcast_act); TC_INDIRECT_ACTION_DECLARE(tcf_gate_act); TC_INDIRECT_ACTION_DECLARE(tcf_ife_act); TC_INDIRECT_ACTION_DECLARE(tcf_ipt_act); @@ -57,6 +58,10 @@ static inline int tc_act(struct sk_buff *skb, const struct tc_action *a, if (a->ops->act == tcf_mirred_act) return tcf_mirred_act(skb, a, res); #endif +#if IS_BUILTIN(CONFIG_NET_ACT_BLOCKCAST) + if (a->ops->act == tcf_blockcast_act) + return tcf_blockcast_act(skb, a, res); +#endif #if IS_BUILTIN(CONFIG_NET_ACT_PEDIT) if (a->ops->act == tcf_pedit_act) return tcf_pedit_act(skb, a, res); diff --git a/include/uapi/linux/pkt_cls.h b/include/uapi/linux/pkt_cls.h index c7082cc60d21..e12fc51c1be1 100644 --- a/include/uapi/linux/pkt_cls.h +++ b/include/uapi/linux/pkt_cls.h @@ -139,6 +139,7 @@ enum tca_id { TCA_ID_MPLS, TCA_ID_CT, TCA_ID_GATE, + TCA_ID_BLOCKCAST, /* other actions go here */ __TCA_ID_MAX = 255 }; diff --git a/include/uapi/linux/tc_act/tc_blockcast.h b/include/uapi/linux/tc_act/tc_blockcast.h new file mode 100644 index 000000000000..fe43d0af439d --- /dev/null +++ b/include/uapi/linux/tc_act/tc_blockcast.h @@ -0,0 +1,32 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +#ifndef __LINUX_TC_BLOCKCAST_H +#define __LINUX_TC_BLOCKCAST_H + +#include +#include + +struct tc_blockcast { + tc_gen; + __u32 blockid; /* block ID to which we'll blockcast */ +}; + +enum { + TCA_BLOCKCAST_UNSPEC, + TCA_BLOCKCAST_TM, + TCA_BLOCKCAST_PARMS, + TCA_BLOCKCAST_TX_TYPE, + TCA_BLOCKCAST_PAD, + __TCA_BLOCKCAST_MAX +}; + +#define TCA_BLOCKCAST_MAX (__TCA_BLOCKCAST_MAX - 1) + +enum tc_blockcast_tx_type { + TCA_BLOCKCAST_TX_TYPE_BROADCAST, + TCA_BLOCKCAST_TX_TYPE_ALL, + __TCA_BLOCKCAST_TX_TYPE_MAX, +}; + +#define TCA_BLOCKCAST_TX_TYPE_MAX (__TCA_BLOCKCAST_TX_TYPE_MAX - 1) + +#endif diff --git a/net/sched/Kconfig b/net/sched/Kconfig index 470c70deffe2..ca1deecdd6ae 100644 --- a/net/sched/Kconfig +++ b/net/sched/Kconfig @@ -780,6 +780,18 @@ config NET_ACT_SIMP To compile this code as a module, choose M here: the module will be called act_simple. +config NET_ACT_BLOCKCAST + tristate "TC block Multicast" + depends on NET_CLS_ACT + help + Say Y here to add an action that will multicast an skb to egress of + netdevs that belong to a tc block + + If unsure, say N. + + To compile this code as a module, choose M here: the + module will be called act_blockcast. + config NET_ACT_SKBEDIT tristate "SKB Editing" depends on NET_CLS_ACT diff --git a/net/sched/Makefile b/net/sched/Makefile index b5fd49641d91..2cdcf30645eb 100644 --- a/net/sched/Makefile +++ b/net/sched/Makefile @@ -17,6 +17,7 @@ obj-$(CONFIG_NET_ACT_IPT) += act_ipt.o obj-$(CONFIG_NET_ACT_NAT) += act_nat.o obj-$(CONFIG_NET_ACT_PEDIT) += act_pedit.o obj-$(CONFIG_NET_ACT_SIMP) += act_simple.o +obj-$(CONFIG_NET_ACT_BLOCKCAST) += act_blockcast.o obj-$(CONFIG_NET_ACT_SKBEDIT) += act_skbedit.o obj-$(CONFIG_NET_ACT_CSUM) += act_csum.o obj-$(CONFIG_NET_ACT_MPLS) += act_mpls.o diff --git a/net/sched/act_blockcast.c b/net/sched/act_blockcast.c new file mode 100644 index 000000000000..dc5d1088e534 --- /dev/null +++ b/net/sched/act_blockcast.c @@ -0,0 +1,283 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * net/sched/act_blockcast.c Block Cast action + * Copyright (c) 2023, Mojatatu Networks + * Authors: Jamal Hadi Salim + * Victor Nogueira + * Pedro Tammela + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +static struct tc_action_ops act_blockcast_ops; + +#define BLOCKCAST_NEST_LIMIT 4 +static DEFINE_PER_CPU(unsigned int, blockcast_nest_level); + +TC_INDIRECT_SCOPE int tcf_blockcast_act(struct sk_buff *skb, + const struct tc_action *a, + struct tcf_result *res) +{ + struct tcf_blockcast_act *p = to_blockcast_act(a); + enum tc_blockcast_tx_type tx_type = READ_ONCE(p->tx_type); + int action = READ_ONCE(p->tcf_action); + unsigned int nest_level; + struct tcf_block *block; + struct net_device *dev; + u32 exception_ifindex; + unsigned long index; + + nest_level = __this_cpu_inc_return(blockcast_nest_level); + if (unlikely(nest_level > BLOCKCAST_NEST_LIMIT)) { + net_warn_ratelimited("Packet exceeded blockcast recursion limit on dev %s\n", + netdev_name(skb->dev)); + __this_cpu_dec(blockcast_nest_level); + return TC_ACT_SHOT; + } + + exception_ifindex = skb->dev->ifindex; + + tcf_action_update_bstats(&p->common, skb); + tcf_lastuse_update(&p->tcf_tm); + + /* we are already under rcu protection, so can call block lookup directly */ + block = tcf_block_lookup(dev_net(skb->dev), p->blockid); + if (!block || xa_empty(&block->ports)) { + __this_cpu_dec(blockcast_nest_level); + return action; + } + + xa_for_each(&block->ports, index, dev) { + struct sk_buff *skb_to_send; + struct net_device *dev; + + if (tx_type == TCA_BLOCKCAST_TX_TYPE_BROADCAST && + index == exception_ifindex) + continue; + + dev = dev_get_by_index_rcu(dev_net(skb->dev), index); + if (unlikely(!dev)) { + tcf_action_inc_overlimit_qstats(&p->common); + continue; + } + + skb_to_send = tcf_mirred_common(skb, false, false, + !dev_is_mac_header_xmit(dev), + dev); + if (IS_ERR(skb_to_send)) { + tcf_action_inc_overlimit_qstats(&p->common); + continue; + } + + if (tcf_mirror_act(skb_to_send, false, false)) + tcf_action_inc_overlimit_qstats(&p->common); + } + + __this_cpu_dec(blockcast_nest_level); + return action; +} + +static const struct nla_policy blockcast_policy[TCA_BLOCKCAST_MAX + 1] = { + [TCA_BLOCKCAST_PARMS] = NLA_POLICY_EXACT_LEN(sizeof(struct tc_blockcast)), + [TCA_BLOCKCAST_TX_TYPE] = NLA_POLICY_RANGE(NLA_U8, + TCA_BLOCKCAST_TX_TYPE_BROADCAST, + TCA_BLOCKCAST_TX_TYPE_MAX), +}; + +static int tcf_blockcast_init(struct net *net, struct nlattr *nla, + struct nlattr *est, struct tc_action **a, + struct tcf_proto *tp, u32 flags, + struct netlink_ext_ack *extack) +{ + struct tc_action_net *tn = net_generic(net, act_blockcast_ops.net_id); + bool bind = flags & TCA_ACT_FLAGS_BIND; + struct nlattr *tb[TCA_BLOCKCAST_MAX + 1]; + struct tcf_chain *goto_ch = NULL; + struct tcf_blockcast_act *p; + struct tc_blockcast *parm; + bool exists = false; + int ret = 0, err; + u32 index; + + if (!nla) + return -EINVAL; + + err = nla_parse_nested(tb, TCA_BLOCKCAST_MAX, nla, + blockcast_policy, extack); + if (err < 0) + return err; + + if (!tb[TCA_BLOCKCAST_PARMS]) { + NL_SET_ERR_MSG_MOD(extack, "Must specify blockcast parms"); + return -EINVAL; + } + + parm = nla_data(tb[TCA_BLOCKCAST_PARMS]); + index = parm->index; + + err = tcf_idr_check_alloc(tn, &index, a, bind); + if (err < 0) + return err; + + exists = err; + if (exists && bind) + return 0; + + if (!exists) { + if (!parm->blockid) { + tcf_idr_cleanup(tn, index); + NL_SET_ERR_MSG_MOD(extack, "Must specify blockid"); + return -EINVAL; + } + + ret = tcf_idr_create_from_flags(tn, index, est, a, + &act_blockcast_ops, bind, flags); + if (ret) { + tcf_idr_cleanup(tn, index); + return ret; + } + + ret = ACT_P_CREATED; + } else { + if (!(flags & TCA_ACT_FLAGS_REPLACE)) { + err = -EEXIST; + goto release_idr; + } + } + p = to_blockcast_act(*a); + + err = tcf_action_check_ctrlact(parm->action, tp, &goto_ch, extack); + if (err < 0) + goto release_idr; + + if (exists) { + spin_lock_bh(&p->tcf_lock); + goto_ch = tcf_action_set_ctrlact(*a, parm->action, goto_ch); + + if (tb[TCA_BLOCKCAST_TX_TYPE]) + p->tx_type = nla_get_u8(tb[TCA_BLOCKCAST_TX_TYPE]); + + p->blockid = parm->blockid ?: p->blockid; + + spin_unlock_bh(&p->tcf_lock); + } else { + goto_ch = tcf_action_set_ctrlact(*a, parm->action, goto_ch); + + /** Default to broadcast if none specified */ + if (tb[TCA_BLOCKCAST_TX_TYPE]) + p->tx_type = nla_get_u8(tb[TCA_BLOCKCAST_TX_TYPE]); + else + p->tx_type = TCA_BLOCKCAST_TX_TYPE_BROADCAST; + + p->blockid = parm->blockid; + } + + if (goto_ch) + tcf_chain_put_by_act(goto_ch); + + return ret; + +release_idr: + tcf_idr_release(*a, bind); + return err; +} + +static int tcf_blockcast_dump(struct sk_buff *skb, struct tc_action *a, + int bind, int ref) +{ + unsigned char *b = skb_tail_pointer(skb); + struct tcf_blockcast_act *p = to_blockcast_act(a); + struct tc_blockcast opt = { + .index = p->tcf_index, + .refcnt = refcount_read(&p->tcf_refcnt) - ref, + .bindcnt = atomic_read(&p->tcf_bindcnt) - bind, + }; + struct tcf_t t; + + spin_lock_bh(&p->tcf_lock); + opt.action = p->tcf_action; + opt.blockid = p->blockid; + if (nla_put(skb, TCA_BLOCKCAST_PARMS, sizeof(opt), &opt)) + goto nla_put_failure; + + tcf_tm_dump(&t, &p->tcf_tm); + if (nla_put_64bit(skb, TCA_BLOCKCAST_TM, sizeof(t), &t, + TCA_BLOCKCAST_PAD)) + goto nla_put_failure; + + if (nla_put_u8(skb, TCA_BLOCKCAST_TX_TYPE, p->tx_type)) + goto nla_put_failure; + + spin_unlock_bh(&p->tcf_lock); + + return skb->len; + +nla_put_failure: + spin_unlock_bh(&p->tcf_lock); + nlmsg_trim(skb, b); + return -1; +} + +static struct tc_action_ops act_blockcast_ops = { + .kind = "blockcast", + .id = TCA_ID_BLOCKCAST, + .owner = THIS_MODULE, + .act = tcf_blockcast_act, + .dump = tcf_blockcast_dump, + .init = tcf_blockcast_init, + .size = sizeof(struct tcf_blockcast_act), +}; + +static __net_init int blockcast_init_net(struct net *net) +{ + struct tc_action_net *tn = net_generic(net, act_blockcast_ops.net_id); + + return tc_action_net_init(net, tn, &act_blockcast_ops); +} + +static void __net_exit blockcast_exit_net(struct list_head *net_list) +{ + tc_action_net_exit(net_list, act_blockcast_ops.net_id); +} + +static struct pernet_operations blockcast_net_ops = { + .init = blockcast_init_net, + .exit_batch = blockcast_exit_net, + .id = &act_blockcast_ops.net_id, + .size = sizeof(struct tc_action_net), +}; + +MODULE_AUTHOR("Mojatatu Networks, Inc"); +MODULE_DESCRIPTION("Action to broadcast to devices on a block"); +MODULE_LICENSE("GPL"); + +static int __init blockcast_init_module(void) +{ + int ret = tcf_register_action(&act_blockcast_ops, &blockcast_net_ops); + + if (!ret) + pr_info("blockcast TC action Loaded\n"); + return ret; +} + +static void __exit blockcast_cleanup_module(void) +{ + tcf_unregister_action(&act_blockcast_ops, &blockcast_net_ops); +} + +module_init(blockcast_init_module); +module_exit(blockcast_cleanup_module);