]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
net: Fix offloading indirect devices dependency on qdisc order creation
authorEli Cohen <elic@nvidia.com>
Tue, 17 Aug 2021 17:05:18 +0000 (20:05 +0300)
committerDavid S. Miller <davem@davemloft.net>
Thu, 19 Aug 2021 12:19:30 +0000 (13:19 +0100)
Currently, when creating an ingress qdisc on an indirect device before
the driver registered for callbacks, the driver will not have a chance
to register its filter configuration callbacks.

To fix that, modify the code such that it keeps track of all the ingress
qdiscs that call flow_indr_dev_setup_offload(). When a driver calls
flow_indr_dev_register(),  go through the list of tracked ingress qdiscs
and call the driver callback entry point so as to give it a chance to
register its callback.

Reviewed-by: Jiri Pirko <jiri@nvidia.com>
Signed-off-by: Eli Cohen <elic@nvidia.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
include/net/flow_offload.h
net/core/flow_offload.c
net/netfilter/nf_flow_table_offload.c
net/netfilter/nf_tables_offload.c
net/sched/cls_api.c

index f3c2841566a01560db1f88d800b1034a371ed991..5aa27acdb0b3ce1c66340e4f43e4ce70c63859c4 100644 (file)
@@ -453,6 +453,7 @@ struct flow_block_offload {
        struct list_head *driver_block_list;
        struct netlink_ext_ack *extack;
        struct Qdisc *sch;
+       struct list_head *cb_list_head;
 };
 
 enum tc_setup_type;
index 1da83997e86a396bbdc313eac8367479dcd22d2c..6beaea13564a8208f66004df24796c947065f08f 100644 (file)
@@ -321,6 +321,7 @@ EXPORT_SYMBOL(flow_block_cb_setup_simple);
 static DEFINE_MUTEX(flow_indr_block_lock);
 static LIST_HEAD(flow_block_indr_list);
 static LIST_HEAD(flow_block_indr_dev_list);
+static LIST_HEAD(flow_indir_dev_list);
 
 struct flow_indr_dev {
        struct list_head                list;
@@ -345,6 +346,33 @@ static struct flow_indr_dev *flow_indr_dev_alloc(flow_indr_block_bind_cb_t *cb,
        return indr_dev;
 }
 
+struct flow_indir_dev_info {
+       void *data;
+       struct net_device *dev;
+       struct Qdisc *sch;
+       enum tc_setup_type type;
+       void (*cleanup)(struct flow_block_cb *block_cb);
+       struct list_head list;
+       enum flow_block_command command;
+       enum flow_block_binder_type binder_type;
+       struct list_head *cb_list;
+};
+
+static void existing_qdiscs_register(flow_indr_block_bind_cb_t *cb, void *cb_priv)
+{
+       struct flow_block_offload bo;
+       struct flow_indir_dev_info *cur;
+
+       list_for_each_entry(cur, &flow_indir_dev_list, list) {
+               memset(&bo, 0, sizeof(bo));
+               bo.command = cur->command;
+               bo.binder_type = cur->binder_type;
+               INIT_LIST_HEAD(&bo.cb_list);
+               cb(cur->dev, cur->sch, cb_priv, cur->type, &bo, cur->data, cur->cleanup);
+               list_splice(&bo.cb_list, cur->cb_list);
+       }
+}
+
 int flow_indr_dev_register(flow_indr_block_bind_cb_t *cb, void *cb_priv)
 {
        struct flow_indr_dev *indr_dev;
@@ -366,6 +394,7 @@ int flow_indr_dev_register(flow_indr_block_bind_cb_t *cb, void *cb_priv)
        }
 
        list_add(&indr_dev->list, &flow_block_indr_dev_list);
+       existing_qdiscs_register(cb, cb_priv);
        mutex_unlock(&flow_indr_block_lock);
 
        return 0;
@@ -462,7 +491,59 @@ out:
 }
 EXPORT_SYMBOL(flow_indr_block_cb_alloc);
 
-int flow_indr_dev_setup_offload(struct net_device *dev, struct Qdisc *sch,
+static struct flow_indir_dev_info *find_indir_dev(void *data)
+{
+       struct flow_indir_dev_info *cur;
+
+       list_for_each_entry(cur, &flow_indir_dev_list, list) {
+               if (cur->data == data)
+                       return cur;
+       }
+       return NULL;
+}
+
+static int indir_dev_add(void *data, struct net_device *dev, struct Qdisc *sch,
+                        enum tc_setup_type type, void (*cleanup)(struct flow_block_cb *block_cb),
+                        struct flow_block_offload *bo)
+{
+       struct flow_indir_dev_info *info;
+
+       info = find_indir_dev(data);
+       if (info)
+               return -EEXIST;
+
+       info = kzalloc(sizeof(*info), GFP_KERNEL);
+       if (!info)
+               return -ENOMEM;
+
+       info->data = data;
+       info->dev = dev;
+       info->sch = sch;
+       info->type = type;
+       info->cleanup = cleanup;
+       info->command = bo->command;
+       info->binder_type = bo->binder_type;
+       info->cb_list = bo->cb_list_head;
+
+       list_add(&info->list, &flow_indir_dev_list);
+       return 0;
+}
+
+static int indir_dev_remove(void *data)
+{
+       struct flow_indir_dev_info *info;
+
+       info = find_indir_dev(data);
+       if (!info)
+               return -ENOENT;
+
+       list_del(&info->list);
+
+       kfree(info);
+       return 0;
+}
+
+int flow_indr_dev_setup_offload(struct net_device *dev,        struct Qdisc *sch,
                                enum tc_setup_type type, void *data,
                                struct flow_block_offload *bo,
                                void (*cleanup)(struct flow_block_cb *block_cb))
@@ -470,6 +551,12 @@ int flow_indr_dev_setup_offload(struct net_device *dev, struct Qdisc *sch,
        struct flow_indr_dev *this;
 
        mutex_lock(&flow_indr_block_lock);
+
+       if (bo->command == FLOW_BLOCK_BIND)
+               indir_dev_add(data, dev, sch, type, cleanup, bo);
+       else if (bo->command == FLOW_BLOCK_UNBIND)
+               indir_dev_remove(data);
+
        list_for_each_entry(this, &flow_block_indr_dev_list, list)
                this->cb(dev, sch, this->cb_priv, type, bo, data, cleanup);
 
index 2bfd9f1b8f11fc53b0997604f2f19ee6051013c9..d6bf1b2cd541b7302bdb7284f954d91af386e7a1 100644 (file)
@@ -1096,6 +1096,7 @@ static void nf_flow_table_block_offload_init(struct flow_block_offload *bo,
        bo->command     = cmd;
        bo->binder_type = FLOW_BLOCK_BINDER_TYPE_CLSACT_INGRESS;
        bo->extack      = extack;
+       bo->cb_list_head = &flowtable->flow_block.cb_list;
        INIT_LIST_HEAD(&bo->cb_list);
 }
 
index b58d73a965232c7e4dfa80b6e229fc99f10d8ea8..9656c1646222201a1ffef46eec24af5478afec3d 100644 (file)
@@ -353,6 +353,7 @@ static void nft_flow_block_offload_init(struct flow_block_offload *bo,
        bo->command     = cmd;
        bo->binder_type = FLOW_BLOCK_BINDER_TYPE_CLSACT_INGRESS;
        bo->extack      = extack;
+       bo->cb_list_head = &basechain->flow_block.cb_list;
        INIT_LIST_HEAD(&bo->cb_list);
 }
 
index 4a7043a4e5d684094056a6d22ca9e291eab8e835..2ef8f5a6205a9d92c2195444cb0469702be93da5 100644 (file)
@@ -634,6 +634,7 @@ static void tcf_block_offload_init(struct flow_block_offload *bo,
        bo->block_shared = shared;
        bo->extack = extack;
        bo->sch = sch;
+       bo->cb_list_head = &flow_block->cb_list;
        INIT_LIST_HEAD(&bo->cb_list);
 }