docs: add DPDK-accelerated underlay enhancement - #549
Conversation
Summary of ChangesHello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed! This pull request proposes a design enhancement to optimize the underlay datapath for Grout by bypassing the kernel. By allowing the direct binding of SR-IOV Virtual Functions to DPDK, the system achieves line-rate forwarding for underlay traffic. The changes include a new API configuration for GroutPort, comprehensive VF selection mechanisms, and a strategy for managing IPAM and port lifecycle in a user-space environment. Highlights
New Features🧠 You can now enable Memory (public preview) to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console. Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize the Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counterproductive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here. Footnotes
|
There was a problem hiding this comment.
Code Review
This pull request introduces a design proposal for DPDK-accelerated underlay ports in Grout, replacing the TAP-based underlay mechanism with direct DPDK port attachment using SR-IOV Virtual Functions. The review feedback highlights several inconsistencies and areas for improvement in the design document: the overview table uses 'CNIDevice' instead of the API enum 'CNI'; the 'VF Selection' table is missing the 'netdevName' selector; the YAML examples do not match the proposed Go API types due to missing 'vfSelector' nesting and type discriminators; the IPAM validation needs CEL rules to properly enforce the dual-stack constraint of at most one IPv4 and one IPv6 address; and there is a typo ('CTODO') in the 'GroutPortOptions' struct.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
| | Mode | Behavior | IPAM | Datapath | | ||
| |------|----------|------|----------| | ||
| | `NetworkDevice` | Moves host device; grout creates TAP+`remote=` | Native (CIDR-derived) | TAP PMD (kernel TC redirect) | | ||
| | `CNIDevice` | Invokes CNI plugin | Delegated to CNI | Kernel or TAP PMD | | ||
| | `GroutPort` | Binds a VF to grout as a DPDK port | Inline in spec | DPDK PMD (user-space) | |
There was a problem hiding this comment.
The table lists the mode as CNIDevice, but the actual enum value in the API types is CNI (as defined in UnderlayInterface and used in the YAML examples of the previous enhancement). It would be clearer to use CNI in the table to avoid confusion.
Suggested change:
| Mode | Behavior | IPAM | Datapath |
|------|----------|------|----------|
| `NetworkDevice` | Moves host device; grout creates TAP+`remote=` | Native (CIDR-derived) | TAP PMD (kernel TC redirect) |
| `CNI` | Invokes CNI plugin | Delegated to CNI | Kernel or TAP PMD |
| `GroutPort` | Binds a VF to grout as a DPDK port | Inline in spec | DPDK PMD (user-space) |There was a problem hiding this comment.
I think gemini hallucinated.
Let's align everything w/ the Device suffix - please call this new attribute GroutDevice.
| | Selector | Use case | | ||
| |----------|----------| | ||
| | `pciAddress` | Exact VF PCI Address (e.g. `0000:03:02.0`) | | ||
| | `pfName`, `vfIndex` | PF name + VF index (e.g. `enp3s0f0` + `2`) | | ||
|
|
There was a problem hiding this comment.
The VFSelector union struct defines NetdevName as a valid selector option, and the resolution flow describes how it is resolved. However, it is missing from the "VF Selection" summary table. It should be added for completeness.
Suggested change:
| Selector | Use case |
|----------|----------|
| `pciAddress` | Exact VF PCI Address (e.g. `0000:03:02.0`) |
| `netdevName` | VF Netdev Name (e.g. `eth1`) |
| `pfName`, `vfIndex` | PF name + VF index (e.g. `enp3s0f0` + `2`) || groutPort: | ||
| pciAddress: "0000:03:02.0" | ||
| ipam: | ||
| addresses: | ||
| - 192.168.1.10/24 |
There was a problem hiding this comment.
The YAML example does not match the proposed Go API types. GroutPortConfig contains a nested VFSelector struct under the vfSelector field, which is a union and requires a type discriminator. The fields pciAddress and ipam are currently shown directly under groutPort without the vfSelector wrapper.
| groutPort: | |
| pciAddress: "0000:03:02.0" | |
| ipam: | |
| addresses: | |
| - 192.168.1.10/24 | |
| groutPort: | |
| vfSelector: | |
| type: PCIAddress | |
| pciAddress: "0000:03:02.0" | |
| ipam: | |
| addresses: | |
| - 192.168.1.10/24 |
| groutPort: | ||
| pfName: enp3s0f0 | ||
| vfIndex: 0 | ||
| ipam: | ||
| addresses: | ||
| - 192.168.1.10/24 |
There was a problem hiding this comment.
Similar to the first example, the YAML here does not match the proposed Go API types. The pfName and vfIndex fields should be nested under vfSelector.pfVFIndex, and the type discriminator PFVFIndex must be specified.
| groutPort: | |
| pfName: enp3s0f0 | |
| vfIndex: 0 | |
| ipam: | |
| addresses: | |
| - 192.168.1.10/24 | |
| groutPort: | |
| vfSelector: | |
| type: PFVFIndex | |
| pfVFIndex: | |
| pfName: enp3s0f0 | |
| vfIndex: 0 | |
| ipam: | |
| addresses: | |
| - 192.168.1.10/24 |
| type GroutPortIPAM struct { | ||
| // At most one IPv4 and one IPv6 (dual-stack). | ||
| // +kubebuilder:validation:MinItems=1 | ||
| // +kubebuilder:validation:MaxItems=2 | ||
| Addresses []string `json:"addresses"` | ||
| } |
There was a problem hiding this comment.
The comment states "At most one IPv4 and one IPv6 (dual-stack)." However, the kubebuilder validation only limits the slice size to 2 (MaxItems=2). To enforce the dual-stack constraint (preventing two IPv4 or two IPv6 addresses), CEL validation rules should be added, similar to those used in TunnelEndpointConfig.
Suggested change:
type GroutPortIPAM struct {
// At most one IPv4 and one IPv6 (dual-stack).
// +kubebuilder:validation:MinItems=1
// +kubebuilder:validation:MaxItems=2
// +kubebuilder:validation:XValidation:rule="self.all(c, isCIDR(c))",message="all entries must be valid CIDRs"
// +kubebuilder:validation:XValidation:rule="self.filter(c, isCIDR(c) && cidr(c).ip().family() == 4).size() <= 1",message="at most one IPv4 address is allowed"
// +kubebuilder:validation:XValidation:rule="self.filter(c, isCIDR(c) && cidr(c).ip().family() == 6).size() <= 1",message="at most one IPv6 address is allowed"
Addresses []string `json:"addresses"`
}| // +kubebuilder:validation:Maximum=64 | ||
| RXQueues *int `json:"rxQueues,omitempty"` | ||
|
|
||
| CTODO - add fields [mtu MTU],[rxqs N_RXQ], [qsize Q_SIZE] |
There was a problem hiding this comment.
| - **Support IPAM for DPDK-bound interfaces.** A VF bound to a DPDK | ||
| driver has no kernel netdev, so CNI IPAM plugins cannot assign an IP | ||
| to it. `GroutPort` carries inline IPAM applied via `grcli`. |
There was a problem hiding this comment.
Slight precision needed: bifurcated DPDK drivers do have a kernel netdev which is used (required in fact) only for control plane operations (MTU change, link state, mac address filter, etc.). But the IP address must not be configured on it.
|
|
||
| | Risk | Mitigation | | ||
| |------|------------| | ||
| | VF not available (not created, already bound) | Clear error at reconcile with PCI address and resolution source | |
There was a problem hiding this comment.
What component is expected to allocate the VFs? Should it be delegated to nmstate?
If so, who will take care of re-binding the device to vfio-pci (most DPDK drivers) or move the linux netdev to the router namespace (bifurcated drivers, e.g. mlx5)?
There was a problem hiding this comment.
What component is expected to allocate the VFs? Should it be delegated to nmstate?
yes, either nmstate or any other configuration would be on the user. At least at this stage of the development.
If so, who will take care of re-binding the device to vfio-pci (most DPDK drivers) or move the linux netdev to the router namespace (bifurcated drivers, e.g. mlx5)?
For vfio-pci driver, the controller will do nothing on the VF during setup/teardown. Just passing the PCIAddress to a grcli interaface add ...
For bifurcated drivers, the controller will also move the netlink in and out of the perouter namespace during setup/teardown
57d8ed4 to
8622fca
Compare
| a VF directly via DPDK so that underlay traffic avoids the kernel | ||
| entirely and achieves line-rate forwarding. | ||
|
|
||
| #### Story 2: VF Selection by PCI Address |
There was a problem hiding this comment.
why a user would want this if they have story 3? Also, the pci address is likely to be different on each node I think
There was a problem hiding this comment.
In real applications, this lets you bind PFs without needing to use SR-IOV or VFs.
for testing purposes, this will become useful when we'll deal with qEMU environment.
There was a problem hiding this comment.
In real applications, this lets you bind PFs without needing to use SR-IOV or VFs.
not sure I understood what you mean by "needing to user sr-iov"
for testing purposes, this will become useful when we'll deal with qEMU environment.
There was a problem hiding this comment.
In real applications, this lets you bind PFs without needing to use SR-IOV or VFs.
not sure I understood what you mean by "needing to user sr-iov"
for testing purposes, this will become useful when we'll deal with qEMU environment.
A DPDK application can run on a Physical Function by using its PCI address. The fact that the SR-IOV technology has been invented is to let multiple DPDK application use the same NIC, each of them using a different VF. But it's not mandatory.
Also, there are NICs that does not support SR-IOV (i.e. VFs) but can be used by Grout and DPDK.
@rjarry do you mind checking this last statement?
There was a problem hiding this comment.
fine, but then we need to reword where we talk about vfs because it's not really only about vfs.
There was a problem hiding this comment.
Sorry I had missed this notification. Yes it would make sense you allow selecting interfaces by explicit PCI address for qemu testing purposes (qemu igc emulated sriov devices do not handle VF to VF communication unless the same vlan id is explicitly configured on the two VFs hardware filters (which grout does not do). Since we need one of the VFs to be a "trunk", we cannot use that solution to run virtualized tests.
The alternative solution is to use plain virtio interfaces and give them to grout as PFs. Then plug the host side tap interfaces to a Linux bridge that will perform the vlan switching (emulating the internal igc VF switch).
| |------|----------|------|----------| | ||
| | `NetworkDevice` | Moves host device; grout creates TAP+`remote=` | Native (CIDR-derived) | TAP PMD (kernel TC redirect) | | ||
| | `CNI` | Invokes CNI plugin | Delegated to CNI | Kernel | | ||
| | `GroutPort` | Binds a VF to grout as a DPDK port | Inline in spec | DPDK PMD (user-space) | |
There was a problem hiding this comment.
I feel like groutport is a bit generic. We should mention it's a sriov vf, and optionally that it relates to grout. Something like acceleratedVF? FastDatapathVF? dpdkVF?
There was a problem hiding this comment.
It can also be a Physical Function.
Besides that, I'm open to suggestions
There was a problem hiding this comment.
but the enhancement describes vfs only, mind expanding then?
There was a problem hiding this comment.
updated the description
| 3. **Create grout port** — | ||
| `grcli interface add port u_<name> devargs <pci> [mtu MTU] [rxqs N_RXQ] [qsize Q_SIZE]` | ||
| Options are appended only when set in `portOptions`. | ||
| 4. **Assign addresses** — |
There was a problem hiding this comment.
how are addresses assigned? The proposal doesn't say that
There was a problem hiding this comment.
That's a good point, and I'm still in the process of defining it.
My current ideas are:
a. put an GroutDevice.Addresses map[string]string[] map array with all the addresses to add to the port for each node (the map is nodeName -> list of addresses)
b. add a GroutDevice.CIDR field and use the nodeIndex to assign IP Address.
c. The user puts the addresses on the network device and the perouter reads them. This is my favorite, but it also implies
c1. The perouter takes care of binding/unbinding the driver of the device (i.e. an Intel device is configured by the user as a netlink device, then the controller saves the addresses to a file and binds the vfio-pci driver)
c2. The controller needs to store the IP addresses in some persistence layer, make the SetupUnderlay a stateful operation
| - **PFVFIndex**: read symlink `/sys/class/net/<pf>/device/virtfn<idx>`, | ||
| extract PCI address from target path. | ||
|
|
||
| *Optional*: The resolved PCI address is stored in Underlay status for observability. |
There was a problem hiding this comment.
we don't have underlay status
| PFName *string `json:"pfName,omitempty"` | ||
| // +kubebuilder:validation:Minimum=0 | ||
| VFIndex *int `json:"vfIndex,omitempty"` | ||
| IPAM GroutPortIPAM `json:"ipam"` |
There was a problem hiding this comment.
do we envision allowing dhcp too?
There was a problem hiding this comment.
integrating grout w/ any CNI based approach will not be straightforward.
Grout takes away the IPs to the user space, which will cause CNI CHECK to fail.
This integration deserves - IMHO - a separate enhancement (or a new chapter focusing on the grout integration).
| | Mode | Behavior | IPAM | Datapath | | ||
| |------|----------|------|----------| | ||
| | `NetworkDevice` | Moves host device; grout creates TAP+`remote=` | Native (CIDR-derived) | TAP PMD (kernel TC redirect) | | ||
| | `CNIDevice` | Invokes CNI plugin | Delegated to CNI | Kernel or TAP PMD | | ||
| | `GroutPort` | Binds a VF to grout as a DPDK port | Inline in spec | DPDK PMD (user-space) | |
There was a problem hiding this comment.
I think gemini hallucinated.
Let's align everything w/ the Device suffix - please call this new attribute GroutDevice.
| PFName *string `json:"pfName,omitempty"` | ||
| // +kubebuilder:validation:Minimum=0 | ||
| VFIndex *int `json:"vfIndex,omitempty"` | ||
| IPAM GroutPortIPAM `json:"ipam"` |
There was a problem hiding this comment.
integrating grout w/ any CNI based approach will not be straightforward.
Grout takes away the IPs to the user space, which will cause CNI CHECK to fail.
This integration deserves - IMHO - a separate enhancement (or a new chapter focusing on the grout integration).
8622fca to
2848444
Compare
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughThe proposal adds opt-in DPDK attachment for ChangesGrout DPDK underlay
Estimated code review effort: 2 (Simple) | ~10 minutes Sequence Diagram(s)sequenceDiagram
participant Controller
participant SysfsNetlink
participant Grout
participant FRR
Controller->>SysfsNetlink: Resolve interfaceName to PCI device
Controller->>SysfsNetlink: Persist state and bind the DPDK driver
Controller->>Grout: Create and configure the Grout port
Controller->>Grout: Migrate IP addresses
Controller->>FRR: Install the connected route
Controller->>Grout: Remove the Grout port during teardown
Controller->>SysfsNetlink: Restore driver, namespace, and IP state
Possibly related PRs
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 6
🧹 Nitpick comments (2)
enhancements/grout-dpdk-underlay.md (2)
246-256: 🎯 Functional Correctness | 🔵 Trivial | 🏗️ Heavy liftMake the test plan exercise
GroutDevice.The Kind tests use
net_tap, so they do not test VF resolution or DPDK port creation. Add tests for sysfs selector resolution, VF validation, port options, inline IPAM, idempotent reconciliation, namespace-move rollback, and address/route teardown.Replace
VFSelectorwith tests for the inlinepciAddress,pfName, andvfIndexfields defined above.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@enhancements/grout-dpdk-underlay.md` around lines 246 - 256, The Test Plan should explicitly exercise GroutDevice behavior beyond net_tap port creation: add coverage for sysfs selector resolution using inline pciAddress, pfName, and vfIndex fields, VF validation, DPDK port options, inline IPAM, idempotent reconciliation, namespace-move rollback, and address/route teardown. Remove the VFSelector sub-struct validation reference and replace it with validation tests for the inline selector fields.
48-58: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winFix skipped Markdown heading levels.
Use
###for the story headings under## User Stories. Use####for the example headings under### API Examples. This resolves the reportedMD001warnings and preserves document navigation.Also applies to: 111-111
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@enhancements/grout-dpdk-underlay.md` around lines 48 - 58, Update the story headings in the documentation to use ### beneath the ## User Stories section, and use #### for example headings beneath ### API Examples. Apply the same heading-level corrections to the corresponding later section identified in the diff.Source: Linters/SAST tools
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@enhancements/grout-dpdk-underlay.md`:
- Around line 101-105: Define a deterministic interface-name derivation from
GroutPortConfig and use it consistently in port creation, address assignment,
route operations, and deletion. Replace raw interface add and repeated
address-add operations with idempotent ensure/update reconciliation so retries
after partial success converge without duplicate resources, while preserving
existing port options.
- Around line 94-107: Update the setup flow around the namespace move and
subsequent grout port, address, and route creation to track completed steps and
clean them up in reverse order when any later step fails, including moving the
netlink device back to its original namespace. Make cleanup idempotent so
retries do not fail when resources are already absent, and preserve the existing
successful setup behavior.
- Around line 221-225: Update the PCIAddress handling described in the sysfs
validation flow to verify the selected PCI node is an SR-IOV VF and has a
supported driver before allowing grcli interface add; reject PFs and unrelated
devices. If PF selection is intended, explicitly revise the API and safety rules
to document and enforce that behavior.
- Around line 104-107: Expand the “Kernel route for FRR” section to define FRR’s
execution context, the interface or forwarding path used to reach Grout for BGP
traffic, and the local endpoint and ARP/ND behavior for both vfio-pci and
bifurcated-driver cases. Document the corresponding teardown steps that remove
the route and any FRR-to-Grout connectivity state.
- Around line 66-74: Extend the underlay reconciliation pipeline in
internal/grout/underlay.go to recognize GroutDevice alongside
UnderlayInterfaceNetDev and UnderlayInterfaceCNIDev, including its internal kind
and API-to-hostnetwork conversion. Add the corresponding RestoreUnderlay cleanup
branch so GroutDevice reaches grcli and is restored correctly instead of
returning unsupported kind.
- Around line 164-173: Update UnderlayInterface in
api/v1alpha1/underlay_types.go rather than replacing its existing API contract:
retain UnderlayInterfaceType, the CNIDevice discriminator value, and the
existing NetworkDevice and CNIDevice payload types, while adding GroutDevice
with the corresponding grout-port payload. Mark Type as required and configure
union validation so the discriminator selects exactly one matching payload.
---
Nitpick comments:
In `@enhancements/grout-dpdk-underlay.md`:
- Around line 246-256: The Test Plan should explicitly exercise GroutDevice
behavior beyond net_tap port creation: add coverage for sysfs selector
resolution using inline pciAddress, pfName, and vfIndex fields, VF validation,
DPDK port options, inline IPAM, idempotent reconciliation, namespace-move
rollback, and address/route teardown. Remove the VFSelector sub-struct
validation reference and replace it with validation tests for the inline
selector fields.
- Around line 48-58: Update the story headings in the documentation to use ###
beneath the ## User Stories section, and use #### for example headings beneath
### API Examples. Apply the same heading-level corrections to the corresponding
later section identified in the diff.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: 816ee8f0-0baa-4ff3-bfc5-121fbbf2f177
📒 Files selected for processing (1)
enhancements/grout-dpdk-underlay.md
6a83fcb to
8a606e0
Compare
There was a problem hiding this comment.
Actionable comments posted: 5
🧹 Nitpick comments (1)
enhancements/grout-dpdk-underlay.md (1)
317-325: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winExercise
GroutDevicein the test plan.The Kind test uses
net_tapdevargs, which tests the existing TAP path rather than PCI DPDK binding. Add tests for selector resolution, driver and IP migration, state recovery, route cleanup, and retry behavior.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@enhancements/grout-dpdk-underlay.md` around lines 317 - 325, Update the Test Plan section to explicitly exercise GroutDevice beyond the net_tap path, covering selector resolution, driver and IP migration, state recovery, route cleanup, and retry behavior; retain the existing Kind and QEMU E2E coverage.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@enhancements/grout-dpdk-underlay.md`:
- Around line 326-327: Update the validation tests described in the GroutDevice
test plan to use the declared flat selector fields in GroutDeviceConfig rather
than a VFSelector sub-struct. Cover no selector, multiple selector groups,
missing vfIndex, missing pfName, and valid pciAddress, PF-name/vfIndex, and
netlinkName selector combinations.
- Around line 105-107: Resolve the GroutDevice IPAM behavior consistently across
the document: choose either API-supplied inline addresses or preconfigured host
addresses, then align selector validation, port setup, route handling, teardown,
risk-table requirements, and examples with that choice. Update the referenced
sections so the minimum address requirement and rejected/accepted inputs are
identical everywhere.
- Around line 120-123: Update the Underlay setup flow around saving original
state to reserve each PCI device before any host mutation or shared state write.
Acquire a per-PCI reservation, then atomically create the state file with the
owning resource identity; reject competing owners before allowing them to
overwrite originalDriver or addresses. Apply the same reservation and ownership
handling to the corresponding flows identified near the other referenced
sections, and release the reservation during teardown.
- Line 57: The four user story headings (including Story 1: High-Throughput
Underlay and the other stories at lines 62, 66, 71) are currently using level-4
heading syntax (####) but should use level-3 heading syntax (###) since they are
direct children under the ## User Stories section. Update each of these four
story headings from #### to ### to establish the correct hierarchy. The API
Examples sections that appear under each story (at lines 140, 164, 186) should
remain as level-4 headings (####) as they are nested under the story sections.
- Around line 295-301: Update the DPDK teardown restore-driver flow to first
unbind the PCI device from its current driver, including vfio-pci, before
writing it to the original driver’s bind file. After rebinding, verify the
device’s driver symlink points to the recorded original driver, while preserving
the bifurcated-driver netlink move behavior.
---
Nitpick comments:
In `@enhancements/grout-dpdk-underlay.md`:
- Around line 317-325: Update the Test Plan section to explicitly exercise
GroutDevice beyond the net_tap path, covering selector resolution, driver and IP
migration, state recovery, route cleanup, and retry behavior; retain the
existing Kind and QEMU E2E coverage.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: 2e8fddd7-b9ce-4fed-beaa-b7e4f2c8465b
📒 Files selected for processing (1)
enhancements/grout-dpdk-underlay.md
|
|
||
| ## User Stories | ||
|
|
||
| #### Story 1: High-Throughput Underlay |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
Fix the Markdown heading hierarchy.
Use level-3 headings for the four user stories under ## User Stories. Use level-4 headings for the API examples under ### API Examples. This resolves markdownlint MD001.
Also applies to: 62-62, 66-66, 71-71, 140-140, 164-164, 186-186
🧰 Tools
🪛 markdownlint-cli2 (0.23.1)
[warning] 57-57: Heading levels should only increment by one level at a time
Expected: h3; Actual: h4
(MD001, heading-increment)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@enhancements/grout-dpdk-underlay.md` at line 57, The four user story headings
(including Story 1: High-Throughput Underlay and the other stories at lines 62,
66, 71) are currently using level-4 heading syntax (####) but should use level-3
heading syntax (###) since they are direct children under the ## User Stories
section. Update each of these four story headings from #### to ### to establish
the correct hierarchy. The API Examples sections that appear under each story
(at lines 140, 164, 186) should remain as level-4 headings (####) as they are
nested under the story sections.
Source: Linters/SAST tools
There was a problem hiding this comment.
yes, this should be using level 3 headings (remove one hash).
There was a problem hiding this comment.
@maiqueb, agreed. Change each user story heading from #### to ###. Keep the nested #### API Examples headings unchanged.
You are interacting with an AI system.
| 2. **Save original state** — Read the IP addresses from the netlink | ||
| device and the current kernel driver name (from | ||
| `/sys/bus/pci/devices/<addr>/driver`). Write both to a per-device | ||
| state file at `/var/run/openperouter/grout/<pci-address>.json`. |
There was a problem hiding this comment.
🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift
Reserve the PCI device before writing shared state.
Two Underlays can write the same /var/run/openperouter/grout/<pci-address>.json before grcli reports the device as busy. The later write can replace originalDriver and addresses; teardown can then restore the wrong state or disrupt the active owner. Acquire a per-PCI reservation and atomically create state with the owning resource identity before any host mutation.
Also applies to: 257-272, 315-315
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@enhancements/grout-dpdk-underlay.md` around lines 120 - 123, Update the
Underlay setup flow around saving original state to reserve each PCI device
before any host mutation or shared state write. Acquire a per-PCI reservation,
then atomically create the state file with the owning resource identity; reject
competing owners before allowing them to overwrite originalDriver or addresses.
Apply the same reservation and ownership handling to the corresponding flows
identified near the other referenced sections, and release the reservation
during teardown.
There was a problem hiding this comment.
@maiqueb, agreed. The proposal should define a per-PCI reservation before it writes the state file or changes the device. The state file should record the owning Underlay identity and use atomic creation. Teardown should verify ownership before restoration and release the reservation after successful cleanup.
🐇 ✅
You are interacting with an AI system.
There was a problem hiding this comment.
are you sure? do we handle multiple Underlays host configuration in parallel for the kernel datapath?
also, do we need to handle the case two different Underlays objects target the same device? Isn't it handled by webhooks?
There was a problem hiding this comment.
Seems like the humans are having a chat. I'll hop back into my burrow for now. If you need me again, just tag @coderabbitai in a new comment, and I'll come hopping out!
There was a problem hiding this comment.
are you sure? do we handle multiple Underlays host configuration in parallel for the kernel datapath? also, do we need to handle the case two different Underlays objects target the same device? Isn't it handled by webhooks?
you're right to push back - we can't have multiple underlays targeting the same node. My bad on not realizing the implications of this comment.
8a606e0 to
a50b84d
Compare
| a VF directly via DPDK so that underlay traffic avoids the kernel | ||
| entirely and achieves line-rate forwarding. | ||
|
|
||
| #### Story 2: VF Selection by PCI Address |
There was a problem hiding this comment.
fine, but then we need to reword where we talk about vfs because it's not really only about vfs.
| index so that the controller resolves the correct VF without requiring | ||
| me to look up PCI addresses. | ||
|
|
||
| #### Story 4: VF Selection by Netlink Name |
| ```go | ||
| // +union | ||
| type UnderlayInterface struct { | ||
| // +kubebuilder:validation:Enum=NetworkDevice;CNI;GroutDevice |
There was a problem hiding this comment.
wrong indentation? github is showing this differently
| |------|----------|------|----------| | ||
| | `NetworkDevice` | Moves host device; grout creates TAP+`remote=` | Native (CIDR-derived) | TAP PMD (kernel TC redirect) | | ||
| | `CNIDevice` | Invokes CNI plugin | Delegated to CNI | Kernel | | ||
| | `GroutDevice` | Binds a network device to grout as a DPDK port | Scraped from kernel netdev | DPDK PMD (user-space) | |
There was a problem hiding this comment.
I am having second thoughs about this. We are mixing how we are selecting the interface and what we are going to do with them.
Basically, when we run in grout mode, the differences between networkdevice and groutdevice.netlink name is only how we are going to operate it.
I wonder if the selection mechanism should be part of networkdevice in any case, with networkdevice being expanded as what you are suggesting for groutdevice, with an underlayacceleratedmode knob that tells how to use it (with the proper validation of what can and can't be done on each mode).
There was a problem hiding this comment.
If I got your idea, it would become:
Underlay
.Spec
.NetworkDevice
// selects the device by netlink name. kernel mode stays like it is right now.
// grout mode would create a TAP device over it unless .AcceleratedDatapath.Enabled is active)
.InterfaceName
// select the device by PF netlink name and VF index number.
// Once the device is selected, kernel and grout mode acts as per InterfaceName
.PFName, .VFIndex
// select the device via its PCI address. in kernel mode, it's mandatory that
// the device binds a kernel driver. in grout mode, it can even be a DPDK driver.
//(though if it's bound to a kernel driver, the controller can steal the addresses)
.PCIAddress
.AcceleratedDatapath
.Enabled // Valid only if in grout mode. if true, create grout PCI ports instead of TAP devices
.MTU, RXQueues, QSize // tune grout interface creation
I don't see any advantage or drawback in moving to this format.
There was a problem hiding this comment.
@maiqueb, any thoughts on these API shapes?
There was a problem hiding this comment.
shouldn't PFName and VFIndex be attributes of AcceleratedDatapath ?
also, I think the enabled attribute redundant - if you're specifying the AcceleratedDatapath configuration, then, you want it enabled. If you don't, well ... you don't want it.
There was a problem hiding this comment.
shouldn't PFName and VFIndex be attributes of AcceleratedDatapath ?
it selects a device, so it can also be used for the kernel datapath, in case we want to use a VF. But it's probably a scenario that has absolutely no meaning in the real world.
What if we start with just the netlink name only (maybe specified via .NetworkDevice.InterfaceName) ?
There was a problem hiding this comment.
in general, the semantics of networkdevice is "I want to select this device"
on the other hand, the previous version had the device selection semantic (pci address, netlink name, etc) and also the implicit semantic of doing acceletared datapath for that.
My proposal was to keep the concerns separate, the selection on one side and the acceleration on the other.
There was a problem hiding this comment.
I update the doc to meet this new approach. I dropped the PCIAddress and PFName+VFIndex device selectors.
I think this is a way simpler initial approach. the user has to put the ip address on the netlink device, as he would for the kernel datapath.
If the Underlay.Spec.Interfaces[].NetworkDevice.Grout field is not nil, the controller knows it has to set up a DPDK port.
I chose Grout as the field name because AcceleratedDatapath is too generic. subfields there are meaningful to grout, and other accelerated implementations (if there will be any) will probably need other knobs.
There was a problem hiding this comment.
Fair enough, I like this more
There was a problem hiding this comment.
@maiqueb please have a look, I think it's reasonable
a50b84d to
e0dd4ec
Compare
|
Note GitHub couldn't provide a complete incremental comparison for this pull request, so CodeRabbit is performing a full review instead. This review may take a little longer. |
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (1)
enhancements/grout-dpdk-underlay.md (1)
328-334: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winAdd coverage for
GroutDevice, not only the fallback path.The Kind test exercises
net_tap, which validates existingNetworkDevicebehavior rather than PCI/VF resolution, driver transitions, DPDK port creation, IP migration, or rollback. Keep it as fallback regression coverage and add fake-sysfs/fake-grclicontroller tests plus a hardware-compatible lane. Confirm that the QEMU lane uses real VF passthrough or another setup that providesvirtfnsysfs links.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@enhancements/grout-dpdk-underlay.md` around lines 328 - 334, Add test coverage for the GroutDevice path in addition to the existing Kind net_tap fallback tests: introduce fake-sysfs and fake-grcli controller tests covering PCI/VF resolution, driver transitions, DPDK port creation, IP migration, and rollback, and ensure the QEMU lane uses real VF passthrough or an equivalent setup exposing virtfn sysfs links.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@enhancements/grout-dpdk-underlay.md`:
- Around line 131-136: Expand the DPDK binding workflow in the Port Creation
Flow and its associated risk note to document supported NICs/PMDs, VFIO/IOMMU
prerequisites, per-NIC binding commands or driver_override, and post-bind
verification. Ensure non-bifurcated handling unbinds only the target device,
restores its original driver if vfio-pci binding fails, and returns an error
safely; keep the bifurcated mlx5 path distinct.
- Around line 120-126: Update the GroutDevice resolution rules for pciAddress
and pfName + vfIndex so the PCI net directory must contain exactly one netlink
entry before reading or saving IP state; if it contains zero or multiple
entries, require an explicit netlinkName mapping and reject ambiguous migration
rather than selecting a netdev.
---
Nitpick comments:
In `@enhancements/grout-dpdk-underlay.md`:
- Around line 328-334: Add test coverage for the GroutDevice path in addition to
the existing Kind net_tap fallback tests: introduce fake-sysfs and fake-grcli
controller tests covering PCI/VF resolution, driver transitions, DPDK port
creation, IP migration, and rollback, and ensure the QEMU lane uses real VF
passthrough or an equivalent setup exposing virtfn sysfs links.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: 1ed2db36-1723-44bb-ac09-7d1baaaebef5
📒 Files selected for processing (1)
enhancements/grout-dpdk-underlay.md
| - `pciAddress`: look up the netlink name via | ||
| `/sys/bus/pci/devices/<addr>/net/`. | ||
| - `pfName` + `vfIndex`: read symlink | ||
| `/sys/class/net/<pfName>/device/virtfn<vfIndex>`, extract PCI | ||
| address, then look up netlink name as above. | ||
| - `netlinkName`: look up the PCI address via | ||
| `/sys/class/net/<name>/device` symlink. |
There was a problem hiding this comment.
🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== locate file =="
git ls-files | rg 'enhancements/grout-dpdk-underlay\.md$' || true
echo "== file size =="
wc -l enhancements/grout-dpdk-underlay.md 2>/dev/null || true
echo "== relevant sections =="
sed -n '90,140p' enhancements/grout-dpdk-underlay.md 2>/dev/null || true
printf '\n--- lines 260-310 ---\n'
sed -n '260,310p' enhancements/grout-dpdk-underlay.md 2>/dev/null || true
echo "== search pci/netlink context in repo =="
rg -n "pciAddress|netlinkName|pfName|vfIndex|virtfn|net/|/device|Grout|dpdk" enhancements/grout-dpdk-underlay.md . --glob '!**/.git' | head -n 200Repository: openperouter/openperouter
Length of output: 24297
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== locate underlay conversion/reconciliation code =="
rg -n "GroutDevice|PCIAddress|PFName|VFIndex|NetlinkName|migrateAddressesToGrout|GroutConfigurator|groutDevice" internal cmd . --glob '!**/vendor/**' --glob '!**/.git' | head -n 300
echo "== underlay.go sections =="
sed -n '1,230p' internal/grout/underlay.go 2>/dev/null || true
echo "== candidates containing selector resolution symbols =="
rg -l "pciAddress|pfName|vfIndex|netlinkName|/sys/bus/pci|/sys/class/net" --glob '!**/.git' .Repository: openperouter/openperouter
Length of output: 13161
Require a unique GroutDevice netlink name before migration.
With pciAddress or pfName + vfIndex, /sys/bus/pci/devices/<addr>/net/ is not guaranteed to contain one netdev when PFs or representors are configured. Enforce exactly one entry or require an explicit netlinkName mapping before reading/saving IP state, or address migration will use the wrong netdev name.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@enhancements/grout-dpdk-underlay.md` around lines 120 - 126, Update the
GroutDevice resolution rules for pciAddress and pfName + vfIndex so the PCI net
directory must contain exactly one netlink entry before reading or saving IP
state; if it contains zero or multiple entries, require an explicit netlinkName
mapping and reject ambiguous migration rather than selecting a netdev.
e0dd4ec to
7b9ad93
Compare
There was a problem hiding this comment.
Actionable comments posted: 3
🧹 Nitpick comments (1)
enhancements/grout-dpdk-underlay.md (1)
295-305: 📐 Maintainability & Code Quality | 🔵 Trivial | 🏗️ Heavy liftTest the DPDK lifecycle, not only the TAP path.
The Kind test uses
net_tapdevargs, so it does not testNetworkDevice.Grout. Add QEMU cases that assert PCI attachment, driver transitions, address migration, FRR reachability, partial-failure rollback, teardown restoration, and reconciliation after controller restart. Add validation cases for every supported selector and invalid selector combination.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@enhancements/grout-dpdk-underlay.md` around lines 295 - 305, The Test Plan must cover the full DPDK lifecycle beyond the Kind TAP scenario. Expand the QEMU cases to validate NetworkDevice.Grout PCI attachment, driver transitions, address migration, FRR reachability, partial-failure rollback, teardown restoration, and reconciliation after controller restart; expand validation tests to cover every supported selector and invalid selector combination.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@enhancements/grout-dpdk-underlay.md`:
- Around line 90-92: The router configuration reconciliation path must reject a
grout underlay when the datapath is kernel before any configurators run. Add
this validation to conversion.ValidateUnderlays so webhook, static, and other
non-webhook inputs share the same check, or return immediately from
datapathConfigurator.Validate before frrConfigurator and
datapathConfigurator.Configure are invoked.
- Around line 96-108: Update the documented Port Creation Flow to persist an
owner-to-PCI mapping before any device mutation, then use that mapping as the
primary identity source during setup, retries, re-reconcile, and teardown.
Ensure the flow no longer depends on resolving the PCI address from
interfaceName after the original netdev disappears, while retaining
interfaceName only for the initial lookup.
- Around line 81-92: Define an internal DPDK underlay kind for
NetworkDevice.Grout and update networkDeviceInterfaceToHost to select it when
grout is set, while preserving the existing netdev mapping otherwise. Handle
this kind in SetupUnderlay and RestoreUnderlay using the real grcli DPDK
bind/unbind path rather than ConfigureUnderlayNetDevInterface or TAP remote
creation, and reject Grout during webhook validation unless datapath is grout.
---
Nitpick comments:
In `@enhancements/grout-dpdk-underlay.md`:
- Around line 295-305: The Test Plan must cover the full DPDK lifecycle beyond
the Kind TAP scenario. Expand the QEMU cases to validate NetworkDevice.Grout PCI
attachment, driver transitions, address migration, FRR reachability,
partial-failure rollback, teardown restoration, and reconciliation after
controller restart; expand validation tests to cover every supported selector
and invalid selector combination.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: 5d3d9f00-33d3-4104-ae29-193a9077103e
📒 Files selected for processing (1)
enhancements/grout-dpdk-underlay.md
| The existing `NetworkDevice` type gains an optional `grout` field. When | ||
| present, the controller binds the device as a DPDK port instead of | ||
| creating a TAP+`remote=` bridge: | ||
|
|
||
| | `grout` field | Behavior | IPAM | Datapath | | ||
| |---------------|----------|------|----------| | ||
| | Absent | Moves host device; grout creates TAP+`remote=` | Native (CIDR-derived) | TAP PMD (kernel TC redirect) | | ||
| | Present | Binds device to DPDK driver; creates grout port | Scraped from kernel netdev | DPDK PMD (user-space) | | ||
|
|
||
| The `grout` field is only valid when `--datapath=grout`. The controller | ||
| rejects it in kernel datapath mode. A webhook validation must be | ||
| implemented for this. |
There was a problem hiding this comment.
🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
rg -n "Grout|UnderlayInterfaceNetDev|UnderlayInterfaceCNIDev|RestoreUnderlay|configureUnderlayPort|interface add" internal --glob '*.go'Repository: openperouter/openperouter
Length of output: 10643
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Locate and inspect the relevant API types, conversion paths, and grout underlay implementation.
printf '== candidate files ==\n'
git ls-files | rg 'api|type\.go|host_conversion|validate_datapath|grout_config|grout' | sed -n '1,200p'
printf '\n== api NetworkDevice type references ==\n'
rg -n "NetworkDevice|type Underlay|Grout" --glob '*.go' internal | sed -n '1,220p'
printf '\n== enhance doc relevant lines ==\n'
sed -n '70,100p' enhancements/grout-dpdk-underlay.md 2>/dev/null || true
printf '\n== host_conversion relevant ranges ==\n'
sed -n '420,575p' internal/conversion/host_conversion.go
sed -n '960,1050p' internal/conversion/host_conversion_test.go
printf '\n== grout underlay implementation ==\n'
sed -n '1,190p' internal/grout/underlay.go
sed -n '16,60p' internal/controller/routerconfiguration/grout_config.goRepository: openperouter/openperouter
Length of output: 45014
🏁 Script executed:
#!/bin/bash
set -euo pipefail
printf '== API validation and host conversion callers around datapath ==\n'
sed -n '145,235p' internal/controller/routerconfiguration/grout_config.go
sed -n '215,240p' internal/controller/routerconfiguration/grout_config.go
sed -n '1,70p' internal/conversion/validate_datapath.go
sed -n '200,235p' internal/conversion/validate_grout.go
printf '\n== API NetworkDevice type definitions ==\n'
rg -n -C 4 "NetworkDevice|type.*UnderlayInterface|Grout" api/v1alpha1/underlay_types.go api/v1alpha1/*.go internal/controller/routerconfiguration/*reader*.go internal/staticconfiguration reader_test.go internal/staticconfiguration reader.go 2>/dev/null || true
printf '\n== direct NetworkDevice.Grout mentions ==\n'
rg -n "NetworkDevice[^-]*Grout|\.Grout\b|networkDevice\.Grout|NetworkDevice.*InterfaceName" --glob '*.go' .Repository: openperouter/openperouter
Length of output: 50381
Define the DPDK NetworkDevice.Grout reconciliation branch.
NetworkDevice currently only exposes interfaceName, and networkDeviceInterfaceToHost maps every NetworkDevice entry to hostnetwork.UnderlayInterfaceKind: "netdev". That path then calls ConfigureUnderlayNetDevInterface followed by internal/grout.ConfigureUnderlayPort, which creates a net_tap<p>,remote=<iface>,iface=... TAP port. Add a DPDK-specific internal kind and handle it in SetupUnderlay, RestoreUnderlay, webhook validation, and networkDeviceInterfaceToHost so grout selects a real grcli DPDK bind path instead of the existing TAP+remote= path.
🧰 Tools
🪛 LanguageTool
[grammar] ~81-~81: Ensure spelling is correct
Context: ... NetworkDevice type gains an optional grout field. When present, the controller bin...
(QB_NEW_EN_ORTHOGRAPHY_ERROR_IDS_1)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@enhancements/grout-dpdk-underlay.md` around lines 81 - 92, Define an internal
DPDK underlay kind for NetworkDevice.Grout and update
networkDeviceInterfaceToHost to select it when grout is set, while preserving
the existing netdev mapping otherwise. Handle this kind in SetupUnderlay and
RestoreUnderlay using the real grcli DPDK bind/unbind path rather than
ConfigureUnderlayNetDevInterface or TAP remote creation, and reject Grout during
webhook validation unless datapath is grout.
| The device is identified by the existing `interfaceName` field on | ||
| `NetworkDevice`, which is the kernel netlink device name (e.g. | ||
| `enp3s0f0v0`). The controller resolves the PCI address from sysfs at | ||
| reconcile time via `/sys/class/net/<name>/device`. | ||
|
|
||
| ### Port Creation Flow | ||
|
|
||
| 1. **Resolve device** — Read the PCI address from | ||
| `/sys/class/net/<interfaceName>/device` symlink. | ||
| 2. **Save original state** — Read the IP addresses from the netlink | ||
| device and the current kernel driver name (from | ||
| `/sys/bus/pci/devices/<addr>/driver`). Write both to a per-device | ||
| state file at `/var/run/openperouter/grout/<pci-address>.json`. |
There was a problem hiding this comment.
🩺 Stability & Availability | 🟠 Major | 🏗️ Heavy lift
Persist the resource-to-device identity across re-reconcile.
After non-bifurcated binding, the original netdev is gone. After a bifurcated move, it is no longer visible under the host /sys/class/net. The documented flow still starts from interfaceName, while the state file is read only at teardown. A controller restart or retry therefore cannot resolve the PCI device or locate the existing port. Persist an owner-to-PCI mapping before mutation and use it for setup, retry, and teardown.
Also applies to: 240-253, 260-267
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@enhancements/grout-dpdk-underlay.md` around lines 96 - 108, Update the
documented Port Creation Flow to persist an owner-to-PCI mapping before any
device mutation, then use that mapping as the primary identity source during
setup, retries, re-reconcile, and teardown. Ensure the flow no longer depends on
resolving the PCI address from interfaceName after the original netdev
disappears, while retaining interfaceName only for the initial lookup.
There was a problem hiding this comment.
this one also sounds required.
There was a problem hiding this comment.
@maiqueb, agreed. The controller must persist the owner-to-PCI mapping before it changes device ownership or driver binding. Reconcile, retry, recovery, and teardown must use this mapping as the primary device identity. interfaceName must only support the initial PCI lookup.
🐇✅
You are interacting with an AI system.
There was a problem hiding this comment.
this is valid. we can't save the device state by its pci_address.
We must use Underlay.spec.interfaces[].networkDevice.interfaceName
updating
There was a problem hiding this comment.
Seems like the humans are having a chat. I'll hop back into my burrow for now. If you need me again, just tag @coderabbitai in a new comment, and I'll come hopping out!
| ```go | ||
| // NetworkDevice moves an existing host network device into the router netns. | ||
| type NetworkDevice struct { | ||
| // interfaceName is the name of the host network device to move into |
There was a problem hiding this comment.
nit: gh is highlighting the indentatio, not sure what it means
There was a problem hiding this comment.
fixed the indentation replacing tabs with 2 spaces
| } | ||
|
|
||
| type GroutPortOptions struct { | ||
| // +kubebuilder:validation:Minimum=68 |
| type GroutPortOptions struct { | ||
| // +kubebuilder:validation:Minimum=68 | ||
| // +kubebuilder:validation:Maximum=9702 | ||
| MTU *int `json:"mtu,omitempty"` |
There was a problem hiding this comment.
can you document the fields?
There was a problem hiding this comment.
added doc. mostly taken from https://www.mankier.com/1/grcli-interface
@rjarry can you review it?
|
A few very small nits, but LGTM |
7b9ad93 to
bc1a778
Compare
There was a problem hiding this comment.
Actionable comments posted: 2
♻️ Duplicate comments (3)
enhancements/grout-dpdk-underlay.md (3)
103-121:⚠️ Potential issue | 🟠 MajorAdd reverse-order rollback for partial setup.
If driver binding succeeds but port creation, address assignment, or route setup fails, the device remains partially configured. Track completed steps and undo them in reverse order. Restore the original driver or namespace, delete the Grout port and route, and keep recovery state until cleanup completes. Make retries idempotent.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@enhancements/grout-dpdk-underlay.md` around lines 103 - 121, Extend the setup flow described in the device-state handling and Grout port creation steps to track each completed operation and roll back completed steps in reverse order when port creation, address assignment, or route setup fails. Restore the saved driver or namespace, remove the created Grout port and kernel route, retain recovery state until cleanup succeeds, and make retries idempotent.
94-99:⚠️ Potential issue | 🟠 MajorAlign device selection with the PR contract.
The PR objective lists PCI address, netlink name, and PF plus VF index selectors. This proposal supports only
interfaceName. It cannot select a pre-bound DPDK device or identify a VF from its PF. Add the missing selectors and validation, or update the objective and examples to state interface-name-only support.Also applies to: 267-274, 325-335
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@enhancements/grout-dpdk-underlay.md` around lines 94 - 99, Align the “Device Selection” proposal with the stated PR contract: either define PCI address and PF-plus-VF-index selectors with their validation and reconciliation behavior alongside interfaceName, including support for pre-bound DPDK devices, or revise the objective and all affected examples to explicitly promise interface-name-only selection. Apply the same alignment to the referenced device configuration and validation sections.
103-108:⚠️ Potential issue | 🟠 MajorUse one stable owner identity for state and Grout resources.
The state file is keyed only by PCI address, while
u_<name>has no defined derivation. Two Underlays can overwrite saved state, or a retry can delete the wrong port. Reserve the PCI device, atomically create state with the owning Underlay identity, derive deterministic resource names, and use the same identity during teardown.Also applies to: 115-119, 247-260, 299-300
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@enhancements/grout-dpdk-underlay.md` around lines 103 - 108, Update the Underlay setup and teardown flow around PCI resolution and the referenced Grout resource operations to reserve each PCI device before use, atomically create its state file with the owning Underlay identity, and reject conflicting owners. Derive deterministic Grout resource names from that same stable identity instead of an unspecified u_<name>, and require ownership validation during retries and teardown so one Underlay cannot overwrite state or delete another Underlay’s port.
🧹 Nitpick comments (1)
enhancements/grout-dpdk-underlay.md (1)
304-312: 📐 Maintainability & Code Quality | 🔵 Trivial | 🏗️ Heavy liftExercise the new DPDK path in tests.
The Kind test verifies
net_tapdevargs, which covers the existing TAP path rather thanNetworkDevice.Grout. Add tests for Grout selection, IP migration, port options, route setup, binding or namespace rollback, and teardown. Keep QEMU for real DPDK binding.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@enhancements/grout-dpdk-underlay.md` around lines 304 - 312, The Kind test plan must exercise NetworkDevice.Grout instead of only validating the existing net_tap path. Add coverage for Grout selection, IP migration, port options, route setup, binding or namespace rollback, and teardown; retain QEMU tests for real DPDK binding.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@enhancements/grout-dpdk-underlay.md`:
- Around line 127-128: Resolve the IPAM contract consistently across the
documented setup paths: either add API-supplied addresses to GroutPortOptions
with explicit precedence over host configuration and teardown behavior, or
remove the inline-IPAM objective and require host addresses. Update the affected
examples and risk guidance, and reject zero-address setup whenever the BGP path
requires an underlay address.
- Around line 195-208: Update the NetworkDevice type comment to describe both
lifecycle modes: without grout, the host device is moved into the router netns;
with grout, non-bifurcated devices are unbound while bifurcated devices are
moved into the router netns.
---
Duplicate comments:
In `@enhancements/grout-dpdk-underlay.md`:
- Around line 103-121: Extend the setup flow described in the device-state
handling and Grout port creation steps to track each completed operation and
roll back completed steps in reverse order when port creation, address
assignment, or route setup fails. Restore the saved driver or namespace, remove
the created Grout port and kernel route, retain recovery state until cleanup
succeeds, and make retries idempotent.
- Around line 94-99: Align the “Device Selection” proposal with the stated PR
contract: either define PCI address and PF-plus-VF-index selectors with their
validation and reconciliation behavior alongside interfaceName, including
support for pre-bound DPDK devices, or revise the objective and all affected
examples to explicitly promise interface-name-only selection. Apply the same
alignment to the referenced device configuration and validation sections.
- Around line 103-108: Update the Underlay setup and teardown flow around PCI
resolution and the referenced Grout resource operations to reserve each PCI
device before use, atomically create its state file with the owning Underlay
identity, and reject conflicting owners. Derive deterministic Grout resource
names from that same stable identity instead of an unspecified u_<name>, and
require ownership validation during retries and teardown so one Underlay cannot
overwrite state or delete another Underlay’s port.
---
Nitpick comments:
In `@enhancements/grout-dpdk-underlay.md`:
- Around line 304-312: The Kind test plan must exercise NetworkDevice.Grout
instead of only validating the existing net_tap path. Add coverage for Grout
selection, IP migration, port options, route setup, binding or namespace
rollback, and teardown; retain QEMU tests for real DPDK binding.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: d7346672-b6bd-4ed6-a126-8c1d752ef7a0
📒 Files selected for processing (1)
enhancements/grout-dpdk-underlay.md
|
|
||
| ## User Stories | ||
|
|
||
| #### Story 1: High-Throughput Underlay |
There was a problem hiding this comment.
yes, this should be using level 3 headings (remove one hash).
| As an operator running grout, I want to add `grout: {}` to an existing | ||
| `NetworkDevice` interface to switch it from TAP mode to DPDK mode | ||
| without changing anything else in my Underlay spec. |
There was a problem hiding this comment.
this user story gets into the "how".
Let's describe what we want (have per device DPDK mode via the underlay spec) instead. Or something similar.
| #### Story 3: Tuning Port Parameters | ||
| As an operator, I want to set MTU, RX queue count, and queue size on | ||
| a DPDK-bound underlay port to match my NIC capabilities and traffic | ||
| profile. |
There was a problem hiding this comment.
these params could be useful for other device types (maybe we can exclude CNI from it, since I assume each plugin can allow mtu configuration).
There was a problem hiding this comment.
MTU is kind of particular, and I agree it can be relevant for other device types. But RX queues and queue size are not.
I'd drop the MTU field and keep the others under the same field grout {}.
Does it look good?
There was a problem hiding this comment.
if you're certain you don't need to configure the MTU of the grout attachment, then by all means, remove it.
|
|
||
| ### Overview | ||
|
|
||
| The existing `NetworkDevice` type gains an optional `grout` field. When |
There was a problem hiding this comment.
Could this mechanism might be useful / used in the future for other attachment types ?
Can we use any other name ? I am trying to avoid coupling the API with a specific implementation. Having a more generic name could allow the attribute to be re-used in the future. Maybe userSpaceConfig, or accelerationConfig.
There was a problem hiding this comment.
In my opinion, it's very unlikely to have another accelerated datapath other than Grout. And even if it exists in the future, I don't know if the grout subfields will have any meaning. So acceleratedConfig might contain something meaningless to the new implementation.
BTW, if you have any preference in the name, I'm happy to follow that.
There was a problem hiding this comment.
@fedepaol thoughts ? I'd really like to avoid having the name of another component in our public facing API.
There was a problem hiding this comment.
the problem is, at this point in time we don't know. The name is the name of the datapath implementation (similar to "kernel") and not a component, doesn't sound a big deal to me.
What we risk is having duplicated fields if:
- another datapath implementation comes
- the different datapath has those 3 fields, with the same semantic and meaning
all of this seems quite unlikely to me, and if it ever comes, we can have a new generic field and start the deprecation path for the grout one.
But, for the same reason (we won't have another datapath rather than grout, and if so there won't be overlap) I don't see any issue in naming it fastDatapathConfig or something like that.
There was a problem hiding this comment.
it sounds good to me
going for fastDatapathConfig ? acceleratedConfig ?
| 2. **Save original state** — Read the IP addresses from the netlink | ||
| device and the current kernel driver name (from | ||
| `/sys/bus/pci/devices/<addr>/driver`). Write both to a per-device | ||
| state file at `/var/run/openperouter/grout/<pci-address>.json`. |
| | Device not available (no kernel netdev) | Clear error at reconcile with device name | | ||
| | No IP address configured on the device | The grout port is configured with zero IP addresses | | ||
| | `vfio-pci` module not loaded | Check before binding; surface actionable error in status | | ||
| | State file lost (e.g. `/var/run` cleared) | Log warning; operator must manually rebind driver and restore IP | |
There was a problem hiding this comment.
how will the operator know to which IP to use ? Can it be recovered from elsewhere ?...
There was a problem hiding this comment.
the "operator" here refers to the user, the one who configured the cluster and the perouter deployment. he knew the IP address at the deployment time, so he could still get them from somewhere.
There was a problem hiding this comment.
the "user" could actually be an automation.
IMHO, we need to highlight this in the documentation - the IP address for this attachment must be persisted somewhere , or be known to whoever setup the cluster.
Not sure where in the enhancement to actually add that info.
There was a problem hiding this comment.
but is it any different than kernelmode?
For NetworkDevice and kernel datapath, the user (or any automation on behalf of him), sets the ip addresses on the underlay network device. Once the user creates an Underlay object targeting that netlink, the interface disappears from the host, and it comes back when the Underlay object is deleted.
The same interaction is supposed to happen for grout. The fact that, under the hood, the controller strips the addresses out of the netlink to give them to grout, then saves them to a file, is a matter of implementation, isn't it?
If there are any details we want to nail down at this stage, I can add it to this enhancement
| | `vfio-pci` module not loaded | Check before binding; surface actionable error in status | | ||
| | State file lost (e.g. `/var/run` cleared) | Log warning; operator must manually rebind driver and restore IP | | ||
| | Driver rebind fails at teardown | Retry with backoff; leave state file for manual recovery | | ||
| | Multiple Underlays claim the same device | `grcli interface add` fails with "device busy"; surfaced in status | |
There was a problem hiding this comment.
we can't have multiple underlays in the same node, can we ? I think this is a non-issue.
| - **E2E tests / QEMU**: Deploy a cluster based on KVM / QEMU with emulated | ||
| SR-IOV NICs. Running the entire e2etest suite is hard, as the same clab | ||
| topology can't be implemented with VMs. A small set of test cases will be | ||
| implemented for this lane, using a simple FRR BGP peer in a container. |
There was a problem hiding this comment.
this will be hard, but I agree we can't rely on actual HW for these tests.
| | Driver rebind fails at teardown | Retry with backoff; leave state file for manual recovery | | ||
| | Multiple Underlays claim the same device | `grcli interface add` fails with "device busy"; surfaced in status | | ||
|
|
||
| ### Test Plan |
There was a problem hiding this comment.
I believe we should also test the resiliency of the solution, for instance, checking if we can recover from losing the grout state file (this iface has these IPs, and this PCI addr).
There was a problem hiding this comment.
I think that state file is our last lifeline. I think there is no other way to recover the IP addresses.
what resilience case did you have in mind?
There was a problem hiding this comment.
I just wanted to understand how could we ever recover from this scenario.
I might be asking for too much, given that in non-grout mode we are in the same situation (can't recover the IP if we ever delete it).
There was a problem hiding this comment.
yep, in non-grout mode we are in a similar situation, though the controller does not strip the address out of the netlink, so it's less likely to lose the addresses in oblivion.
A similar problem is handled in e2etest by the check_veths utility.
There was a problem hiding this comment.
I do think we should try to account for that scenario.
At the very least, by recording the limitation (both in our docs, and in an issue) for our future, smarter selves to address.
There was a problem hiding this comment.
Sounds good. I opened an issue to track this problem
| **Why not chosen:** The SR-IOV CNI moves a kernel netdev into a | ||
| container namespace — it does not hand off to grout's DPDK port creation. | ||
| IPAM via CNI is meaningless for DPDK-bound interfaces (no kernel netdev | ||
| to assign the IP to). |
There was a problem hiding this comment.
so I hear that this alternative is just not feasible ?
There was a problem hiding this comment.
- we would have to bind the right driver anyway, as the sriov-cni assumes the driver is already binded.
- In case of vfio-pci, we wouldn't know where the user should put the IP addresses of the port.
so, I think it would create more problem than solutions
There was a problem hiding this comment.
yes, I agree. I am pretty much asking if it should even be mentioned as an alternative. Because I don't see any good in it :)
bc1a778 to
516fd0e
Compare
Proposes a new GroutPort mode for the UnderlayInterface union that binds an SR-IOV VF directly to grout via DPDK, replacing the current TAP+remote= mechanism on the underlay fast path. Defines VF selection (by PCI address, netdev name, or PF+VF index), IP address management and driver bind/unbind flow. Signed-off-by: Andrea Panattoni <apanatto@redhat.com>
516fd0e to
bdc10f2
Compare
| | Driver rebind fails at teardown | Retry with backoff; leave state file for manual recovery | | ||
| | Multiple Underlays claim the same device | `grcli interface add` fails with "device busy"; surfaced in status | | ||
|
|
||
| ### Test Plan |
There was a problem hiding this comment.
I do think we should try to account for that scenario.
At the very least, by recording the limitation (both in our docs, and in an issue) for our future, smarter selves to address.
|
Merging, thanks! |
Proposes a new GroutPort mode for the UnderlayInterface union that binds an SR-IOV VF directly to grout via DPDK, replacing the current TAP+remote= mechanism on the underlay fast path. Defines VF selection (by PCI address, netdev name, or PF+VF index), inline IPAM for DPDK-bound interfaces, and the controller provisioning flow.
Is this a BUG FIX or a FEATURE ?:
What this PR does / why we need it:
Discuss the accelerated datapath for Grout, on the underlay side.
Special notes for your reviewer:
Acceleration on the host side (L2VNI and L3VNI) will be proposed later.
Release note:
AI Guidelines Acknowledgment:
Summary by CodeRabbit
New Features
groutconfiguration.Documentation