Configuring VLAN Linux networks with iproute2 lets you divide a single physical link into multiple isolated broadcast domains without extra hardware. This guide covers 802.1Q tagged interfaces, trunk port setup, and network segmentation using only the ip command included in every modern Linux distribution. By the end you will understand how to create and persist VLAN sub-interfaces, connect Linux hosts over a trunk, and verify isolation between segments.

Prerequisites

  • A Linux host running kernel 3.2 or later (any current distro qualifies)
  • Root or sudo access
  • The iproute2 package installed (ships by default on Debian, Ubuntu, RHEL, Fedora, Arch)
  • A physical or virtual NIC; for a real trunk you need an 802.1Q-capable managed switch configured in trunk mode
  • Basic familiarity with IP addressing and subnetting

Understanding 802.1Q VLANs

A VLAN (Virtual Local Area Network) creates logical network segments on top of a shared physical medium. 802.1Q is the IEEE standard that inserts a 4-byte tag into Ethernet frames to carry the VLAN ID. Linux implements this in the kernel’s 8021q module, which exposes VLAN sub-interfaces (sometimes called virtual interfaces) that appear to the network stack as ordinary Ethernet devices.

Key terminology:

  • VLAN ID (VID): A 12-bit number (1–4094) that identifies a VLAN.
  • Tagged port / trunk port: A switch or NIC port that carries frames with 802.1Q tags for multiple VLANs.
  • Untagged port / access port: Carries traffic for one VLAN; the switch removes the tag before forwarding to the end device.
  • Sub-interface: In Linux, a virtual interface like eth0.10 layered on top of a parent (eth0) that filters or injects tagged frames for VLAN 10.

When a frame arrives on eth0 with VLAN tag 10, the kernel routes it to eth0.10. Outgoing traffic sent via eth0.10 is tagged with VLAN 10 before hitting the wire.

Loading 802.1Q Support

Before creating VLAN interfaces, ensure the 8021q kernel module is loaded:

# Load the module for the current session
sudo modprobe 8021q

# Verify it is loaded
lsmod | grep 8021q

To load it automatically at boot, add it to the modules file:

echo "8021q" | sudo tee /etc/modules-load.d/8021q.conf

Most distributions load it on demand when you create the first VLAN interface, but being explicit avoids surprises.

Creating VLAN Sub-Interfaces with iproute2

The ip link add command creates a VLAN sub-interface in a single step. The syntax is straightforward:

# Create VLAN 10 on top of eth0
sudo ip link add link eth0 name eth0.10 type vlan id 10

# Bring the interface up
sudo ip link set eth0.10 up

# Assign an IP address
sudo ip addr add 192.168.10.1/24 dev eth0.10

Repeat for additional VLANs. Here we add VLAN 20 on the same parent:

sudo ip link add link eth0 name eth0.20 type vlan id 20
sudo ip link set eth0.20 up
sudo ip addr add 192.168.20.1/24 dev eth0.20

Inspect the result with the -d (detail) flag to confirm the VLAN ID and protocol:

ip -d link show eth0.10
# Output includes: vlan protocol 802.1Q id 10 <REORDER_HDR>

You can use any interface name — eth0.10 is a common convention but vlan10 or mgmt are equally valid. The VLAN ID is what matters, not the name.

Trunk Port Configuration

A trunk port carries tagged traffic for multiple VLANs between network devices. When connecting two Linux hosts back-to-back or connecting a Linux host to a managed switch, the physical interface acts as the trunk and each sub-interface represents one VLAN.

Two Linux hosts connected directly:

On Host A:

sudo ip link add link eth1 name eth1.100 type vlan id 100
sudo ip link set eth1.100 up
sudo ip addr add 10.0.100.1/24 dev eth1.100

sudo ip link add link eth1 name eth1.200 type vlan id 200
sudo ip link set eth1.200 up
sudo ip addr add 10.0.200.1/24 dev eth1.200

On Host B:

sudo ip link add link eth1 name eth1.100 type vlan id 100
sudo ip link set eth1.100 up
sudo ip addr add 10.0.100.2/24 dev eth1.100

sudo ip link add link eth1 name eth1.200 type vlan id 200
sudo ip link set eth1.200 up
sudo ip addr add 10.0.200.2/24 dev eth1.200

From Host A, ping 10.0.100.2 reaches Host B on VLAN 100. ping 10.0.200.2 reaches it on VLAN 200 — same physical wire, isolated broadcast domains.

Connecting to a managed switch:

On the switch, configure the port facing the Linux host as a trunk (or “tagged” on some vendors) and allow VLAN IDs 100 and 200. The Linux side requires no additional change — the parent interface already passes all tagged frames up to the appropriate sub-interface.

iproute2 vs. Other Tools for VLAN Management

ToolApproachPersistenceComplexity
iproute2 (ip)Kernel sub-interfacesManual or via networkd/NMLow
NetworkManager (nmcli)VLAN connection profilesBuilt-inLow
systemd-networkd.netdev + .network filesBuilt-inLow–Medium
Open vSwitch (OVS)Virtual switch, full VLAN/tunnel supportOVS databaseHigh
bridge + vlan_filtering802.1Q on Linux bridgeManual or networkdMedium

For a single host with a few VLANs, iproute2 plus systemd-networkd is the simplest reliable stack. For complex virtual networking (multiple VMs, VXLAN overlays), Open vSwitch is the right choice.

Real-World Scenario: Isolating Management and Production Traffic

You manage a hypervisor with a single 10 GbE NIC. Security policy requires that VM traffic and host management traffic never share a broadcast domain. The upstream switch port is already a trunk carrying VLAN 10 (management) and VLAN 100 (production VMs).

# Management network for the host itself
sudo ip link add link eno1 name eno1.10 type vlan id 10
sudo ip link set eno1.10 up
sudo ip addr add 192.168.10.5/24 dev eno1.10
sudo ip route add default via 192.168.10.1 dev eno1.10

# Production bridge for VMs — attach the VLAN interface to a bridge
sudo ip link add name br100 type bridge
sudo ip link set eno1.100 master br100
sudo ip link add link eno1 name eno1.100 type vlan id 100
sudo ip link set eno1.100 up
sudo ip link set br100 up

VM virtual interfaces (tap devices) are then added as bridge ports on br100. VM traffic is isolated inside VLAN 100; the host’s management plane lives on VLAN 10 and is reachable only through its own sub-interface.

Making VLAN Configuration Persistent with systemd-networkd

The ip link commands above are ephemeral — they disappear on reboot. With systemd-networkd, persistence is declarative and clean.

Create the VLAN netdev definition at /etc/systemd/network/10-vlan10.netdev:

[NetDev]
Name=eth0.10
Kind=vlan

[VLAN]
Id=10

Create the network file at /etc/systemd/network/10-vlan10.network:

[Match]
Name=eth0.10

[Network]
Address=192.168.10.1/24

Also ensure the parent interface is brought up and configured to pass VLAN traffic at /etc/systemd/network/05-eth0.network:

[Match]
Name=eth0

[Network]
VLAN=eth0.10
VLAN=eth0.20

Apply changes:

sudo systemctl enable --now systemd-networkd
sudo networkctl reload

For NetworkManager users, the equivalent is:

sudo nmcli connection add type vlan con-name vlan10 dev eth0 id 10 ip4 192.168.10.1/24
sudo nmcli connection up vlan10

Gotchas and Edge Cases

MTU and jumbo frames: Adding an 802.1Q tag increases the frame size by 4 bytes. If the parent interface MTU is 1500 and a remote host also uses 1500, you may hit fragmentation on intermediate devices that do not allow 1504-byte frames. Either lower the sub-interface MTU to 1496 or enable jumbo frames on the NIC and switch.

sudo ip link set eth0.10 mtu 1496

Promiscuous mode is not needed: The kernel’s 802.1Q stack filters by VLAN ID at the driver level. You do not need promisc mode on the parent interface for normal VLAN operation.

VLAN 1 is special on many switches: Some managed switches treat VLAN 1 as the native/untagged VLAN and may strip or mishandle its tag. Prefer VIDs 2–4094 for explicitly tagged VLANs to avoid ambiguity.

Double-tagging (QinQ): Linux supports nested VLAN tags with type vlan protocol 802.1ad. Use this only when your network explicitly requires provider bridging (IEEE 802.1ad).

Virtual machines and bridge VLAN filtering: When VMs share a Linux bridge, enable VLAN filtering on the bridge itself (bridge vlan filtering 1) rather than creating sub-interfaces per VM. This is more scalable and avoids MAC flooding across bridge ports.

NetworkManager interference: On desktops or servers running NetworkManager, it may try to manage your manually created VLAN interfaces. Mark the parent interface as unmanaged in /etc/NetworkManager/conf.d/ or use nmcli to define the VLANs properly so NM and networkd do not conflict.

Troubleshooting Common Issues

No traffic on the VLAN sub-interface:

  1. Confirm the parent is up: ip link show eth0 — state must be UP.
  2. Confirm the sub-interface is up: ip link show eth0.10.
  3. Check the switch port is in trunk mode and the VLAN ID is allowed.
  4. Capture with tcpdump -i eth0 -e vlan to see whether tagged frames arrive.

Wrong VLAN ID filtering:

# Confirm the VLAN ID of a sub-interface
ip -d link show eth0.10 | grep "vlan id"

A mismatch between Linux and the switch VLAN ID is the most common error.

Route conflicts between VLANs:

If you assign overlapping subnets across VLANs, the kernel will route between them via the host’s routing table, defeating isolation. Use distinct, non-overlapping subnets for each VLAN.

Interface disappears after reboot:

Runtime ip link commands do not persist. Use systemd-networkd, NetworkManager, or /etc/network/interfaces (Debian/Ubuntu legacy) to define persistent VLAN interfaces.

Summary

  • 802.1Q VLAN Linux configuration uses the ip link add ... type vlan id command from iproute2 — no extra packages required.
  • Sub-interfaces like eth0.10 sit on top of a physical parent and filter or inject tagged frames for a specific VLAN ID.
  • A trunk port carries multiple VLANs over one physical link; each VLAN gets its own sub-interface and IP.
  • For persistent configuration use systemd-networkd .netdev/.network files or nmcli connection profiles.
  • Watch out for MTU overhead, VLAN 1 quirks on switches, and NetworkManager conflicts.
  • Combine VLAN sub-interfaces with Linux bridges to connect VMs to tagged segments without a physical managed switch.