|WARNING| [v2,9/9] net/iavf: fix IPsec flow metadata leaks
dpdklab at iol.unh.edu
dpdklab at iol.unh.edu
Mon Oct 19 18:08:11 CEST 2026
Test-Label: ai-code-review
Test-Status: WARNING
https://dpdk.org/patch/171676
_AI Code Review_
=== Patch Review: series.patch (via Claude) ===
Review date: 2026-10-19
# DPDK Patch Review
## Patch 1/9: net/iavf: keep device stopped if start fails
### Errors
**Resource leak on start failure:**
Line: `iavf_dev_start()` function body (lines 1039-1135)
The patch correctly moves `adapter->stopped = 0` to after startup succeeds, and adds early-return in stop when already stopped. However, the new error path at `irq_error:` does not release all resources allocated during the failed start.
The function allocates:
- Queue pairs via `iavf_start_queues()` at line 1112
- IRQ resources via `iavf_config_rx_queues_irqs()` before line 1112
On failure after line 1112, the `irq_error:` path cleans up IRQ resources but does not clean up queues. The queues remain configured in hardware/PF state even though start failed.
Suggested fix: Add `iavf_stop_queues(dev)` before the IRQ cleanup in the error path:
```c
irq_error:
iavf_stop_queues(dev);
if (!wb_on_itr && dev->data->dev_conf.intr_conf.rxq != 0)
rte_intr_disable(intr_handle);
rte_intr_efd_disable(intr_handle);
rte_intr_vec_list_free(intr_handle);
rte_free(vf->qv_map);
vf->qv_map = NULL;
error:
return -1;
```
---
## Patch 2/9: net/iavf: do not store ethdev pointer
### Warnings
**Missing null check on adapter dereference:**
Line: `iavf_get_eth_dev()` function (lines 410-413)
The new inline function `iavf_get_eth_dev()` dereferences `adapter->dev_data->port_id` without checking if `adapter` or `adapter->dev_data` is NULL. While callers in this patch always have a valid adapter, defensive programming would check these before dereferencing, or document that the caller guarantees validity.
---
## Patch 3/9: net/iavf: fix false success on flow validation
### Clean
No issues found. The fix correctly returns NULL on validation failure instead of returning the engine pointer after setting an error.
---
## Patch 4/9: net/iavf: fix memory leak in raw pattern parsing
### Clean
No issues found. The fix correctly frees the previously allocated packet buffer when mask buffer allocation fails.
---
## Patch 5/9: net/iavf: fix memory leaks around IRQ resources
### Errors
**Double cleanup risk:**
Line: 1130 in error path
The error path at `irq_error:` calls `rte_intr_vec_list_free()` and `rte_intr_efd_disable()`. However, if `iavf_config_rx_queues_irqs()` succeeded and `iavf_start_queues()` failed, these resources were already set up correctly. The subsequent call to `iavf_dev_stop()` by the application will call these cleanup functions again at lines 1161-1162.
`rte_intr_vec_list_free()` and `rte_intr_efd_disable()` are not documented as idempotent. While they may handle double-free internally, explicitly calling them twice on the same handle is unsafe without verification.
Suggested fix: Only clean up IRQ resources on the error path if `iavf_config_rx_queues_irqs()` itself succeeded but a later step failed. The existing `iavf_dev_stop()` call by the application will clean up otherwise:
```c
irq_error:
if (!wb_on_itr && dev->data->dev_conf.intr_conf.rxq != 0)
rte_intr_disable(intr_handle);
rte_intr_efd_disable(intr_handle);
rte_intr_vec_list_free(intr_handle);
rte_free(vf->qv_map);
vf->qv_map = NULL;
```
Actually, re-reading: `iavf_dev_stop()` is not called on start failure in the existing code. The error path must do all cleanup. The issue is that the cleanup at `irq_error:` assumes IRQ setup succeeded, but if called from before IRQ setup completes, it may clean up partially initialized state.
Revised: The error path is correct only if reached after `iavf_config_rx_queues_irqs()` fully succeeds. If that function fails partway through, its internal error path at `qv_map_alloc_err:` and `efd_alloc_err:` already cleans up its own allocations. The `irq_error:` label in `iavf_dev_start()` should only be reached after line 1089 succeeds.
The code is correct as written: `iavf_config_rx_queues_irqs()` cleans up on its own failure; `iavf_dev_start()` cleans up if IRQ setup succeeded but queue start failed.
**Retraction:** No error here. The cleanup paths are correctly separated.
---
## Patch 6/9: net/iavf: fix generic flow error-path leaks
### Clean
No issues found. The patch correctly unwinds parser registrations on init failure and frees the item array when match-result allocation fails.
---
## Patch 7/9: net/iavf: centralize memory management for flows
### Errors
**Missing validation of filter allocation:**
Line: 1564 in `iavf_fdir_parse()`
The function allocates `filter` via `rte_zmalloc()` at line 1564 and checks for NULL. However, the error path at line 1566 does not set `*meta` to NULL before returning, and the function later (line 1596) conditionally assigns to `*meta` only if `meta != NULL`. If the caller passes a non-NULL `meta` pointer with garbage initial value and allocation fails, the caller sees uninitialized `*meta` rather than a clear failure signal.
Suggested fix: Initialize `*meta = NULL` at the top of the function if `meta != NULL`, or explicitly set it on the error path before returning.
**Use of `rte_errno` without setting it:**
Line: 1568, 1585, 1591 in `iavf_fdir_parse()`
Multiple error paths call `rte_flow_error_set()` but then return `-rte_errno`. If `rte_errno` was not set by the failure (e.g., `ci_flow_check_attr()` or pattern matching failure), the return value may be zero or a stale error code.
Suggested fix: Return a specific error code (e.g., `-EINVAL`) or ensure `rte_errno` is set before each use. The `rte_flow_error_set()` macro does not set `rte_errno` itself.
**Inconsistent freeing of `item` in `iavf_fdir_parse()`:**
Line: 1595 and 1602
The function frees `item` at line 1595 on the success path and again at line 1602 on the error path. If `iavf_fdir_parse_pattern()` fails after `iavf_search_pattern_match_item()` succeeds, execution reaches line 1594 (`goto error`), then line 1602 frees `item`. Correct.
But if `iavf_search_pattern_match_item()` itself fails, it returns NULL and sets `rte_errno`. Line 1585 checks `if (item == NULL)`, sets `ret = -rte_errno`, and does `goto error`. Then line 1602 calls `rte_free(item)` on a NULL pointer. `rte_free(NULL)` is safe, so this is not a bug. However, it is redundant.
Not an error, but could be cleaner: move `rte_free(item)` inside the conditional branches or ensure `item` is always valid before the error label.
---
### Warnings
**Removed per-VF filter structure without checking all references:**
Line: `struct iavf_fdir_info` removal in `iavf.h`
The patch removes `struct iavf_fdir_info` and its instance `vf->fdir`. The commit message states this is now allocated per-parse. However, the removed `vf->fdir.conf` was a persistent scratch buffer. Verify that no code path expected this to survive between calls.
Checked: the old code used `&vf->fdir.conf` as a temporary during parsing and did not rely on it being persistent. The new code allocates `filter` per-parse and returns it as the rule. This is correct.
Not a warning.
---
## Patch 8/9: net/iavf: fix null engine for egress security flows
### Clean
No issues found. The patch correctly registers an egress security engine and routes these flows through normal parsers, avoiding the NULL engine dereference.
---
## Patch 9/9: net/iavf: fix IPsec flow metadata leaks
### Errors
**Incorrect error return on item parse failure:**
Line: 1969 in `iavf_ipsec_flow_parse()`
When `iavf_ipsec_flow_item_parse()` returns NULL at line 1964, the code reaches line 1968 and calls `rte_flow_error_set()`, which sets the error but does not modify `rte_errno`. The function then returns `rte_flow_error_set(...)` directly. The `rte_flow_error_set()` macro returns the error code passed as its second argument (here, `EINVAL`), but that is not the same as `-rte_errno`.
Wait, checking the line numbers: line 1969 has the `return rte_flow_error_set(...)` call. The macro signature is:
```c
static inline int
rte_flow_error_set(struct rte_flow_error *error,
int code,
enum rte_flow_error_type type,
const void *cause,
const char *message)
{
if (error) {
*error = (struct rte_flow_error){
.type = type,
.cause = cause,
.message = message,
};
}
rte_errno = code;
return -code;
}
```
So `rte_flow_error_set(error, EINVAL, ...)` returns `-EINVAL` and sets `rte_errno = EINVAL`. This is correct. No error.
**Retraction:** No issue here.
---
## Summary of Findings
### Errors (1)
**Patch 1/9:**
- Missing `iavf_stop_queues()` call in the new `irq_error:` path when start fails after queue configuration
### Warnings (1)
**Patch 2/9:**
- `iavf_get_eth_dev()` dereferences adapter and dev_data without null checks (acceptable if caller contract guarantees validity, but not documented)
### Info
**Patch 7/9:**
- `iavf_fdir_parse()` could set `*meta = NULL` explicitly on allocation failure for clarity
- Multiple uses of `-rte_errno` where the calling function may not have set `rte_errno`; returning explicit error codes would be safer
---
Review-Result: ERROR
More information about the test-report
mailing list