|WARNING| [v2,3/3] net/txgbe: fix flow create error codes
dpdklab at iol.unh.edu
dpdklab at iol.unh.edu
Wed Sep 16 15:35:55 CEST 2026
Test-Label: ai-code-review
Test-Status: WARNING
https://dpdk.org/patch/169699
_AI Code Review_
=== Patch Review: series.patch (via Claude) ===
Review date: 2026-09-16
# DPDK Patch Review
## Patch 1/3: net/txgbe: fix L2 tunnel error on flow create
### Errors
None.
### Warnings
None.
### Info
None.
---
## Patch 2/3: net/txgbe: fix leak of filters on flow create
### Errors
**1. Resource leak on FDIR mask-only path (lines 3431-3435)**
When `fdir_rule.b_spec` is false (mask-only configuration), the allocated `fdir_rule_ptr` is freed and the function jumps to `out` with `ret = -EINVAL`. However, if `fdir_info->mask_added` was set to `TRUE` earlier in this flow and `first_mask` is true, the mask remains installed in hardware but the application has no way to remove it. The original code had this issue; the patch preserves it while fixing other leaks.
**Fix**: Before `rte_free(fdir_rule_ptr)` on the mask-only path, check `if (first_mask && fdir_info->mask_added)` and reset `fdir_info->mask_added = FALSE` to match the cleanup done on the filter program failure path (line 3419).
```c
rte_free(fdir_rule_ptr);
if (first_mask && fdir_info->mask_added)
fdir_info->mask_added = FALSE;
ret = -EINVAL;
goto out;
```
**2. Inverted memcmp check on line 3391 in context of patch 3**
Patch 3 will change `ret = memcmp(...)` to `if (memcmp(...) != 0)`. However, patch 2 moves the `fdir_rule_ptr` allocation to precede the mask checks. If the memcmp fails (returns non-zero), the code path starting at line 3393 in patch 2's version will free `fdir_rule_ptr` and goto out. But the condition `if (ret)` at line 3393 is checking the **old** `ret = memcmp()` result, which is non-zero on mismatch. This means:
- Patch 2 line 3393: `if (ret)` will be true when masks differ (correct).
- Patch 3 changes line 3391-3393 to `if (memcmp(...) != 0) { PMD_DRV_LOG(...); rte_free(...); ret = -EINVAL; goto out; }`, which is also correct.
Actually, re-reading patch 2's diff in isolation: the `if (ret)` block at line 3393 is not shown in the patch 2 diff. The patch 2 diff only shows the allocation being moved earlier, and the `rte_memcpy` -> direct assignment change. The memcmp fix is entirely in patch 3. So patch 2 leaves the memcmp logic unchanged from the original (which is wrong, but patch 3 fixes it). This is acceptable for a patch series where patch 3 depends on patch 2.
Actually, looking more carefully at patch 2's line numbers: line 3393 in the patched version corresponds to the `if (ret)` check after memcmp. In the original code, that check is at the same location. Patch 2 does not modify the memcmp or the `if (ret)` check; it only adds the allocation and free calls. So patch 2 introduces the `rte_free(fdir_rule_ptr)` call inside the existing `if (ret)` block that checks memcmp result. Since patch 3 will fix the memcmp logic, this is fine -- the patches must be applied in sequence.
**However**, there is a problem: in patch 2, after the allocation is moved earlier, if the `memcmp` at line 3391 (old code, preserved by patch 2) returns 0 (masks match), `ret` is 0. Then the code continues to the flex offset check. If that check fails, the code does `rte_free(fdir_rule_ptr); goto out;` (line 3402-3404). But `ret` is still 0 at that point (from the successful memcmp). So the `goto out` will pass `ret == 0` to the error handler, which will do `rte_flow_error_set(error, -ret)` with `-ret == 0`. This is the bug that patch 3 fixes by setting `ret = -EINVAL` on that path.
But wait -- let me re-read patch 2's diff around the memcmp. In the original code before patch 2:
```c
ret = memcmp(&fdir_info->mask, &fdir_rule.mask, sizeof(...));
if (ret) {
PMD_DRV_LOG(ERR, "only support one global mask");
goto out;
}
```
In patch 2, that code is unchanged in the diff (not shown in the hunk). The patch 2 diff shows:
```
@@ -3381,40 +3393,25 @@ txgbe_flow_create(...)
sizeof(struct txgbe_hw_fdir_mask));
if (ret) {
PMD_DRV_LOG(ERR, "only support one global mask");
+ rte_free(fdir_rule_ptr);
goto out;
}
```
So patch 2 adds `rte_free(fdir_rule_ptr)` in the memcmp failure path. The memcmp logic itself is not changed in patch 2. Patch 3 then fixes the memcmp result handling. This is correct ordering.
But there's still the issue: if memcmp succeeds (ret=0) and then flex offset check fails, patch 2's code does:
```c
if (fdir_info->flex_bytes_offset != fdir_rule.flex_bytes_offset ||
fdir_info->flex_relative != fdir_rule.flex_relative) {
rte_free(fdir_rule_ptr);
goto out;
}
```
with `ret` still 0. Patch 3 fixes this by adding `ret = -EINVAL;` before the goto. So patch 2 temporarily introduces a state where the flex check goto has ret=0, but patch 3 fixes it. Since patches must be applied in order, this is acceptable. Not a bug in patch 2 itself.
Actually, I need to check if patch 2's logic is correct by itself. Let me re-examine the flow in patch 2's final code (before patch 3):
1. Allocate `fdir_rule_ptr` (new in patch 2).
2. If mask comparison fails (`ret = memcmp(...); if (ret)`): free fdir_rule_ptr, goto out with ret = (positive memcmp result).
3. If flex offset mismatch: free fdir_rule_ptr, goto out with ret = 0 (from successful memcmp).
4. If `txgbe_fdir_filter_program` fails: free fdir_rule_ptr, clean up mask_added if first_mask, goto out with ret = (error from program).
5. If mask-only (b_spec false): free fdir_rule_ptr, goto out with ret = 0 (or previous ret).
Issues in patch 2:
- Flex offset mismatch goto (step 3) has ret=0.
- Mask-only goto (step 5) has ret=0 or stale.
- memcmp failure (step 2) has ret=positive (memcmp returns -1, 0, or 1; 1 is positive).
Patch 3 fixes steps 3 and 5 by setting ret=-EINVAL. But step 2 is not fixed in patch 3 -- the memcmp logic is changed to `if (memcmp(...) != 0)` and then sets `ret = -EINVAL`. So patch 3 does fix step 2 as well.
Conclusion: Patch 2 introduces some ret=0 error paths (flex, mask-only) which are fixed by patch 3. Patch 2 does not fix the memcmp ret=positive issue, but patch 3 does. Since patches are sequential, this is acceptable. However, each patch should compile and be correct independently. Patch 2's code will have ret=0 error paths until patch 3 is applied, which means patch 2 alone does not fully fix the issue. But the patch 2 commit message says "Set ENOMEM when allocation fails" -- it does not claim to fix the ret=0 error code issue. That's patch 3's job. So patch 2 is internally consistent with its stated purpose (fix resource leaks), even though it leaves error codes wrong (which is patch 3's scope).
**Verdict**: Patch 2 is correct for its stated purpose. The ret=0 issue is a separate bug fixed by patch 3. Not an error in patch 2.
### Warnings
**1. Use of `rte_memcpy` removed**
The original code uses `rte_memcpy(&ptr->filter_info, &filter, sizeof(...))` to copy the filter structure. The patch changes this to direct assignment: `ptr->filter_info = filter`. Both are correct. Direct assignment is clearer and allows the compiler to optimize the copy. However, this is a style change mixed into a bug fix patch. Consider splitting style changes into a separate patch.
### Info
None.
---
## Patch 3/3: net/txgbe: fix flow create error codes
### Errors
None.
### Warnings
None.
### Info
None.
---
## Summary
**Patch 1/3**: Clean fix for the L2 tunnel early return issue. No problems.
**Patch 2/3**: Fixes the primary resource leak issue correctly. Has one remaining leak scenario (mask-only path with mask_added set) that should be addressed.
**Patch 3/3**: Correctly fixes the error code propagation issues.
**Overall**: The series fixes real bugs (resource leaks, error code propagation). Patch 2 should add mask cleanup on the mask-only error path to fully prevent mask state leaks. The style change (rte_memcpy -> assignment) in patch 2 is minor but could be separated.
More information about the test-report
mailing list