[PATCH net-next v21 09/13] virtio_net: Use existing classifier if possible
From: Shahar Shitrit <hidden>
Date: 2026-08-03 14:07:53
Also in:
virtualization
Subsystem:
networking drivers, the rest, virtio net driver · Maintainers:
Andrew Lunn, "David S. Miller", Eric Dumazet, Jakub Kicinski, Paolo Abeni, Linus Torvalds, "Michael S. Tsirkin", Jason Wang
From: Daniel Jurgens <redacted> Classifiers can be used by more than one rule. If there is an existing classifier, use it instead of creating a new one. If duplicate classifiers are created it would artifically limit the number of rules to the classifier limit, which is likely less than the rules limit. Signed-off-by: Daniel Jurgens <redacted> Reviewed-by: Parav Pandit <redacted> Reviewed-by: Xuan Zhuo <xuanzhuo@linux.alibaba.com> Signed-off-by: Shahar Shitrit <redacted> --- drivers/net/virtio_net.c | 51 ++++++++++++++++++++++++++-------------- 1 file changed, 34 insertions(+), 17 deletions(-)
diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
index 2540b9a23e5b..cfcbd8bcd550 100644
--- a/drivers/net/virtio_net.c
+++ b/drivers/net/virtio_net.c@@ -33,6 +33,7 @@ #include <uapi/linux/virtio_pci.h> #include <uapi/linux/virtio_net_ff.h> #include <linux/xarray.h> +#include <linux/refcount.h> static int napi_weight = NAPI_POLL_WEIGHT; module_param(napi_weight, int, 0444);
@@ -303,7 +304,6 @@ struct virtnet_ff { struct virtio_net_ff_cap_mask_data *ff_mask; struct virtio_net_ff_actions *ff_actions; struct xarray classifiers; - int num_classifiers; struct virtnet_ethtool_ff ethtool; };
@@ -5718,12 +5718,13 @@ struct virtnet_ethtool_rule { /* The classifier struct must be the last field in this struct */ struct virtnet_classifier { size_t size; + refcount_t refcount; u32 id; - struct virtio_net_resource_obj_ff_classifier classifier; + struct virtio_net_resource_obj_ff_classifier obj; }; static_assert(sizeof(struct virtnet_classifier) == - ALIGN(offsetofend(struct virtnet_classifier, classifier), + ALIGN(offsetofend(struct virtnet_classifier, obj), __alignof__(struct virtnet_classifier)), "virtnet_classifier: classifier must be the last member");
@@ -5811,11 +5812,24 @@ static bool validate_mask(const struct virtnet_ff *ff, return false; } -static int setup_classifier(struct virtnet_ff *ff, struct virtnet_classifier *c) +static int setup_classifier(struct virtnet_ff *ff, + struct virtnet_classifier **c) { + struct virtnet_classifier *tmp; + unsigned long i; int err; - err = xa_alloc(&ff->classifiers, &c->id, c, + xa_for_each(&ff->classifiers, i, tmp) { + if ((*c)->size == tmp->size && + !memcmp(&tmp->obj, &(*c)->obj, tmp->size)) { + refcount_inc(&tmp->refcount); + kfree(*c); + *c = tmp; + goto out; + } + } + + err = xa_alloc(&ff->classifiers, &(*c)->id, *c, XA_LIMIT(0, le32_to_cpu(ff->ff_caps->classifiers_limit) - 1), GFP_KERNEL); if (err)
@@ -5823,29 +5837,30 @@ static int setup_classifier(struct virtnet_ff *ff, struct virtnet_classifier *c) err = virtio_admin_obj_create(ff->vdev, VIRTIO_NET_RESOURCE_OBJ_FF_CLASSIFIER, - c->id, + (*c)->id, VIRTIO_ADMIN_GROUP_TYPE_SELF, 0, - &c->classifier, - c->size); + &(*c)->obj, + (*c)->size); if (err) goto err_xarray; + refcount_set(&(*c)->refcount, 1); +out: return 0; err_xarray: - xa_erase(&ff->classifiers, c->id); + xa_erase(&ff->classifiers, (*c)->id); return err; } -static void destroy_classifier(struct virtnet_ff *ff, - u32 classifier_id) +static void try_destroy_classifier(struct virtnet_ff *ff, u32 classifier_id) { struct virtnet_classifier *c; c = xa_load(&ff->classifiers, classifier_id); - if (c) { + if (c && refcount_dec_and_test(&c->refcount)) { virtio_admin_obj_destroy(ff->vdev, VIRTIO_NET_RESOURCE_OBJ_FF_CLASSIFIER, c->id,
@@ -5869,7 +5884,7 @@ static void destroy_ethtool_rule(struct virtnet_ff *ff, 0); xa_erase(&ff->ethtool.rules, eth_rule->flow_spec.location); - destroy_classifier(ff, eth_rule->classifier_id); + try_destroy_classifier(ff, eth_rule->classifier_id); kfree(eth_rule); }
@@ -6047,7 +6062,7 @@ static int build_and_insert(struct virtnet_ff *ff, } c->size = classifier_size; - classifier = &c->classifier; + classifier = &c->obj; classifier->count = num_hdrs; selector = (void *)&classifier->selectors[0];
@@ -6057,14 +6072,16 @@ static int build_and_insert(struct virtnet_ff *ff, if (err) goto err_classifier; - err = setup_classifier(ff, c); + err = setup_classifier(ff, &c); if (err) goto err_classifier; err = insert_rule(ff, eth_rule, c->id, key, key_size); if (err) { - /* destroy_classifier will free the classifier */ - destroy_classifier(ff, c->id); + /* try_destroy_classifier will decrement the refcount on the + * classifier and free it if needed. + */ + try_destroy_classifier(ff, c->id); goto err_key; }
--
2.49.0