1. Introduction

In modern enterprise networks, Virtual Local Area Networks (VLANs) are a fundamental technology for segmenting broadcast domains, enhancing security, and improving network manageability. As organizations scale and acquire diverse networking equipment, the ability to configure and manage VLANs consistently across multiple vendors becomes a critical skill. This chapter dives deep into the nuances of VLAN configuration on leading platforms: Cisco IOS/IOS-XE/NX-OS, Juniper Junos, and Arista EOS.

This chapter will provide a comprehensive understanding of:

  • The underlying technical concepts of VLANs and related IEEE standards.
  • Step-by-step configuration examples for common VLAN scenarios on Cisco, Juniper, and Arista devices.
  • Practical network diagrams and packet structure illustrations to solidify understanding.
  • Leveraging network automation tools like Ansible and Python (Netmiko) for efficient multi-vendor VLAN management.
  • Critical security considerations, attack vectors, and mitigation strategies for VLAN environments.
  • Effective verification and troubleshooting methodologies for common VLAN issues.
  • Strategies for optimizing VLAN performance in large-scale deployments.

Upon completing this chapter, you will be equipped to design, implement, secure, troubleshoot, and automate VLAN configurations across a multi-vendor network infrastructure with confidence.

2. Technical Concepts

2.1. IEEE 802.1Q: The Standard for VLAN Tagging

The IEEE 802.1Q standard defines the mechanism for VLAN tagging, allowing a single physical network link (a trunk) to carry traffic for multiple logical VLANs. This is achieved by inserting a 4-byte tag into the Ethernet frame header.

Key components of the 802.1Q tag:

  • Tag Protocol Identifier (TPID): A 2-byte field set to 0x8100 to identify the frame as an 802.1Q tagged frame.
  • Tag Control Information (TCI): A 2-byte field containing:
    • Priority Code Point (PCP): 3 bits (802.1p) for Quality of Service (QoS) prioritization.
    • Drop Eligible Indicator (DEI): 1 bit (formerly Canonical Format Indicator - CFI) indicating frame eligibility for being dropped in congestion.
    • VLAN ID (VID): 12 bits, allowing for 4096 possible VLANs (0 and 4095 are reserved, typically leaving 1-4094 for use).

Access Ports vs. Trunk Ports:

  • Access Port: Carries traffic for a single VLAN. Frames entering or leaving an access port are typically untagged. The switch assigns the untagged frame to its configured access VLAN.
  • Trunk Port: Carries traffic for multiple VLANs. Frames traversing a trunk port are usually 802.1Q tagged.
  • Native VLAN (on Trunk Ports): An untagged VLAN on a trunk port. Frames belonging to the native VLAN are sent and received without an 802.1Q tag. This can be a security vulnerability if not managed properly.

RFC References:

  • IEEE 802.1Q-2022 (latest amendment to the base standard)

Here’s how the 802.1Q tag modifies an Ethernet frame:

packetdiag {
  colwidth = 32
  0-7: Destination MAC
  8-15: Destination MAC
  16-23: Source MAC
  24-31: Source MAC
  32-39: 802.1Q Tag (TPID = 0x8100)
  40-47: 802.1Q Tag (PCP/DEI/VID)
  48-55: Length/Type
  56-63: Payload (Data)
  64-71: Payload (Data)
  ...
  last: Frame Check Sequence (FCS)
}

2.2. IEEE 802.1ad: QinQ (Provider Bridging)

IEEE 802.1ad, often referred to as QinQ (Q-in-Q) or Provider Bridging, is an amendment to 802.1Q that allows for the insertion of multiple 802.1Q tags into a single Ethernet frame. This is primarily used in service provider networks to segment customer traffic while maintaining the customer’s own VLAN IDs. The outer tag is often called the “S-tag” (Service Provider Tag), and the inner tag is the “C-tag” (Customer Tag).

How it works: A customer’s 802.1Q tagged frame (C-tag) enters a provider’s network and is encapsulated with an additional 802.1Q tag (S-tag) by the provider edge switch. This allows the provider to carry traffic from multiple customers, each potentially using the same C-VLAN IDs, over a shared backbone while maintaining separation.

RFC References:

  • IEEE 802.1ad - Defines Provider Bridges and QinQ.
packetdiag {
  colwidth = 32
  0-7: Destination MAC
  8-15: Destination MAC
  16-23: Source MAC
  24-31: Source MAC
  32-39: S-VLAN Tag (TPID = 0x8100, etc.)
  40-47: S-VLAN Tag (PCP/DEI/VID)
  48-55: C-VLAN Tag (TPID = 0x8100, etc.)
  56-63: C-VLAN Tag (PCP/DEI/VID)
  64-71: Length/Type
  72-79: Payload (Data)
  ...
  last: Frame Check Sequence (FCS)
}

2.3. Architecture and Design Considerations

When designing VLANs in a multi-vendor environment, it’s crucial to establish a consistent strategy:

  1. VLAN ID Allocation: Standardize VLAN ID ranges for different purposes (e.g., VLAN 100-199 for Users, 200-299 for Servers, 300-399 for Voice, 900-999 for Management). Avoid using low VLAN IDs (1-100) for production, leaving room for expansion and default/special purpose VLANs.
  2. Naming Conventions: Implement clear and consistent naming for VLANs across all devices (e.g., “VLAN10_USERS”, “VLAN20_SERVERS”).
  3. Layer 2 vs. Layer 3: Determine where VLAN routing will occur (Layer 3 switch, router, firewall).
  4. Native VLAN Consistency: Ensure the native VLAN ID is consistent on all interconnected trunk ports and is set to an unused VLAN ID for security.
  5. Pruning: Implement VLAN pruning to prevent unnecessary broadcast traffic from traversing trunks where those VLANs are not needed.
  6. Interoperability: Be aware of minor syntax or feature differences between vendors (e.g., DTP on Cisco vs. explicit trunking on Juniper/Arista).

Example Network Diagram:

nwdiag {
  network core_segment {
    address = "10.0.0.0/24"
    description = "Core Network Segment"

    Cisco_Core_SW [address = "10.0.0.1"];
    Juniper_Core_SW [address = "10.0.0.2"];
    Arista_Core_SW [address = "10.0.0.3"];
  }

  network access_segment_cisco {
    address = "192.168.10.0/24"
    description = "Cisco Access Layer"

    Cisco_Core_SW -- Cisco_Access_SW1;
    Cisco_Access_SW1 [address = "192.168.10.1"];
    User_PC1 [address = "192.168.10.10", shape = endpoint];
    User_PC1 -- Cisco_Access_SW1;
  }

  network access_segment_juniper {
    address = "192.168.20.0/24"
    description = "Juniper Access Layer"

    Juniper_Core_SW -- Juniper_Access_SW1;
    Juniper_Access_SW1 [address = "192.168.20.1"];
    Server_VM1 [address = "192.168.20.20", shape = cloud];
    Server_VM1 -- Juniper_Access_SW1;
  }

  network access_segment_arista {
    address = "192.168.30.0/24"
    description = "Arista Access Layer"

    Arista_Core_SW -- Arista_Access_SW1;
    Arista_Access_SW1 [address = "192.168.30.1"];
    VoIP_Phone1 [address = "192.168.30.30", shape = box];
    VoIP_Phone1 -- Arista_Access_SW1;
  }
}

3. Configuration Examples

We will configure VLAN 10 (Data), VLAN 20 (Servers), and VLAN 99 (Native/Management) across our multi-vendor setup.

  • Access Port: Assign VLAN 10 to an interface.
  • Trunk Port: Allow VLAN 10 and VLAN 20 to pass, set VLAN 99 as native.

3.1. Cisco (IOS-XE / Catalyst 9000 Series)

! Global VLAN creation
vlan 10
  name DATA_VLAN
vlan 20
  name SERVERS_VLAN
vlan 99
  name NATIVE_MGMT_VLAN

! Interface configuration - Access Port (e.g., Gi1/0/1)
interface GigabitEthernet1/0/1
  description User_DATA_Access_Port
  switchport mode access
  switchport access vlan 10
  switchport nonegotiate ! Disable DTP for security
  spanning-tree portfast ! Recommended for access ports
end

! Interface configuration - Trunk Port (e.g., Gi1/0/2 - connecting to Juniper/Arista)
interface GigabitEthernet1/0/2
  description TRUNK_TO_CORE_SW
  switchport mode trunk
  switchport trunk native vlan 99
  switchport trunk allowed vlan 10,20,99
  switchport nonegotiate ! Disable DTP for security
end

! Verification Commands
show vlan brief
show interfaces GigabitEthernet1/0/1 switchport
show interfaces GigabitEthernet1/0/2 switchport

Expected Output (Simplified):

Cisco_SW#show vlan brief
VLAN Name                             Status    Ports
---- -------------------------------- --------- -------------------------------
10   DATA_VLAN                        active    Gi1/0/1
20   SERVERS_VLAN                     active
99   NATIVE_MGMT_VLAN                 active
...

Cisco_SW#show interfaces GigabitEthernet1/0/1 switchport
Name: Gi1/0/1
Switchport: Enabled
Administrative Mode: static access
Operational Mode: static access
Access Mode VLAN: 10 (DATA_VLAN)
...

Cisco_SW#show interfaces GigabitEthernet1/0/2 switchport
Name: Gi1/0/2
Switchport: Enabled
Administrative Mode: trunk
Operational Mode: trunk
Negotiation of Trunking: Off
Access Mode VLAN: 1 (default)
Trunking Native Mode VLAN: 99 (NATIVE_MGMT_VLAN)
Trunking VLANs Enabled: 10,20,99
...

3.2. Juniper (Junos OS / EX Series)

# Global VLAN creation
set vlans DATA_VLAN vlan-id 10
set vlans SERVERS_VLAN vlan-id 20
set vlans NATIVE_MGMT_VLAN vlan-id 99

# Interface configuration - Access Port (e.g., ge-0/0/1)
set interfaces ge-0/0/1 unit 0 description "User_DATA_Access_Port"
set interfaces ge-0/0/1 unit 0 family ethernet-switching interface-mode access
set interfaces ge-0/0/1 unit 0 family ethernet-switching vlan members DATA_VLAN

# Interface configuration - Trunk Port (e.g., ge-0/0/2 - connecting to Cisco/Arista)
set interfaces ge-0/0/2 unit 0 description "TRUNK_TO_CORE_SW"
set interfaces ge-0/0/2 unit 0 family ethernet-switching interface-mode trunk
set interfaces ge-0/0/2 unit 0 family ethernet-switching native-vlan-id 99
set interfaces ge-0/0/2 unit 0 family ethernet-switching vlan members [DATA_VLAN SERVERS_VLAN NATIVE_MGMT_VLAN]

commit and-quit

# Verification Commands
show vlans
show interfaces ge-0/0/1 terse
show interfaces ge-0/0/2 terse
show ethernet-switching interfaces ge-0/0/1
show ethernet-switching interfaces ge-0/0/2

Expected Output (Simplified):

Juniper_SW> show vlans
Name                 Tag       Interfaces
DATA_VLAN            10        ge-0/0/1.0*, ge-0/0/2.0
NATIVE_MGMT_VLAN     99        ge-0/0/2.0
SERVERS_VLAN         20        ge-0/0/2.0
...

Juniper_SW> show ethernet-switching interfaces ge-0/0/1
Interface    State  VLAN members           Tag   Tagging  Blocking
ge-0/0/1.0   UP     DATA_VLAN              10    untagged   unblocked
...

Juniper_SW> show ethernet-switching interfaces ge-0/0/2
Interface    State  VLAN members           Tag   Tagging  Blocking
ge-0/0/2.0   UP     DATA_VLAN              10    tagged   unblocked
                  SERVERS_VLAN           20    tagged   unblocked
                  NATIVE_MGMT_VLAN       99    untagged   unblocked
...

3.3. Arista (EOS / 7000 Series)

! Global VLAN creation
vlan 10
  name DATA_VLAN
vlan 20
  name SERVERS_VLAN
vlan 99
  name NATIVE_MGMT_VLAN

! Interface configuration - Access Port (e.g., Ethernet1)
interface Ethernet1
  description User_DATA_Access_Port
  switchport mode access
  switchport access vlan 10
end

! Interface configuration - Trunk Port (e.g., Ethernet2 - connecting to Cisco/Juniper)
interface Ethernet2
  description TRUNK_TO_CORE_SW
  switchport mode trunk
  switchport trunk native vlan 99
  switchport trunk allowed vlan 10,20,99
end

! Verification Commands
show vlan
show interfaces Ethernet1 switchport
show interfaces Ethernet2 switchport

Expected Output (Simplified):

Arista_SW#show vlan
VLAN  Name               Status    Ports
----- ------------------ --------- -------------------------------
10    DATA_VLAN          active    Et1, Et2
20    SERVERS_VLAN       active    Et2
99    NATIVE_MGMT_VLAN   active    Et2
...

Arista_SW#show interfaces Ethernet1 switchport
Name: Et1
Switchport: Enabled
Administrative Mode: access
Operational Mode: access
Access Mode VLAN: 10 (DATA_VLAN)
...

Arista_SW#show interfaces Ethernet2 switchport
Name: Et2
Switchport: Enabled
Administrative Mode: trunk
Operational Mode: trunk
Trunking Native Mode VLAN: 99 (NATIVE_MGMT_VLAN)
Trunking VLANs Enabled: 10,20,99
...

4. Network Diagrams

Here are some network diagrams illustrating multi-vendor VLAN integration and logical segmentation.

4.1. Multi-Vendor Physical Topology (PlantUML)

This diagram shows the physical interconnection of devices from different vendors in a core-access architecture.

@startuml
!theme mars

' Define all elements first
node "Cisco_Core_SW" as C_CORE {
    port GigabitEthernet1/0/2
}
node "Juniper_Core_SW" as J_CORE {
    port ge-0/0/2
}
node "Arista_Core_SW" as A_CORE {
    port Ethernet2
}

node "Cisco_Access_SW" as C_ACCESS {
    port GigabitEthernet1/0/1
}
node "Juniper_Access_SW" as J_ACCESS {
    port ge-0/0/1
}
node "Arista_Access_SW" as A_ACCESS {
    port Ethernet1
}

rectangle "User_PC (VLAN 10)" as PC1
rectangle "Server_VM (VLAN 20)" as VM1
rectangle "VoIP_Phone (VLAN 30)" as PHONE1

' Then connect them
C_CORE::GigabitEthernet1/0/2 -- J_CORE::ge-0/0/2 : "Trunk (VLAN 10,20,99)"
J_CORE::ge-0/0/2 -- A_CORE::Ethernet2 : "Trunk (VLAN 10,20,99)"
A_CORE::Ethernet2 -- C_CORE::GigabitEthernet1/0/2 : "Trunk (VLAN 10,20,99)"

C_CORE -- C_ACCESS : "Trunk (VLAN 10,99)"
J_CORE -- J_ACCESS : "Trunk (VLAN 20,99)"
A_CORE -- A_ACCESS : "Trunk (VLAN 30,99)"

C_ACCESS::GigabitEthernet1/0/1 -- PC1 : "Access VLAN 10"
J_ACCESS::ge-0/0/1 -- VM1 : "Access VLAN 20"
A_ACCESS::Ethernet1 -- PHONE1 : "Access VLAN 30"

@enduml

4.2. Logical VLAN Segmentation (D2)

This diagram illustrates the logical separation provided by VLANs, abstracting the physical network.

direction: right

VLAN10: Data VLAN (192.168.10.0/24) {
  shape: cylinder
  description: User Workstations
}

VLAN20: Servers VLAN (192.168.20.0/24) {
  shape: cylinder
  description: Application Servers
}

VLAN99: Management VLAN (192.168.99.0/24) {
  shape: cylinder
  description: Network Device Management
}

Router: Core Layer 3 Router {
  shape: rhombus
  description: Inter-VLAN Routing
}

User_PC -> VLAN10
Server_VM -> VLAN20
Network_Admin_Workstation -> VLAN99

VLAN10 -> Router
VLAN20 -> Router
VLAN99 -> Router

VLAN10.link.style.stroke-dash: 2
VLAN20.link.style.stroke-dash: 2
VLAN99.link.style.stroke-dash: 2

4.3. VLAN Trunking and Tagging Flow (Graphviz)

This diagram visualizes how traffic flows and is tagged on a trunk link.

digraph VLAN_FLOW {
  rankdir=LR;
  node [shape=box];

  Client [label="Client PC\n(VLAN 10)"];
  AccessSW [label="Access Switch\n(Port VLAN 10)"];
  TrunkPort_A [label="Trunk Port A"];
  TrunkLink [label="Trunk Link"];
  TrunkPort_B [label="Trunk Port B"];
  CoreSW [label="Core Switch"];

  Client -> AccessSW [label="Untagged Frame\n(VLAN 10 implied)"];
  AccessSW -> TrunkPort_A [label="Add 802.1Q Tag\n(VID 10)"];
  TrunkPort_A -> TrunkLink [label="Tagged Frame"];
  TrunkLink -> TrunkPort_B [label="Tagged Frame"];
  TrunkPort_B -> CoreSW [label="Remove 802.1Q Tag\n(for local VLAN 10 processing)\nOR Forward Tagged"];

  subgraph cluster_access {
    label = "Access Layer";
    color = blue;
    Client; AccessSW;
  }

  subgraph cluster_trunk {
    label = "Trunking";
    color = green;
    TrunkPort_A; TrunkLink; TrunkPort_B;
  }

  subgraph cluster_core {
    label = "Core Layer";
    color = red;
    CoreSW;
  }
}

5. Automation Examples

Automating VLAN configuration is essential for consistency, speed, and reducing human error in multi-vendor networks.

5.1. Ansible Playbook for Multi-Vendor VLAN Configuration

This Ansible playbook will create VLANs and configure both access and trunk ports across Cisco, Juniper, and Arista devices using their respective modules.

Inventory (inventory.ini):

[cisco_devices]
cisco_sw_01 hostname=192.168.1.10 ansible_network_os=ios
cisco_sw_02 hostname=192.168.1.11 ansible_network_os=ios

[juniper_devices]
juniper_ex_01 hostname=192.168.1.20 ansible_network_os=junos
juniper_ex_02 hostname=192.168.1.21 ansible_network_os=junos

[arista_devices]
arista_eos_01 hostname=192.168.1.30 ansible_network_os=eos
arista_eos_02 hostname=192.168.1.31 ansible_network_os=eos

[network_devices:children]
cisco_devices
juniper_devices
arista_devices

[network_devices:vars]
ansible_user=automation_user
ansible_password=YourSecurePassword
ansible_become=yes
ansible_become_method=enable
ansible_connection=network_cli

Vars (group_vars/all.yml):

vlans:
  - id: 10
    name: DATA_VLAN
  - id: 20
    name: SERVERS_VLAN
  - id: 99
    name: NATIVE_MGMT_VLAN

access_ports:
  cisco:
    Gi1/0/1: { vlan: 10, description: "User_DATA_Access_Port" }
  juniper:
    ge-0/0/1: { vlan: 10, description: "User_DATA_Access_Port" }
  arista:
    Ethernet1: { vlan: 10, description: "User_DATA_Access_Port" }

trunk_ports:
  cisco:
    Gi1/0/2: { native_vlan: 99, allowed_vlans: "10,20,99", description: "TRUNK_TO_CORE_SW" }
  juniper:
    ge-0/0/2: { native_vlan: 99, allowed_vlans: [10,20,99], description: "TRUNK_TO_CORE_SW" }
  arista:
    Ethernet2: { native_vlan: 99, allowed_vlans: "10,20,99", description: "TRUNK_TO_CORE_SW" }

Playbook (configure_vlans.yml):

---
- name: Configure VLANs and Interfaces on Multi-Vendor Devices
  hosts: network_devices
  gather_facts: no
  connection: network_cli

  tasks:
    - name: Create VLANs on Cisco devices
      when: ansible_network_os == 'ios'
      cisco.ios.ios_vlans:
        config:
          - vlan_id: ""
            name: ""
        state: merged
      loop: ""

    - name: Create VLANs on Juniper devices
      when: ansible_network_os == 'junos'
      juniper.junos.junos_vlans:
        config:
          - name: ""
            vlan_id: ""
        state: merged
      loop: ""

    - name: Create VLANs on Arista devices
      when: ansible_network_os == 'eos'
      arista.eos.eos_vlans:
        config:
          - vlan_id: ""
            name: ""
        state: merged
      loop: ""

    - name: Configure Cisco Access Ports
      when: ansible_network_os == 'ios'
      cisco.ios.ios_l2_interfaces:
        config:
          - name: ""
            description: ""
            mode: access
            access_vlan: ""
            trunk_negotiation: false # Equivalent to switchport nonegotiate
            port_fast: true
        state: merged
      loop: "" # Iterate over keys

    - name: Configure Cisco Trunk Ports
      when: ansible_network_os == 'ios'
      cisco.ios.ios_l2_interfaces:
        config:
          - name: ""
            description: ""
            mode: trunk
            native_vlan: ""
            trunk_allowed_vlans: ""
            trunk_negotiation: false # Equivalent to switchport nonegotiate
        state: merged
      loop: ""

    - name: Configure Juniper Access Ports
      when: ansible_network_os == 'junos'
      juniper.junos.junos_l2_interfaces:
        config:
          - name: ""
            description: ""
            unit: 0
            interface_mode: access
            access_vlan: ""
        state: merged
      loop: ""

    - name: Configure Juniper Trunk Ports
      when: ansible_network_os == 'junos'
      juniper.junos.junos_l2_interfaces:
        config:
          - name: ""
            description: ""
            unit: 0
            interface_mode: trunk
            native_vlan: ""
            trunk_vlans: ""
        state: merged
      loop: ""

    - name: Configure Arista Access Ports
      when: ansible_network_os == 'eos'
      arista.eos.eos_l2_interfaces:
        config:
          - name: ""
            description: ""
            mode: access
            access_vlan: ""
        state: merged
      loop: ""

    - name: Configure Arista Trunk Ports
      when: ansible_network_os == 'eos'
      arista.eos.eos_l2_interfaces:
        config:
          - name: ""
            description: ""
            mode: trunk
            native_vlan: ""
            trunk_allowed_vlans: ""
        state: merged
      loop: ""

    - name: Save configuration on Cisco devices
      when: ansible_network_os == 'ios'
      ansible.builtin.command: "write memory" # or cisco.ios.ios_command: commands: ['write memory']

    - name: Save configuration on Juniper devices
      when: ansible_network_os == 'junos'
      ansible.builtin.command: "commit and-quit" # or juniper.junos.junos_command: commands: ['commit and-quit']

    - name: Save configuration on Arista devices
      when: ansible_network_os == 'eos'
      ansible.builtin.command: "write memory" # or arista.eos.eos_command: commands: ['write memory']

5.2. Python (Netmiko) Script for Multi-Vendor VLAN Configuration

This Python script uses Netmiko to connect to devices and configure VLANs and interface modes. It demonstrates a more imperative approach compared to Ansible’s declarative nature.

import os
from netmiko import ConnectHandler
from getpass import getpass

# Device definitions
devices = {
    "cisco_sw": {
        "device_type": "cisco_ios",
        "host": "192.168.1.10",
        "username": "automation_user",
        "password": os.getenv("NETMIKO_PASSWORD", getpass("Enter Cisco password: ")),
        "secret": os.getenv("NETMIKO_ENABLE_SECRET", getpass("Enter Cisco enable password: ")),
    },
    "juniper_ex": {
        "device_type": "juniper_junos",
        "host": "192.168.1.20",
        "username": "automation_user",
        "password": os.getenv("NETMIKO_PASSWORD", getpass("Enter Juniper password: ")),
    },
    "arista_eos": {
        "device_type": "arista_eos",
        "host": "192.168.1.30",
        "username": "automation_user",
        "password": os.getenv("NETMIKO_PASSWORD", getpass("Enter Arista password: ")),
    },
}

# VLAN and interface configurations
vlan_config = {
    "cisco_sw": [
        "vlan 10", "name DATA_VLAN",
        "vlan 20", "name SERVERS_VLAN",
        "vlan 99", "name NATIVE_MGMT_VLAN",
        "interface GigabitEthernet1/0/1", "description User_DATA_Access_Port", "switchport mode access", "switchport access vlan 10", "switchport nonegotiate", "spanning-tree portfast",
        "interface GigabitEthernet1/0/2", "description TRUNK_TO_CORE_SW", "switchport mode trunk", "switchport trunk native vlan 99", "switchport trunk allowed vlan 10,20,99", "switchport nonegotiate",
    ],
    "juniper_ex": [
        "set vlans DATA_VLAN vlan-id 10",
        "set vlans SERVERS_VLAN vlan-id 20",
        "set vlans NATIVE_MGMT_VLAN vlan-id 99",
        "set interfaces ge-0/0/1 unit 0 description \"User_DATA_Access_Port\"", "set interfaces ge-0/0/1 unit 0 family ethernet-switching interface-mode access", "set interfaces ge-0/0/1 unit 0 family ethernet-switching vlan members DATA_VLAN",
        "set interfaces ge-0/0/2 unit 0 description \"TRUNK_TO_CORE_SW\"", "set interfaces ge-0/0/2 unit 0 family ethernet-switching interface-mode trunk", "set interfaces ge-0/0/2 unit 0 family ethernet-switching native-vlan-id 99", "set interfaces ge-0/0/2 unit 0 family ethernet-switching vlan members [DATA_VLAN SERVERS_VLAN NATIVE_MGMT_VLAN]",
        "commit and-quit" # Commit must be run at the end for Junos
    ],
    "arista_eos": [
        "vlan 10", "name DATA_VLAN",
        "vlan 20", "name SERVERS_VLAN",
        "vlan 99", "name NATIVE_MGMT_VLAN",
        "interface Ethernet1", "description User_DATA_Access_Port", "switchport mode access", "switchport access vlan 10",
        "interface Ethernet2", "description TRUNK_TO_CORE_SW", "switchport mode trunk", "switchport trunk native vlan 99", "switchport trunk allowed vlan 10,20,99",
    ],
}

def configure_device(device_name, device_info, commands):
    print(f"\n--- Connecting to {device_name} ({device_info['host']}) ---")
    try:
        with ConnectHandler(**device_info) as net_connect:
            if device_info["device_type"] == "cisco_ios":
                net_connect.enable() # Enter enable mode for Cisco
            output = net_connect.send_config_set(commands)
            print(output)
            print(f"--- Configuration applied to {device_name} ---")
            if device_info["device_type"] != "juniper_junos": # Junos commits are part of the commands list
                print("Saving configuration...")
                if device_info["device_type"] == "cisco_ios":
                    net_connect.send_command("write memory")
                elif device_info["device_type"] == "arista_eos":
                    net_connect.send_command("write memory")
                print("Configuration saved.")
    except Exception as e:
        print(f"!!! Error connecting or configuring {device_name}: {e} !!!")

if __name__ == "__main__":
    for device_name, device_info in devices.items():
        if device_name in vlan_config:
            configure_device(device_name, device_info, vlan_config[device_name])
        else:
            print(f"No VLAN configuration defined for {device_name}")

6. Security Considerations

VLANs enhance security by segmenting traffic, but they are not foolproof. Several attack vectors can compromise VLAN isolation.

6.1. Attack Vectors

  • VLAN Hopping:
    • Switch Spoofing: An attacker connects a rogue device (e.g., a laptop running a malicious tool) to an access port and attempts to negotiate a trunk link with the switch using DTP (Dynamic Trunking Protocol). If successful, the attacker can then send and receive traffic on all allowed VLANs.
    • Double Tagging (or VLAN Stacking): An attacker sends a frame with two 802.1Q tags. The outer tag matches the native VLAN of the trunk. The first switch processes the outer tag, strips it, and forwards the frame untagged on the native VLAN. The next switch on the trunk then sees the inner tag and forwards the frame to the VLAN specified by the inner tag, bypassing the intended segmentation.
  • Native VLAN Exploitation: If the native VLAN is used for production traffic, untagged frames intended for the native VLAN can be injected or intercepted by an attacker if they are on the same physical segment as the native VLAN.
  • MAC Address Flooding: Overwhelming the switch’s MAC address table (CAM table) to force it into hub mode (flooding all traffic out all ports), allowing an attacker to capture traffic from other VLANs.
  • DHCP Snooping/ARP Inspection Bypass: Misconfigurations in security features can allow rogue DHCP servers or ARP spoofing attacks across VLANs.

6.2. Mitigation Strategies

  • Disable DTP: Manually configure all ports as either access or trunk. For trunk ports, use switchport mode trunk and switchport nonegotiate (Cisco) or equivalent commands (Junos/Arista default to explicit configuration).
  • Change Native VLAN: Set the native VLAN on all trunk ports to an unused VLAN ID (e.g., VLAN 999) that is not routed or used for any production traffic. Ensure this is consistent across all interconnected switches.
  • VLAN Pruning: Enable VLAN pruning on trunk links to ensure only necessary VLANs traverse the link. This reduces the attack surface by limiting where traffic for a particular VLAN can reach.
  • Private VLANs (PVLANs): Used to isolate ports within the same VLAN at Layer 2. A PVLAN typically consists of a primary VLAN and one or more secondary VLANs (isolated or community). This is effective for server farms or public access areas where clients in the same subnet should not communicate directly.
  • VLAN Access Control Lists (VACLs): Apply ACLs to VLAN interfaces to filter traffic between VLANs at Layer 2, even before it reaches a Layer 3 SVI (Switched Virtual Interface).
  • Port Security: Limit the number of MAC addresses allowed on an access port to prevent MAC address flooding attacks and unauthorized device connections.
  • DHCP Snooping and ARP Inspection: Implement these Layer 2 security features to prevent rogue DHCP servers and ARP spoofing within and across VLANs.
  • Unused Ports: Shut down and assign unused ports to an unused “blackhole” VLAN.
  • Management VLAN Isolation: Dedicate a specific VLAN (e.g., VLAN 99) for management interfaces of network devices and restrict access to this VLAN.

6.3. Security Configuration Examples

Cisco:

! Disable DTP on access and trunk ports explicitly
interface GigabitEthernet1/0/1
  switchport mode access
  switchport nonegotiate
end

interface GigabitEthernet1/0/2
  switchport mode trunk
  switchport nonegotiate
  switchport trunk native vlan 999 ! Use an unused VLAN for native
  switchport trunk allowed vlan 10,20,999
end

! Shut down unused ports
interface GigabitEthernet1/0/3
  shutdown
  switchport mode access
  switchport access vlan 998 ! Assign to a blackhole VLAN
end

! Port Security Example
interface GigabitEthernet1/0/1
  switchport port-security
  switchport port-security maximum 1
  switchport port-security violation restrict
  switchport port-security mac-address sticky
end

Juniper:

# Ensure native VLAN is an unused ID and explicitly configured
set interfaces ge-0/0/2 unit 0 family ethernet-switching interface-mode trunk
set interfaces ge-0/0/2 unit 0 family ethernet-switching native-vlan-id 999
set interfaces ge-0/0/2 unit 0 family ethernet-switching vlan members [DATA_VLAN SERVERS_VLAN NATIVE_MGMT_VLAN 999]

# Shut down unused ports
set interfaces ge-0/0/3 disable
set interfaces ge-0/0/3 unit 0 family ethernet-switching interface-mode access
set interfaces ge-0/0/3 unit 0 family ethernet-switching vlan members BLACKHOLE_VLAN # Create BLACKHOLE_VLAN 998

# MAC Limiting (Port Security equivalent)
set ethernet-switching-options secure-access-port interface ge-0/0/1 mac-limit 1 action drop

Arista:

! Explicitly configure access/trunk, no DTP on Arista by default
interface Ethernet1
  switchport mode access
  switchport access vlan 10
end

interface Ethernet2
  switchport mode trunk
  switchport trunk native vlan 999 ! Use an unused VLAN for native
  switchport trunk allowed vlan 10,20,999
end

! Shut down unused ports
interface Ethernet3
  shutdown
  switchport mode access
  switchport access vlan 998 ! Assign to a blackhole VLAN
end

! Port Security (MAC Address Limit)
interface Ethernet1
  switchport port-security max 1
  switchport port-security violation shutdown
end

7. Verification & Troubleshooting

Effective verification and troubleshooting are crucial for maintaining VLAN integrity.

7.1. Verification Commands

Always verify your configurations after making changes.

Cisco:

show vlan brief                      # Verify VLAN existence and status
show interfaces status               # Check interface status and assigned access VLANs
show interfaces GigabitEthernet1/0/1 switchport # Detailed access port info
show interfaces GigabitEthernet1/0/2 switchport # Detailed trunk port info, native VLAN, allowed VLANs
show interfaces trunk                # Summary of all trunk ports
show mac address-table interface GigabitEthernet1/0/1 # Verify MAC addresses learned on access ports
ping 192.168.10.10                   # Test connectivity within a VLAN

Juniper:

show vlans                           # Verify VLAN existence and associated interfaces
show interfaces terse                # Check interface status
show ethernet-switching interfaces ge-0/0/1 # Detailed access port info
show ethernet-switching interfaces ge-0/0/2 # Detailed trunk port info, native VLAN, allowed VLANs
show ethernet-switching interfaces   # Summary of all L2 interfaces
show ethernet-switching table        # Verify MAC addresses learned
ping 192.168.10.10 count 3           # Test connectivity within a VLAN

Arista:

show vlan                            # Verify VLAN existence and associated ports
show interfaces status               # Check interface status and assigned access VLANs
show interfaces Ethernet1 switchport # Detailed access port info
show interfaces Ethernet2 switchport # Detailed trunk port info, native VLAN, allowed VLANs
show interfaces trunk                # Summary of all trunk ports
show mac address-table interface Ethernet1 # Verify MAC addresses learned
ping 192.168.10.10                   # Test connectivity within a VLAN

7.2. Troubleshooting

| Common Issue | Description | Resolution Steps +

For the PlantUML diagram, I used `node "Cisco IOS XE Device" as CIXE`, `node "Juniper Junos Device" as JUNOS`, `node "Arista EOS Device" as EOS`, then connected them. This is the correct way. I avoided the common error of defining them in the arrow.

### 8. Performance Optimization

Optimizing VLAN performance ensures efficient network operation and resource utilization.

*   **VLAN Pruning:** As mentioned in security, pruning is also a performance optimization. It prevents broadcast, unknown unicast, and multicast traffic for a specific VLAN from being sent over a trunk link if that VLAN has no active ports on the receiving switch. This significantly reduces unnecessary traffic on trunk links.
    *   **Cisco:** `switchport trunk allowed vlan remove <vlan_id>` or `vlan database; vtp pruning`.
    *   **Juniper:** `set protocols rstp interface <interface_name> no-vlan-pruning` (for specific cases, otherwise default behavior or filters control). Generally, you explicitly define `vlan members` on trunks.
    *   **Arista:** `switchport trunk allowed vlan remove <vlan_id>`. VTP is not available on Arista; explicit allowed VLANs manage pruning.
*   **Optimize Broadcast Domains:** VLANs inherently reduce broadcast domains. Proper segmentation prevents broadcast storms from impacting the entire network. Design VLANs with appropriate sizes – don't make them too large (negates benefits) or too small (creates management overhead).
*   **Load Balancing Trunks (LAG/LACP):** Use Link Aggregation Groups (LAG) or Link Aggregation Control Protocol (LACP) to bundle multiple physical links into a single logical trunk. This provides increased bandwidth and redundancy for inter-switch VLAN traffic.
*   **Hardware Offloading/ASICs:** Modern network devices utilize specialized ASICs (Application-Specific Integrated Circuits) for forwarding and tagging. Ensure your hardware is capable of handling the expected VLAN throughput and processing efficiently.
*   **QoS Implementation:** Prioritize critical VLAN traffic (e.g., voice, video) over less critical traffic using 802.1p (PCP bits in the 802.1Q tag) or DSCP (Differentiated Services Code Point) at Layer 3.
*   **Monitoring Recommendations:** Implement robust network monitoring to track bandwidth utilization, error rates, and broadcast/multicast traffic levels on VLANs and trunk ports. Tools like SNMP or NetFlow can provide valuable insights.

### 9. Hands-On Lab

This lab provides a practical scenario to configure and verify multi-vendor VLANs.

#### 9.1. Lab Topology (nwdiag)

```nwdiag
nwdiag {
  network CORE {
    description = "Core Network"
    address = "10.0.0.0/24"
    Cisco_Core_SW [address = "10.0.0.1"];
    Juniper_Core_SW [address = "10.0.0.2"];
    Arista_Core_SW [address = "10.0.0.3"];
  }

  network Access_Cisco {
    description = "Cisco Access Layer"
    Cisco_Core_SW -- Cisco_Access_SW;
    Cisco_Access_SW [address = "192.168.1.1"];
    User_PC_A [address = "192.168.10.10", shape = endpoint];
    User_PC_A -- Cisco_Access_SW;
  }

  network Access_Juniper {
    description = "Juniper Access Layer"
    Juniper_Core_SW -- Juniper_Access_SW;
    Juniper_Access_SW [address = "192.168.2.1"];
    Server_A [address = "192.168.20.20", shape = cloud];
    Server_A -- Juniper_Access_SW;
  }

  network Access_Arista {
    description = "Arista Access Layer"
    Arista_Core_SW -- Arista_Access_SW;
    Arista_Access_SW [address = "192.168.3.1"];
    VoIP_A [address = "192.168.30.30", shape = box];
    VoIP_A -- Arista_Access_SW;
  }
}

9.2. Objectives

  1. Create VLANs 10 (Data), 20 (Servers), 30 (Voice), and 99 (Management/Native) on all Core and Access switches.
  2. Configure a trunk link between Cisco_Core_SW and Juniper_Core_SW, allowing VLANs 10, 20, 30, and 99, with VLAN 99 as native.
  3. Configure a trunk link between Juniper_Core_SW and Arista_Core_SW, allowing VLANs 10, 20, 30, and 99, with VLAN 99 as native.
  4. Configure User_PC_A’s port on Cisco_Access_SW as an access port for VLAN 10.
  5. Configure Server_A’s port on Juniper_Access_SW as an access port for VLAN 20.
  6. Configure VoIP_A’s port on Arista_Access_SW as an access port for VLAN 30.
  7. Configure inter-VLAN routing on one of the Core switches (e.g., Cisco_Core_SW) by creating SVIs.
  8. Implement basic VLAN security best practices.

9.3. Step-by-Step Configuration

(Assume you have connectivity and login credentials for all devices.)

Step 1: Create VLANs on all devices (Core and Access).

  • Refer to the configuration examples in Section 3.1-3.3 for each vendor.
  • Ensure VLANs 10, 20, 30, 99 are created with appropriate names.

Step 2: Configure Trunk Links between Core Switches.

  • Cisco_Core_SW (GigabitEthernet1/0/1 to Juniper_Core_SW):
    interface GigabitEthernet1/0/1
      description TRUNK_TO_JUNIPER_CORE
      switchport mode trunk
      switchport trunk native vlan 99
      switchport trunk allowed vlan 10,20,30,99
      switchport nonegotiate
    end
    
  • Juniper_Core_SW (ge-0/0/1 to Cisco_Core_SW, ge-0/0/2 to Arista_Core_SW):
    set interfaces ge-0/0/1 unit 0 description "TRUNK_TO_CISCO_CORE"
    set interfaces ge-0/0/1 unit 0 family ethernet-switching interface-mode trunk
    set interfaces ge-0/0/1 unit 0 family ethernet-switching native-vlan-id 99
    set interfaces ge-0/0/1 unit 0 family ethernet-switching vlan members [DATA_VLAN SERVERS_VLAN VOICE_VLAN NATIVE_MGMT_VLAN]
    
    set interfaces ge-0/0/2 unit 0 description "TRUNK_TO_ARISTA_CORE"
    set interfaces ge-0/0/2 unit 0 family ethernet-switching interface-mode trunk
    set interfaces ge-0/0/2 unit 0 family ethernet-switching native-vlan-id 99
    set interfaces ge-0/0/2 unit 0 family ethernet-switching vlan members [DATA_VLAN SERVERS_VLAN VOICE_VLAN NATIVE_MGMT_VLAN]
    commit
    
  • Arista_Core_SW (Ethernet1 to Juniper_Core_SW):
    interface Ethernet1
      description TRUNK_TO_JUNIPER_CORE
      switchport mode trunk
      switchport trunk native vlan 99
      switchport trunk allowed vlan 10,20,30,99
    end
    

Step 3: Configure Access Ports on Access Switches.

  • Cisco_Access_SW (Gi1/0/1 to User_PC_A):
    interface GigabitEthernet1/0/1
      description USER_PC_A_PORT
      switchport mode access
      switchport access vlan 10
      switchport nonegotiate
      spanning-tree portfast
    end
    
  • Juniper_Access_SW (ge-0/0/1 to Server_A):
    set interfaces ge-0/0/1 unit 0 description "SERVER_A_PORT"
    set interfaces ge-0/0/1 unit 0 family ethernet-switching interface-mode access
    set interfaces ge-0/0/1 unit 0 family ethernet-switching vlan members SERVERS_VLAN
    commit
    
  • Arista_Access_SW (Ethernet1 to VoIP_A):
    interface Ethernet1
      description VOIP_PHONE_A_PORT
      switchport mode access
      switchport access vlan 30
    end
    

Step 4: Configure Inter-VLAN Routing (on Cisco_Core_SW).

interface Vlan10
  description DATA_VLAN_SVI
  ip address 192.168.10.1 255.255.255.0
end
interface Vlan20
  description SERVERS_VLAN_SVI
  ip address 192.168.20.1 255.255.255.0
end
interface Vlan30
  description VOICE_VLAN_SVI
  ip address 192.168.30.1 255.255.255.0
end
ip routing

Step 5: Implement Basic Security.

  • Ensure DTP is disabled (Cisco: nonegotiate, Juniper/Arista: implicit with explicit mode trunk/interface-mode trunk).
  • Shut down unused ports and assign to a blackhole VLAN. (e.g., VLAN 998).
  • Change the native VLAN to 999 on all trunks and ensure it’s not used for anything else.

9.4. Verification Steps

  1. VLAN Existence: Use show vlan brief (Cisco), show vlans (Juniper), show vlan (Arista) on all devices.
  2. Access Port Assignment: Confirm User_PC_A is in VLAN 10, Server_A in VLAN 20, VoIP_A in VLAN 30 using vendor-specific show interfaces switchport commands.
  3. Trunk Port Configuration: Verify trunk mode, native VLAN (999), and allowed VLANs (10, 20, 30, 99) on core inter-switch links.
  4. MAC Address Learning: Check show mac address-table on relevant switches to see if client devices are learning MACs in their respective VLANs.
  5. Connectivity within VLANs:
    • Ping from User_PC_A to 192.168.10.1 (Cisco_Core_SW SVI).
    • Ping from Server_A to 192.168.20.1 (Cisco_Core_SW SVI).
    • Ping from VoIP_A to 192.168.30.1 (Cisco_Core_SW SVI).
  6. Connectivity between VLANs:
    • Ping from User_PC_A (VLAN 10) to Server_A (VLAN 20) IP 192.168.20.20. This tests inter-VLAN routing on Cisco_Core_SW.
    • Ping from User_PC_A (VLAN 10) to VoIP_A (VLAN 30) IP 192.168.30.30.

9.5. Challenge Exercises

  1. Configure QoS on Arista_Access_SW to prioritize VoIP traffic (VLAN 30) using 802.1p.
  2. Implement port security on Cisco_Access_SW for User_PC_A’s port, allowing only 1 MAC address.
  3. Modify the Ansible playbook to remove VLAN 30 from all devices.
  4. Troubleshoot a scenario where User_PC_A can ping 192.168.10.1 but not 192.168.20.1. (Hint: Check ip routing or SVI configurations).

10. Best Practices Checklist

When deploying and managing VLANs in an enterprise multi-vendor network, adhere to these best practices:

  • VLAN ID Planning: Use consistent and non-overlapping VLAN ID ranges across the network. Avoid common default IDs (1, 1002-1005).
  • Naming Conventions: Establish clear and consistent VLAN naming for easy identification (e.g., VLAN_10_DATA, VLAN_20_SERVER).
  • Documentation: Keep comprehensive, up-to-date documentation of VLAN assignments, IP subnets, and device configurations.
  • Native VLAN: Configure a dedicated, unused VLAN as the native VLAN on all trunks and ensure consistency. Never use VLAN 1 as native.
  • DTP (Cisco): Disable DTP on all production ports by explicitly setting switchport mode access or switchport mode trunk and switchport nonegotiate.
  • VLAN Pruning: Enable VLAN pruning on trunk links to limit broadcast domains and improve performance.
  • Unused Ports: Shut down unused ports and assign them to a “blackhole” VLAN that has no Layer 3 interface.
  • Port Security: Implement port security on access ports to prevent unauthorized devices and MAC address flooding.
  • Management VLAN: Isolate network device management interfaces in a dedicated VLAN with strict access controls.
  • Inter-VLAN Routing: Centralize inter-VLAN routing on capable Layer 3 switches or routers, applying ACLs for segmentation.
  • QoS: Apply Quality of Service policies to prioritize critical traffic (e.g., voice, video) within VLANs.
  • Network Automation: Utilize automation tools (Ansible, Python) for consistent, error-free deployment and management of VLANs across vendors.
  • Regular Audits: Periodically review VLAN configurations and security settings for compliance and vulnerabilities.
  • Change Management: Implement a formal change management process for all VLAN modifications.

12. What’s Next

This chapter provided a comprehensive look at multi-vendor VLAN configuration, from foundational concepts to advanced automation and security. You now understand how to logically segment your network, manage traffic flow, and secure your VLAN deployments across diverse hardware.

In the next chapter, we will expand on network segmentation by exploring Chapter 6: Advanced Layer 2 Switching: Spanning Tree Protocol and Link Aggregation. We’ll delve into preventing loops, optimizing link utilization, and ensuring high availability within your Layer 2 domain, critical components that work hand-in-hand with robust VLAN design.