[dpdk-dev] Issues with ixgbe and rte_flow

Le Scouarnec Nicolas Nicolas.LeScouarnec at technicolor.com
Tue Mar 7 12:11:31 CET 2017

Dear all,

I have been using the new API rte_flow to program filtering on an X540 (ixgbe) NIC. My goal is to send packets from different VLANs to different queues (filtering which should be supported by flow director as far as I understand). I enclosed the setup code at the bottom of this email. However, the code in ixgbe rejects the request I formulated. I looked at the rte_flow related code in ixgbe and I found some weird checkings in function ixgbe_parse_fdir_filter_normal. The code verifies that vlan_spec->tpid == ETHER_TYPE_VLAN, which should never happen on real packets, as it is eth_spec->type which has this value in typical setups. The same comment applies to the mask, only eth_mask->tpid should be required to be 0xffff. Overall, unless I misunderstood the rte_flow API, the checks should be done on eth_spec/eth_mask rather than vlan_spec/vlan_mask.  

I also have a side comment which might be more related to the general rte_flow API than to the specific implementation in ixgbe. The rte_flow_error returned is not very useful for it does return the error of the last tried filter-type (L2 tunnel in ixgbe), and not the error of the filter-type that my setup should use (flow director). As NICs can have several filter-types, It would be be useful to the user if rte_flow_validate/create could return the errors for all filter types tried although that would require to change the rte_flow API and returning an array of rte_flow_error and not a single struct. 

Excerpt of the code that reject my filtering rule:

              if (vlan_spec->tpid != rte_cpu_to_be_16(ETHER_TYPE_VLAN)) {
			memset(rule, 0, sizeof(struct ixgbe_fdir_rule));
			rte_flow_error_set(error, EINVAL,
				item, "Not supported by fdir filter");
			return -rte_errno;

		rule->ixgbe_fdir.formatted.vlan_id = vlan_spec->tci;

		if (vlan_mask->tpid != (uint16_t)~0U) {
			memset(rule, 0, sizeof(struct ixgbe_fdir_rule));
			rte_flow_error_set(error, EINVAL,
				item, "Not supported by fdir filter");
			return -rte_errno;

For reference, here is the setup code I use

	struct rte_flow_attr attr;
	attr.group = 0;
	attr.priority = 0;
	attr.egress = 0;
	attr.ingress = 1;

	struct rte_flow_item_eth eth_mask;
	struct rte_flow_item_eth eth_spec;
	struct rte_flow_item_vlan vlan_mask;
	struct rte_flow_item_vlan vlan_spec;
	struct rte_flow_action_queue queue;

	struct rte_flow_item items[3];
	items[0].type = RTE_FLOW_ITEM_TYPE_ETH;
	items[1].type = RTE_FLOW_ITEM_TYPE_VLAN;
	items[0].last = NULL;
	items[0].spec = &eth_spec;
	items[0].mask = &eth_mask;
	items[1].last = NULL;
	items[1].spec = &vlan_spec;
	items[1].mask = &vlan_mask;
	items[2].type = RTE_FLOW_ITEM_TYPE_END;

	eth_mask.src = ETH(00,00,00,00,00,00);
	eth_mask.dst = ETH(ff,ff,ff,ff,ff,ff);
	eth_mask.type = 0xffff;

	eth_spec.src = ETH(00,00,00,00,00,00);
	eth_spec.dst = *dst;
	eth_spec.type = rte_cpu_to_be_16(ETHER_TYPE_VLAN);

	vlan_spec.tci = vlan_be;
	vlan_spec.tpid = 0;

	vlan_mask.tci = rte_cpu_to_be_16(0x0fff);
	vlan_mask.tpid =  0;

	struct rte_flow_action actions[2];
	actions[0].type = RTE_FLOW_ACTION_TYPE_QUEUE;
	actions[0].conf = &queue;
	actions[1].type = RTE_FLOW_ACTION_TYPE_END;
	actions[1].conf = NULL;
	queue.index = queue_id;

	struct rte_flow_error error;

	printf("%p %p %p %p %p\n", &items[0], &items[1], &items[2], &actions[0], &actions[1]);

	if(rte_flow_validate(port_id, &attr, items, actions, &error) < 0){

Best regards,
Nicolas Le Scouarnec

 This e-mail and any files transmitted with it are confidential and are intended solely for the use of the individual or entity to whom they are addressed.  If you are not the intended recipient or the person responsible  for delivering this communication to the intended recipient, please be advised that you have received this communication in error and that any use, dissemination, printing or copying of this communication (including any attachments) is strictly prohibited.

More information about the dev mailing list