On Tue, Nov 18, 2025 at 08:38:57AM -0600, Daniel Jurgens wrote:

...

> +static int insert_rule(struct virtnet_ff *ff,
> +                    struct virtnet_ethtool_rule *eth_rule,
> +                    u32 classifier_id,
> +                    const u8 *key,
> +                    size_t key_size)
> +{
> +     struct ethtool_rx_flow_spec *fs = &eth_rule->flow_spec;
> +     struct virtio_net_resource_obj_ff_rule *ff_rule;
> +     int err;
> +
> +     ff_rule = kzalloc(sizeof(*ff_rule) + key_size, GFP_KERNEL);
> +     if (!ff_rule)
> +             return -ENOMEM;
> +
> +     /* Intentionally leave the priority as 0. All rules have the same
> +      * priority.
> +      */
> +     ff_rule->group_id = cpu_to_le32(VIRTNET_FF_ETHTOOL_GROUP_PRIORITY);
> +     ff_rule->classifier_id = cpu_to_le32(classifier_id);
> +     ff_rule->key_length = (u8)key_size;
> +     ff_rule->action = fs->ring_cookie == RX_CLS_FLOW_DISC ?
> +                                          VIRTIO_NET_FF_ACTION_DROP :
> +                                          VIRTIO_NET_FF_ACTION_RX_VQ;
> +     ff_rule->vq_index = fs->ring_cookie != RX_CLS_FLOW_DISC ?
> +                                            cpu_to_le16(fs->ring_cookie) : 0;
> +     memcpy(&ff_rule->keys, key, key_size);
> +
> +     err = virtio_admin_obj_create(ff->vdev,
> +                                   VIRTIO_NET_RESOURCE_OBJ_FF_RULE,
> +                                   fs->location,
> +                                   VIRTIO_ADMIN_GROUP_TYPE_SELF,
> +                                   0,
> +                                   ff_rule,
> +                                   sizeof(*ff_rule) + key_size);
> +     if (err)
> +             goto err_ff_rule;
> +
> +     eth_rule->classifier_id = classifier_id;
> +     ff->ethtool.num_rules++;
> +     kfree(ff_rule);
> +
> +     return 0;
> +
> +err_ff_rule:
> +     kfree(ff_rule);
> +
> +     return err;
> +}


...

> +static int build_and_insert(struct virtnet_ff *ff,
> +                         struct virtnet_ethtool_rule *eth_rule)
> +{
> +     struct virtio_net_resource_obj_ff_classifier *classifier;
> +     struct ethtool_rx_flow_spec *fs = &eth_rule->flow_spec;
> +     struct virtio_net_ff_selector *selector;
> +     struct virtnet_classifier *c;
> +     size_t classifier_size;
> +     size_t key_size;
> +     int num_hdrs;
> +     u8 *key;
> +     int err;
> +
> +     calculate_flow_sizes(fs, &key_size, &classifier_size, &num_hdrs);
> +
> +     key = kzalloc(key_size, GFP_KERNEL);
> +     if (!key)
> +             return -ENOMEM;

So key is allocated here ...


> +
> +     /*
> +      * virtio_net_ff_obj_ff_classifier is already included in the
> +      * classifier_size.
> +      */
> +     c = kzalloc(classifier_size +
> +                 sizeof(struct virtnet_classifier) -
> +                 sizeof(struct virtio_net_resource_obj_ff_classifier),
> +                 GFP_KERNEL);
> +     if (!c) {
> +             kfree(key);
> +             return -ENOMEM;
> +     }
> +
> +     c->size = classifier_size;
> +     classifier = &c->classifier;
> +     classifier->count = num_hdrs;
> +     selector = (void *)&classifier->selectors[0];
> +
> +     setup_eth_hdr_key_mask(selector, key, fs);
> +
> +     err = validate_classifier_selectors(ff, classifier, num_hdrs);
> +     if (err)
> +             goto err_key;
> +
> +     err = setup_classifier(ff, c);
> +     if (err)
> +             goto err_classifier;
> +
> +     err = insert_rule(ff, eth_rule, c->id, key, key_size);


... copied by insert_rule


> +     if (err) {
> +             /* destroy_classifier will free the classifier */
> +             destroy_classifier(ff, c->id);
> +             goto err_key;
> +     }
> +


... and apparently never freed?


I think it's because the API of insert_rule is confusing...

> +     return 0;
> +
> +err_classifier:
> +     kfree(c);
> +err_key:
> +     kfree(key);
> +
> +     return err;
> +}
> +

-- 
MST


Reply via email to