Skip to main content

VLAN Demux Deep Dive

Technical deep dive into the VLAN demultiplexer daemon.

Overview​

abng-demux is a high-performance packet capture and VLAN interface creation daemon that dynamically creates QinQ VLAN sub-interfaces on-demand when subscriber packets arrive.

Packet Capture​

AF_PACKET Socket​

abng-demux uses AF_PACKET socket for raw packet capture:

socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL))

Advantages:

  • No IP address required on interface
  • Captures all frames at link layer
  • Supports BPF filtering at kernel level

BPF Filter​

Kernel-level BPF (Berkeley Packet Filter) reduces CPU overhead by filtering at the socket level:

(ether[12:2] == 0x8100 or ether[12:2] == 0x88A8) and
(
(ether[16:2] == 0x8863) or
(udp and udp[6:2] == 67)
)

Filters for:

  • VLAN-tagged frames (802.1Q or 802.1ad)
  • PPPoE Discovery (ethertype 0x8863)
  • DHCP Discover (UDP port 67)

PACKET_AUXDATA​

Kernel software VLAN acceleration strips outer VLAN tag into metadata. abng-demux enables PACKET_AUXDATA and uses recvmsg() to recover the stripped tag:

setsockopt(sock, SOL_PACKET, PACKET_AUXDATA, &val, sizeof(val))

When tp_vlan_tci is set in control message, the stripped tag is reinserted into the frame.

VLAN Parsing​

Ethernet Header​

Destination MAC (6 bytes)
Source MAC (6 bytes)
EtherType (2 bytes)

VLAN Tag​

TPID (2 bytes): 0x8100 (802.1Q) or 0x88A8 (802.1ad)
TCI (2 bytes):
├─ Priority (3 bits)
├─ DEI (1 bit)
└─ VID (12 bits)

Multi-Level VLAN Nesting​

abng-demux supports arbitrary VLAN nesting depth:

Parsing algorithm:

  1. Start at offset 12 (after src/dst MAC)
  2. Read EtherType
  3. If VLAN (0x8100 or 0x88A8):
    • Extract VID
    • Move to next layer (offset += 4)
    • Repeat
  4. Stop when non-VLAN EtherType found

Interface Creation​

Naming Convention​

{trunk_interface}.{outer_vlan}.{stag}.{ctag}

Example:

eth1.111.500.100  (trunk=eth1, outer=111, stag=500, ctag=100)

Creation Process​

  1. Check Existence — Verify interface doesn't already exist
  2. Create VLAN Interface — Use netlink to create VLAN interface
  3. Set Protocol — Set S-Tag protocol (802.1ad or 802.1q)
  4. Bring Up — Set interface to UP state
  5. Notify abngd — Send interface_created event via IPC

Uses rtnetlink crate to:

  • Create VLAN interfaces
  • Set interface state
  • Query interface properties

Safety Features​

Rate Limiting​

Maximum creation_rate_limit interfaces created per second (default 100).

Implemented via token bucket algorithm:

  • Tokens replenished at rate_limit per second
  • Each interface creation costs 1 token
  • If no tokens available, creation deferred

Packet Validation​

Requires require_packets matching packets within require_window seconds before creating interface.

Prevents spurious interface creation from single corrupt frames.

Hard Limits​

Maximum max_interfaces dynamic VLAN interfaces (default 50000).

Prevents resource exhaustion from unlimited interface creation.

Idle Cleanup​

Background task runs every 60 seconds:

  1. Check each dynamic interface for active sessions
  2. Check traffic counters via ethtool
  3. If no sessions and no traffic for idle_timeout seconds:
    • Remove interface
    • Notify abngd

Performance Considerations​

Packet Processing​

  • BPF filter at kernel level reduces CPU overhead
  • PACKET_AUXDATA for VLAN tag recovery
  • Minimal copying of packet data

Interface Management​

  • HashMap for O(1) interface lookup
  • Batch netlink operations where possible
  • Lazy interface creation (on-demand)

Memory Usage​

  • One interface per subscriber (typical)
  • ~1KB per interface for kernel state
  • 50,000 interfaces ≈ 50MB memory

Troubleshooting​

No VLAN Interfaces Created​

Check 1: Demux Enabled

show configuration | match demux

Check 2: Trunk Interface Up

ip link show eth1

Check 3: Matching Packets

tcpdump -i eth1 -e 'ether[12:2] == 0x8100'

Check 4: Demux Logs

journalctl -u abng-demux -f

VLAN Interfaces Not Cleaned Up​

Check 1: Idle Timeout

show configuration | match idle_timeout

Check 2: Active Sessions

show subscribers

Check 3: Interface Traffic

ethtool -S eth1.111.500.100

Too Many VLAN Interfaces​

Check 1: Max Interfaces Limit

show configuration | match max_interfaces

Check 2: Stale Sessions

show subscribers

Next Steps​