Networking for beginners. Part 17: VLAN
All parts of the series “Networking for beginners”In part two the switch split collision domains but not the broadcast domain: an ARP request, a DHCP DISCOVER and a Router Advertisement reached everyone plugged into the switch. One switch — one network, one IP subnet. In an office with accounting, guest Wi-Fi, phones and servers, that would mean a switch and a cable for every network. VLAN, Virtual LAN, IEEE 802.1Q, solves the problem differently: one switch and one cable carry several independent networks that do not see each other, as if they were different switches. It is the most widely used segmentation technology, and, as usual, we are interested in what was added to the frame for it and what the switch does with it.
The tag: four bytes in the frame
A VLAN marks a frame with a network number. To do that, four bytes are inserted between the source MAC address and the EtherType:
bytes: 6 6 2 2 2 46…1500 4
┌──────────┬──────────┬───────┬────────┬─────────┬─────────┬─────┐
│ MAC │ MAC │ TPID │ TCI │ Ether │ data │ FCS │
│ dest. │ source │0x8100 │ │ Type │ │ │
└──────────┴──────────┴───────┴────────┴─────────┴─────────┴─────┘
└── 802.1Q tag ──┘
TCI, 16 bits: PCP (3) │ DEI (1) │ VID (12)
priority drop VLAN number, 1…4094
0…7 under
congestion
- TPID sits where the switch and the network card expect the EtherType. The value
0x8100says: "this is not a type, it is a tag; the real EtherType follows". This way old equipment that knows nothing about VLANs sees a frame of an unknown type and drops it rather than parsing it wrongly. - PCP is the priority, 0–7: switches with QoS queue high-priority frames (voice is 5) ahead of the rest.
- VID is the VLAN number. 12 bits give 4096 values, of which
0means "tag for priority only, no VLAN set" and4095is reserved, leaving 4094 networks. VLAN 1 is the default on most switches: all ports are in it until configured otherwise.
A tagged frame is 4 bytes longer, 1522 at most. The MTU for IP does not change: the tag lives in the Ethernet header, not in its payload. In tcpdump -e the tag is clearly visible:
3c:52:82:1a:2b:3c > d8:47:32:0a:0b:0c, ethertype 802.1Q (0x8100), length 78: vlan 10, p 0, ethertype IPv4 (0x0800), 192.168.10.5 > 192.168.20.7: ...
Two EtherTypes in a row: the first, 0x8100, is the tag; the second, 0x0800, is what's inside.
There is also a double tag, 802.1ad (QinQ): a provider wraps a customer's frames, which already have their own VLANs, in an outer tag with TPID 0x88a8, and carries the customer's VLANs through its network without caring about their numbers. The customer gets a "virtual cable" between offices with all of its 4094 networks inside.
Ports: access and trunk
Hosts, as a rule, know nothing about VLANs. A laptop sends an ordinary frame, and it is the switch that puts it into a VLAN, based on the port configuration.
An access port belongs to one VLAN. A frame arriving on such a port without a tag is treated internally by the switch as belonging to that VLAN (the number is called the PVID — port VLAN ID). A frame leaving through an access port is sent untagged: the host sees ordinary Ethernet. Tagged frames on an access port are usually dropped.
A trunk port carries several VLANs at once, and every frame on it is tagged, so the other end knows whose it is. A trunk is the cable between two switches, between a switch and a router, between a switch and a virtualization server, between a switch and an access point with several SSIDs.
┌──────────────── switch 1 ────────────┐ ┌─────── switch 2 ───────┐
A ──────────┤ port 1, access VLAN 10 │ │ port 1, access VLAN 10 ├──── B
192.168.10.5 │ │ trunk │ │ 192.168.10.7
│ port 2, access VLAN 20 port 24├────────────┤ port 24 │
C ──────────┤ │ 10, 20, 30 │ port 2, access VLAN 20 ├──── D
192.168.20.9 └──────────────────────────────────────┘ └────────────────────────┘ 192.168.20.3
A frame from A to B: arrives on port 1 untagged → switch 1 assigns it to VLAN 10 → the MAC table for VLAN 10 says "B is behind port 24" → the frame goes into the trunk with tag 10 → switch 2 reads the tag, strips it and sends the frame out of port 1 untagged. B received an ordinary frame. C and D saw nothing, even if it was a broadcast: broadcasts are flooded only to ports of the same VLAN.
Hence the key property: a VLAN is a broadcast domain. ARP, DHCP and RA live within one VLAN, and each VLAN needs its own IP subnet. A and C, on adjacent ports of the same switch, cannot exchange a frame in any way — for them these are different wires.
The switch's MAC address table becomes a table per VLAN: the key is the pair (VID, MAC). The same MAC can be in two VLANs behind different ports, and those are different entries. STP, which protects against loops (part two), also becomes either one tree for all VLANs, a tree per VLAN (PVST), or several trees for groups of VLANs (MSTP): this matters because a port blocked by STP is blocked for all VLANs of its tree.
Native VLAN
There is an exception on a trunk port: one VLAN can travel untagged — the native VLAN. Historically this was needed for compatibility with devices that send untagged frames into the same cable; by default the native VLAN is VLAN 1. An untagged frame arriving on a trunk goes into the native VLAN; a native VLAN frame leaves through the trunk untagged.
This leads to the most common VLAN mistake: a native VLAN mismatch between the two ends of a trunk. Switch 1 has native 1, switch 2 has native 10. An untagged frame from VLAN 1 leaves the first switch without a tag, arrives at the second and is treated as VLAN 10. Two networks silently merge into one, ARP starts finding other networks' addresses, DHCP hands out addresses from the wrong subnet. Switches can report this (CDP/LLDP — the protocols neighbors use to tell each other about themselves, including the native VLAN — will show "native VLAN mismatch"), but they cannot fix it.
In practice: use a separate unused number for the native VLAN on trunks (for example, 999), or "tag everything, including native". That way a mistake on one end does not merge networks but simply leaves VLAN 1 without connectivity, which is noticed immediately.
Hybrid: a phone and a computer on one wall jack
A port where one VLAN is untagged and another is tagged. The classic case is an IP phone with a pass-through port for a computer: the phone sends its own frames tagged with VLAN 30 (voice), and passes the computer's frames through untagged, so they land in VLAN 10 (data). The switch sees both VLANs on one port and tells them apart by the tag. The phone learns about VLAN 30 either from its configuration or via LLDP from the switch.
Routing between VLANs
We have split things up. Now accounting in VLAN 10 needs a server in VLAN 20. Two different broadcast domains are two IP subnets, and between subnets, as we know from part six, a router does the work.
Router on a stick. The router is connected with one cable to a trunk port, and on that interface it has subinterfaces, one per VLAN, with an address in each subnet:
┌────────────────────────────┐
trunk 10, 20 ──────────────┤ eth0 │
│ eth0.10 192.168.10.1/24 │
│ eth0.20 192.168.20.1/24 │
└────────────────────────────┘
A packet from A (192.168.10.5) to the server (192.168.20.7): A sends it to the gateway 192.168.10.1 → a frame tagged 10 travels up the trunk to the router → the router strips the Ethernet header, routes the packet, wraps it in a new frame tagged 20 and sends it into the same cable → the switch delivers it to the server. Every inter-VLAN packet crosses the cable twice, and that cable is the bottleneck. For a home or a small office it is fine, and this is exactly how routing works in Linux routers and in most home devices with a guest network.
L3 switch. A switch that can route by itself: it has an SVI (switch virtual interface, interface vlan 10) with an address in each VLAN, and forwarding between them happens in the same chip as switching, at full speed. All serious office and rack switches can do this. The router then remains for the way out, while traffic between VLANs never leaves the switch.
An important caveat: once there is a router between VLANs, isolation rests only on its rules. VLANs by themselves do not protect anything: they separate L2, and L3 joins them again. If accounting must not see the guest network, that has to be written in an ACL on the L3 switch or in the router's firewall. A typical design: the guest VLAN is routed only to the internet.
DHCP for each VLAN then works through the relay from part eleven: ip helper-address on each SVI, and one server serves all VLANs, picking the pool by giaddr. For IPv6, the router sends RAs with each subinterface's own prefix.
Why this is insecure
VLAN hopping with a double tag. An attacker in a trunk's native VLAN sends a frame with two tags: the outer one is native (1), the inner one is the target (20). The first switch sees the native tag, strips it and sends the frame into the trunk without it. The second switch sees the remaining tag 20 and delivers the frame into VLAN 20. It is one-way (no reply will come back), but enough to send something nasty. The cure is the same as for native mistakes: don't use the native VLAN for hosts.
Trunk spoofing. Cisco switches can negotiate trunks automatically using DTP: a port in "auto" mode becomes a trunk if the neighbor asks. An attacker sends DTP frames, the port becomes a trunk, and all VLANs are open to the host. The cure: hard-set access mode on host-facing ports and switchport nonegotiate.
Isolation within a VLAN. Sometimes hosts in one VLAN (guests) must not see each other but must see the gateway. For this there are private VLANs and port isolation: the switch does not forward frames between isolated ports, only to the uplink. It is the same client isolation from the list of defenses in part seven, only on cable.
Switch management belongs in a separate VLAN, unreachable from user VLANs. Otherwise a guest laptop can knock on the switch's web interface.
VLANs on Linux and in virtualization
Linux can do both tagged interfaces and a VLAN-aware switch.
A subinterface — a host or router connected to a trunk:
$ sudo ip link add link eth0 name eth0.10 type vlan id 10
$ sudo ip link set eth0.10 up
$ sudo ip addr add 192.168.10.1/24 dev eth0.10
eth0.10 is an ordinary interface: addresses, routes, tcpdump. Frames leaving through it get tag 10; frames tagged 10 arriving on eth0 go into it. Untagged ones stay on eth0. For a Linux router, this is router on a stick: a subinterface per VLAN, forwarding enabled, a firewall between them.
A Linux bridge with VLAN filtering — a switch with access and trunk ports:
$ sudo ip link add br0 type bridge vlan_filtering 1
$ sudo ip link set eth1 master br0 && sudo bridge vlan add dev eth1 vid 10 pvid untagged # access 10
$ sudo ip link set eth2 master br0 && sudo bridge vlan add dev eth2 vid 10 && sudo bridge vlan add dev eth2 vid 20 # trunk
$ bridge vlan show
pvid untagged means access: treat incoming untagged frames as VLAN 10, send outgoing ones untagged. This is how bridges for virtual machines are set up: each VM on its own bridge port in its own VLAN, and the physical eth2 is a trunk to the switch. In Hyper-V the same is done by Set-VMNetworkAdapterVlan -Access -VlanId 10, in VMware by a port group with a VLAN ID.
One trap when capturing: network cards can strip the tag in hardware (VLAN offload), and tcpdump -i eth0 may show frames without a tag even though they are tagged. ethtool -K eth0 rxvlan off txvlan off brings the tags back into the capture.
On a managed switch, the same configuration in Cisco terms:
interface GigabitEthernet0/1
switchport mode access
switchport access vlan 10
interface GigabitEthernet0/24
switchport mode trunk
switchport trunk allowed vlan 10,20,30
switchport trunk native vlan 999
switchport nonegotiate
Wi-Fi fits in through the access point: it has a trunk port, and each SSID maps to its own VLAN. Guest SSID → VLAN 30 → a subnet routed only to the internet.
Hands-on
On a host connected to a trunk, see which VLANs arrive at all:
$ sudo tcpdump -i eth0 -n -e vlan
If this is empty but there should be frames, the switch port is in access mode, or the card is stripping tags (see above). On a Linux router — which subinterfaces exist and what is in them:
$ ip -d link show type vlan
$ cat /proc/net/vlan/config
On the switch — the MAC address table per VLAN: show mac address-table vlan 10 shows which host is behind which port in that VLAN, and show interfaces trunk shows which VLANs are allowed on trunks and which one is native. When hosts "can't see each other", the first thing to compare is native and allowed on both ends of the trunk.
In Wireshark the tag expands as an 802.1Q Virtual LAN line between Ethernet and IP, with the PCP, DEI and ID fields.
Key takeaways
- A VLAN is a broadcast domain within one switch or a group of switches; each VLAN gets its own IP subnet. 4094 numbers.
- The 802.1Q tag is 4 bytes after the source MAC: TPID
0x8100, a priority and a 12-bit VID. - Access port: one VLAN, the host sees untagged frames. Trunk: many VLANs, all tagged except the native one. The native VLAN must match on both ends of a trunk; better not to use it for hosts.
- The MAC table is keyed by (VLAN, MAC). Flooding stays within the VLAN.
- Between VLANs there is a router: subinterfaces on a trunk (router on a stick, the cable twice) or an L3 switch with SVIs. After that, isolation lives only in the firewall rules.
- Linux:
ip link add link eth0 name eth0.10 type vlan id 10for a host, a bridge withvlan_filteringfor a switch. VLAN offload hides tags from tcpdump.
Next — Part 18: VXLAN: what to do when 4094 VLANs are not enough and the network has to stretch across routers and data centers. An Ethernet frame inside a UDP datagram, VNI, VTEP, how the tunnel learns where a remote MAC lives, and why clouds and Kubernetes need it.
Only registered users can leave a comment.
Sign in or register to leave a comment.