Summary
A VF adds protocol-agnostic ("raw") FDIR rules via VIRTCHNL_OP_ADD_FDIR_FILTER.
The rules are programmed and demonstrably steer traffic to the intended
queue. However the flow_id returned to the VF is 0 for every rule, so
every subsequent VIRTCHNL_OP_DEL_FDIR_FILTER is rejected by the PF:
ice 0000:81:00.1: VF 4: FDIR invalid flow_id:0x0
Because the VF never receives a usable handle, rules that work can never be
deleted. They accumulate until the VF's VSI is destroyed (sriov_numvfs=0).
VF FLR, PF devlink driver_reinit and PF PCIe FLR do not release them.
This makes raw FDIR unusable for any application that restarts: each restart
permanently consumes filter resources on that VF.
Reproduced with stock dpdk-testpmd — no application code required.
Environment
| item |
value |
| ice driver |
2.3.10 (out-of-tree). Also verified present in v2.6.7 / main by source inspection |
| adapter |
E810, PCI ID [8086:1592], subsystem [8086:0002] |
| firmware / NVM |
fw 7.9.1 api 1.7.11 nvm 4.90 0x80020ef2 1.3863.0 |
| DDP |
ICE COMMS Package 1.3.57.0 (fw.app.bundle_id 0xc0000002), loaded successfully at probe |
| fw.netlist |
4.4.2000-3.28.0 (build 0x2723426e) |
| host kernel |
6.8.12-15-pve (SMP PREEMPT_DYNAMIC) |
| guest kernel |
7.0.0-29-generic |
| VF driver |
DPDK 25.11.0 iavf PMD via vfio-pci |
Reproducer
VF bound to vfio-pci:
dpdk-testpmd -l 6-7 -n 4 -a 0000:05:00.0 --file-prefix=t -m 1024 \
-- -i --rxq=4 --txq=4 --forward-mode=rxonly
Create raw rules. The spec is a complete 79-byte Ethernet/IPv4/UDP frame; the
mask selects only the EtherType, IP protocol, UDP destination port, and two
bytes of UDP payload (a 1-bit flag and a 4-bit selector at a fixed offset).
Each rule targets a different queue by matching a different selector value:
# queue 0
flow create 0 ingress pattern raw pattern spec aabbccddeeff11223344556608004500004112340000401142640a0909010a090902303901bb002d000040000000000000000000000000000000000000000000000000000000000000000000000000 pattern mask 000000000000000000000000ffff000000000000000000ff000000000000000000000000ffff00000000803c0000000000000000000000000000000000000000000000000000000000000000000000 / end actions mark id 233472 / queue index 0 / end
# queue 1 (payload byte 43 = 0x04 instead of 0x00)
flow create 0 ingress pattern raw pattern spec aabbccddeeff11223344556608004500004112340000401142640a0909010a090902303901bb002d000040040000000000000000000000000000000000000000000000000000000000000000000000 pattern mask 000000000000000000000000ffff000000000000000000ff000000000000000000000000ffff00000000803c0000000000000000000000000000000000000000000000000000000000000000000000 / end actions mark id 233473 / queue index 1 / end
Repeat for 16 rules, then delete them one at a time:
flow destroy 0 rule 0
flow destroy 0 rule 1
...
Observed
All creates report success. Every delete fails:
iavf_fdir_del(): Failed to delete rule request due to this rule doesn't exist
iavf_flow_destroy(): Failed to destroy flow
port_flow_complain(): Caught PMD error type 2 (flow rule (handle)):
Failed to delete filter rule.: Operation not permitted
With PF-side dynamic debug enabled:
echo 'file ice_virtchnl_fdir.c +p' > /sys/kernel/debug/dynamic_debug/control
the PF logs, once per delete attempt:
ice 0000:81:00.1: VF 4: FDIR invalid flow_id:0x0
Expected
Each delete succeeds — or, failing that, the preceding add reports failure.
Side observation in the same run
The first flow create of a fresh session fails, and subsequent identical
creates succeed:
port_flow_complain(): Caught PMD error type 2 (flow rule (handle)):
Failed to create parser engine.: Invalid argument
In the attached log 15 of 16 rules were created, the single failure being the
first. This is reproducible and looks like first-use initialisation of the
parser profile; it is reported here for completeness rather than as the main
issue, but may share a root cause with the flow_id handling.
Attachments
repro-raw-fdir-delete.sh — standalone reproducer (testpmd only)
testpmd-raw-fdir-delete-failure.log — full testpmd session showing the
creates succeeding and all deletes failing
pf-dmesg-excerpt.txt — PF-side driver/firmware/DDP provenance and the
FDIR invalid flow_id:0x0 lines
Evidence the rules really are programmed in hardware
With a full rule set (16 raw rules, 4 queues) installed on a freshly created VF,
the device steers every packet to the intended queue:
|
rules |
RX packets |
delivered to wrong queue |
| no rules (baseline) |
0 |
6,106,479 |
4,971,215 — 81.4% |
| 16 raw rules |
16 |
3,451,435 |
0 — none |
All 16 rules installed first try, zero retries. Every received packet was
delivered to the queue its matched rule selected; the cross-queue counter did
not increment once. Sustained throughput 501 Mbps at 0.0000% loss
(0 of 7,614,267 packets).
A second run with a partial rule set (8 rules covering 2 of the 4 packet shapes)
steered 47.5% — consistent with the uncovered shapes having no rule to match,
and confirming the rules act exactly where they are installed and nowhere else.
These rules work perfectly. They still cannot be deleted. That is the whole
of this report: the filters are correctly programmed and demonstrably steering
millions of packets, while the flow_id returned to the VF is 0, so there is no
handle with which to remove them.
Analysis
1. Blocker — flow_id returned as 0 for rules that were programmed
ice_vc_del_fdir_fltr() rejects at its first step:
conf = ice_vc_fdir_lookup_entry(vf, fltr->flow_id);
if (!conf) {
stat->status = VIRTCHNL_FDIR_FAILURE_RULE_NONEXIST;
dev_dbg(dev, "VF %d: FDIR invalid flow_id:0x%X", vf->vf_id, fltr->flow_id);
On its success path ice_vc_add_fdir_raw() does return 0 without sending a
response; the reply is emitted asynchronously by ice_vc_add_fdir_fltr_post(),
which is the only site that sets resp->flow_id = conf->flow_id. A raw add that
programs hardware but whose reply carries flow_id = 0 implies that completion
either did not run for the raw path, or ran against a stale ctx->conf.
2. VF reset orphans raw rules in hardware
ice_vf_fdir_exit() runs on every VF reset. Its rule-clearing step is
software-only:
static void ice_vc_fdir_flush_entry(struct ice_vf *vf)
{
list_for_each_entry_safe(desc, temp, &vf->fdir.fdir_rule_list, fltr_node) {
list_del(&desc->fltr_node);
kfree(conf); /* no hardware write anywhere */
}
}
It never calls ice_vc_fdir_add_del_raw(vf, conf, false). The classic FDIR path
does reach hardware (ice_vc_fdir_rem_prof_all() → ice_rem_prof_id_flow() /
ice_flow_rem_entry()); the raw path has no equivalent, and
vf->fdir_prof_info[ptg] is touched by no cleanup path in the tree. Hardware
entries survive while the conf holding their handle is freed.
This function is byte-identical in v2.6.7 and main.
3. 0 is a legal flow_id
ice_vc_fdir_insert_entry() uses
idr_alloc(&vf->fdir.fdir_rule_idr, conf, 0, ICE_FDIR_MAX_FLTRS, GFP_KERNEL),
so id 0 is allocatable and the PF cannot distinguish "id 0" from "unset".
Unchanged in v2.6.7.
Status in the latest release
src/ice_virtchnl_fdir.c at tag v2.6.7 is byte-identical to main. Diffed
against 2.3.10 the whole file changes by 102 lines, and no changed line
touches flow_id, fdir_prof_info, or idr_alloc. So items 1–3 above are
all still present in the latest release.
One related fix has landed since 2.3.10 and is acknowledged: the
ice_flow_set_hw_prof() failure path in ice_vc_add_fdir_raw() now sets
stat->status = VIRTCHNL_FDIR_FAILURE_RULE_NORESOURCE rather than falling
through with a kzalloc'd stat (which previously reported success with
flow_id = 0). That is a real improvement, but it does not address the case
reported here, where the rule is successfully programmed.
Requested fixes, in priority order
- Return the real
flow_id in the raw add response. This is the blocker.
ice_vc_fdir_flush_entry() should delete each entry from hardware before
freeing its conf, so a VF reset does not orphan working rules.
ice_vf_fdir_exit() should release vf->fdir_prof_info[].
- Reserve
0 as an invalid flow_id.
Ruled out
- Not a DPDK bug — the
iavf PMD returns to the PF exactly the flow_id
the PF supplied. Reproduced identically under a second, unrelated DPDK
application.
- Not resource exhaustion — reproduced immediately after
sriov_numvfs=0 teardown and recreate, on a PF with no other FDIR users.
- Not the action set — fails identically with
queue alone and with
mark + queue.
- Not DDP —
devlink dev info reports ICE COMMS Package 1.3.57.0, which
provides raw/protocol-agnostic pattern support, loaded successfully at probe.
pf-dmesg-excerpt.txt
repro-raw-fdir-delete.sh
testpmd-raw-fdir-delete-failure.log
Summary
A VF adds protocol-agnostic ("raw") FDIR rules via
VIRTCHNL_OP_ADD_FDIR_FILTER.The rules are programmed and demonstrably steer traffic to the intended
queue. However the
flow_idreturned to the VF is0for every rule, soevery subsequent
VIRTCHNL_OP_DEL_FDIR_FILTERis rejected by the PF:Because the VF never receives a usable handle, rules that work can never be
deleted. They accumulate until the VF's VSI is destroyed (
sriov_numvfs=0).VF FLR, PF
devlink driver_reinitand PF PCIe FLR do not release them.This makes raw FDIR unusable for any application that restarts: each restart
permanently consumes filter resources on that VF.
Reproduced with stock
dpdk-testpmd— no application code required.Environment
mainby source inspection[8086:1592], subsystem[8086:0002]fw 7.9.1 api 1.7.11 nvm 4.90 0x80020ef2 1.3863.0fw.app.bundle_id 0xc0000002), loaded successfully at probeiavfPMD viavfio-pciReproducer
VF bound to
vfio-pci:dpdk-testpmd -l 6-7 -n 4 -a 0000:05:00.0 --file-prefix=t -m 1024 \ -- -i --rxq=4 --txq=4 --forward-mode=rxonlyCreate raw rules. The spec is a complete 79-byte Ethernet/IPv4/UDP frame; the
mask selects only the EtherType, IP protocol, UDP destination port, and two
bytes of UDP payload (a 1-bit flag and a 4-bit selector at a fixed offset).
Each rule targets a different queue by matching a different selector value:
Repeat for 16 rules, then delete them one at a time:
Observed
All creates report success. Every delete fails:
With PF-side dynamic debug enabled:
the PF logs, once per delete attempt:
Expected
Each delete succeeds — or, failing that, the preceding add reports failure.
Side observation in the same run
The first
flow createof a fresh session fails, and subsequent identicalcreates succeed:
In the attached log 15 of 16 rules were created, the single failure being the
first. This is reproducible and looks like first-use initialisation of the
parser profile; it is reported here for completeness rather than as the main
issue, but may share a root cause with the
flow_idhandling.Attachments
repro-raw-fdir-delete.sh— standalone reproducer (testpmd only)testpmd-raw-fdir-delete-failure.log— full testpmd session showing thecreates succeeding and all deletes failing
pf-dmesg-excerpt.txt— PF-side driver/firmware/DDP provenance and theFDIR invalid flow_id:0x0linesEvidence the rules really are programmed in hardware
With a full rule set (16 raw rules, 4 queues) installed on a freshly created VF,
the device steers every packet to the intended queue:
All 16 rules installed first try, zero retries. Every received packet was
delivered to the queue its matched rule selected; the cross-queue counter did
not increment once. Sustained throughput 501 Mbps at 0.0000% loss
(0 of 7,614,267 packets).
A second run with a partial rule set (8 rules covering 2 of the 4 packet shapes)
steered 47.5% — consistent with the uncovered shapes having no rule to match,
and confirming the rules act exactly where they are installed and nowhere else.
These rules work perfectly. They still cannot be deleted. That is the whole
of this report: the filters are correctly programmed and demonstrably steering
millions of packets, while the
flow_idreturned to the VF is 0, so there is nohandle with which to remove them.
Analysis
1. Blocker —
flow_idreturned as 0 for rules that were programmedice_vc_del_fdir_fltr()rejects at its first step:On its success path
ice_vc_add_fdir_raw()doesreturn 0without sending aresponse; the reply is emitted asynchronously by
ice_vc_add_fdir_fltr_post(),which is the only site that sets
resp->flow_id = conf->flow_id. A raw add thatprograms hardware but whose reply carries
flow_id = 0implies that completioneither did not run for the raw path, or ran against a stale
ctx->conf.2. VF reset orphans raw rules in hardware
ice_vf_fdir_exit()runs on every VF reset. Its rule-clearing step issoftware-only:
It never calls
ice_vc_fdir_add_del_raw(vf, conf, false). The classic FDIR pathdoes reach hardware (
ice_vc_fdir_rem_prof_all()→ice_rem_prof_id_flow()/ice_flow_rem_entry()); the raw path has no equivalent, andvf->fdir_prof_info[ptg]is touched by no cleanup path in the tree. Hardwareentries survive while the
confholding their handle is freed.This function is byte-identical in v2.6.7 and
main.3.
0is a legal flow_idice_vc_fdir_insert_entry()usesidr_alloc(&vf->fdir.fdir_rule_idr, conf, 0, ICE_FDIR_MAX_FLTRS, GFP_KERNEL),so id 0 is allocatable and the PF cannot distinguish "id 0" from "unset".
Unchanged in v2.6.7.
Status in the latest release
src/ice_virtchnl_fdir.cat tagv2.6.7is byte-identical tomain. Diffedagainst 2.3.10 the whole file changes by 102 lines, and no changed line
touches
flow_id,fdir_prof_info, oridr_alloc. So items 1–3 above areall still present in the latest release.
One related fix has landed since 2.3.10 and is acknowledged: the
ice_flow_set_hw_prof()failure path inice_vc_add_fdir_raw()now setsstat->status = VIRTCHNL_FDIR_FAILURE_RULE_NORESOURCErather than fallingthrough with a
kzalloc'd stat (which previously reported success withflow_id = 0). That is a real improvement, but it does not address the casereported here, where the rule is successfully programmed.
Requested fixes, in priority order
flow_idin the raw add response. This is the blocker.ice_vc_fdir_flush_entry()should delete each entry from hardware beforefreeing its
conf, so a VF reset does not orphan working rules.ice_vf_fdir_exit()should releasevf->fdir_prof_info[].0as an invalidflow_id.Ruled out
iavfPMD returns to the PF exactly theflow_idthe PF supplied. Reproduced identically under a second, unrelated DPDK
application.
sriov_numvfs=0teardown and recreate, on a PF with no other FDIR users.queuealone and withmark+queue.devlink dev inforeports ICE COMMS Package 1.3.57.0, whichprovides raw/protocol-agnostic pattern support, loaded successfully at probe.
pf-dmesg-excerpt.txt
repro-raw-fdir-delete.sh
testpmd-raw-fdir-delete-failure.log