The isle router
OpenWRT-based mesh router with automatic remote nginx proxy discovery and integration.
Architecture Overview
┌─────────────────────────────────────────────────────────────┐
│ Host Machine A │
│ ┌────────────────────────────────────────┐ │
│ │ OpenWRT KVM Router │ │
│ │ - vLAN: 10.10.0.1/24 │ │
│ │ - DHCP server for virtual MACs │ │
│ │ - Discovery beacon (broadcasts UDP) │ │
│ │ - mDNS reflector │ │
│ └────────────────────────────────────────┘ │
│ │ Physical interfaces (eth/wifi) │
└───────────┼─────────────────────────────────────────────────┘
│
│ Network Connection
│
┌───────────┼─────────────────────────────────────────────────┐
│ Host Machine B (Remote) │ │
│ ┌────────────────────────────────────────┐│ │
│ │ isle-agent (listens for discovery) ││ │
│ │ - Receives beacon from OpenWRT ││ │
│ │ - Auto-creates bridge: br-isle10 ││ │
│ │ - Enslaves physical interface ││ │
│ └────────────────────────────────────────┘│ │
│ │ │ │
│ ▼ │ │
│ ┌────────────────────────────────────────┐│ │
│ │ nginx proxy container ││ │
│ │ - Virtual MAC: 02:00:00:00:0a:XX ││ │
│ │ - DHCP IP: 10.10.0.50 (from OpenWRT) ││ │
│ │ - mDNS broadcasts with this IP ││ │
│ └────────────────────────────────────────┘│ │
│ │ │
│ OpenWRT never sees Machine B's real IP! │ │
└─────────────────────────────────────────────────────────────┘
Key Feature: Remote nginx containers join the mesh with virtual MAC addresses, getting DHCP IPs directly from OpenWRT. The host machine's real IP is never exposed to the mesh network.
Directory Structure
openwrt-router/
├── scripts/
│ ├── lib/ # Shared libraries (DRY principle)
│ │ ├── common-log.sh # Unified logging functions
│ │ ├── common-utils.sh # Shared utility functions
│ │ └── template-engine.sh # Template variable substitution
│ │
│ ├── router-setup/ # VM initialization & configuration
│ │ ├── router-init.main.sh # Initialize OpenWRT VM
│ │ ├── router-init-lib/ # Init script modules
│ │ ├── isle-vlan-router-config.main.sh # Configure vLAN
│ │ ├── isle-vlan-router-config-lib/ # Config modules
│ │ ├── configure-dhcp-vlan.sh # DHCP for virtual MACs
│ │ ├── configure-discovery.sh # Discovery beacon setup
│ │ └── ...
│ │
│ ├── utilities/ # Connection management
│ │ ├── add-ethernet-connection.main.sh
│ │ ├── add-usb-wifi.main.sh
│ │ └── ...
│ │
│ ├── hotplug-handlers/ # Event-driven port detection
│ │ ├── install-port-detection.sh
│ │ └── ...
│ │
│ └── setup-isle-mesh-router.sh # Master setup script
│
└── templates/ # Configuration templates
├── libvirt/ # VM XML templates
│ ├── base-vm.xml # Base VM definition
│ ├── interface-bridge.xml # Bridge interface snippet
│ ├── interface-direct.xml # Direct interface snippet
│ └── usb-passthrough.xml # USB passthrough snippet
│
└── openwrt/ # OpenWRT configuration templates
├── uci/ # UCI config scripts
│ ├── network-vlan.uci # vLAN network config
│ ├── firewall-zone.uci # Firewall zone config
│ ├── dhcp-server.uci # DHCP server config
│ └── mdns-reflector.uci # mDNS reflector config
│
├── configs/ # Configuration files
│ └── avahi-daemon.conf # Avahi mDNS config
│
└── scripts/ # OpenWRT runtime scripts
├── isle-discovery-beacon.sh # Discovery broadcaster
└── isle-discovery-init.sh # Service installer
Quick Start
Complete Setup (One Command)
cd openwrt-router/scripts
sudo ./setup-isle-mesh-router.sh --isle-name my-isle --vlan-id 10
This will:
- Initialize OpenWRT VM
- Configure vLAN networking
- Setup DHCP server
- Deploy discovery beacon
- Enable mDNS reflection
Step-by-Step Setup
1. Initialize Router VM
cd openwrt-router/scripts/router-setup
sudo ./router-init.main.sh --vm-name openwrt-isle-router
2. Configure vLAN and Network
sudo ./isle-vlan-router-config.main.sh \
--isle-name my-isle \
--vlan-id 10
3. Configure DHCP for Virtual MACs
sudo ./configure-dhcp-vlan.sh \
--isle-name my-isle \
--vlan-id 10 \
--dhcp-start 50 \
--dhcp-limit 200
This enables OpenWRT to assign IPs to remote nginx containers with virtual MAC addresses.
4. Deploy Discovery Beacon
sudo ./configure-discovery.sh \
--isle-name my-isle \
--vlan-id 10 \
--interval 30
OpenWRT will broadcast discovery packets every 30 seconds:
ISLE_MESH_DISCOVERY|isle=my-isle|vlan=10|router=10.10.0.1|dhcp=10.10.0.0/24
5. Add Physical Interfaces (Optional)
# Ethernet
sudo ../utilities/add-ethernet-connection.main.sh
# USB WiFi
sudo ../utilities/add-usb-wifi.main.sh
How Discovery Works
1. OpenWRT Side (Already Implemented)
Discovery Beacon (templates/openwrt/scripts/isle-discovery-beacon.sh):
- Runs as OpenWRT service
- Broadcasts UDP packets every 30s
- Contains: Isle name, vLAN ID, router IP, DHCP range
DHCP Server configured to accept virtual MACs:
- Pattern:
02:00:00:00:VLAN_ID:XX - Assigns IPs from pool:
10.VLAN.0.50-250 - No authentication needed (virtual MACs are ephemeral)
2. Remote Machine Side (To Be Implemented)
isle-agent daemon (not yet built):
- Listens on UDP port 7878
- Receives discovery broadcasts
- Auto-creates bridge on physical interface
- Connects nginx container with virtual MAC
- Container requests DHCP from OpenWRT
3. nginx Container Side (To Be Implemented)
Container must have labels:
labels:
- "isle-mesh.isle=my-isle"
- "isle-mesh.proxy=true"
- "isle-mesh.vlan=10"
When agent detects matching isle, it:
- Creates
br-isle10bridge - Enslaves physical interface
- Generates virtual MAC:
02:00:00:00:0a:XX - Connects container to bridge
- Container gets DHCP IP from OpenWRT
Shared Libraries
common-log.sh
Unified logging functions used by all scripts:
source "$(dirname $0)/../lib/common-log.sh"
log_info "Information message"
log_success "Success message"
log_warning "Warning message"
log_error "Error message"
log_step "Major step header"
log_banner "Script title banner"
common-utils.sh
Shared utility functions:
source "$(dirname $0)/../lib/common-utils.sh"
require_root # Exit if not root
require_commands ssh scp virsh # Check commands exist
init_common_env # Initialize directories
vm_exists "vm-name" # Check if VM exists
assert_vm_exists "vm-name" # Exit if VM doesn't exist
is_port_reserved "eth0" # Check if port is reserved
reserve_port "eth0" # Reserve a port
get_isp_interface # Get ISP interface name
template-engine.sh
Simple variable substitution for templates:
source "$(dirname $0)/../lib/template-engine.sh"
# Apply template to file
apply_template \
"$(get_template 'libvirt/base-vm.xml')" \
"/etc/isle-mesh/router/vm.xml" \
"VM_NAME=my-router" \
"MEMORY=512" \
"VCPUS=2"
# Render template to stdout
render_template \
"$(get_template 'openwrt/uci/network-vlan.uci')" \
"VLAN_ID=10" \
"ISLE_IP=10.10.0.1"
Templates
All configuration files are stored as templates with variable placeholders: {{VARIABLE_NAME}}
Example: network-vlan.uci
# Create tagged subinterface for isle
uci set network.{{ISLE_UCI}}=interface
uci set network.{{ISLE_UCI}}.proto='static'
uci set network.{{ISLE_UCI}}.device='{{ISLE_IF_DEV}}'
uci set network.{{ISLE_UCI}}.ipaddr='{{ISLE_IP}}'
uci set network.{{ISLE_UCI}}.netmask='{{ISLE_NETMASK}}'
Variables are substituted by template-engine.sh at runtime.
Virtual MAC Address Scheme
Remote nginx containers use deterministic virtual MACs:
02:00:00:00:VLAN_ID:XX
│ │ │ │ │ └─ Random per container
│ │ │ │ └──────── VLAN ID (hex)
│ │ │ └────────────── Reserved
│ └──└────────────────── Locally administered
└──────────────────────── Unicast
Example:
- vLAN 10 (0x0a):
02:00:00:00:0a:42 - vLAN 20 (0x14):
02:00:00:00:14:7f
OpenWRT DHCP server recognizes this pattern and assigns IPs.
Testing
Test Discovery Broadcasts
On any machine on the network:
# Listen for discovery packets
sudo nc -l -u 7878
# You should see:
# ISLE_MESH_DISCOVERY|isle=my-isle|vlan=10|router=10.10.0.1|dhcp=10.10.0.0/24
Test DHCP Server
On OpenWRT:
# View DHCP leases
cat /tmp/dhcp.leases
# View DHCP configuration
uci show dhcp
# Monitor DHCP requests
logread -f | grep dnsmasq
Test VM Status
# List VMs
sudo virsh list --all
# Access OpenWRT console
sudo virsh console openwrt-isle-router
# Check VM XML
sudo virsh dumpxml openwrt-isle-router
Router Management
Access OpenWRT
# Console (no network needed)
sudo virsh console openwrt-isle-router
# SSH (if configured)
ssh root@192.168.1.1
Service Management on OpenWRT
# Discovery beacon
/etc/init.d/isle-discovery {start|stop|restart|status}
# Network
/etc/init.d/network restart
# DHCP
/etc/init.d/dnsmasq restart
# mDNS
/etc/init.d/avahi-daemon restart
Logs
# On OpenWRT
logread -f
# Filter discovery logs
logread | grep isle-discovery
# Filter DHCP logs
logread | grep dnsmasq
Troubleshooting
Discovery Not Working
# On OpenWRT, check if beacon is running
ps | grep isle-discovery
# Check logs
logread | grep isle-discovery
# Manually test broadcast
echo "TEST" | nc -u -b 255.255.255.255 7878
DHCP Not Assigning IPs
# On OpenWRT, check DHCP config
uci show dhcp
# Check if dnsmasq is running
ps | grep dnsmasq
# View DHCP logs
logread -f | grep dnsmasq
# Check leases
cat /tmp/dhcp.leases
VM Not Starting
# Check VM status
sudo virsh list --all
# View VM logs
sudo virsh console openwrt-isle-router
# Check libvirt logs
sudo journalctl -u libvirtd -f
SSH to OpenWRT Fails
# Set root password via console
sudo virsh console openwrt-isle-router
# At OpenWRT prompt:
passwd
# Or use isle-vlan-router-config.main.sh which sets it
Next Steps
- Build remote isle-agent (not yet implemented)
- Daemon that listens for discovery
- Auto-configures bridges
- Connects nginx containers
- nginx container labeling (not yet implemented)
- Add isle labels to nginx proxies
- Automatic detection by agent
- mDNS integration (partially implemented)
- Ensure nginx broadcasts mDNS with vLAN IP
- Test mDNS reflection across mesh
- Physical interface management
- Consolidate add-ethernet and add-usb-wifi
- Integrate with hotplug system
Contributing
When adding new scripts:
- Use shared libraries - Source from
lib/ - Extract configs to templates - No embedded heredocs
- Follow naming conventions - Clear, descriptive names
- Add documentation - Update this README
License
Part of the Isle Mesh project.
Polari