Skip to content

BMv2 Docker image fails to bind veth interfaces on WSL2 (official image only) #1338

@engranaabubakar

Description

@engranaabubakar

BMv2 Interface Binding Issue - WSL2 & Docker

TL;DR: Official p4lang/behavioral-model Docker images fail to bind veth interfaces on WSL2, while a source-built image (Ubuntu 22.04, newer deps) works reliably with identical runtime configuration.

Issue Summary

The official p4lang/behavioral-model:latest and p4lang/behavioral-model:stable Docker images fail to bind network interfaces with "Add port operation failed" error when run on WSL2, while a custom build from source works perfectly.

Environment

  • OS: Windows 11 with WSL2 (Ubuntu 22.04)
  • Docker: Docker Desktop on Windows
  • BMv2 Images Tested:
    • p4lang/behavioral-model:latest FAILS
    • p4lang/behavioral-model:stable FAILS
    • Custom build from source WORKS

Reproduction Steps

1. Create container with network isolation

docker run -d --name sw-test \
  --privileged \
  --cap-add NET_ADMIN --cap-add NET_RAW --cap-add SYS_ADMIN \
  --network=none \
  p4lang/behavioral-model:latest \
  tail -f /dev/null

2. Create veth pair and attach to container

# Create veth pair
ip link add s1p2 type veth peer name h1e1

# Move one end to container namespace
PID=$(docker inspect -f '{{.State.Pid}}' sw-test)
ip link set h1e1 netns $PID

# Rename inside container
nsenter -t $PID -n ip link set h1e1 name eth2
nsenter -t $PID -n ip link set eth2 up

# Bring up host side
ip link set s1p2 up

3. Try to start BMv2 with interface

docker exec sw-test simple_switch_grpc \
  -i 2@eth2 \
  --no-p4 \
  --device-id 1 \
  -- --grpc-server-addr 0.0.0.0:50051

Expected vs Actual

Expected: Interface binds successfully

Adding interface eth2 as port 2

Actual (with official images):

Add port operation failed
Could not add interface eth2 as port 2

Actual (with custom build from source):

Adding interface eth2 as port 2   SUCCESS

Root Cause Analysis

Differences Between Official Image and Working Build

Aspect Official Image (FAILS) Custom Build (WORKS)
Base Image Ubuntu 20.04 Ubuntu 22.04
Boost Version 1.71.0 1.74.0
gRPC/Protobuf Older versions System packages (newer)
Build Flags --enable-Werror, stripped -O0 -g (debug)
Dependencies Minimal runtime Full dev deps included

Key Finding

The issue is NOT WSL2 blocking packet capture. We verified with tcpdump:

docker exec sw-test tcpdump -i eth2 -c 5 -nn
# Result: "listening on eth2, link-type EN10MB" - WSL2 works fine!

The issue is in how the official Docker images are built or their dependency versions.

Working Solution: Build from Source

Dockerfile that WORKS

FROM ubuntu:22.04

ARG DEBIAN_FRONTEND=noninteractive
ARG BMV2_BRANCH=main

# System dependencies including libnanomsg
RUN apt-get update && apt-get install -y --no-install-recommends \
    git ca-certificates curl \
    autoconf automake libtool make cmake pkg-config \
    g++ gcc \
    libpcap-dev libssl-dev \
    libboost-dev libboost-system-dev libboost-thread-dev \
    libboost-program-options-dev libboost-filesystem-dev \
    libboost-iostreams-dev \
    protobuf-compiler libprotobuf-dev \
    grpc++ libgrpc++-dev \
    libthrift-dev thrift-compiler \
    libgmp-dev libjudy-dev \
    libnanomsg-dev \
    python3 python3-pip python3-setuptools python3-dev \
    libevent-dev \
    iproute2 tcpdump strace net-tools \
    && rm -rf /var/lib/apt/lists/*

# Build PI (P4Runtime) first
WORKDIR /opt
RUN git clone --depth 1 --recursive https://github.com/p4lang/PI.git
WORKDIR /opt/PI
RUN ./autogen.sh && \
    ./configure --with-proto && \
    make -j"$(nproc)" && \
    make install && \
    ldconfig

# Build BMv2 with PI support
WORKDIR /opt
RUN git clone --depth 1 --recursive --branch ${BMV2_BRANCH} \
    https://github.com/p4lang/behavioral-model.git bmv2
WORKDIR /opt/bmv2
RUN ./autogen.sh && \
    ./configure \
      --with-pi \
      --enable-debugger \
      CXXFLAGS="-O0 -g" \
      && \
    make -j"$(nproc)" && \
    make install && \
    ldconfig

ENV PATH="/usr/local/bin:${PATH}"
CMD ["bash"]

Build Command (IMPORTANT: Use native WSL filesystem, not /mnt/c)

# WRONG - fails with buildx I/O error:
cd /mnt/c/work && docker build -t bmv2-custom:dbg .

# CORRECT - works:
mkdir -p ~/bmv2-build
cp Dockerfile.bmv2 ~/bmv2-build/
cd ~/bmv2-build
docker build -t bmv2-custom:dbg -f Dockerfile.bmv2 .

Verification

# With custom image - ALL INTERFACES BIND SUCCESSFULLY:
docker exec sw-test simple_switch_grpc \
  -i 2@eth2 -i 3@eth3 -i 4@eth4 -i 5@eth5 \
  --no-p4 --device-id 1 -- --grpc-server-addr 0.0.0.0:50051

# Output:
# Adding interface eth2 as port 2 
# Adding interface eth3 as port 3 
# Adding interface eth4 as port 4 
# Adding interface eth5 as port 5 

Recommendations for P4 Project

Short-term Fix

Update the official Dockerfile to:

  1. Use Ubuntu 22.04 (related to issue Update docker image from Ubuntu 20.04 to Ubuntu 24.04 #1296)
  2. Include libnanomsg-dev in dependencies
  3. Consider not stripping symbols for debugging

Long-term Improvements

  1. Add CI tests for interface binding with veth pairs
  2. Test official images on WSL2 (large user base)
  3. Provide both minimal and debug variants
  4. Document WSL2-specific setup requirements

Impact

This issue affects:

  • Research labs using WSL2 for P4 development
  • Tutorials like P4.org tutorials running on Windows
  • Students learning P4 on Windows machines
  • Any containerized BMv2 deployment using manual veth wiring

Related Issues

Testing Environment Details

# WSL Version
wsl --version
# WSL version: 2.0.14.0
# Kernel version: 5.15.133.1-1

# Docker Version
docker version
# Docker version 24.0.6

# Verified interfaces exist and are UP
ip link show  # All veths present and functional
docker exec sw-test ip link  # Interfaces visible in container

# Verified capabilities
docker exec sw-test capsh --print
# Current: cap_net_admin,cap_net_raw,cap_sys_admin=eip

Tested Workarounds That FAILED

  1. Using p4lang/behavioral-model:stable instead of latest
  2. Adding more capabilities (SYS_PTRACE, etc.)
  3. Different veth naming conventions
  4. Starting BMv2 without -i flags and adding ports later (no API available)
  5. Using host network mode (defeats purpose of isolation)

Only Working Solution

Build BMv2 from source using Ubuntu 22.04 base with full dependencies


Author: Rana Abu Bakar, Working on: Virtual Reconfigurable Pipeline Router on WSL2
Date: February 2, 2026
Build Time: ~20 minutes for custom image
Result: 100% success rate with custom build vs 0% with official images

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions