I am trying to use a DPDK flow rule to route received UDP packets to different queues based on their UDP destination port. My flow passes validation when running rte_flow_validate()
. However, the packets still all arrive in queue 0 on every device, regardless of destination port, as if the flow rules had not been configured. Does anyone have a clue as to why the flow rule might not be applied as expected?
Below is the function that I wrote to configure this flow rule. Right now, this function is called immediately after configuring and starting my devices. (I have tried calling it elsewhere, but no luck. See troubleshooting section for details)
rte_flow * configure_udp_flow(uint16_t device_id, uint16_t udp_dst_port, uint16_t queue_id)
{
rte_flow *flow = NULL;
rte_flow_attr attr;
rte_flow_item pattern[5];
rte_flow_action action[5];
rte_flow_action_queue queue;
struct rte_flow_item_eth eth_spec;
rte_flow_item_ipv4 ip_spec;
rte_flow_item_udp udp_spec;
rte_flow_item_udp udp_mask;
memset(&attr, 0, sizeof(rte_flow_attr));
memset(pattern, 0, sizeof(pattern));
memset(action, 0, sizeof(action));
memset(&queue, 0, sizeof(rte_flow_action_queue));
memset(ð_spec, 0, sizeof(rte_flow_item_eth));
memset(&ip_spec, 0, sizeof(rte_flow_item_ipv4));
memset(&udp_spec, 0, sizeof(rte_flow_item_udp));
memset(&udp_mask, 0, sizeof(rte_flow_item_udp));
attr.ingress = 1;
// First level pattern, ETH, apply no actions
pattern[0].type = RTE_FLOW_ITEM_TYPE_ETH;
pattern[0].spec = ð_spec;
// Second level pattern, IP, apply no actions
pattern[1].type = RTE_FLOW_ITEM_TYPE_IPV4;
pattern[1].spec = &ip_spec;
// Third level, UDP, match UDP destination port
pattern[2].type = RTE_FLOW_ITEM_TYPE_UDP;
udp_spec.hdr.dst_port = htons(udp_dst_port);
pattern[2].spec = &udp_spec;
udp_mask.hdr.dst_port = 0xffff;
pattern[2].mask = &udp_mask;
// Set pattern end
pattern[3].type = RTE_FLOW_ITEM_TYPE_END;
// Set action to move packet to queue
action[0].type = RTE_FLOW_ACTION_TYPE_QUEUE;
queue.index = queue_id;
action[0].conf = &queue;
action[1].type = RTE_FLOW_ACTION_TYPE_END;
// Validate and create
rte_flow_error flow_error;
int res = rte_flow_validate(device_id, &attr, pattern, action, &flow_error);
if (res < 0)
{
spdlog::error("Could not configure flow rule: {0}", flow_error.message);
return flow;
}
flow = rte_flow_create(device_id, &attr, pattern, action, &flow_error);
return flow;
}
I have tried the following:
configure_udp_flow()
to different parts of the configuration
I fixed this problem by not setting ANY spec for the ETH and IPV4 levels.
Previously, the pattern looked like this:
// First level pattern, ETH, apply no actions
pattern[0].type = RTE_FLOW_ITEM_TYPE_ETH;
pattern[0].spec = ð_spec;
// Second level pattern, IP, apply no actions
pattern[1].type = RTE_FLOW_ITEM_TYPE_IPV4;
pattern[1].spec = &ip_spec;
// Third level, UDP, match UDP destination port
pattern[2].type = RTE_FLOW_ITEM_TYPE_UDP;
udp_spec.hdr.dst_port = htons(udp_dst_port);
pattern[2].spec = &udp_spec;
udp_mask.hdr.dst_port = 0xffff;
pattern[2].mask = &udp_mask;
// Set pattern end
pattern[3].type = RTE_FLOW_ITEM_TYPE_END;
Now, the pattern looks like this, and works.
// First level pattern, ETH, apply no actions
pattern[0].type = RTE_FLOW_ITEM_TYPE_ETH;
// Second level pattern, IP, apply no actions
pattern[1].type = RTE_FLOW_ITEM_TYPE_IPV4;
// Third level, UDP, match UDP destination port
pattern[2].type = RTE_FLOW_ITEM_TYPE_UDP;
udp_spec.hdr.dst_port = htons(udp_dst_port);
pattern[2].spec = &udp_spec;
udp_mask.hdr.dst_port = 0xffff;
pattern[2].mask = &udp_mask;
// Set pattern end
pattern[3].type = RTE_FLOW_ITEM_TYPE_END;
I assumed that assigning a zeroed-out spec for the ETH and IPV4 levels without specifying a mask would be the same as setting no spec at all. However, I was likely accidentally specifying a match to all zero values for ETH and IPV4 levels. I suspect I could have also fixed this problem by adding explicitly specifying a zeroed out masks for ETH and IPV4 levels as well, but have not verified it as there was no need.