On Wed,  4 Dec 2024 09:47:36 +0000
Anatoly Burakov <[email protected]> wrote:

> It has been suggested [1] that a major cleanup/rewrite of devbind would be
> beneficial in terms of long term maintainability of the code. I was in a
> coding mood over the weekend, and so I've went ahead and rewritten devbind.
> 
> Note that this is one giant patch, rather than a series of patches adjusting
> existing code. Making it a patch series is possible, however the internal
> code architecture diverges quite significantly from the original devbind
> script due to its copious usage of string operations/pattern matching and
> global variables, so it is unclear whether subdividing this patch would be
> worth the effort. Instead, as has been suggested [2], the patchset now
> consists of creating a new file, followed by a removal of old file and
> rename of the new file. It is expected that this will be squashed on apply.
> 
> The script has become slightly bigger - 1000 lines instead of 800, however
> I would argue that since most of that increase is infrastructure, comments,
> and sacrificing code golf for code readability (such as expanding one-liners
> into multiple lines), the trade-off between being able to read and reason
> about what happens in the script is worth the added line count.
> 
> [1] 
> https://patches.dpdk.org/project/dpdk/patch/c2bf00195c2d43833a831a9cc9346b4606d6ea2e.1723810613.git.anatoly.bura...@intel.com/
> [2] 
> https://patches.dpdk.org/project/dpdk/cover/[email protected]/
> 
> Anatoly Burakov (2):
>   usertools/devbind: update coding style
>   usertools/devbind: replace devbind
> 
>  doc/guides/tools/devbind.rst |   11 +
>  usertools/dpdk-devbind.py    | 1683 ++++++++++++++++++----------------
>  2 files changed, 924 insertions(+), 770 deletions(-)
> 

This patch seemed to get no reviews. So sent it to AI; especially since my 
python-fu is rudimentary.
It identified some small things, could you fix those and resubmit.

# DPDK Patch Review: usertools/devbind rewrite

**Series**: [PATCH v3 1/2] usertools/devbind: update coding style  
**Author**: Anatoly Burakov <[email protected]>  
**Reviewer**: Stephen Hemminger <[email protected]>

---

## Overview

This is a 2-patch series providing a complete rewrite of `dpdk-devbind.py`:

1. **Patch 1/2**: Introduces the new rewritten script as `dpdk-devbind-new.py`
2. **Patch 2/2**: Replaces the original script with the rewritten version

The rewrite brings significant improvements including PEP-484 type hints, 
modern Python idioms with context managers, structured classes, JSON parsing 
for `ip route` output, and deprecation of kernel <3.15 support.

---

## Errors (Must Fix)

### 1. Tag Formatting Error (Patch 1)
**Line 96:**
```
Reviewed-By: Stephen Hemminger <[email protected]>
```
Should be:
```
Reviewed-by: Stephen Hemminger <[email protected]>
```
The `By` should be lowercase. DPDK tag format is `Reviewed-by:`.

### 2. Typo in Variable Name
**Line 325:**
```python
BASEDBAND_DEVICES = [CLASS_ACCELERATION]
```
Should be:
```python
BASEBAND_DEVICES = [CLASS_ACCELERATION]
```
This typo is referenced at line 369 as well.

### 3. Typo in Error Message  
**Line 820:**
```python
raise DevbindError(f"CLeanup failed for {dev}: {e}") from e
```
Should be:
```python
raise DevbindError(f"Cleanup failed for {dev}: {e}") from e
```

---

## Warnings (Should Fix)

### 4. Docstring Inconsistency
**Line 452-453:**
```python
def read_output(args: T.List[str]) -> str:
    """Run a subprocess, collect its output, and return it as a list of 
lines."""
```
The docstring says "list of lines" but the function returns a `str`. Either 
update the docstring to say "return it as a string" or change the return type.

### 5. `--noiommu-mode` Flag Not Checked
**Lines 876-877:**
```python
if use_vfio and not sysfs_iommu_enabled():
    sysfs_enable_unsafe_noiommu()
```
The `ctx.noiommu` flag is parsed (line 1100) but the code unconditionally 
enables no-IOMMU mode when IOMMU is disabled, regardless of whether the user 
specified `--noiommu-mode`. The original devbind required the flag to be 
explicitly set. Consider:
```python
if use_vfio and not sysfs_iommu_enabled():
    if not ctx.noiommu:
        raise DevbindError(
            "IOMMU not available. Use --noiommu-mode to enable unsafe no-IOMMU 
mode."
        )
    sysfs_enable_unsafe_noiommu()
```

### 6. No Unit Tests Added
A rewrite of this magnitude would benefit from unit tests in `app/test` or at 
minimum a standalone test script. Consider adding tests for:
- Device pattern matching
- lspci line parsing
- Argument parsing edge cases

### 7. Patch 2/2 Missing Commit Message Body
**Line 1213:**
The second patch has only `Signed-off-by:` with no commit message body 
explaining what it does. Even simple patches should have a brief description.

---

## Info (Suggestions)

### 8. File Mode for Bind Operation
**Line 807:**
```python
with open(bind_path, "a", encoding="utf-8") as f:
    f.write(dev.slot)
```
Using append mode (`"a"`) for writing to sysfs bind file is unusual. While it 
likely works, write mode (`"w"`) is more conventional and matches what the 
kernel expects. Consider changing to `"w"`.

### 9. Null Byte for driver_override Cleanup
**Line 818:**
```python
f.write("\00")
```
Writing a null byte works, but an empty string or newline might be more 
portable/conventional:
```python
f.write("")
```

### 10. Generator Consumed Multiple Times Risk
**Line 862:**
```python
devices = (devbind.pci_devices[dbdf] for dbdf in ctx.devices)
```
This creates a generator that can only be iterated once. If the code path were 
to iterate it multiple times, this would silently fail. Consider using a list 
comprehension instead:
```python
devices = [devbind.pci_devices[dbdf] for dbdf in ctx.devices]
```

### 11. Consider Using `shutil.which()` Instead of `subprocess`
**Lines 446-449:**
```python
if subprocess.call(
    ["which", program], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL
):
```
Python 3.3+ provides `shutil.which()` which is more Pythonic:
```python
import shutil
if shutil.which(program) is None:
```

### 12. Documentation Formatting
**Lines 129-138 in doc/guides/tools/devbind.rst:**
The added documentation has a double blank line after line 128. RST typically 
uses single blank lines.

---

## Positive Observations

The rewrite demonstrates excellent software engineering:

- **Type Safety**: Comprehensive PEP-484 type annotations throughout
- **Modern Python**: Context managers, dataclasses pattern, proper exception 
hierarchy
- **Code Organization**: Clean separation with `Device`, `Devbind`, and 
`DevbindCtx` classes
- **Error Handling**: Consistent `DevbindError` exception with clear messages
- **Resource Management**: All file operations use context managers
- **JSON Parsing**: Using `ip -j route` for structured output is much better 
than text parsing
- **Reduced External Calls**: Fewer lspci invocations, unified parsing
- **Backward Compatibility**: Command-line interface remains compatible

---

## Summary

| Severity | Count |
|----------|-------|
| Error    | 3     |
| Warning  | 4     |
| Info     | 5     |

**Recommendation**: Fix the three errors (tag case, two typos) and address the 
`--noiommu-mode` logic, then this is ready for merge. The rewrite is a 
significant improvement over the original code.

---

## Checklist

- [x] SPDX license identifier present
- [x] Copyright line present  
- [x] Signed-off-by present
- [ ] Reviewed-by tag correctly formatted
- [x] Subject line ≤60 characters
- [x] Subject lowercase (except acronyms)
- [x] Imperative mood
- [x] No trailing period
- [x] Lines ≤100 characters (Python allows this)
- [x] Documentation updated
- [ ] Tests added/updated

Reply via email to