Skip to content
LinuxDeep Dive Published Updated 7 min readViews unavailable

Linux Bridge VLAN Filtering: Building and Verifying Layer-2 Segmentation

Configure Linux bridge VLAN filtering with explicit port membership, PVIDs, tagged traffic, safe lab commands, and a systematic forwarding-table check.

A Linux bridge forwards Ethernet frames between attached ports. With VLAN filtering enabled, it can apply VLAN membership and forwarding decisions at the bridge rather than relying on separate bridges for every broadcast domain. The configuration is only correct when the bridge’s VLAN filtering mode, port membership, PVID, tagged/untagged behavior, and any host-facing VLAN interfaces agree. A port being attached to a bridge does not, by itself, mean that it carries every VLAN.

Bridge VLAN filtering is a Layer-2 function. It does not automatically assign IP addresses, configure routing, provide DHCP, or create firewall policy. Those are separate concerns. Start with a clear traffic matrix that says which ports should send or receive which VLAN IDs and whether endpoints send tagged frames or ordinary untagged Ethernet. Then express that matrix in the bridge VLAN database and verify the actual kernel state.

Understand the bridge and its VLAN database

The bridge device has global settings, including vlan_filtering; each bridge port has VLAN membership entries. A VLAN entry can indicate whether a VLAN is allowed on that port and whether egress frames are tagged or untagged. A port’s PVID classifies incoming untagged frames into a VLAN. If untagged ingress is not assigned to the intended PVID, a host that sends ordinary Ethernet may not enter the expected broadcast domain.

The bridge itself can also have VLAN membership. This matters when the host needs to communicate through an IP interface associated with a VLAN or terminate traffic on the bridge device. Pure port-to-port switching and host-originated traffic are distinct paths. Do not assume that putting a VLAN on two bridge ports automatically makes the host reachable on that VLAN.

The following commands can alter connectivity immediately. Practice in a disposable network namespace or maintenance window, and keep an out-of-band management path. Avoid enabling filtering on a bridge carrying production management traffic until all existing untagged and tagged membership is understood.

Create an isolated two-endpoint lab

The lab below uses two network namespaces with veth links attached to a bridge in the root namespace. Each namespace behaves as an untagged endpoint in VLAN 100. The bridge is configured with no default PVID so the desired membership must be explicit. These names are disposable; do not reuse them on a host that already has interfaces with the same names.

sudo ip netns add vlan-a
sudo ip netns add vlan-b
sudo ip link add br-lab type bridge vlan_filtering 1 vlan_default_pvid 0
sudo ip link set br-lab up
sudo ip link add va-host type veth peer name eth0 netns vlan-a
sudo ip link add vb-host type veth peer name eth0 netns vlan-b
sudo ip link set va-host master br-lab
sudo ip link set vb-host master br-lab
sudo ip link set va-host up
sudo ip link set vb-host up
sudo bridge vlan add dev va-host vid 100 pvid untagged
sudo bridge vlan add dev vb-host vid 100 pvid untagged
sudo ip -n vlan-a link set lo up
sudo ip -n vlan-b link set lo up
sudo ip -n vlan-a addr add 192.0.2.1/24 dev eth0
sudo ip -n vlan-b addr add 192.0.2.2/24 dev eth0
sudo ip -n vlan-a link set eth0 up
sudo ip -n vlan-b link set eth0 up

Because the veth peers in the namespaces send untagged Ethernet frames, the PVID classifies their ingress into VLAN 100. The untagged flag means frames transmitted toward those ports leave without a VLAN header for that VLAN. Confirm the table before testing:

sudo bridge vlan show
sudo bridge -d link show master br-lab
sudo ip -n vlan-a route
sudo ip -n vlan-b route
sudo ip netns exec vlan-a ping -c 3 192.0.2.2

The IPv4 addresses use the documentation-only TEST-NET-1 block. A successful ping demonstrates Layer-2 reachability and endpoint configuration in this lab, not that production routing, firewall, or MTU behavior is correct. To test isolation, add a third namespace on another VLAN and confirm that same-subnet traffic does not cross VLAN membership merely because the ports share a bridge.

Clean up only the lab objects after collecting state:

sudo ip netns del vlan-a
sudo ip netns del vlan-b
sudo ip link del br-lab

Deleting the namespace removes the veth endpoints it owns; deleting the bridge removes remaining bridge lab configuration. Review names first and never paste cleanup commands against production interfaces.

An uplink or trunk generally carries multiple VLANs with tags. Add an explicit entry for every VLAN permitted on the port. For example, after confirming uplink0 is already a bridge port in a controlled environment:

sudo bridge vlan add dev uplink0 vid 100
sudo bridge vlan add dev uplink0 vid 200
sudo bridge vlan show dev uplink0

Do not set pvid or untagged on a trunk VLAN unless the peer expects untagged traffic for that specific VLAN. A common access port has one untagged VLAN and a PVID; a trunk usually transmits VLAN tags. Hybrid designs exist, but they should be specified as a table and tested one VLAN at a time.

If the host itself needs an IP address on a VLAN, configure bridge self membership and a host VLAN interface according to the topology. The exact method depends on whether the VLAN is terminated on the bridge device, a VLAN upper device, or another routed interface. Verify with bridge vlan show, ip -d link show, ip addr, and packet capture at the appropriate interface. Avoid adding an IP address directly to a bridge slave port; the bridge normally owns Layer-3 configuration for a bridged segment.

Verify forwarding and diagnose leaks

Use bridge vlan show to inspect membership per bridge device and port. Use bridge fdb show br br-lab to see learned MAC addresses and VLAN association, and bridge link show to inspect port state. A VLAN entry alone does not guarantee forwarding: the port must be up, the peer must agree on tagging, and the bridge must learn or receive the frame.

Capture on both sides when results differ from expectation. tcpdump -eni on a trunk should show VLAN tags if the NIC offload and capture point expose them; hardware VLAN offload can affect what a capture displays. Compare the bridge’s VLAN database and FDB with endpoint counters. A missing tag in a packet capture is not conclusive until capture location and offload are accounted for.

Common failure patterns include a PVID mismatch, an allowed VLAN missing from one trunk, an endpoint that sends tags on an access port, an unexpected default PVID, and the host bridge itself lacking membership for local traffic. Also inspect MTU consistency, STP state, and filtering/firewall rules. VLAN membership is not a substitute for Layer-3 firewall policy or host isolation from privileged local processes.

For a safe change, save the current bridge vlan show output and link topology, apply one membership change, and test the expected path plus at least one forbidden path. A production acceptance matrix should include source port, destination port, VLAN ID, tagging expectation, expected result, and evidence. Test after link flap or reboot if configuration is managed by NetworkManager, systemd-networkd, or another network manager; transient ip commands are not persistent configuration.

Persist the design through the network manager

The ip and bridge commands alter runtime state. They are ideal for a lab and for a carefully planned diagnostic, but a boot-time network manager may remove or replace those settings. Persist the VLAN filtering and port membership in the system’s authoritative configuration tool, then compare the runtime table after a clean restart. Avoid configuring the same bridge in multiple managers because races can produce non-reproducible membership.

Document whether the bridge is a host bridge, a container/VM switch, or a transit bridge. Container and virtualization managers may create ports dynamically, so a static configuration can omit future ports or expose them to the wrong VLAN. Use manager hooks or supported per-port settings to apply membership at port creation, and verify new ports are isolated by default until classified.

Linux bridge VLAN filtering makes one bridge capable of enforcing explicit Layer-2 segmentation, but correctness lives in the full port matrix. Define ingress classification, permitted VLANs, egress tagging, host membership, and persistence as one design. Then test both intended reachability and prohibited cross-VLAN paths rather than treating vlan_filtering 1 as the whole configuration.

Related:

Sources:

Comments