net/enic: fix VLAN inner type matching for old hardware
[dpdk.git] / drivers / net / enic / enic_flow.c
index 5924a01..511c177 100644 (file)
@@ -39,6 +39,7 @@ struct copy_item_args {
        uint8_t *inner_ofst;
        uint8_t l2_proto_off;
        uint8_t l3_proto_off;
+       struct enic *enic;
 };
 
 /* functions for copying items into enic filters */
@@ -723,12 +724,26 @@ enic_copy_item_vlan_v2(struct copy_item_args *arg)
        if (eth_mask->ether_type)
                return ENOTSUP;
        /*
+        * For recent models:
         * When packet matching, the VIC always compares vlan-stripped
         * L2, regardless of vlan stripping settings. So, the inner type
         * from vlan becomes the ether type of the eth header.
+        *
+        * Older models w/o hardware vxlan parser have a different
+        * behavior when vlan stripping is disabled. In this case,
+        * vlan tag remains in the L2 buffer.
         */
-       eth_mask->ether_type = mask->inner_type;
-       eth_val->ether_type = spec->inner_type;
+       if (!arg->enic->vxlan && !arg->enic->ig_vlan_strip_en) {
+               struct vlan_hdr *vlan;
+
+               vlan = (struct vlan_hdr *)(eth_mask + 1);
+               vlan->eth_proto = mask->inner_type;
+               vlan = (struct vlan_hdr *)(eth_val + 1);
+               vlan->eth_proto = spec->inner_type;
+       } else {
+               eth_mask->ether_type = mask->inner_type;
+               eth_val->ether_type = spec->inner_type;
+       }
        /* For TCI, use the vlan mask/val fields (little endian). */
        gp->mask_vlan = rte_be_to_cpu_16(mask->tci);
        gp->val_vlan = rte_be_to_cpu_16(spec->tci);
@@ -967,7 +982,8 @@ enic_copy_item_raw_v2(struct copy_item_args *arg)
        if (!spec->relative || spec->offset != 0 || spec->search || spec->limit)
                return EINVAL;
        /* Need non-null pattern that fits within the NIC's filter pattern */
-       if (spec->length == 0 || spec->length > FILTER_GENERIC_1_KEY_LEN ||
+       if (spec->length == 0 ||
+           spec->length + sizeof(struct udp_hdr) > FILTER_GENERIC_1_KEY_LEN ||
            !spec->pattern || !mask->pattern)
                return EINVAL;
        /*
@@ -1082,6 +1098,7 @@ enic_copy_filter(const struct rte_flow_item pattern[],
 
        args.filter = enic_filter;
        args.inner_ofst = &inner_ofst;
+       args.enic = enic;
        for (; item->type != RTE_FLOW_ITEM_TYPE_END; item++) {
                /* Get info about how to validate and copy the item. If NULL
                 * is returned the nic does not support the item.