the idea is to make them similar to route interface, to avoid confusion * they can be also be mgmt/inet/iptv * they will have default proto set to dhcp * syntax is now direct:vlan:100 or direct:transparent
12 KiB
Advanced Mode - Implementation Summary
Overview
The advanced mode is a unified network configuration mode that consolidates and extends the functionality of the previous bridged and routed-multi-service modes into a single, flexible interface.
Design Rationale
Problems with Old Approach
- Mode Fragmentation: Separate modes for bridged and routed scenarios
- Limited Flexibility: Couldn't mix bridges and routed interfaces
- Confusing Naming: "bridged" mode actually supported standalone interfaces too
- Parameter Proliferation: routed-multi-service had 6+ parameters for just 3 services
- No Scalability: Adding new services required new parameters
New Unified Approach
The advanced mode uses a declarative, array-based configuration:
interface_names: wan, iptv, mgmt
interface_types: route:vlan:100, bridge:tagged:200, direct:vlan:300
ports: WAN, LAN1-LAN2-WAN, WAN
Benefits:
- ✅ Single mode for all scenarios
- ✅ Scalable (add N interfaces without new parameters)
- ✅ Flexible (mix bridge/route/standalone)
- ✅ Intuitive syntax
- ✅ Self-documenting configuration
Architecture
File Structure
netmode/
├── files/
│ ├── etc/netmodes/advanced/
│ │ └── scripts/
│ │ └── 10-advanced # Main mode script
│ ├── lib/netmode/
│ │ └── advanced_helper.sh # Helper library
│ └── etc/netmodes/supported_modes.json
└── docs/
├── ADVANCED_MODE_GUIDE.md # Complete guide
└── ADVANCED_MODE_QUICK_REFERENCE.md
Components
1. advanced_helper.sh
Purpose: Core library for interface creation
Key Functions:
parse_interface_type()- Parse interface type specificationscreate_bridge()- Create bridge interfaces with VLAN/QinQcreate_routed_interface()- Create routed interfaces with VLAN/MACVLANcreate_standalone_interface()- Create direct VLAN interfacesparse_port_list()- Resolve port macros to device namesresolve_device_name()- Resolve LAN1/WAN to actual device namescleanup_interfaces()- Clean up all interfaces before applying new config
2. 10-advanced Script
Purpose: Main mode script
Flow:
- Parse environment variables (NETMODE_*)
- Split comma-separated values
- Loop through each interface
- Parse interface type
- Call appropriate creation function (bridge/route/direct)
- Configure multicast, DHCP, firewall
- Update service dependencies
3. supported_modes.json
Purpose: Mode definition for UCI import
Configuration:
{
"name": "advanced",
"description": "Advanced Mode - Unified configuration...",
"supported_args": [
{
"name": "interface_names",
"description": "Interface names (comma-separated...)",
"type": "string"
},
...
]
}
Interface Type Syntax
Design Philosophy
Format: MODE:SUBTYPE[:PARAMS][:MODIFIERS]
Examples:
bridge:transparent- Mode=bridge, Subtype=transparentbridge:tagged:100- Mode=bridge, Subtype=tagged, Param=VIDroute:vlan:100:AA:BB:CC:DD:EE:FF- Mode=route, Subtype=vlan, Params=VID+MACdirect:vlan:2501-n- Mode=direct, Param=VID, Modifier=proto_none
Parsing Logic
The parse_interface_type() function:
- Extract modifiers (-n, -d)
- Parse mode prefix (bridge:/route:/direct:)
- Parse subtype (transparent/tagged/vlan/macvlan)
- Parse parameters (VID, SVID, MAC address)
- Export to environment variables for caller
UCI Device Resolution
Problem
Port macros (LAN1, LAN2, WAN) are logical names that need to be mapped to actual hardware interfaces.
Solution
resolve_device_name() {
local device_id="$1"
local resolved_name=""
# Try UCI device section
resolved_name="$(uci -q get network.${device_id}.name)"
# Fallback to input
if [ -z "$resolved_name" ]; then
resolved_name="$device_id"
fi
echo "$resolved_name"
}
Example:
LAN1 → uci get network.LAN1.name → eth1
WAN → uci get network.WAN.name → ae_wan
Port List Resolution
The parse_port_list() function:
- Check for "ALL" → Resolve all LAN1-8 + WAN
- Parse dash-separated → LAN1-LAN2-WAN → resolve each
- Return space-separated → "eth1 eth2 ae_wan"
VLAN Device Creation
802.1Q (C-tag)
create_vlan_device "eth0" "100" "8021q"
Creates:
config device 'eth0__100'
option type '8021q'
option enabled '1'
option vid '100'
option ifname 'eth0'
option name 'eth0.100'
802.1ad (S-tag)
create_vlan_device "eth0" "300" "8021ad"
Creates:
config device 'eth0__300'
option type '8021ad'
option enabled '1'
option vid '300'
option ifname 'eth0'
option name 'eth0.300'
QinQ (Double Tagging)
For bridge:qinq:100:300:
# Create S-tag first
svlan=$(create_vlan_device "eth0" "300" "8021ad") # eth0.300
# Create C-tag on top of S-tag
cvlan=$(create_vlan_device "$svlan" "100" "8021q") # eth0.300.100
Result: eth0.300.100 (S-tag 300, C-tag 100)
MACVLAN Device Creation
For route:macvlan:AA:BB:CC:DD:EE:FF:
create_macvlan_device "ae_wan" "AA:BB:CC:DD:EE:FF" "iptv"
Creates:
config device 'iptv_macvlan'
option type 'macvlan'
option enabled '1'
option ifname 'ae_wan'
option name 'iptv_macvlan'
option macaddr 'AA:BB:CC:DD:EE:FF'
option mode 'passthru'
Bridge Creation
Transparent Bridge
For bridge:transparent with ports='ALL':
create_bridge "wan" "bridge:transparent" "ALL"
Creates:
config interface 'wan'
option proto 'dhcp'
option device 'br-wan'
config device 'br_wan'
option name 'br-wan'
option type 'bridge'
option bridge_empty '1'
list ports 'eth1'
list ports 'eth2'
list ports 'ae_wan'
VLAN-Tagged Bridge
For bridge:tagged:100 with ports='ALL':
Creates VLAN devices on all ports first, then adds to bridge:
config device 'br_mgmt'
option name 'br-mgmt'
option type 'bridge'
list ports 'eth1.100'
list ports 'eth2.100'
list ports 'ae_wan.100'
Routed Interface Creation
For route:vlan:100:
create_routed_interface "wan" "vlan" "100" "" "dhcp" "ae_wan" "0"
Creates:
config device 'ae_wan__100'
option type '8021q'
option vid '100'
option ifname 'ae_wan'
option name 'ae_wan.100'
config interface 'wan'
option proto 'dhcp'
option device 'ae_wan.100'
Firewall Logic
The advanced mode has intelligent firewall handling:
configure_firewall() {
local has_routed=0
# Check if ANY interface is routed
for if_type in $interface_types; do
if echo "$if_type" | grep -q "^route:"; then
has_routed=1
break
fi
done
if [ "$has_routed" = "1" ]; then
uci set firewall.globals.enabled="1" # Enable for routed
else
uci set firewall.globals.enabled="0" # Disable for bridge-only
fi
}
Logic:
- If any interface is routed → Enable firewall
- If all interfaces are bridges → Disable firewall
Environment Variable Flow
Input (UCI → Environment)
# In netmode init script
export NETMODE_interface_names="wan,iptv,mgmt"
export NETMODE_interface_types="route:vlan:100,route:vlan:200,route:vlan:300"
export NETMODE_ports="WAN,WAN,WAN"
Parsing (Script)
# In 10-advanced script
local interface_names="${NETMODE_interface_names:-wan}"
local interface_types="${NETMODE_interface_types:-bridge:transparent}"
local ports="${NETMODE_ports:-ALL}"
# Split by comma
IFS=','
for name in $interface_names; do
names_arr="$names_arr $name"
done
Output (UCI Network Config)
config interface 'wan'
option proto 'dhcp'
option device 'ae_wan.100'
config interface 'iptv'
option proto 'dhcp'
option device 'ae_wan.200'
...
Cleanup Strategy
Before applying new configuration, all existing interfaces are cleaned up:
cleanup_interfaces() {
# Delete VLAN devices (8021q and 8021ad)
for vlandev_sec in $(uci show network | grep -E "\.type='(8021q|8021ad)'" ...); do
uci delete "$vlandev_sec"
done
# Delete MACVLAN devices
for macvlandev_sec in $(uci show network | grep "\.type='macvlan'" ...); do
uci delete "$macvlandev_sec"
done
# Delete bridge devices
for brdev_sec in $(uci show network | grep "\.type='bridge'" ...); do
uci delete "$brdev_sec"
done
# Delete standard interfaces
uci delete network.lan
uci delete network.wan
uci delete network.wan6
}
This ensures a clean slate for the new configuration.
Migration Path
From bridged Mode
Before:
mode='bridged'
interface_names='wan,lan100'
interface_types='transparent,tagged:100'
ports='ALL,LAN1-LAN2'
After:
mode='advanced'
interface_names='wan,lan100'
interface_types='bridge:transparent,bridge:tagged:100'
ports='ALL,LAN1-LAN2'
Change: Add bridge: prefix to types.
From routed-multi-service Mode
Before:
mode='routed-multi-service'
inet_vlanid='100'
iptv_vlanid='200'
mgmt_vlanid='300'
After:
mode='advanced'
interface_names='wan,iptv,mgmt'
interface_types='route:vlan:100,route:vlan:200,route:vlan:300'
ports='WAN,WAN,WAN'
Change: Explicit interface names and unified syntax.
Testing Approach
Unit Testing
Test individual helper functions:
# Test device resolution
resolve_device_name "LAN1" # Should return eth1
# Test port parsing
parse_port_list "LAN1-LAN2-WAN" # Should return "eth1 eth2 ae_wan"
# Test type parsing
parse_interface_type "bridge:qinq:100:300-n"
# Should set: mode=bridge, vlan_type=qinq, cvid=100, svid=300, proto=none
Integration Testing
Test complete scenarios:
# Test transparent bridge
uci set netmode.global.mode='advanced'
uci set netmode.@supported_args[0].value='wan'
uci set netmode.@supported_args[1].value='bridge:transparent'
uci set netmode.@supported_args[2].value='ALL'
uci commit netmode
service netmode restart
# Verify
brctl show | grep br-wan
Validation
# Check UCI output
uci show network
# Check actual interfaces
ip addr show
brctl show
ip -d link show type vlan
# Check logs
logread | grep netmode-advanced
Performance Considerations
Comma Splitting Optimization
The script uses efficient IFS-based splitting:
local OLD_IFS="$IFS"
IFS=','
for name in $interface_names; do
names_arr="$names_arr $name"
done
IFS="$OLD_IFS"
This is faster than using cut or awk in loops.
UCI Batching
All UCI commands are batched, with a single uci commit at the end:
# Multiple uci set commands
uci set ...
uci set ...
uci set ...
# Single commit
uci commit network
Logging
Logging is selective - info level for major steps, debug for details:
_log "Creating interface $idx/$total_interfaces" # Info
logger -s -p user.debug -t "$_log_prefix" "Adding port: $port" # Debug
Security Considerations
Input Validation
- VLANs IDs: 1-4094
- MAC addresses: Validated format
- Port names: Resolved through UCI (trusted source)
Privilege Separation
- Script runs as root (required for network config)
- No user input directly executed
- Environment variables sanitized through UCI
Future Enhancements
Possible future additions:
- Static IP support:
route:vlan:100:static:192.168.1.1 - Port roles:
ports='LAN1(tagged),LAN2(untagged)' - Bridge STP:
bridge:transparent:stp - IPv6 specific:
route:vlan:100:ipv6 - Validation: Pre-flight checks for VLAN conflicts
Backward Compatibility
Status: ⚠️ Breaking change by design
The old bridged and routed-multi-service modes are replaced by advanced mode. This is acceptable because:
- This is the first deployment of advanced features
- No existing production deployments use old syntax
- Cleaner architecture without legacy baggage
- Documentation focuses on new syntax only
Summary
The advanced mode represents a significant architectural improvement:
- ✅ Unified: One mode for all scenarios
- ✅ Scalable: Array-based configuration
- ✅ Flexible: Mix bridges, routed, standalone
- ✅ Intuitive: Self-documenting syntax
- ✅ Powerful: VLAN, QinQ, MACVLAN support
- ✅ Clean: No backward compatibility burden
Implementation Version: 1.0 Date: 2024-12-12 Status: Production Ready