Grout (DPDK Dataplane)

Overview #

Grout is an optional, DPDK-accelerated data plane that can replace the Linux kernel’s networking stack for packet forwarding in OpenPERouter. When enabled, grout handles VXLAN encapsulation/decapsulation and routing in user-space using poll-mode drivers, while FRR continues to manage the control plane (BGP, EVPN, route exchange).

The integration is opt-in: grout is disabled by default and enabling it does not affect existing kernel-based deployments.

Architecture #

When grout is enabled, it runs as a sidecar container in the router DaemonSet pod. It exposes a UNIX socket that serves two consumers:

  • FRR (zebra): uses the dplane_grout module to push forwarding entries into grout instead of the kernel’s routing tables.
  • The controller: uses the grcli CLI to configure grout ports, addresses, VRFs, and routes.

Compared to the default kernel-based deployment, enabling grout adds:

  • A grout sidecar container in the router pod
  • The -M dplane_grout module flag to FRR’s zebra process
  • The GROUT_SOCK_PATH environment variable for FRR to locate the grout socket
  • --datapath=grout flag to the controller
  • A shared grout-socket volume between the grout sidecar and the FRR container

Current Scope and Limitations #

Grout support is being delivered incrementally. The current implementation covers:

  • Underlay interface setup via grout ports
  • L3Passthrough forwarding via grout

The following are not yet supported with grout:

  • L3VNI (EVPN Layer 3 overlays)
  • L2VNI (EVPN Layer 2 overlays)
  • Hardware acceleration with SR-IOV NICs

Additionally, grout currently:

  • Uses TAP devices rather than DPDK poll-mode drivers bound to physical NICs
  • Runs in --test-mode, meaning no hugepages are required

These limitations will be addressed in subsequent milestones.

Prerequisites #

For the current scope, no special hardware is required — grout uses TAP devices and test-mode. In future milestones, DPDK-capable NICs and hugepage configuration will be needed for hardware-accelerated forwarding.

Helm Configuration #

Grout is configured under openperouter.grout in the Helm values:

openperouter:
  grout:
    enabled: true
    image:
      repository: quay.io/openperouter/router
      tag: "main-grout"
      pullPolicy: ""
    resources:
      requests:
        memory: "512Mi"
        cpu: "250m"
      limits:
        memory: "1Gi"
        cpu: "500m"

Configuration Fields #

FieldTypeDefaultDescription
dataoathstringkernelDatapath to use for L3 forwarding. “kernel” uses the standard Linux kernel datapath; “grout” adds a DPDK-accelerated sidecar that runs alongside FRR
grout.image.repositorystringquay.io/openperouter/routerGrout container image repository
grout.image.tagstringmain-groutGrout container image tag
grout.image.pullPolicystring""Image pull policy (defaults to Kubernetes default)
grout.resourcesobjectsee aboveResource requests and limits for the grout container

Enabling Grout for L3Passthrough #

The Underlay and L3Passthrough Custom Resources are the same as the kernel-based deployment. The only difference is enabling grout in the Helm values.

Step 1: Install with Grout Enabled #

helm install openperouter openperouter/openperouter \
  --set openperouter.grout.enabled=true

Or using a values file:

# values.yaml
openperouter:
  grout:
    enabled: true
helm install openperouter openperouter/openperouter -f values.yaml

Step 2: Configure Underlay and L3Passthrough #

Apply the same CRs as the kernel-based passthrough setup. See the Passthrough Configuration documentation for full details.

apiVersion: openpe.openperouter.github.io/v1alpha1
kind: Underlay
metadata:
  name: underlay
  namespace: openperouter-system
spec:
  asn: 64514
  interfaces:
    - type: NetworkDevice
      networkDevice:
        interfaceName: toswitch
  neighbors:
    - asn: 64512
      address: 192.168.11.2
---
apiVersion: openpe.openperouter.github.io/v1alpha1
kind: L3Passthrough
metadata:
  name: passthrough
  namespace: openperouter-system
spec:
  hostsession:
    asn: 64514
    hostasn: 64515
    localcidr:
      ipv4: 192.169.10.0/24

When grout is enabled, the controller configures FRR as usual but delegates the host network setup to the grout data path instead of kernel interfaces.

Verification #

Check Grout Sidecar Status #

Verify that the grout container is running in the router pod:

kubectl get pods -n openperouter-system -l app=router

Check grout container logs:

kubectl logs -n openperouter-system -l app=router -c grout

Check BGP Sessions #

Verify that BGP sessions are established. The control plane behavior is identical to the kernel-based deployment — FRR handles all BGP operations, with grout handling the forwarding plane.