
Linux Bridge or OVS: Which Fits Your Network?
Use Open vSwitch when something outside the host needs to program how packets move. Use the Linux bridge when you need a plain layer 2 switch on one machine. Most of the noise around Linux bridge vs Open vSwitch for software-defined networking comes from calling every virtual switch "SDN." Open vSwitch (OVS) gives you a transactional config database, OpenFlow control, flow-based tunnels, and per-flow telemetry. The Linux bridge gives you a fast, boring kernel switch with almost nothing to break.
Linux bridge or Open vSwitch for software-defined networking?
Open vSwitch wins as soon as a controller or orchestrator decides forwarding. Software-defined networking (SDN) means forwarding rules come from a control plane outside the switch, usually one that sees many hosts at once. The Linux bridge has no such control plane. It learns MAC addresses, filters VLANs, and runs spanning tree, and every host decides alone.
So the dividing question is who programs forwarding, not how many VMs you run. If OpenStack, OVN, or your own automation must push policy across many hypervisors, run OVS. If one box hosts a handful of VMs on a few VLANs that rarely change, run the Linux bridge and spend the saved hours elsewhere.
| Linux bridge | Open vSwitch | |
|---|---|---|
| Where it runs | Entirely in the kernel | Kernel datapath module plus ovs-vswitchd and ovsdb-server in userspace |
| How you configure it | rtnetlink, through ip, bridge, NetworkManager, or systemd-networkd | OVSDB, through ovs-vsctl or a remote manager |
| Config after a reboot | Gone until your network config rebuilds it | Kept in conf.db |
| Forwarding logic | MAC learning, VLAN filtering, STP | MAC learning or multi-table OpenFlow pipelines |
| External controller | None | OpenFlow controller over TCP or TLS |
| Overlays | Separate VXLAN or Geneve devices added as ports | Tunnel ports, with remote endpoints set per flow |
| Telemetry | Interface counters, FDB dumps, packet capture | Per-flow counters, sFlow, NetFlow, IPFIX, mirroring |
| Datapath choices | Kernel, with switchdev hardware offload | Kernel, userspace DPDK, TC flower offload |
| What can break | One kernel object | Two daemons, a kernel module, and often a controller |
Linux bridge is a dependable kernel switch
The Linux bridge does one job, and it's been in mainline long enough that most of its bugs are now other people's. You add interfaces as ports. The kernel learns which MAC lives behind which port and stores it in the forwarding database (FDB). Entries age out after 300 seconds by default, according to the kernel's netlink docs for IFLA_BR_AGEING_TIME.
With spanning tree on, a new port waits through listening and learning before it forwards. The default forward delay for each of those stages is 15 seconds, which is a noticeable gap when a VM boots. Run this first on any bridge you didn't build yourself:
ip -d link show br0 # bridge options: stp_state, vlan_filtering, timers
bridge link show # which interfaces are ports, and their STP state
bridge fdb show br br0 # learned and static MAC entries
bridge vlan show # per-port VLANs, if vlan_filtering is on
One quirk will mislead you. The kernel takes these timers in clock_t, which is seconds times USER_HZ, usually 100. As a result, ip -d link prints the ageing time in those units, so the default looks far too large, and you briefly wonder why your MAC entries live most of a day.
The real limit is scope. The bridge forwards frames on one host and knows nothing about the next one. You can add policy with nftables bridge rules or tc filters, but you write and distribute that logic yourself. If you're setting one up, build the Linux bridge safely with ip or NetworkManager so you don't cut off your own SSH session halfway through.
Open vSwitch was built for hypervisors
OVS assumes ports come and go all day, which is how hypervisors and container hosts behave. It splits the work between userspace and the kernel. ovsdb-server holds configuration, ovs-vswitchd turns config and OpenFlow rules into forwarding decisions, and the openvswitch kernel module runs the fast path.
VM tap devices, container veth pairs, and OVS internal ports all attach to the same bridge. The usual design puts every workload on one integration bridge and tags each port with external_ids:iface-id. That tag tells the orchestrator which logical port a tap belongs to. Meanwhile, VXLAN or Geneve tunnel ports on the same switch keep tenant traffic separate across hosts without stretching VLANs through physical gear.
Policy is the other half. OpenFlow rules match on layer 2 through layer 4 fields and then act: forward, drop, rewrite, tunnel, or hand off to the next table. The Open vSwitch documentation has the full field and action reference.
Moving VMs favors Open vSwitch
Live migration exposes the weakest part of a bridge setup. Here is what happens with the Linux bridge. Libvirt or Proxmox creates a tap on the destination host and adds it to the bridge. QEMU then announces the guest's MAC with a broadcast, and the switches relearn where it lives.
That works when both hosts share a layer 2 segment and the destination bridge has the right VLANs on the right ports. Across sites, however, you need VXLAN devices, FDB entries for remote endpoints, and something to keep them in sync. Without EVPN or a similar control plane, that something is you, editing configs on every host.
OVS handles this better. A tunnel port with options:remote_ip=flow lets the controller choose the remote endpoint per flow, so one port reaches every host. When a VM moves, the controller rewrites the flows that point at it.
ovs-vsctl add-port br-int vxlan0 -- set interface vxlan0 \
type=vxlan options:remote_ip=flow options:key=flow
MAC learning still matters when OVS runs without a controller. From the source, OVS expires an idle MAC entry after 300 seconds by default. So if a guest moves silently, frames chase the old port until that entry ages out. ovs-appctl fdb/flush br-int clears the table on the spot.
Migration state lives in the orchestrator
Neither switch migrates network state on its own. Libvirt, OpenStack Neutron, OVN, or Proxmox decides what the destination needs, and the switch applies it. The difference is what each switch gives the orchestrator to work with.
The Linux bridge keeps its state in kernel memory and nothing on disk. After a reboot, it exists only because NetworkManager, systemd-networkd, or /etc/network/interfaces rebuilds it. Per-port VLANs and static FDB entries need the same treatment, or they're gone.
OVS keeps bridges, ports, and external IDs in /etc/openvswitch/conf.db. Because of that, the iface-id binding survives a restart, and the controller recognizes the port on a new host. Controller flows live only in ovs-vswitchd, though, so the fail mode decides what happens until the controller reconnects:
ovs-vsctl get-fail-mode br-int
ovs-vsctl set-fail-mode br-int secure # no flows until the controller sends them
standalone falls back to a learning switch, which keeps traffic moving and may also pass traffic your policy should block. secure drops traffic until flows arrive. For package upgrades, the ovs-ctl restart path saves and restores flows with flow-restore-wait, so an update doesn't blackhole every VM.
OVSDB turns configuration into something you can watch
OVSDB is the Open vSwitch Database Management Protocol, published as RFC 7047. It speaks JSON-RPC, groups changes into transactions, and lets clients subscribe to updates. In practice, the switch config is queryable and atomic.
Every ovs-vsctl call commits atomically. Chain commands with -- and they commit together or not at all:
ovs-vsctl add-port br-int vnet3 -- set interface vnet3 external_ids:iface-id=<logical-port-id>
If the set half fails, the port never appears. That matters, because a half-tagged tap is exactly what leaves a controller unable to place a VM.
Subscriptions are what make OVS programmable from outside. An orchestrator watches the tables it cares about and reacts when a port shows up. You can watch the same stream yourself:
ovsdb-client monitor Open_vSwitch Interface name,ofport,external_ids
Each row change prints as it commits. That tells you exactly when libvirt added a tap and whether the iface-id landed. The Linux bridge has a rough equivalent in bridge monitor and ip monitor link, which show events live but keep no stored record of what the config should be.
Trace the packet before you blame the controller
When traffic dies on an OVS host, the flow table is your first suspect. Check the counters before you touch anything else:
ovs-ofctl dump-flows br-int # OpenFlow rules with packet and byte counters
ovs-appctl dpctl/dump-flows # what the kernel datapath actually cached
ovs-appctl ofproto/trace br-int in_port=vnet3,dl_dst=<mac> # walk one packet through every table
A counter stuck at zero tells you the rule never matched. The trace output names the table and rule that dropped the packet, which beats guessing from controller logs. If the controller itself went quiet, journalctl -u ovs-vswitchd or /var/log/openvswitch/ovs-vswitchd.log shows the reconnect attempts.
On the Linux bridge, the same hunt is tcpdump on each port plus bridge fdb show. There's no pipeline to trace, so diagnosis is shorter, and so is the list of things that can go wrong.
My call for common setups
For a single host running a few VMs or containers on VLANs that rarely change, run the Linux bridge. For a fleet where OpenStack, OVN, or your own controller pushes policy to many hypervisors, run Open vSwitch. If you're not sure yet, start with the bridge and move when a controller actually shows up.
Proxmox defaults to a Linux bridge, vmbr0, and most single-node homelabs never outgrow it. An OVS stack you don't need is extra daemons to debug in the middle of the night.
FAQ
Does Docker or Kubernetes use the Linux bridge or Open vSwitch?
Docker's default network is a Linux bridge called docker0, with a veth pair for each container. Kubernetes leaves the choice to its CNI plugin. Flannel and the basic bridge plugin build on a Linux bridge, while OVN-Kubernetes and Antrea run Open vSwitch underneath. Run ip -d link show type bridge and ovs-vsctl show on a node, and the output tells you which one you're on.
Is Open vSwitch slower than the Linux bridge?
Once a flow is cached in the kernel datapath, the per-packet cost is close. The difference shows up on the first packet of a new flow, which goes up to ovs-vswitchd for a decision before the kernel caches it. Workloads with huge numbers of short connections feel that upcall path most. The DPDK userspace datapath raises the packet-rate ceiling, but it dedicates CPU cores and hugepages to the switch, so only reach for it after you've measured a real bottleneck.
Can I run both on the same host?
Yes, and OpenStack did it for years. Its iptables_hybrid firewall driver put a small Linux bridge between each VM tap and the OVS integration bridge, because iptables can't see traffic inside OVS. The catch is that a dropped packet now has two switches to hide in, and you have to check both.
Do I need Open vSwitch to run VXLAN overlays?
No. The kernel's vxlan driver works fine as a port on a plain Linux bridge. For a small static setup, bridge fdb append with the all-zeros MAC and dst <remote-ip> adds a flood entry for each remote host. For anything that changes often, run BGP EVPN (Ethernet VPN) with FRRouting so remote MAC entries get filled in for you.
