[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20231005184228.467845-2-victor@mojatatu.com>
Date: Thu, 5 Oct 2023 15:42:26 -0300
From: Victor Nogueira <victor@...atatu.com>
To: jhs@...atatu.com,
xiyou.wangcong@...il.com,
jiri@...nulli.us,
davem@...emloft.net,
pabeni@...hat.com,
edumazet@...gle.com,
kuba@...nel.org
Cc: mleitner@...hat.com,
vladbu@...dia.com,
simon.horman@...igine.com,
pctammela@...atatu.com,
netdev@...r.kernel.org,
kernel@...atatu.com
Subject: [PATCH net-next v4 1/3] net/sched: Introduce tc block netdev tracking infra
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 is unaware of its ports. This patch fixes that
and makes the tc block ports available to the datapath.
Suggested-by: Jiri Pirko <jiri@...dia.com>
Co-developed-by: Jamal Hadi Salim <jhs@...atatu.com>
Signed-off-by: Jamal Hadi Salim <jhs@...atatu.com>
Co-developed-by: Pedro Tammela <pctammela@...atatu.com>
Signed-off-by: Pedro Tammela <pctammela@...atatu.com>
Signed-off-by: Victor Nogueira <victor@...atatu.com>
---
include/net/sch_generic.h | 4 +++
net/sched/cls_api.c | 2 ++
net/sched/sch_api.c | 58 +++++++++++++++++++++++++++++++++++++++
net/sched/sch_generic.c | 34 +++++++++++++++++++++--
4 files changed, 96 insertions(+), 2 deletions(-)
diff --git a/include/net/sch_generic.h b/include/net/sch_generic.h
index c7318c73cfd6..a01979b0a2a1 100644
--- a/include/net/sch_generic.h
+++ b/include/net/sch_generic.h
@@ -19,6 +19,7 @@
#include <net/gen_stats.h>
#include <net/rtnetlink.h>
#include <net/flow_offload.h>
+#include <linux/xarray.h>
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;
};
@@ -458,6 +461,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 a193cc7b3241..06b55344a948 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..66543e4d6cdc 100644
--- a/net/sched/sch_api.c
+++ b/net/sched/sch_api.c
@@ -1180,6 +1180,60 @@ 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;
+ unsigned long cl = 0;
+ int err;
+
+ if (tca[TCA_INGRESS_BLOCK]) {
+ /* works for both ingress and clsact */
+ cl = TC_H_MIN_INGRESS;
+ in_block = cl_ops->tcf_block(sch, cl, 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]) {
+ cl = TC_H_MIN_EGRESS;
+ eg_block = cl_ops->tcf_block(sch, cl, 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 +1404,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..b0c28b2ee713 100644
--- a/net/sched/sch_generic.c
+++ b/net/sched/sch_generic.c
@@ -1049,7 +1049,12 @@ 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;
+ unsigned long cl;
+ u32 block_index;
#ifdef CONFIG_NET_SCHED
qdisc_hash_del(qdisc);
@@ -1060,11 +1065,36 @@ 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) {
+ cl = TC_H_MIN_INGRESS;
+ block = cops->tcf_block(qdisc, cl, 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) {
+ cl = TC_H_MIN_EGRESS;
+ block = cops->tcf_block(qdisc, cl, 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);
--
2.25.1
Powered by blists - more mailing lists