VLAN

Inter-VLAN Routing with Router-on-a-Stick on Cisco IOS XE

When you don't have a Layer 3 switch, router-on-a-stick provides inter-VLAN routing via a single physical link split into subinterfaces. Learn when this design is appropriate, how to configure subinterfaces, and why it's a bandwidth bottleneck.
Inter-VLAN Routing with Router-on-a-Stick on Cisco IOS XE
In: VLAN

Router-on-a-Stick (ROAS) is a routing design where a single physical link between a switch and a router carries traffic for multiple VLANs. The router creates subinterfaces (one per VLAN) on that physical port, each subinterface tagged with a different VLAN ID via 802.1Q. When a host in VLAN 10 needs to reach a host in VLAN 20, the packet goes from the switch to the router's VLAN 10 subinterface, the router routes it, and sends it back on the VLAN 20 subinterface. Router-on-a-Stick was standard before Layer 3 switches were affordable. Today it's used in smaller deployments or labs, but it's a significant bandwidth bottleneck: all inter-VLAN traffic flows through a single link, constraining throughput to that link's capacity.

When to Use Router-on-a-Stick

Appropriate scenarios: - Lab environments: You have a switch without routing capability and a Cisco router available - Small remote sites: A single ISR (Integrated Services Router) provides WAN connectivity and inter-VLAN routing - Budget constraints: No Layer 3 switch in the rack; existing router becomes the VLAN router - Temporary routing: You need inter-VLAN routing during a switch upgrade

Not appropriate for: - High-traffic environments: All inter-VLAN traffic passes through one link (typically 1 Gbps max) - Large deployments: Scales poorly with many VLANs - Redundancy: Single point of failure (if the router goes down, inter-VLAN routing stops)

How Router-on-a-Stick Works

A standard physical interface carries one VLAN. Router-on-a-Stick uses subinterfaces to carry multiple VLANs on the same physical link:

  • Physical link: Gi0/0/0 (1 Gbps) connects the router to the switch
  • Switch trunk: The switch port is configured as a trunk, carrying all VLANs on that link
  • Subinterfaces: Router creates Gi0/0/0.10, Gi0/0/0.20, Gi0/0/0.30 (one per VLAN)
  • 802.1Q tagging: Each subinterface is encapsulated with a VLAN tag
  • Routing happens per subinterface: Traffic between VLANs routes through the physical link at the IP layer

Traffic flow example (Host in VLAN 10 sends packet to Host in VLAN 20):

  1. Host A (VLAN 10, 10.10.10.10) sends packet to Host B (VLAN 20, 10.10.20.20)
  2. Host A's ARP request resolves to the default gateway (10.10.10.254, router's VLAN 10 SVI)
  3. Host A sends packet to the router via Gi0/0/0.10 (tagged with VLAN 10)
  4. Router receives on Gi0/0/0.10, looks at routing table
  5. Router sees destination 10.10.20.20 is on Gi0/0/0.20 (VLAN 20)
  6. Router sends packet out Gi0/0/0.20 (tagged with VLAN 20)
  7. Switch receives VLAN 20 tagged frame on the trunk, forwards to Host B's port

All inter-VLAN traffic goes down the same physical link—a critical bottleneck.

Configuring Router-on-a-Stick (R1-GW in Lab)

Step 1: Create Subinterface for VLAN 10 (Users)

R1-GW(config)# interface Gi0/0/0.10
R1-GW(config-subif)# description VLAN 10 Users Subinterface
R1-GW(config-subif)# encapsulation dot1q 10
R1-GW(config-subif)# ip address 10.10.10.254 255.255.255.0
R1-GW(config-subif)# no shutdown
R1-GW(config-subif)# exit

Key commands: - encapsulation dot1q 10: Tags all traffic on this subinterface with VLAN 10 - ip address 10.10.10.254 255.255.255.0: Gateway address for VLAN 10 - no shutdown: Enables the subinterface

Step 2: Create Subinterface for VLAN 20 (Servers)

R1-GW(config)# interface Gi0/0/0.20
R1-GW(config-subif)# description VLAN 20 Servers Subinterface
R1-GW(config-subif)# encapsulation dot1q 20
R1-GW(config-subif)# ip address 10.10.20.254 255.255.255.0
R1-GW(config-subif)# no shutdown
R1-GW(config-subif)# exit

Step 3: Create Subinterface for VLAN 30 (Management)

R1-GW(config)# interface Gi0/0/0.30
R1-GW(config-subif)# description VLAN 30 Management Subinterface
R1-GW(config-subif)# encapsulation dot1q 30
R1-GW(config-subif)# ip address 10.10.30.254 255.255.255.0
R1-GW(config-subif)# no shutdown
R1-GW(config-subif)# exit

Step 4: Create Subinterface for VLAN 40 (Voice)

R1-GW(config)# interface Gi0/0/0.40
R1-GW(config-subif)# description VLAN 40 Voice Subinterface
R1-GW(config-subif)# encapsulation dot1q 40
R1-GW(config-subif)# ip address 10.10.40.254 255.255.255.0
R1-GW(config-subif)# no shutdown
R1-GW(config-subif)# exit

Step 5: Create Subinterface for VLAN 50 (Guest)

R1-GW(config)# interface Gi0/0/0.50
R1-GW(config-subif)# description VLAN 50 Guest Subinterface
R1-GW(config-subif)# encapsulation dot1q 50
R1-GW(config-subif)# ip address 10.10.50.254 255.255.255.0
R1-GW(config-subif)# no shutdown
R1-GW(config-subif)# exit

Step 6: Create Subinterface for VLAN 99 (Native)

R1-GW(config)# interface Gi0/0/0.99
R1-GW(config-subif)# description VLAN 99 Native Subinterface
R1-GW(config-subif)# encapsulation dot1q 99 native
R1-GW(config-subif)# ip address 10.10.99.254 255.255.255.0
R1-GW(config-subif)# no shutdown
R1-GW(config-subif)# exit
R1-GW(config)# end

Note: encapsulation dot1q 99 native marks this subinterface as handling untagged traffic (the native VLAN). See the Troubleshooting section for why this matters.

Step 7: Configure the Physical Interface

The physical interface must be up for subinterfaces to work:

R1-GW(config)# interface Gi0/0/0
R1-GW(config-if)# description Trunk to CORE-SW1
R1-GW(config-if)# no shutdown
R1-GW(config-if)# exit
R1-GW(config)# end

Don't assign an IP address to the physical interface—subinterfaces handle all IP routing.

Step 8: Configure the Switch Trunk Port

On CORE-SW1, configure the port connecting to R1-GW as a trunk:

CORE-SW1(config)# interface Gi1/0/5
CORE-SW1(config-if)# switchport trunk encapsulation dot1q
CORE-SW1(config-if)# switchport mode trunk
CORE-SW1(config-if)# switchport nonegotiate
CORE-SW1(config-if)# switchport trunk allowed vlan 10,20,30,40,50,99
CORE-SW1(config-if)# switchport trunk native vlan 99
CORE-SW1(config-if)# description Trunk to R1-GW
CORE-SW1(config-if)# no shutdown
CORE-SW1(config-if)# end

This port now carries all VLANs to the router.

Verification

Check Subinterfaces on Router

R1-GW# show ip interface brief | include Gi0/0/0
Interface                  IP-Address      OK? Method Status    Protocol
Gi0/0/0                    unassigned      YES unset  up        up
Gi0/0/0.10                 10.10.10.254    YES manual up        up
Gi0/0/0.20                 10.10.20.254    YES manual up        up
Gi0/0/0.30                 10.10.30.254    YES manual up        up
Gi0/0/0.40                 10.10.40.254    YES manual up        up
Gi0/0/0.50                 10.10.50.254    YES manual up        up
Gi0/0/0.99                 10.10.99.254    YES manual up        up

All subinterfaces are up/up. The physical interface Gi0/0/0 is also up/up (it's Layer 1 active because the cable is plugged in).

View Subinterface Details

R1-GW# show interfaces Gi0/0/0.10
GigabitEthernet0/0/0.10 is up, line protocol is up (connected)
  Hardware is Gigabit Ethernet, address is aabb.cc00.0300 (bia aabb.cc00.0300)
  Description: VLAN 10 Users Subinterface
  Internet address is 10.10.10.254/24
  MTU 1500 bytes, BW 1000000 Kbit/sec
  Encapsulation ARPA, loopback not set
  Keepalive set (10 sec)
  ARP type: ARPA, ARP Timeout 04:00:00
  Last input 0:00:03, output 0:00:01, output hang never
  Last clearing of "show interface" counters 12:45:22
  Input queue: 0/75/0/0 (size/max/drops/flushes); Total output drops: 0
  Queueing strategy: fifo
  Output queue: 0/40 (size/max)
  5 minute input rate 45 bits/sec, 0 packets/sec
  5 minute output rate 23 bits/sec, 0 packets/sec
     156 packets input, 12456 bytes, 0 no buffer
     Received 45 broadcasts, 0 runts, 0 giants
     Input errors: 0, CRC: 0, frame: 0, overrun: 0, ignored: 0
     7856 packets output, 123456 bytes, 0 underruns
     Output errors: 0, collisions: 0, interface resets: 0

Key observations: - Encapsulation ARPA: Uses standard IP addressing (not Ethernet broadcast) - Internet address: 10.10.10.254/24 (gateway for VLAN 10) - Input/output rates: Shows inter-VLAN traffic flowing through this subinterface

Check Routing Table

R1-GW# show ip route | include "10.10"
      10.0.0.0/8 is variably subnetted, 7 subnets, 2 masks
C        10.10.10.0/24 is directly connected, GigabitEthernet0/0/0.10
L        10.10.10.254/32 is local, GigabitEthernet0/0/0.10
C        10.10.20.0/24 is directly connected, GigabitEthernet0/0/0.20
L        10.10.20.254/32 is local, GigabitEthernet0/0/0.20
C        10.10.30.0/24 is directly connected, GigabitEthernet0/0/0.30
L        10.10.30.254/32 is local, GigabitEthernet0/0/0.30
C        10.10.40.0/24 is directly connected, GigabitEthernet0/0/0.40
L        10.10.40.254/32 is local, GigabitEthernet0/0/0.40
C        10.10.50.0/24 is directly connected, GigabitEthernet0/0/0.50
L        10.10.50.254/32 is local, GigabitEthernet0/0/0.50
C        10.10.99.0/24 is directly connected, GigabitEthernet0/0/0.99
L        10.10.99.254/32 is local, GigabitEthernet0/0/0.99

Each VLAN subnet is directly connected via its subinterface.

Verify Trunk on Switch

CORE-SW1# show interfaces Gi1/0/5 switchport | include "Operational\|Allowed\|Pruning\|Trunking"
Operational Mode              : trunk
Trunking Native Mode VLAN      : 99
Trunking VLANs Enabled         : 10,20,30,40,50,99
Pruning VLANs Enabled          : 2-1001

The trunk is active and allowing VLANs 10-50 and 99.

Testing Inter-VLAN Routing

Ping from VLAN 10 Host to VLAN 20 Host

Host A in VLAN 10 (10.10.10.100):

C:\> ping 10.10.20.100
Pinging 10.10.20.100 with 32 bytes of data:
Reply from 10.10.20.100: bytes=32 time=15ms TTL=63
Reply from 10.10.20.100: bytes=32 time=14ms TTL=63
Reply from 10.10.20.100: bytes=32 time=15ms TTL=63
Reply from 10.10.20.100: bytes=32 time=14ms TTL=63

Ping statistics for 10.10.20.100:
    Sent = 4, Received = 4, Lost = 0%

Successful! TTL is 63 (sent as 64 from Host A, decremented once by the router).

Trace Route from VLAN 10 to VLAN 20

C:\> tracert 10.10.20.100
Tracing route to 10.10.20.100 over a maximum of 30 hops:

  1   10.10.10.254 [router's VLAN 10 SVI]
  2   10.10.20.100 [destination host]

Trace complete.

Two hops: 1. Gateway (10.10.10.254 on R1-GW) 2. Destination (10.10.20.100 on the server)

View Inter-VLAN Traffic on Router

R1-GW# show interfaces Gi0/0/0.10 | include "packets\|bytes"
  156 packets input, 12456 bytes
  7856 packets output, 123456 bytes

R1-GW# show interfaces Gi0/0/0.20 | include "packets\|bytes"
  234 packets input, 45678 bytes
  3456 packets output, 56789 bytes

Both subinterfaces show traffic (input and output packets), confirming inter-VLAN routing is active.

Router-on-a-Stick Bandwidth Limitations

Router-on-a-Stick has a critical limitation: all inter-VLAN traffic traverses a single physical link. If that link is 1 Gbps and you have heavy communication between VLANs, you'll hit the link's throughput limit.

Example: - VLAN 10 (users) and VLAN 20 (servers) send 2 Gbps of traffic between them - The 1 Gbps link between the switch and router becomes the bottleneck - Only 1 Gbps can cross; 1 Gbps is dropped - Users experience slow server access

Layer 3 switching (via SVIs) has no bottleneck: All inter-VLAN traffic is routed in hardware at line rate—no shared link.

For example, on CORE-SW1 (9300): - VLAN 10 to VLAN 20 traffic: Routed in hardware at 10+ Gbps - No single link is the bottleneck - Per-VLAN throughput is not limited by router-on-a-stick constraints

Troubleshooting Router-on-a-Stick Issues

Symptom 1: Subinterface Is down/down

Symptom: Gi0/0/0.10 is down, line protocol is down

Cause (Priority 1): Physical interface is down.

Check:

R1-GW# show interfaces Gi0/0/0
GigabitEthernet0/0/0 is administratively down, line protocol is down

If the physical interface is administratively down, subinterfaces can't be up.

Fix:

R1-GW(config)# interface Gi0/0/0
R1-GW(config-if)# no shutdown
R1-GW(config-if)# end

Cause (Priority 2): Physical interface has no cable or is notconnect.

Check:

R1-GW# show interfaces status | include Gi0/0/0
Interface        Status       VLAN       Duplex Speed Type
Gi0/0/0          notconnect   routed     auto   auto  10/100/1000BaseTX

Fix: Plug in the cable from the switch trunk port.

Cause (Priority 3): Switch trunk port is disabled or not a trunk.

Check on switch:

CORE-SW1# show interfaces Gi1/0/5 status
Interface        Status       VLAN       Duplex Speed Type
Gi1/0/5          notconnect   1          auto   auto  10/100/1000BaseTX

Port is in VLAN 1 (access mode), not trunk.

Fix on switch:

CORE-SW1(config)# interface Gi1/0/5
CORE-SW1(config-if)# switchport mode trunk
CORE-SW1(config-if)# switchport trunk allowed vlan 10,20,30,40,50,99
CORE-SW1(config-if)# no shutdown
CORE-SW1(config-if)# end

Verify on router:

R1-GW# show interfaces Gi0/0/0 status
GigabitEthernet0/0/0 is up, line protocol is up (connected)

Subinterfaces should now be up/up.

Symptom 2: Host in VLAN 10 Can't Ping Host in VLAN 20

Symptom: ping 10.10.20.100 from VLAN 10 host times out or fails.

Cause (Priority 1): Subinterface doesn't exist or is down.

Check on router:

R1-GW# show ip interface brief | grep Gi0/0/0.20
Gi0/0/0.20                 10.10.20.254    YES manual down     down

The subinterface is down. Follow Symptom 1 troubleshooting above.

Cause (Priority 2): Host doesn't have VLAN 10 subinterface IP as default gateway.

Check on host:

C:\> ipconfig
...
Default Gateway   : 10.10.10.1

Default gateway is 10.10.10.1, but router's VLAN 10 SVI is 10.10.10.254. Either: - Configure DHCP to assign 10.10.10.254 as gateway, or - Manually set gateway to 10.10.10.254

Cause (Priority 3): Switch trunk port doesn't allow VLAN 20.

Check on switch:

CORE-SW1# show interfaces Gi1/0/5 switchport | include "Allowed"
Trunking VLANs Enabled         : 10,20,30,40,50,99

VLAN 20 is allowed (should be fine).

If VLAN 20 is not allowed:

CORE-SW1(config)# interface Gi1/0/5
CORE-SW1(config-if)# switchport trunk allowed vlan add 20
CORE-SW1(config-if)# end

Symptom 3: Native VLAN Traffic Doesn't Route Correctly

Symptom: Hosts in VLAN 99 (native) can't communicate with other VLANs, even though the subinterface exists.

Cause: The native VLAN subinterface is configured without native keyword in the encapsulation.

Incorrect:

interface Gi0/0/0.99
 encapsulation dot1q 99
 ip address 10.10.99.254 255.255.255.0

This creates a subinterface that only receives tagged VLAN 99 traffic, not untagged traffic.

Correct:

interface Gi0/0/0.99
 encapsulation dot1q 99 native
 ip address 10.10.99.254 255.255.255.0

The native keyword tells the subinterface to accept untagged traffic (native VLAN).

Fix:

R1-GW(config)# interface Gi0/0/0.99
R1-GW(config-subif)# encapsulation dot1q 99 native
R1-GW(config-subif)# end

Verify:

R1-GW# show interfaces Gi0/0/0.99 | include "Encapsulation"
Encapsulation ARPA

(The output doesn't explicitly show "native," but the configuration is there.)

Test native VLAN routing:

C:\> ping 10.10.30.100
Reply from 10.10.30.100

Key Takeaways

  • Router-on-a-Stick uses subinterfaces to carry multiple VLANs on one physical link: Each subinterface is encapsulated with a specific VLAN ID via encapsulation dot1q {vlan-id}.
  • All inter-VLAN traffic is bottlenecked by the single physical link: If that link is 1 Gbps, inter-VLAN throughput is capped at 1 Gbps, regardless of how many VLANs exist.
  • Catalyst 9000 Series with SVIs is superior for performance: Hardware-based routing in SVIs provides line-rate inter-VLAN switching with no bandwidth constraints.
  • Router-on-a-Stick is still useful in small labs and branch offices: When a Layer 3 switch isn't available, it provides inter-VLAN routing via an existing router.
  • Native VLAN subinterface requires the native keyword: Otherwise, it won't accept untagged traffic, breaking communication for native VLAN hosts.
Written by
More from Ping Labz
Great! You’ve successfully signed up.
Welcome back! You've successfully signed in.
You've successfully subscribed to Ping Labz.
Your link has expired.
Success! Check your email for magic link to sign-in.
Success! Your billing info has been updated.
Your billing was not updated.