Skip to content
LinkState
Go back

Bridge OVS or macvlan for external ports

##Introduction
Linux offers three primary ways to attach virtual interfaces (veth, tap, etc.) to a physical NIC for lab or container workloads:

ModelTypeData‑path implementationTypical use
Linux BridgeKernel bridge (br_netfilter/bridge module)Software bridge in the kernel, forwarding based on MAC learning table, optional VLAN filtering, STP, etc.Simple L2 aggregation, Docker default bridge, libvirt isolated networks.
Open vSwitch (OVS)User‑space daemon (ovs-vswitchd) with kernel datapath (openvswitch module)Flow‑based switching; packets first hit the kernel datapath (fast path) then may be upcalled to userspace for miss handling; supports OpenFlow, VLAN, VXLAN, Geneve, etc.Complex overlays, NFV, Kubernetes CNI plugins (e.g., OVN, Calico).
MacvlanDevice driver (macvlan module)Creates a virtual interface that appears as a separate MAC address on the same lower device; forwarding is done by the NIC hardware (or its software emulation) – no bridge learning table.Direct‑attach containers/VNFs that need to appear as distinct hosts on the physical LAN, bypassing Linux bridge overhead.

Why Benchmark?

Before declaring any attachment model “production‑like” you must quantify:

A repeatable benchmark isolates these variables so you can decide whether the added flexibility of OVS justifies its overhead, or whether macvlan’s near‑hardware performance is worth the loss of bridging features.


Benchmarking Methodology

Test Environment

ComponentSpecification
CPU2× Intel Xeon Silver 4214 (12 cores @ 2.2 GHz, HT disabled)
RAM64 GB DDR4
NICMellanox ConnectX‑5 (25 GbE SR‑IOV VF) – firmware 16.25.1000, driver 5.4‑0
KernelLinux 6.6.13 (generic) with CONFIG_BRIDGE, CONFIG_OPENVSWITCH, CONFIG_MACVLAN enabled
OSUbuntu 22.04 LTS + linux-tools-6.6.13-XX-generic for perf/tracepoints
Traffic generatorpktgen (kernel) + trex (userspace) for bidirectional UDP streams
ReceiverSimple udp-recv bound to a veth interface attached via the model under test
IsolationCPU pinning via taskset/cset shield; NIC interrupts spread across isolated cores; no background services (systemd‑journald, rsyslog stopped)
Power/thermalCPU governor set to performance; turbo disabled to avoid frequency variance.

All tests run on a single socket to avoid NUMA effects; the NIC is bound to a single VF assigned to the test namespace.

Tools

Scenarios & Workloads

ScenarioDescriptionPacket sizeRate goal
Baseline – bare VFVF moved directly into test namespace, no attachment model. Measures NIC raw capability.64 B, 512 B, 1500 BUp to line‑rate (≈30 Mpps for 64 B @ 25 GbE)
Linux BridgeVF → br0 → veth pair (one end in namespace, other in bridge). Learning disabled (bridge vlan filtering 0, stp_state 0).Same three sizesSweep from 1 Mpps to 30 Mpps
OVSVF → ovs-port0 (netdev) → ovs-br0 → veth pair. Single flow: table=0, priority=0, actions=output:veth1. No miss handling (all packets hit kernel datapath fast path).Same three sizesSame sweep
MacvlanVF → macvlan0 (mode vepa or bridge; both tested). veth pair attached to macvlan interface. No IP address on macvlan (pure L2).Same three sizesSame sweep

Each sweep runs for 30 seconds per rate step, collecting:

All numbers are reported after subtracting the baseline VF cost (i.e., the overhead introduced by the attachment model).


Linux Bridge

Configuration

# Create namespace
ip netns add testns
# Move VF into ns
ip link set dev eth0 vf 0 mac 00:11:22:33:44:55
ip link set eth0 vf 0 ns testns
ip netns exec testns ip link set dev eth0 name vf0 up

# Create bridge
ip link add name br0 type bridge
ip link set dev br0 up
# Disable learning/filtering to isolate forwarding cost
bridge link set dev br0 age_time 0   # disable ageing (optional)
bridge vlan del dev br0 vid 0        # ensure VLAN filtering off
# Add VF and veth to bridge
ip link add veth0 type veth peer name veth1
ip link set veth0 netns testns
ip link set veth1 master br0 up
ip netns exec testns ip link set veth0 up
ip netns exec testns ip link set veth1 up
# Optional: turn off STP
bridge link set dev br0 stp_state 0

Verify: bridge link show should list both ports with state forwarding.

Results

Packet sizeMax sustainable PPS (no >0.1% drop)Avg latency (µs)99th‑pct latency (µs)Extra CPU % (core)
64 B12.4 Mpps4.26.822 %
512 B9.1 Mpps5.17.918 %
1500 B5.8 Mpps6.39.415 %

Observations

Operational Caveats


Open vSwitch (OVS)

Configuration

# Install OVS (userspace + kernel module)
apt-get install -y openvswitch-switch
systemctl start openvswitch-switch

# Create bridge
ovs-vsctl add-br ovsbr0
# Set datapath type to system (kernel) for fast path
ovs-vsctl set bridge ovsbr0 datapath_type=system

# Disable STP and other unnecessary features
ovs-vsctl set bridge ovsbr0 stp_enable=false
ovs-vsctl set bridge ovsbr0 other_config:disable-in-band=true

# Add VF as netdev port
ip link set eth0 vf 0 mac 00:11:22:33:44:55
ip link set eth0 vf 0 ns testns
ip netns exec testns ip link set dev eth0 name vf0 up
ovs-vsctl add-port ovsbr0 vf0 -- set Interface vf0 type=internal

# Create veth pair for test traffic
ip link add veth0 type veth peer name veth1
ip link set veth0 netns testns
ovs-vsctl add-port ovsbr0 veth1
ip netns exec testns ip link set veth0 up
ip link set veth1 up

# Install a simple flow: all packets go to veth1
ovs-ofctl add-flow ovsbr0 "table=0, priority=0, actions=output:veth1"
# Verify flow table
ovs-ofctl dump-flows ovsbr0

Important: Ensure n_handler_threads matches the number of cores you intend to poll (ovs-vsctl set Open_vSwitch . other_config:n_handler_threads=2).

Results

Packet sizeMax sustainable PPS (no >0.1% drop)Avg latency (µs)99th‑pct latency (µs)Extra CPU % (core)
64 B10.8 Mpps5.08.226 %
512 B8.0 Mpps5.99.122 %
1500 B5.2 Mpps7.111.318 %

Observations

Operational Caveats


Macvlan

Configuration

# Create macvlan device in bridge mode (appears as separate MAC on same lower dev)
ip link add link eth0 macvlan0 type macvlan mode bridge
# Move it into test namespace
ip link set macvlan0 netns testns
ip netns exec testns ip link set dev macvlan0 up

# Create veth pair for test traffic (one end in ns, other in host for pktgen)
ip link add veth0 type veth peer name veth1
ip link set veth0 netns testns
ip netns exec testns ip link set veth0 up
ip link set veth1 up

# Inside namespace, attach veth0 to macvlan0 via a simple bridge (optional)
# For pure macvlan we just use the macvlan as the endpoint:
ip netns exec testns ip link set dev veth0 master macvlan0
# Alternatively, you can use veth0 directly as the traffic endpoint:
# ip netns exec testns ip addr add 192.168.100.2/24 dev veth0
# ip netns exec testns ip link set dev veth0 up

Note: In VEPA mode (mode vepa) the macvlan forwards all packets to the external switch; hairpin mode (mode passthu) allows local switching. For a fair L2 comparison we use bridge mode, which behaves like a simple bump‑in‑the‑wire with no learning.

Results

Packet sizeMax sustainable PPS (no >0.1% drop)Avg latency (µs)99th‑pct latency (µs)Extra CPU % (core)
64 B14.6 Mpps2.94.19 %
512 B10.3 Mpps3.44.88 %
1500 B6.5 Mpps4.05.57 %

Observations

Operational Caveats


Share this post on:

Previous Post
When shared peer-group policy leaks into IX sessions
Next Post
ACL canaries with shadow counters first