net/sched: Introduce tc block netdev tracking infra
authorVictor Nogueira <victor@mojatatu.com>
Tue, 19 Dec 2023 18:16:19 +0000 (15:16 -0300)
committerDavid S. Miller <davem@davemloft.net>
Tue, 26 Dec 2023 21:20:08 +0000 (21:20 +0000)
This commit makes tc blocks track which ports have been added to them.
And, with that, we'll be able to use this new information to send
packets to the block's ports. Which will be done in the patch #3 of this
series.

Suggested-by: Jiri Pirko <jiri@nvidia.com>
Co-developed-by: Jamal Hadi Salim <jhs@mojatatu.com>
Signed-off-by: Jamal Hadi Salim <jhs@mojatatu.com>
Co-developed-by: Pedro Tammela <pctammela@mojatatu.com>
Signed-off-by: Pedro Tammela <pctammela@mojatatu.com>
Signed-off-by: Victor Nogueira <victor@mojatatu.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
include/net/sch_generic.h
net/sched/cls_api.c
net/sched/sch_api.c
net/sched/sch_generic.c

index 1d70c2c1572f9667aaa77e548924feeb6493adfd..aca11127154fa222bcbaf9fb06e8fb656442fb5a 100644 (file)
@@ -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;
@@ -456,6 +457,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).
         */
index 8978cf5531d074b657b004e25f7e6d2b025c7a08..421ea10bc82ab0361a2d93b8ecf525526dbd82e6 100644 (file)
@@ -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);
 }
 
@@ -1002,6 +1003,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))
index e9eaf637220e9cfc2145f7e7cfb8194b4cf77dc2..299086bb6205ff4935112e9158ad4b657115b6ce 100644 (file)
@@ -1180,6 +1180,43 @@ skip:
        return 0;
 }
 
+static int qdisc_block_add_dev(struct Qdisc *sch, struct net_device *dev,
+                              struct netlink_ext_ack *extack)
+{
+       const struct Qdisc_class_ops *cl_ops = sch->ops->cl_ops;
+       struct tcf_block *block;
+       int err;
+
+       block = cl_ops->tcf_block(sch, TC_H_MIN_INGRESS, NULL);
+       if (block) {
+               err = xa_insert(&block->ports, dev->ifindex, dev, GFP_KERNEL);
+               if (err) {
+                       NL_SET_ERR_MSG(extack,
+                                      "ingress block dev insert failed");
+                       return err;
+               }
+       }
+
+       block = cl_ops->tcf_block(sch, TC_H_MIN_EGRESS, NULL);
+       if (block) {
+               err = xa_insert(&block->ports, dev->ifindex, dev, GFP_KERNEL);
+               if (err) {
+                       NL_SET_ERR_MSG(extack,
+                                      "Egress block dev insert failed");
+                       goto err_out;
+               }
+       }
+
+       return 0;
+
+err_out:
+       block = cl_ops->tcf_block(sch, TC_H_MIN_INGRESS, NULL);
+       if (block)
+               xa_erase(&block->ports, dev->ifindex);
+
+       return err;
+}
+
 static int qdisc_block_indexes_set(struct Qdisc *sch, struct nlattr **tca,
                                   struct netlink_ext_ack *extack)
 {
@@ -1350,6 +1387,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, extack);
+       if (err)
+               goto err_out4;
+
        return sch;
 
 err_out4:
index 8dd0e5925342aed7d385c46a5236cd62748f9df7..e33568df97a5f63184cada8d4e85ebbb9e6793c9 100644 (file)
@@ -1051,6 +1051,9 @@ 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_class_ops *cops;
+       struct tcf_block *block;
 
 #ifdef CONFIG_NET_SCHED
        qdisc_hash_del(qdisc);
@@ -1061,11 +1064,24 @@ static void __qdisc_destroy(struct Qdisc *qdisc)
 
        qdisc_reset(qdisc);
 
+       cops = ops->cl_ops;
+       if (ops->ingress_block_get) {
+               block = cops->tcf_block(qdisc, TC_H_MIN_INGRESS, NULL);
+               if (block)
+                       xa_erase(&block->ports, dev->ifindex);
+       }
+
+       if (ops->egress_block_get) {
+               block = cops->tcf_block(qdisc, TC_H_MIN_EGRESS, NULL);
+               if (block)
+                       xa_erase(&block->ports, dev->ifindex);
+       }
+
        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);