[PATCH net-next v6 08/12] virtio_net: Use existing classifier if possible
From: Daniel Jurgens <hidden>
Date: 2025-10-27 17:40:50
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
Classifiers can be used by more than one rule. If there is an existing
classifier, use it instead of creating a new one.
Signed-off-by: Daniel Jurgens <redacted>
Reviewed-by: Parav Pandit <redacted>
Reviewed-by: Shahar Shitrit <redacted>
---
v4:
- Fixed typo in commit message
- for (int -> for (
---
drivers/net/virtio_net.c | 42 +++++++++++++++++++++++++++-------------
1 file changed, 29 insertions(+), 13 deletions(-)
diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
index 73194b51c318..d94ac72fc02c 100644
--- a/drivers/net/virtio_net.c
+++ b/drivers/net/virtio_net.c@@ -6806,6 +6806,7 @@ 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; };
@@ -6899,11 +6900,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->classifier, &(*c)->classifier, 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)
@@ -6911,29 +6925,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)->classifier, + (*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,
@@ -6957,7 +6972,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); }
@@ -7082,8 +7097,9 @@ validate_classifier_selectors(struct virtnet_ff *ff, int num_hdrs) { struct virtio_net_ff_selector *selector = (void *)classifier->selectors; + int i; - for (int i = 0; i < num_hdrs; i++) { + for (i = 0; i < num_hdrs; i++) { if (!validate_mask(ff, selector)) return -EINVAL;
@@ -7137,14 +7153,14 @@ static int build_and_insert(struct virtnet_ff *ff, if (err) goto err_key; - 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(ff, c->id); goto err_key; }
--
2.50.1