+static void calculate_flow_sizes(struct ethtool_rx_flow_spec *fs,
+                                size_t *key_size, size_t *classifier_size,
+                                int *num_hdrs)
+{
+       *num_hdrs = 1;
+       *key_size = sizeof(struct ethhdr);
+       /*
+        * The classifier size is the size of the classifier header, a selector
+        * header for each type of header in the match critea, and each header

typo critea -> criteria

+        * providing the mask for matching against.
+        */
+       *classifier_size = *key_size +
+                          sizeof(struct virtio_net_resource_obj_ff_classifier) 
+
+                          sizeof(struct virtio_net_ff_selector) * (*num_hdrs);
+}
+
+static void setup_eth_hdr_key_mask(struct virtio_net_ff_selector *selector,
+                                  u8 *key,
+                                  const struct ethtool_rx_flow_spec *fs)
+{
+       struct ethhdr *eth_m = (struct ethhdr *)&selector->mask;
+       struct ethhdr *eth_k = (struct ethhdr *)key;
+
+       selector->type = VIRTIO_NET_FF_MASK_TYPE_ETH;
+       selector->length = sizeof(struct ethhdr);
+
+       memcpy(eth_m, &fs->m_u.ether_spec, sizeof(*eth_m));
+       memcpy(eth_k, &fs->h_u.ether_spec, sizeof(*eth_k));
+}
+
+static int
+validate_classifier_selectors(struct virtnet_ff *ff,
+                             struct virtio_net_resource_obj_ff_classifier 
*classifier,
+                             int num_hdrs)
+{
+       struct virtio_net_ff_selector *selector = classifier->selectors;
+
+       for (int i = 0; i < num_hdrs; i++) {
+               if (!validate_mask(ff, selector))
+                       return -EINVAL;
+
+               selector = (struct virtio_net_ff_selector *)(((u8 *)selector) +
+                           sizeof(*selector) + selector->length);
+       }
+
+       return 0;
+}
+
+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;
+
+       /*
+        * virio_net_ff_obj_ff_classifier is already included in the

virio_net_ff_obj_ff_classifier -> virtio_net_ff_obj_ff_classifier

+        * classifier_size.
+        */
+       c = kzalloc(classifier_size +
+                   sizeof(struct virtnet_classifier) -
+                   sizeof(struct virtio_net_resource_obj_ff_classifier),
+                   GFP_KERNEL);
+       if (!c)
+               return -ENOMEM;

kfree(key) before returning -ENOMEM

+
+       c->size = classifier_size;
+       classifier = &c->classifier;
+       classifier->count = num_hdrs;
+       selector = &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);
+       if (err) {
+               destroy_classifier(ff, c->id);
+               goto err_key;
+       }
+
+       return 0;
+
+err_classifier:
+       kfree(c);
+err_key:
+       kfree(key);
+
+       return err;
+}
+

Thanks,
Alok

Reply via email to