Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 6 additions & 4 deletions docs/architecture/09_design_decisions/003_vyos_gitops.md
Original file line number Diff line number Diff line change
Expand Up @@ -209,13 +209,15 @@ infrastructure/network/vyos/

#### Interface Mapping

The test environment uses simplified interface mapping:
The test environment remaps interfaces because Containerlab reserves eth0:

| Production | Test | Network |
|:-----------|:-----|:--------|
| eth4 | eth1 | WAN |
| eth5.10 | eth2 | MGMT (VLAN 10) |
| eth5.30 | eth3 | Platform (VLAN 30) |
| eth0 | eth2 | WAN (Transit to CCR2004) |
| eth1.10 | eth3.10 | MGMT (VLAN 10) |
| eth1.30 | eth3.30 | Platform (VLAN 30) |

The `render-config-boot.sh` script automatically performs this remapping.

#### CI Integration

Expand Down
2 changes: 1 addition & 1 deletion docs/architecture/appendices/B_bootstrap_procedure.md
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,7 @@ VyOS provides the network connectivity (NAT, DHCP relay, inter-VLAN routing) req

**Configuration Source:**
The production VyOS configuration is maintained in Git at `infrastructure/network/vyos/configs/gateway.conf`. This file contains:
- Interface configuration (WAN on eth4, trunk on eth5 with all VLANs)
- Interface configuration (WAN on eth0, trunk on eth1 with all VLANs)
- Firewall rules (WAN isolation, lab network policies)
- NAT (masquerade for lab → internet)
- BGP configuration (for Cilium LoadBalancer VIPs)
Expand Down
2 changes: 1 addition & 1 deletion infrastructure/network/vyos/ansible/inventory/hosts.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ all:
gateway:
# Connect via Tailscale in CI/CD
# Or direct IP for local execution
ansible_host: "{{ lookup('env', 'VYOS_HOST') | default('gateway.lab.gilman.io', true) }}"
ansible_host: "{{ lookup('env', 'VYOS_HOST') | default('10.0.0.2', true) }}"
ansible_user: vyos
ansible_network_os: vyos.vyos.vyos
ansible_connection: ansible.netcommon.network_cli
Expand Down
38 changes: 25 additions & 13 deletions infrastructure/network/vyos/configs/gateway.conf
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,11 @@
* Applied via Ansible on merge to main branch.
*
* Interface Mapping:
* WAN_IFACE = eth4 (Top SFP+ -> CCR2004 DOWNLINK)
* TRUNK_IFACE = eth5 (Bottom SFP+ -> CRS Switch)
* WAN_IFACE = eth0 (Top SFP+ -> CCR2004 DOWNLINK)
* TRUNK_IFACE = eth1 (Bottom SFP+ -> CRS Switch)
* LAN_IFACES = eth2-eth5 (2.5GbE LAN ports)
*
* Transit Link (eth4 <-> CCR2004):
* Transit Link (eth0 <-> CCR2004):
* 10.0.0.0/30 - Point-to-point between lab and home routers
* VyOS: 10.0.0.2/30
* CCR2004: 10.0.0.1/30
Expand Down Expand Up @@ -41,7 +42,7 @@ firewall {
network 192.168.0.0/16
}
}
interface eth4 {
interface eth0 {
in {
name WAN_TO_LAB
}
Expand Down Expand Up @@ -179,11 +180,11 @@ firewall {
}
}
interfaces {
ethernet eth4 {
ethernet eth0 {
address 10.0.0.2/30
description "WAN - Transit to Home (CCR2004)"
}
ethernet eth5 {
ethernet eth1 {
description "TRUNK - Lab Switch (CRS)"
vif 10 {
address 10.10.10.1/24
Expand Down Expand Up @@ -215,7 +216,7 @@ nat {
source {
rule 100 {
outbound-interface {
name eth4
name eth0
}
source {
address 10.10.0.0/16
Expand Down Expand Up @@ -292,8 +293,9 @@ protocols {
}
service {
dhcp-relay {
interface eth5.30
interface eth5.40
listen-interface eth1.30
listen-interface eth1.40
upstream-interface eth0
relay-options {
relay-agents-packets discard
}
Expand Down Expand Up @@ -334,10 +336,20 @@ service {
system {
domain-name lab.gilman.io
host-name gateway
/* SSH keys managed separately via Ansible
* Do not commit real keys to this file
* Ansible: deploy.yml -e ssh_public_key_file=~/.ssh/id_rsa.pub
*/
login {
/* User authentication managed separately via Ansible
* Do not commit passwords or keys to this file
* Ansible adds SSH keys and optionally sets password
* Console access requires password set via:
* set system login user vyos authentication plaintext-password <pw>
*/
user vyos {
authentication {
/* SSH public keys added by Ansible deploy.yml */
/* Password set manually for console access */
}
}
}
name-server 1.1.1.1
name-server 8.8.8.8
ntp {
Expand Down
5 changes: 3 additions & 2 deletions infrastructure/network/vyos/tests/README.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
# VyOS Containerlab Tests

This suite validates the VyOS gateway configuration using a Containerlab
topology and pytest. The topology keeps the production interface layout
(`eth4` WAN, `eth5` trunk) to exercise the real configuration.
topology and pytest. The test environment remaps production interfaces
(eth0 WAN, eth1 trunk) to test interfaces (eth2 WAN, eth3 trunk) because
Containerlab reserves eth0 for management.

## Prerequisites

Expand Down
27 changes: 14 additions & 13 deletions infrastructure/network/vyos/tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,16 +50,17 @@ class TestTopology:
"""Expected values for the Containerlab test topology."""

# WAN interface (transit link to CCR2004)
wan_iface: str = "eth4"
wan_ip: str = "10.0.0.2"
wan_cidr: str = "10.0.0.2/30"
wan_gateway: str = "10.0.0.1"
# wan-client simulates both CCR2004 (10.0.0.1) and home network (192.168.1.100)
wan_client_transit_ip: str = "10.0.0.1"
wan_client_ip: str = "192.168.1.100"

# Trunk interface
trunk_iface: str = "eth5"
# Note: Test uses eth2 (remapped from production eth0 - Containerlab reserves eth0)
wan_iface: str = "eth2"
wan_ip: str = "192.168.0.2"
wan_cidr: str = "192.168.0.2/24"
wan_gateway: str = "192.168.0.1"
# wan-client simulates both CCR2004 and home network traffic
wan_client_transit_ip: str = "192.168.0.1"
wan_client_ip: str = "192.168.0.100"

# Trunk interface (remapped from production eth1)
trunk_iface: str = "eth3"

# VLAN networks (gateway IPs)
mgmt_vif: str = "10"
Expand All @@ -86,9 +87,9 @@ class TestTopology:
storage_gateway: str = "10.10.60.1"
storage_client_ip: str = "10.10.60.100"

# Network ranges
transit_cidr: str = "10.0.0.0/30"
home_cidr: str = "192.168.1.0/24"
# Network ranges (test environment uses 192.168.0.0/24 for WAN simulation)
transit_cidr: str = "192.168.0.0/24"
home_cidr: str = "192.168.0.0/24"
lab_cidr: str = "10.10.0.0/16"

# DHCP configuration
Expand Down
56 changes: 39 additions & 17 deletions infrastructure/network/vyos/tests/render-config-boot.sh
Original file line number Diff line number Diff line change
@@ -1,8 +1,14 @@
#!/bin/bash
# Render config.boot for containerlab testing
#
# Takes gateway.conf as the base configuration and injects an SSH public key
# for test authentication.
# Takes gateway.conf as the base configuration and:
# 1. Remaps production interfaces to test interfaces (Containerlab reserves eth0)
# 2. Injects an SSH public key for test authentication
# 3. Adjusts network addresses for the isolated test environment
#
# Interface Mapping (production -> test):
# eth0 -> eth2 (WAN)
# eth1 -> eth3 (Trunk)
#
# Usage: render-config-boot.sh <ssh_public_key>

Expand Down Expand Up @@ -43,23 +49,39 @@ fi
# Start with the base gateway.conf
cp "${CONFIG_FILE}" "${OUTPUT_FILE}"

# Inject SSH key into the system login section
# Find the closing brace of the system block and insert login config before it
# Use temp file approach for portability (macOS vs GNU sed)
# Remap interfaces for test environment (Containerlab reserves eth0 for management)
# Production: eth0 (WAN), eth1 (Trunk)
# Test: eth2 (WAN), eth3 (Trunk)
sed -i.bak -e 's/eth0/eth2/g' -e 's/eth1/eth3/g' "${OUTPUT_FILE}"
rm -f "${OUTPUT_FILE}.bak"

# Adjust WAN IP for test environment (192.168.0.0/24 instead of 10.0.0.0/30)
# This allows the test topology to use a simpler addressing scheme
sed -i.bak -e 's|10\.0\.0\.2/30|192.168.0.2/24|g' \
-e 's|next-hop 10\.0\.0\.1|next-hop 192.168.0.1|g' \
-e 's|192\.168\.1\.0/24|192.168.0.0/24|g' "${OUTPUT_FILE}"
rm -f "${OUTPUT_FILE}.bak"

# Inject SSH key into the existing vyos user authentication block
# The gateway.conf already has the user vyos { authentication { ... }} structure
# We just need to add the public-keys section inside it
TEMP_FILE=$(mktemp)
sed '/^system {$/,/^}$/{
/^}$/i\
login {\
user vyos {\
authentication {\
public-keys test {\
key "'"${SSH_KEY_BODY}"'"\
type '"${SSH_KEY_TYPE}"'\
}\
}\
}\
awk '
/user vyos \{/ { in_user = 1 }
in_user && /authentication \{/ {
in_auth = 1
print
# Insert the public key right after the authentication { line
print " public-keys test {"
print " key \"'"${SSH_KEY_BODY}"'\""
print " type '"${SSH_KEY_TYPE}"'"
print " }"
next
}
}' "${OUTPUT_FILE}" > "${TEMP_FILE}"
in_auth && /\}/ { in_auth = 0 }
in_user && /^\s*\}\s*$/ && !in_auth { in_user = 0 }
{ print }
' "${OUTPUT_FILE}" > "${TEMP_FILE}"
mv "${TEMP_FILE}" "${OUTPUT_FILE}"

# Fix SELinux context if applicable (for container environments)
Expand Down
4 changes: 2 additions & 2 deletions infrastructure/network/vyos/tests/test_operational.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,8 @@ class TestRoutingState:
def test_wan_gateway_reachable(self, ping, test_topology):
"""WAN gateway (transit link peer) is reachable from VyOS.

This validates that the eth4 interface is correctly configured
and can reach the transit link peer (10.0.0.1).
This validates that the WAN interface is correctly configured
and can reach the transit link peer.
"""
# VyOS can reach the WAN gateway - verified through lab client connectivity
# If lab clients can reach WAN via NAT, the routing is working
Expand Down
33 changes: 18 additions & 15 deletions infrastructure/network/vyos/tests/topology.clab.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,16 @@
# This topology creates a minimal lab environment to test the VyOS gateway
# configuration. It simulates key network segments with Linux clients.
#
# Interface Mapping:
# eth0 - Containerlab management (reserved)
# eth4 - WAN interface (production mapping)
# eth5 - Trunk interface (production mapping)
# Production Interface Mapping (VP6630):
# eth0 - WAN interface (Top SFP+ -> CCR2004 DOWNLINK)
# eth1 - Trunk interface (Bottom SFP+ -> CRS Switch)
# eth2-eth5 - LAN interfaces (2.5GbE ports)
#
# This topology keeps the production interface layout and uses a VLAN-aware
# trunk so tests exercise the real gateway configuration.
# Test Interface Mapping (Containerlab reserves eth0 for management):
# eth2 - WAN interface (remapped from eth0)
# eth3 - Trunk interface (remapped from eth1)
#
# The render-config-boot.sh script remaps interfaces from production to test.

name: vyos-gateway-test

Expand Down Expand Up @@ -38,16 +41,16 @@ topology:
- sh -c "for iface in eth1 eth2 eth3 eth4 eth5 eth6 eth7; do ip link set $iface up && ip link set $iface master br0; done"

# WAN-side client (simulates CCR2004 on transit link + home network client)
# Primary: 10.0.0.1/30 (transit link - acts as CCR2004)
# Secondary: 192.168.1.100/24 (home network simulation for firewall tests)
# Primary: 192.168.0.1/24 (acts as gateway/CCR2004 in test environment)
# Secondary: 192.168.0.100/24 (home network simulation for firewall tests)
wan-client:
kind: linux
image: alpine:latest
exec:
- apk add --no-cache tcpdump netcat-openbsd
- sh -c "ip addr add 10.0.0.1/30 dev eth1 && ip link set eth1 up"
- sh -c "ip addr add 192.168.1.100/24 dev eth1"
- ip route replace default via 10.0.0.2
- sh -c "ip addr add 192.168.0.1/24 dev eth1 && ip link set eth1 up"
- sh -c "ip addr add 192.168.0.100/24 dev eth1"
- ip route replace default via 192.168.0.2

# Management network client (VLAN 10 simulation)
mgmt-client:
Expand Down Expand Up @@ -100,11 +103,11 @@ topology:
- ip route replace default via 10.10.60.1

links:
# WAN connection (gateway eth4 <-> wan-client eth1)
- endpoints: ["gateway:eth4", "wan-client:eth1"]
# WAN connection (gateway eth2 <-> wan-client eth1)
- endpoints: ["gateway:eth2", "wan-client:eth1"]

# Trunk connection (gateway eth5 <-> trunk-switch eth1)
- endpoints: ["gateway:eth5", "trunk-switch:eth1"]
# Trunk connection (gateway eth3 <-> trunk-switch eth1)
- endpoints: ["gateway:eth3", "trunk-switch:eth1"]

# VLAN clients connected to trunk-switch
- endpoints: ["trunk-switch:eth2", "mgmt-client:eth1"]
Expand Down