|WARNING| lpm: fix tbl8 reuse after delete all with RCU defer queue

dpdklab at iol.unh.edu dpdklab at iol.unh.edu
Mon Nov 9 08:32:24 CET 2026


Test-Label: ai-code-review
Test-Status: WARNING
https://dpdk.org/patch/172737

_AI Code Review_

=== Patch Review: series.patch (via Claude) ===
Review date: 2026-11-09

# DPDK Patch Review

## Correctness Bugs

**Error: RCU synchronization logic error**

The patch calls `rte_rcu_qsbr_synchronize()` with `RTE_QSBR_THRID_INVALID` as the thread ID parameter.

```c
rte_rcu_qsbr_synchronize(i_lpm->v, RTE_QSBR_THRID_INVALID);
```

`RTE_QSBR_THRID_INVALID` is used to indicate an invalid/unregistered thread ID. Passing it to `rte_rcu_qsbr_synchronize()` will not wait for any threads at all - it will return immediately without synchronization. This defeats the purpose of the fix, which is to wait for readers before reclaiming deferred tbl8 groups.

The correct approach is to wait for all registered threads. According to the RCU QSBR API, this is done by calling `rte_rcu_qsbr_synchronize()` without specifying a thread ID (pass `RTE_QSBR_THRID_INVALID` only if you want to wait for a specific thread that you know is registered, or use the proper wait-for-all semantics).

Looking at the DPDK RCU documentation, to wait for all reader threads, you should iterate through registered threads or use the proper API pattern. However, the simpler and correct approach here is:

```c
if (i_lpm->dq != NULL) {
    rte_rcu_qsbr_synchronize(i_lpm->v, RTE_QSBR_THRID_INVALID);
```

Actually, reviewing the RCU QSBR API more carefully: `rte_rcu_qsbr_synchronize()` waits for all registered threads to enter quiescent state. The thread ID parameter should be the thread calling the function (which may not be registered as a reader). If the control plane thread is not registered, passing `RTE_QSBR_THRID_INVALID` may be correct.

However, there's a more fundamental issue: the patch assumes that calling `rte_rcu_qsbr_synchronize()` once is sufficient, but this only ensures that readers have passed through a quiescent state. It doesn't guarantee that all deferred reclamations have completed if readers are still active. The defer queue may contain multiple batches of deferred work.

**Suggested fix**: Call `rte_rcu_qsbr_dq_reclaim()` with `~0U` (unlimited) as the `n` parameter instead of `i_lpm->number_tbl8s`, to ensure all pending entries are reclaimed:

```c
if (i_lpm->dq != NULL) {
    rte_rcu_qsbr_synchronize(i_lpm->v, RTE_QSBR_THRID_INVALID);
    rte_rcu_qsbr_dq_reclaim(i_lpm->dq, ~0U, NULL, NULL, NULL);
}
```

But verify whether `RTE_QSBR_THRID_INVALID` is correct for your use case. If the calling thread should be registered, pass its thread ID instead.

---

**Warning: Incorrect reclaim limit parameter**

```c
rte_rcu_qsbr_dq_reclaim(i_lpm->dq, i_lpm->number_tbl8s,
    NULL, NULL, NULL);
```

The second parameter to `rte_rcu_qsbr_dq_reclaim()` is the maximum number of entries to reclaim. Using `i_lpm->number_tbl8s` limits reclamation to that number of entries. However, if the defer queue has accumulated more entries (e.g., through multiple add/delete cycles), not all of them will be reclaimed.

Since `rte_lpm_delete_all()` is clearing the entire table, all deferred work should be processed. The limit should be `~0U` (unlimited) to ensure complete reclamation:

```c
rte_rcu_qsbr_dq_reclaim(i_lpm->dq, ~0U, NULL, NULL, NULL);
```

---

## C Coding Style

**Warning: NULL pointer comparison not explicit**

The comparison `i_lpm->dq != NULL` should be written as:
```c
if (i_lpm->dq != NULL)
```

This is already correct in the patch - no issue here. (Removing this from the review per guidelines.)

---

## Testing

**Info: Test could be more comprehensive**

The test validates the basic fix but could be strengthened:

1. The test doesn't register any reader threads with the RCU QSBR variable. Consider adding `rte_rcu_qsbr_thread_register()` and periodic `rte_rcu_qsbr_quiescent()` calls in a loop to better simulate real-world usage where readers are active.

2. The test only uses a single tbl8 group (`number_tbl8s = 1`). Testing with 2-3 groups would verify that all deferred entries are reclaimed, not just the first `number_tbl8s` entries.

3. Consider adding a lookup for `ip1` after `delete_all()` to verify it's truly gone.

These are enhancements rather than requirements - the existing test does validate the core fix.

---

## Documentation

**Warning: Missing release notes**

This is a bug fix with a Fixes tag and Cc: stable. The fix should be documented in `doc/guides/rel_notes/release_26_11.rst` (or the current release notes file for DPDK 26.11) under the "Fixed Issues" section.

Example entry:
```
* **lpm: Fixed tbl8 group corruption after delete_all with RCU defer queue.**

  In RCU defer queue mode, ``rte_lpm_delete_all()`` did not reclaim pending
  tbl8 groups, causing use-after-free when groups were reused for new rules.
  The function now synchronizes and reclaims all deferred work before returning.
```

---

Review-Result: ERROR


More information about the test-report mailing list