+static int
+ch_rte_parsetype_vlan(const void *dmask, const struct rte_flow_item *item,
+ struct ch_filter_specification *fs,
+ struct rte_flow_error *e)
+{
+ const struct rte_flow_item_vlan *spec = item->spec;
+ const struct rte_flow_item_vlan *umask = item->mask;
+ const struct rte_flow_item_vlan *mask;
+
+ /* If user has not given any mask, then use chelsio supported mask. */
+ mask = umask ? umask : (const struct rte_flow_item_vlan *)dmask;
+
+ CXGBE_FILL_FS(1, 1, ivlan_vld);
+ if (!spec)
+ return 0; /* Wildcard, match all VLAN */
+
+ /* Chelsio hardware supports matching on only one ethertype
+ * (i.e. either the outer or inner ethertype, but not both).
+ * If outer ethertype is already set and is not VLAN (0x8100),
+ * then don't proceed further. Otherwise, reset the outer
+ * ethertype, so that it can be replaced by inner ethertype.
+ * Note that the hardware will automatically match on outer
+ * ethertype 0x8100, if 'ivlan_vld' bit is set in Chelsio
+ * filter spec.
+ */
+ if (fs->mask.ethtype) {
+ if (fs->val.ethtype != RTE_ETHER_TYPE_VLAN)
+ return rte_flow_error_set(e, EINVAL,
+ RTE_FLOW_ERROR_TYPE_ITEM,
+ item,
+ "Outer ethertype not 0x8100");
+
+ fs->val.ethtype = 0;
+ fs->mask.ethtype = 0;
+ }
+
+ CXGBE_FILL_FS(be16_to_cpu(spec->tci), be16_to_cpu(mask->tci), ivlan);
+ if (spec->inner_type)
+ CXGBE_FILL_FS(be16_to_cpu(spec->inner_type),
+ be16_to_cpu(mask->inner_type), ethtype);
+
+ return 0;
+}
+