Hello,
I’m currently working with a DOCA Flow program on a BlueField2 DPU, using DOCA SDK version 2.8.0081, I am trying to filter TCP packets based on destination port, but the match rule does not seem to work.
Environment:
- DOCA SDK Version: 2.8.0081
- Open vSwitch (OVS) Version: 2.8.0-0091-24.07-based-3.3.0
- DPU Model: BlueField2
- OVS Configuration:
Bridge ovsbr2
Port ovsbr2
Interface ovsbr2
type: internal
Port p1
Interface p1
Port en3f1pf1sf0
Interface en3f1pf1sf0
Port pf1hpf
Interface pf1hpf
Bridge ovsbr1
Port ovsbr1
Interface ovsbr1
type: internal
Port en3f0pf0sf88
Interface en3f0pf0sf88
Port p0
Interface p0
Port pf0hpf
Interface pf0hpf
Port en3f0pf0sf0
Interface en3f0pf0sf0
I have set up a port mirror to capture traffic from port pf0hpf
and mirror it to en3f0pf0sf88
:
ovs-vsctl -- --id=@p1 get port en3f0pf0sf88 \
-- --id=@p2 get port pf0hpf \
-- --id=@m create mirror name=m0 select-dst-port=@p2 output-port=@p1 \
-- set bridge ovsbr2 mirrors=@m
Code
I am trying to filter packets based on TCP destination port from sf88
and forward them to RSS for processing. My flow match is defined as follows in the code:
static doca_error_t create_rss_pipe(struct doca_flow_port *port, struct doca_flow_pipe **pipe)
{
struct doca_flow_match match;
struct doca_flow_actions actions, *actions_arr[NB_ACTIONS_ARR];
struct doca_flow_fwd fwd;
struct doca_flow_fwd fwd_miss;
struct doca_flow_pipe_cfg *pipe_cfg;
uint16_t rss_queues[1];
doca_error_t result;
memset(&match, 0, sizeof(match));
memset(&actions, 0, sizeof(actions));
memset(&fwd, 0, sizeof(fwd));
memset(&fwd_miss, 0, sizeof(fwd_miss));
actions_arr[0] = &actions;
/* 5-tuple match */
match.parser_meta.outer_l4_type = DOCA_FLOW_L4_META_TCP;
match.parser_meta.outer_l3_type = DOCA_FLOW_L3_META_IPV4;
match.outer.l4_type_ext = DOCA_FLOW_L4_TYPE_EXT_TCP;
match.outer.l3_type = DOCA_FLOW_L3_TYPE_IP4;
match.outer.ip4.src_ip = 0xffffffff;
match.outer.ip4.dst_ip = 0xffffffff;
match.outer.tcp.l4_port.src_port = 0xffff;
match.outer.tcp.l4_port.dst_port = 0xffff;
result = doca_flow_pipe_cfg_create(&pipe_cfg, port);
if (result != DOCA_SUCCESS) {
DOCA_LOG_ERR("Failed to create doca_flow_pipe_cfg: %s", doca_error_get_descr(result));
return result;
}
result = set_flow_pipe_cfg(pipe_cfg, "RSS_META_PIPE", DOCA_FLOW_PIPE_BASIC, true);
if (result != DOCA_SUCCESS) {
DOCA_LOG_ERR("Failed to set doca_flow_pipe_cfg: %s", doca_error_get_descr(result));
goto destroy_pipe_cfg;
}
result = doca_flow_pipe_cfg_set_match(pipe_cfg, &match, NULL);
if (result != DOCA_SUCCESS) {
DOCA_LOG_ERR("Failed to set doca_flow_pipe_cfg match: %s", doca_error_get_descr(result));
goto destroy_pipe_cfg;
}
result = doca_flow_pipe_cfg_set_actions(pipe_cfg, actions_arr, NULL, NULL, NB_ACTIONS_ARR);
if (result != DOCA_SUCCESS) {
DOCA_LOG_ERR("Failed to set doca_flow_pipe_cfg actions: %s", doca_error_get_descr(result));
goto destroy_pipe_cfg;
}
/* RSS queue - send matched traffic to queue 0 */
rss_queues[0] = 0;
fwd.type = DOCA_FLOW_FWD_RSS;
fwd.rss_queues = rss_queues;
fwd.rss_inner_flags = DOCA_FLOW_RSS_IPV4 | DOCA_FLOW_RSS_TCP;
fwd.num_of_queues = 1;
fwd_miss.type = DOCA_FLOW_FWD_DROP;
result = doca_flow_pipe_create(pipe_cfg, &fwd, &fwd_miss, pipe);
destroy_pipe_cfg:
doca_flow_pipe_cfg_destroy(pipe_cfg);
return result;
}
And the flow entry is defined as:
static doca_error_t add_rss_pipe_entry(struct doca_flow_pipe *pipe, struct entries_status *status)
{
DOCA_LOG_INFO("Start add entry...");
struct doca_flow_match match;
struct doca_flow_actions actions;
struct doca_flow_pipe_entry *entry;
doca_error_t result;
/* example 5-tuple to drop */
doca_be32_t dst_ip_addr = BE_IPV4_ADDR(192, 168, 200, 2);
doca_be32_t src_ip_addr = BE_IPV4_ADDR(192, 168, 200, 1);
doca_be16_t dst_port = rte_cpu_to_be_16(8082);
doca_be16_t src_port = rte_cpu_to_be_16(1234);
memset(&match, 0, sizeof(match));
memset(&actions, 0, sizeof(actions));
match.outer.ip4.dst_ip = dst_ip_addr;
match.outer.ip4.src_ip = src_ip_addr;
match.outer.tcp.l4_port.dst_port = dst_port;
match.outer.tcp.l4_port.src_port = src_port;
result = doca_flow_pipe_add_entry(0, pipe, &match, &actions, NULL, NULL, 0, status, &entry);
DOCA_LOG_INFO("Matching IP: src=%x, dst=%x, dst_port=%u", src_ip_addr, dst_ip_addr, dst_port);
if (result != DOCA_SUCCESS)
return result;
return DOCA_SUCCESS;
}
doca_error_t flow_rss(int nb_queues)
{
const int nb_ports = 1;
struct flow_resources resource = {0};
uint32_t nr_shared_resources[SHARED_RESOURCE_NUM_VALUES] = {0};
struct doca_flow_port *ports[nb_ports];
struct doca_dev *dev_arr[nb_ports];
struct doca_flow_pipe *pipe;
struct entries_status status;
int num_of_entries = 1;
doca_error_t result;
int port_id;
result = init_doca_flow(nb_queues, "vnf,hws", &resource, nr_shared_resources);
// result = init_doca_flow(nb_queues, "vnf,hws", &resource, nr_shared_resources);
if (result != DOCA_SUCCESS) {
DOCA_LOG_ERR("Failed to init DOCA Flow: %s", doca_error_get_descr(result));
return -1;
}
memset(dev_arr, 0, sizeof(struct doca_dev *) * nb_ports);
result = init_doca_flow_ports(nb_ports, ports, true, dev_arr);
if (result != DOCA_SUCCESS) {
DOCA_LOG_ERR("Failed to init DOCA ports: %s", doca_error_get_descr(result));
doca_flow_destroy();
return result;
}
for (port_id = 0; port_id < nb_ports; port_id++) {
memset(&status, 0, sizeof(status));
result = create_rss_pipe(ports[port_id], &pipe);
if (result != DOCA_SUCCESS) {
DOCA_LOG_ERR("Failed to create pipe: %s", doca_error_get_descr(result));
stop_doca_flow_ports(nb_ports, ports);
doca_flow_destroy();
return result;
}
result = add_rss_pipe_entry(pipe, &status);
if (result != DOCA_SUCCESS) {
DOCA_LOG_ERR("Failed to add entry: %s", doca_error_get_descr(result));
stop_doca_flow_ports(nb_ports, ports);
doca_flow_destroy();
return result;
}
result = doca_flow_entries_process(ports[port_id], 0, DEFAULT_TIMEOUT_US, num_of_entries);
if (result != DOCA_SUCCESS) {
DOCA_LOG_ERR("Failed to process entries: %s", doca_error_get_descr(result));
stop_doca_flow_ports(nb_ports, ports);
doca_flow_destroy();
return result;
}
if (status.nb_processed != num_of_entries || status.failure) {
DOCA_LOG_ERR("Failed to process entries");
stop_doca_flow_ports(nb_ports, ports);
doca_flow_destroy();
return DOCA_ERROR_BAD_STATE;
}
}
DOCA_LOG_INFO("Wait few seconds for packets to arrive");
sleep(1);
for (port_id = 0; port_id < nb_ports; port_id++)
process_packets(port_id);
result = stop_doca_flow_ports(nb_ports, ports);
doca_flow_destroy();
return result;
}
The Issue:
The match rule does not seem to work properly, and after calling the flow_rss
function, all packets received on sf88
are forwarded to the RSS, regardless of whether they match the filter.
Question:
I’m currently using VNF mode for the pipe, but I’m wondering if pipe mode could be the cause of the issue? Since I’m running OVS, would using switch mode be necessary for the flow match to work properly?
Has anyone encountered a similar issue or could provide some insights on this?
Thanks in advance!