VLAN Tag Handling in Network Switches: Tagged vs Untagged Port Behavior for Programmers


10 views

When examining VLAN operations in modern network switches, the handling of tagged and untagged frames follows specific IEEE 802.1Q standards. Let's analyze the exact behavior using your 4-port switch example:

Switch Configuration:
Port 1: TAGGED VLAN10, UNTAGGED VLAN1
Port 2: UNTAGGED VLAN10
Port 3: UNTAGGED VLAN10
Port 4: Default configuration

For a VLAN10-tagged packet entering Port 1:

  1. The switch maintains the VLAN tag internally while processing
  2. When forwarding to Port 2 (UNTAGGED for VLAN10):
    Original Frame: [Preamble][DA][SA][802.1Q][Type][Data][FCS]
    Egress Frame:   [Preamble][DA][SA][Type][Data][FCS]

    The switch strips the VLAN tag before transmission

For an ICMP reply from the Port 2 device:

1. Untagged frame enters Port 2 (assigned to VLAN10)
2. Switch internally marks it with VLAN10 PVID
3. When routing to Port 1 (TAGGED for VLAN10):
   The switch adds the VLAN tag:
   [Preamble][DA][SA][802.1Q][Type][Data][FCS]

Here's how to configure this in Cisco IOS:

interface GigabitEthernet1/0/1
 switchport mode trunk
 switchport trunk native vlan 1
 switchport trunk allowed vlan 10
!
interface GigabitEthernet1/0/2
 switchport mode access
 switchport access vlan 10
!

And the equivalent in Linux using vconfig:

vconfig add eth0 10
ifconfig eth0.10 up
vconfig set_egress_map eth0.10 0 10
  • Tags are preserved internally even when stripped on egress
  • Untagged ingress traffic inherits the port's PVID
  • Layer 3 routing decisions occur after VLAN processing
  • Packet headers are modified during tag add/remove operations

Use these commands to verify configuration:

# Cisco
show vlan brief
show interfaces trunk

# Linux
cat /proc/net/vlan/config
bridge vlan show

In a VLAN-capable switch, packet handling depends on both ingress and egress port configurations. Let's break down the exact behavior using your 4-port switch example:

SWITCH_CONFIG = {
    "Port1": {"tagged_vlans": [10], "untagged_vlan": 1},
    "Port2": {"untagged_vlan": 10},
    "Port3": {"untagged_vlan": 10},
    "Port4": {}  # Default VLAN1 untagged
}

When a VLAN10-tagged frame enters Port1:

  1. The switch validates the VLAN tag against Port1's allowed VLANs
  2. Forwards to all ports in VLAN10 (Ports 2 and 3 in this case)
  3. Before egress on Port2: removes the VLAN tag because Port2 is configured as untagged for VLAN10

The return untagged ICMP reply from Port2:

def handle_untagged_frame(port, frame):
    if port.untagged_vlan:
        frame.vlan = port.untagged_vlan  # Assigns VLAN10
        if egress_port.tagged_vlans.includes(frame.vlan):
            frame.add_tag()  # Port1 will tag with VID10

When the switch performs inter-VLAN routing:

# Pseudocode for routed packet flow
if packet.dest_ip not in current_vlan:
    routed_packet = layer3_route(packet)
    if egress_port.untagged_vlan == routed_packet.vlan:
        strip_vlan_tag(routed_packet)
    elif egress_port.tagged_vlans.includes(routed_packet.vlan):
        add_vlan_tag(routed_packet, routed_packet.vlan)

Cisco IOS equivalent configuration:

interface GigabitEthernet0/1
 switchport mode trunk
 switchport trunk allowed vlan 10
 switchport trunk native vlan 1  # Untagged VLAN1
!
interface GigabitEthernet0/2
 switchport access vlan 10  # Untagged member of VLAN10
  • Tags are always preserved when traversing tagged trunk ports
  • Tags are stripped when egressing access (untagged) ports
  • Untagged frames inherit the PVID (Port VLAN ID) of the ingress port
  • Routed packets follow the egress port's tagging rules