[PATCH net-next v22 10/14] virtio_net: Use existing classifier if possible
From: Shahar Shitrit <hidden>
Date: 2026-08-16 12:22:03
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 artificially 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: Shahar Shitrit <redacted> Reviewed-by: Xuan Zhuo <xuanzhuo@linux.alibaba.com> --- drivers/net/virtio_net.c | 50 +++++++++++++++++++++++++++------------- 1 file changed, 34 insertions(+), 16 deletions(-)
diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
index eb2e5e92c786..9d58ac0b96b2 100644
--- a/drivers/net/virtio_net.c
+++ b/drivers/net/virtio_net.c@@ -32,6 +32,7 @@ #include <net/ip.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);
@@ -5716,12 +5717,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");
@@ -5809,11 +5811,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)
@@ -5821,29 +5836,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,
@@ -5867,7 +5883,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); }
@@ -6048,7 +6064,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];
@@ -6058,14 +6074,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