mirror of
https://dev.iopsys.eu/feed/iopsys.git
synced 2026-01-28 01:47:19 +01:00
1038 lines
26 KiB
Markdown
1038 lines
26 KiB
Markdown
# Netmode Implementation Guide
|
|
|
|
## Table of Contents
|
|
1. [Overview](#overview)
|
|
2. [Architecture](#architecture)
|
|
3. [Directory Structure](#directory-structure)
|
|
4. [Configuration System](#configuration-system)
|
|
5. [Mode Implementation](#mode-implementation)
|
|
6. [Creating a New Network Mode](#creating-a-new-network-mode)
|
|
7. [Environment Variables](#environment-variables)
|
|
8. [Hooks and Scripts](#hooks-and-scripts)
|
|
9. [Data Model Integration](#data-model-integration)
|
|
10. [Testing and Validation](#testing-and-validation)
|
|
|
|
---
|
|
|
|
## Overview
|
|
|
|
The netmode package provides a flexible mechanism for switching between different WAN network configurations on OpenWrt/iopsys systems. It enables easy transitions between routing modes (DHCP, PPPoE, Static IP) and bridged mode without manual configuration changes.
|
|
|
|
### Key Features
|
|
- Dynamic WAN mode switching with reboot
|
|
- Support for routed and bridged modes
|
|
- UCI-based configuration
|
|
- TR-069/USP data model integration via bbfdm
|
|
- Extensible architecture for custom modes
|
|
- Environment variable-based parameter passing
|
|
- Pre/post mode switch hooks
|
|
|
|
### Version Information
|
|
- Package Version: 1.1.11
|
|
- License: GPL-2.0-only
|
|
|
|
---
|
|
|
|
## Architecture
|
|
|
|
### Core Components
|
|
|
|
```
|
|
┌─────────────────────────────────────────────────────────────┐
|
|
│ Netmode System │
|
|
├─────────────────────────────────────────────────────────────┤
|
|
│ │
|
|
│ ┌─────────────┐ ┌──────────────┐ ┌───────────────┐ │
|
|
│ │ UCI Config │───▶│ Init Service │───▶│ Mode Scripts │ │
|
|
│ │ /etc/config │ │ (START=11) │ │ /etc/netmodes │ │
|
|
│ │ /netmode │ │ │ │ /<mode> │ │
|
|
│ └─────────────┘ └──────────────┘ └───────────────┘ │
|
|
│ │ │ │ │
|
|
│ │ ▼ │ │
|
|
│ │ ┌──────────────────┐ │ │
|
|
│ └────────▶│ Env Var Manager │◀───────────┘ │
|
|
│ │ (NETMODE_*) │ │
|
|
│ └──────────────────┘ │
|
|
│ │ │
|
|
│ ▼ │
|
|
│ ┌──────────────────┐ │
|
|
│ │ Hook Execution │ │
|
|
│ │ pre/post/lib │ │
|
|
│ └──────────────────┘ │
|
|
│ │ │
|
|
│ ▼ │
|
|
│ ┌──────────────────┐ │
|
|
│ │ UCI Reconfig │ │
|
|
│ │ network/dhcp/ │ │
|
|
│ │ firewall/etc │ │
|
|
│ └──────────────────┘ │
|
|
└─────────────────────────────────────────────────────────────┘
|
|
```
|
|
|
|
### Execution Flow
|
|
|
|
1. **Trigger**: System boot or `service netmode restart`
|
|
2. **Configuration Load**: Read UCI netmode config
|
|
3. **Mode Detection**: Get mode from `netmode.global.mode` or `fw_printenv`
|
|
4. **Change Detection**: Compare with last saved mode in `/etc/netmodes/.last_mode`
|
|
5. **Environment Setup**: Configure `NETMODE_*` environment variables
|
|
6. **Pre-hooks**: Execute `/lib/netmode/pre/*` scripts
|
|
7. **UCI Copy**: Copy mode-specific UCI files from `/etc/netmodes/<mode>/uci/`
|
|
8. **Generic Scripts**: Execute `/lib/netmode/*` scripts
|
|
9. **Mode Scripts**: Execute `/etc/netmodes/<mode>/scripts/*` in order
|
|
10. **Last Mode Update**: Save current mode to `.last_mode`
|
|
11. **Post-hooks**: Execute `/lib/netmode/post/*` scripts
|
|
12. **Cleanup**: Unset environment variables and clear argument values
|
|
|
|
---
|
|
|
|
## Directory Structure
|
|
|
|
```
|
|
netmode/
|
|
├── Makefile # OpenWrt package definition
|
|
├── bbfdm_service.json # BBF data model service registration
|
|
├── IMPLEMENTATION_GUIDE.md # This document
|
|
├── DEVELOPER_GUIDE.md # Developer documentation
|
|
├── USER_GUIDE.md # User documentation
|
|
└── files/
|
|
├── etc/
|
|
│ ├── config/
|
|
│ │ └── netmode # UCI configuration file
|
|
│ ├── init.d/
|
|
│ │ └── netmode # Procd init script (START=11)
|
|
│ ├── uci-defaults/
|
|
│ │ ├── 40_netmode_populated_supported_modes
|
|
│ │ ├── 40_netmode_set_default_netmode
|
|
│ │ └── 62-netmode.l2mode
|
|
│ └── netmodes/
|
|
│ ├── supported_modes.json # Mode definitions for import
|
|
│ ├── .last_mode # Runtime: last applied mode
|
|
│ ├── routed-dhcp/
|
|
│ │ ├── scripts/
|
|
│ │ │ └── 10-routed-dhcp
|
|
│ │ └── uci/ # Optional: pre-configured UCI files
|
|
│ ├── routed-pppoe/
|
|
│ │ └── scripts/
|
|
│ │ └── 10-routed-pppoe
|
|
│ ├── routed-static/
|
|
│ │ └── scripts/
|
|
│ │ └── 10-routed-static
|
|
│ └── bridged/
|
|
│ └── scripts/
|
|
│ └── 10-bridged
|
|
└── lib/
|
|
├── upgrade/
|
|
│ └── keep.d/
|
|
│ └── netmode # Files to keep during sysupgrade
|
|
└── netmode/
|
|
├── pre/ # Pre-mode-switch hooks
|
|
├── post/ # Post-mode-switch hooks
|
|
│ └── datamodel_init.sh # Reboot after mode switch
|
|
└── [default]/ # Generic mode-switch hooks
|
|
|
|
```
|
|
|
|
---
|
|
|
|
## Configuration System
|
|
|
|
### UCI Configuration Format
|
|
|
|
**File**: `/etc/config/netmode`
|
|
|
|
```uci
|
|
config netmode 'global'
|
|
option enabled '1'
|
|
option mode 'routed-dhcp'
|
|
|
|
config supported_modes
|
|
option name 'routed-dhcp'
|
|
option description 'DHCP'
|
|
|
|
config supported_args
|
|
option dm_parent '@supported_modes[0]'
|
|
option name 'vlanid'
|
|
option description 'VLAN ID'
|
|
option required '0'
|
|
option type 'integer'
|
|
option value ''
|
|
|
|
config supported_args
|
|
option dm_parent '@supported_modes[0]'
|
|
option name 'dns_servers'
|
|
option description 'DNS Servers'
|
|
option required '0'
|
|
option type 'string'
|
|
option value ''
|
|
|
|
config supported_modes
|
|
option name 'routed-pppoe'
|
|
option description 'PPPoE'
|
|
|
|
config supported_args
|
|
option dm_parent '@supported_modes[1]'
|
|
option name 'username'
|
|
option description 'PPPoE Username'
|
|
option required '1'
|
|
option type 'string'
|
|
option value ''
|
|
|
|
config supported_args
|
|
option dm_parent '@supported_modes[1]'
|
|
option name 'password'
|
|
option description 'PPPoE Password'
|
|
option required '1'
|
|
option type 'string'
|
|
option value ''
|
|
```
|
|
|
|
### Supported Modes JSON Schema
|
|
|
|
**File**: `/etc/netmodes/supported_modes.json`
|
|
|
|
```json
|
|
{
|
|
"supported_modes": [
|
|
{
|
|
"name": "routed-dhcp",
|
|
"description": "DHCP",
|
|
"supported_args": [
|
|
{
|
|
"name": "vlanid",
|
|
"description": "VLAN ID",
|
|
"required": false,
|
|
"type": "integer"
|
|
},
|
|
{
|
|
"name": "dns_servers",
|
|
"description": "DNS Servers",
|
|
"required": false,
|
|
"type": "string"
|
|
}
|
|
]
|
|
}
|
|
]
|
|
}
|
|
```
|
|
|
|
### Configuration Fields
|
|
|
|
| Field | Type | Description |
|
|
|-------|------|-------------|
|
|
| `name` | string | Unique identifier for the mode (must match directory name) |
|
|
| `description` | string | Human-readable mode description |
|
|
| `required` | boolean | If true, argument value must be provided |
|
|
| `type` | string | Data type: `integer`, `string`, `boolean` |
|
|
| `value` | string | Runtime value (set via TR-069/CLI) |
|
|
| `dm_parent` | reference | Links argument to parent mode section |
|
|
|
|
---
|
|
|
|
## Mode Implementation
|
|
|
|
### Standard Modes
|
|
|
|
#### 1. Routed DHCP Mode
|
|
- **Name**: `routed-dhcp`
|
|
- **Description**: Router with DHCP WAN
|
|
- **Configuration**:
|
|
- LAN: Static IP (192.168.1.1/24)
|
|
- WAN: DHCP client
|
|
- WAN6: DHCPv6 client
|
|
- Firewall: Enabled
|
|
- DHCP Server: Enabled on LAN
|
|
- Multicast: L3 proxy mode
|
|
|
|
#### 2. Routed PPPoE Mode
|
|
- **Name**: `routed-pppoe`
|
|
- **Description**: Router with PPPoE WAN
|
|
- **Required Arguments**: `username`, `password`
|
|
- **Optional Arguments**: `vlanid`, `mtu`, `dns_servers`
|
|
- **Configuration**:
|
|
- LAN: Static IP (192.168.1.1/24)
|
|
- WAN: PPPoE
|
|
- Firewall: Enabled
|
|
- DHCP Server: Enabled on LAN
|
|
- Multicast: L3 proxy mode
|
|
|
|
#### 3. Routed Static Mode
|
|
- **Name**: `routed-static`
|
|
- **Description**: Router with Static IP WAN
|
|
- **Required Arguments**: `ipaddr`, `netmask`, `gateway`
|
|
- **Optional Arguments**: `vlanid`, `dns_servers`
|
|
- **Configuration**:
|
|
- LAN: Static IP (192.168.1.1/24)
|
|
- WAN: Static IP
|
|
- Firewall: Enabled
|
|
- DHCP Server: Enabled on LAN
|
|
- Multicast: L3 proxy mode
|
|
|
|
#### 4. Bridged Mode
|
|
- **Name**: `bridged`
|
|
- **Description**: L2 Bridge Mode
|
|
- **Configuration**:
|
|
- LAN: DHCP client (bridged to WAN)
|
|
- WAN: Deleted (ports added to br-lan)
|
|
- Firewall: Disabled
|
|
- DHCP Server: Disabled
|
|
- Multicast: L2 snooping mode
|
|
|
|
---
|
|
|
|
## Creating a New Network Mode
|
|
|
|
### Step-by-Step Guide
|
|
|
|
#### Step 1: Create Mode Directory Structure
|
|
|
|
```bash
|
|
mkdir -p /etc/netmodes/my-custom-mode/scripts
|
|
mkdir -p /etc/netmodes/my-custom-mode/uci
|
|
```
|
|
|
|
#### Step 2: Define Mode in supported_modes.json
|
|
|
|
Add to `/etc/netmodes/supported_modes.json`:
|
|
|
|
```json
|
|
{
|
|
"supported_modes": [
|
|
{
|
|
"name": "my-custom-mode",
|
|
"description": "My Custom WAN Mode",
|
|
"supported_args": [
|
|
{
|
|
"name": "custom_param",
|
|
"description": "Custom Parameter",
|
|
"required": true,
|
|
"type": "string"
|
|
}
|
|
]
|
|
}
|
|
]
|
|
}
|
|
```
|
|
|
|
#### Step 3: Import Mode to UCI
|
|
|
|
Run the uci-defaults script to populate UCI:
|
|
|
|
```bash
|
|
sh /etc/uci-defaults/40_netmode_populated_supported_modes
|
|
```
|
|
|
|
Or manually add to `/etc/config/netmode`:
|
|
|
|
```uci
|
|
config supported_modes
|
|
option name 'my-custom-mode'
|
|
option description 'My Custom WAN Mode'
|
|
|
|
config supported_args
|
|
option dm_parent '@supported_modes[N]' # Replace N with index
|
|
option name 'custom_param'
|
|
option description 'Custom Parameter'
|
|
option required '1'
|
|
option type 'string'
|
|
option value ''
|
|
```
|
|
|
|
#### Step 4: Create Mode Script
|
|
|
|
**File**: `/etc/netmodes/my-custom-mode/scripts/10-my-custom-mode`
|
|
|
|
```bash
|
|
#!/bin/sh
|
|
|
|
. /lib/functions.sh
|
|
. /usr/share/libubox/jshn.sh
|
|
|
|
source "/etc/device_info"
|
|
|
|
logger -s -p user.info -t "netmode" "Applying custom mode configuration"
|
|
|
|
# Access environment variables
|
|
custom_value="$NETMODE_custom_param"
|
|
|
|
# Get WAN device from board configuration
|
|
wandev="$(uci -q get network.WAN.ifname)"
|
|
|
|
# Configure network
|
|
uci -q set network.lan=interface
|
|
uci -q set network.lan.device='br-lan'
|
|
uci -q set network.lan.proto='static'
|
|
uci -q set network.lan.ipaddr='192.168.1.1'
|
|
uci -q set network.lan.netmask='255.255.255.0'
|
|
|
|
uci -q set network.wan=interface
|
|
uci -q set network.wan.device="$wandev"
|
|
uci -q set network.wan.proto='dhcp'
|
|
# Add your custom configuration here
|
|
|
|
uci -q commit network
|
|
|
|
# Configure other subsystems
|
|
uci -q set dhcp.lan.ignore=0
|
|
uci -q commit dhcp
|
|
|
|
uci -q set firewall.globals.enabled="1"
|
|
uci -q commit firewall
|
|
|
|
logger -s -p user.info -t "netmode" "Custom mode configuration complete"
|
|
```
|
|
|
|
Make it executable:
|
|
|
|
```bash
|
|
chmod +x /etc/netmodes/my-custom-mode/scripts/10-my-custom-mode
|
|
```
|
|
|
|
#### Step 5: (Optional) Pre-configure UCI Files
|
|
|
|
If you have complex UCI configurations, place them in:
|
|
|
|
```bash
|
|
/etc/netmodes/my-custom-mode/uci/network
|
|
/etc/netmodes/my-custom-mode/uci/dhcp
|
|
/etc/netmodes/my-custom-mode/uci/firewall
|
|
```
|
|
|
|
These will be copied to `/etc/config/` before mode scripts execute.
|
|
|
|
#### Step 6: Test the Mode
|
|
|
|
```bash
|
|
# Set the mode
|
|
uci set netmode.global.mode='my-custom-mode'
|
|
|
|
# Set required arguments (if any)
|
|
uci set netmode.@supported_args[N].value='test-value'
|
|
uci commit netmode
|
|
|
|
# Restart netmode service
|
|
service netmode restart
|
|
|
|
# Check logs
|
|
logread | grep netmode
|
|
```
|
|
|
|
---
|
|
|
|
## Environment Variables
|
|
|
|
### Variable Naming Convention
|
|
|
|
All mode arguments are exported as environment variables with the prefix `NETMODE_`:
|
|
|
|
```bash
|
|
NETMODE_<argument_name>="<value>"
|
|
```
|
|
|
|
### Examples
|
|
|
|
For PPPoE mode:
|
|
```bash
|
|
NETMODE_username="user@isp.com"
|
|
NETMODE_password="secret123"
|
|
NETMODE_vlanid="100"
|
|
NETMODE_mtu="1492"
|
|
NETMODE_dns_servers="8.8.8.8,8.8.4.4"
|
|
```
|
|
|
|
### Accessing in Scripts
|
|
|
|
```bash
|
|
#!/bin/sh
|
|
|
|
# Direct access
|
|
echo "Username: $NETMODE_username"
|
|
echo "VLAN ID: $NETMODE_vlanid"
|
|
|
|
# With validation
|
|
if [ -n "$NETMODE_vlanid" ] && [ "$NETMODE_vlanid" -ge 1 ]; then
|
|
# Configure VLAN
|
|
uci set network.wan_vlan.vid="$NETMODE_vlanid"
|
|
fi
|
|
|
|
# CSV parsing for lists
|
|
if [ -n "$NETMODE_dns_servers" ]; then
|
|
dns_servers="$(echo $NETMODE_dns_servers | tr ',' ' ')"
|
|
for server in $dns_servers; do
|
|
uci add_list network.wan.dns="$server"
|
|
done
|
|
fi
|
|
```
|
|
|
|
### Variable Lifecycle
|
|
|
|
1. **Set**: Before pre-hooks (if mode is being switched)
|
|
2. **Available**: During pre-hooks, generic scripts, and mode scripts
|
|
3. **Cleared**: After post-hooks via `cleanup_env_vars()`
|
|
|
|
### Security Considerations
|
|
|
|
- Password values marked as "Secure" in data model
|
|
- Environment variables are process-local
|
|
- Cleared after mode application
|
|
- UCI values are cleared after use (`cleanup_arg_values()`)
|
|
|
|
---
|
|
|
|
## Hooks and Scripts
|
|
|
|
### Hook Execution Order
|
|
|
|
```
|
|
1. /lib/netmode/pre/* (Pre-mode-switch hooks)
|
|
↓
|
|
2. Copy /etc/netmodes/<mode>/uci/* → /etc/config/
|
|
↓
|
|
3. /lib/netmode/* (Generic mode-switch scripts)
|
|
↓
|
|
4. /etc/netmodes/<mode>/scripts/* (Mode-specific scripts)
|
|
↓
|
|
5. Save .last_mode
|
|
↓
|
|
6. /lib/netmode/post/* (Post-mode-switch hooks)
|
|
↓
|
|
7. cleanup_env_vars()
|
|
```
|
|
|
|
### Script Naming Convention
|
|
|
|
Scripts are executed in **lexicographical order**. Use numeric prefixes:
|
|
|
|
```
|
|
10-first-script
|
|
20-second-script
|
|
30-third-script
|
|
```
|
|
|
|
### Pre-hooks (`/lib/netmode/pre/`)
|
|
|
|
**Purpose**: Prepare system before mode switch
|
|
|
|
**Example Use Cases**:
|
|
- Backup current configuration
|
|
- Stop conflicting services
|
|
- Validate prerequisites
|
|
|
|
**Example**:
|
|
```bash
|
|
#!/bin/sh
|
|
# /lib/netmode/pre/10-backup
|
|
|
|
logger -t "netmode" "Backing up current network config"
|
|
cp /etc/config/network /tmp/network.backup
|
|
```
|
|
|
|
### Post-hooks (`/lib/netmode/post/`)
|
|
|
|
**Purpose**: Finalize mode switch and cleanup
|
|
|
|
**Default Post-hook**: `datamodel_init.sh`
|
|
```bash
|
|
#!/bin/sh
|
|
# Reboot system after mode switch
|
|
|
|
if [ ! -f /var/run/boot_complete ]; then
|
|
exit 0
|
|
fi
|
|
|
|
# Clear data model caches
|
|
rm -f /etc/bbfdm/dmmap/PPP
|
|
rm -f /etc/bbfdm/dmmap/IP
|
|
rm -f /etc/bbfdm/dmmap/Ethernet
|
|
|
|
sleep 5
|
|
reboot -f
|
|
```
|
|
|
|
**Example Additional Post-hook**:
|
|
```bash
|
|
#!/bin/sh
|
|
# /lib/netmode/post/20-notify
|
|
|
|
logger -t "netmode" "Mode switch complete, notifying ACS"
|
|
# Trigger TR-069 inform
|
|
```
|
|
|
|
### Generic Scripts (`/lib/netmode/`)
|
|
|
|
**Purpose**: Common operations for all modes
|
|
|
|
**Example**:
|
|
```bash
|
|
#!/bin/sh
|
|
# /lib/netmode/10-common-setup
|
|
|
|
logger -t "netmode" "Applying common network settings"
|
|
|
|
# Set common timezone
|
|
uci set system.@system[0].timezone='UTC'
|
|
uci commit system
|
|
```
|
|
|
|
---
|
|
|
|
## Data Model Integration
|
|
|
|
### BBF Data Model Structure
|
|
|
|
**TR-181 Path**: `Device.X_IOWRT_EU_NetMode.`
|
|
|
|
```
|
|
Device.X_IOWRT_EU_NetMode.
|
|
├── Enable (boolean, r/w)
|
|
├── Mode (string, r/w) [Reference]
|
|
├── SupportedModesNumberOfEntries (unsignedInt, r)
|
|
└── SupportedModes.{i}.
|
|
├── Name (string, r) [Unique, Linker]
|
|
├── Description (string, r)
|
|
├── SupportedArgumentsNumberOfEntries (unsignedInt, r)
|
|
└── SupportedArguments.{i}.
|
|
├── Name (string, r)
|
|
├── Type (string, r/w)
|
|
├── Description (string, r)
|
|
├── Required (boolean, r)
|
|
└── Value (string, r/w) [Secure]
|
|
```
|
|
|
|
### Data Model Operations
|
|
|
|
#### Get Current Mode
|
|
```xml
|
|
<GetParameterValues>
|
|
<ParameterNames>
|
|
<string>Device.X_IOWRT_EU_NetMode.Mode</string>
|
|
</ParameterNames>
|
|
</GetParameterValues>
|
|
```
|
|
|
|
#### Set PPPoE Mode with Credentials
|
|
```xml
|
|
<SetParameterValues>
|
|
<ParameterList>
|
|
<ParameterValueStruct>
|
|
<Name>Device.X_IOWRT_EU_NetMode.Mode</Name>
|
|
<Value>routed-pppoe</Value>
|
|
</ParameterValueStruct>
|
|
<ParameterValueStruct>
|
|
<Name>Device.X_IOWRT_EU_NetMode.SupportedModes.2.SupportedArguments.1.Value</Name>
|
|
<Value>username@isp.com</Value>
|
|
</ParameterValueStruct>
|
|
<ParameterValueStruct>
|
|
<Name>Device.X_IOWRT_EU_NetMode.SupportedModes.2.SupportedArguments.2.Value</Name>
|
|
<Value>password123</Value>
|
|
</ParameterValueStruct>
|
|
</ParameterList>
|
|
</SetParameterValues>
|
|
```
|
|
|
|
#### Trigger Mode Switch
|
|
```bash
|
|
# After setting parameters via TR-069/USP
|
|
service netmode restart
|
|
# Or reload
|
|
service netmode reload
|
|
```
|
|
|
|
### BBF Service Configuration
|
|
|
|
**File**: `bbfdm_service.json`
|
|
|
|
```json
|
|
{
|
|
"daemon": {
|
|
"enable": "1",
|
|
"service_name": "netmode",
|
|
"unified_daemon": false,
|
|
"services": [
|
|
{
|
|
"parent_dm": "Device.",
|
|
"object": "{BBF_VENDOR_PREFIX}NetMode"
|
|
}
|
|
],
|
|
"config": {
|
|
"loglevel": "3"
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
**Vendor Prefix Configuration** (Makefile):
|
|
```make
|
|
config NETMODE_VENDOR_PREFIX
|
|
depends on PACKAGE_netmode
|
|
string "Vendor Extension used for netmode datamodel"
|
|
default ""
|
|
```
|
|
|
|
If empty, inherits from `CONFIG_BBF_VENDOR_PREFIX`.
|
|
|
|
---
|
|
|
|
## Testing and Validation
|
|
|
|
### Pre-deployment Checklist
|
|
|
|
- [ ] Mode directory created: `/etc/netmodes/<mode-name>/`
|
|
- [ ] Mode script created and executable: `scripts/10-<mode-name>`
|
|
- [ ] Mode defined in `supported_modes.json`
|
|
- [ ] UCI configuration populated (via uci-defaults)
|
|
- [ ] Required arguments identified and documented
|
|
- [ ] Environment variable handling implemented
|
|
- [ ] UCI subsystems configured (network, dhcp, firewall)
|
|
- [ ] Multicast configuration appropriate for mode
|
|
- [ ] Service dependencies updated (cwmp, gateway, ssdpd)
|
|
|
|
### Manual Testing Procedure
|
|
|
|
#### 1. Enable Debug Logging
|
|
```bash
|
|
logger -s -p user.info -t "netmode-test" "Starting mode test"
|
|
```
|
|
|
|
#### 2. Set Mode via UCI
|
|
```bash
|
|
uci set netmode.global.enabled='1'
|
|
uci set netmode.global.mode='<mode-name>'
|
|
|
|
# Set required arguments
|
|
uci set netmode.@supported_args[X].value='<value>'
|
|
uci commit netmode
|
|
```
|
|
|
|
#### 3. Trigger Mode Switch
|
|
```bash
|
|
service netmode restart
|
|
```
|
|
|
|
#### 4. Monitor Logs
|
|
```bash
|
|
logread -f | grep netmode
|
|
```
|
|
|
|
Expected output:
|
|
```
|
|
netmode: Switching to [<mode>] Mode
|
|
netmode: Executing /lib/netmode/pre scripts
|
|
netmode: Generating L3 network configuration
|
|
netmode: Executing [<mode>], script [10-<mode>]
|
|
netmode: Switching to Mode [<mode>] done, last mode updated
|
|
netmode: Executing /lib/netmode/post scripts
|
|
```
|
|
|
|
#### 5. Verify Configuration
|
|
```bash
|
|
# Check network configuration
|
|
uci show network | grep -E "lan|wan"
|
|
|
|
# Check DHCP configuration
|
|
uci show dhcp
|
|
|
|
# Check firewall status
|
|
uci show firewall.globals.enabled
|
|
|
|
# Check last mode
|
|
cat /etc/netmodes/.last_mode
|
|
|
|
# Verify environment cleanup
|
|
env | grep NETMODE
|
|
```
|
|
|
|
#### 6. Test Network Connectivity
|
|
```bash
|
|
# Ping gateway
|
|
ping -c 3 $(ip route | grep default | awk '{print $3}')
|
|
|
|
# DNS resolution
|
|
nslookup example.com
|
|
|
|
# Check WAN IP
|
|
ip addr show wan
|
|
```
|
|
|
|
### Automated Testing Script
|
|
|
|
```bash
|
|
#!/bin/sh
|
|
# test-netmode.sh
|
|
|
|
MODE="$1"
|
|
ARGS="$2"
|
|
|
|
if [ -z "$MODE" ]; then
|
|
echo "Usage: $0 <mode> [args]"
|
|
exit 1
|
|
fi
|
|
|
|
echo "Testing mode: $MODE"
|
|
|
|
# Set mode
|
|
uci set netmode.global.mode="$MODE"
|
|
|
|
# Parse and set arguments (format: "arg1=val1,arg2=val2")
|
|
if [ -n "$ARGS" ]; then
|
|
IFS=',' read -ra ARGLIST <<< "$ARGS"
|
|
for arg in "${ARGLIST[@]}"; do
|
|
name="${arg%%=*}"
|
|
value="${arg#*=}"
|
|
|
|
# Find matching argument section
|
|
idx=$(uci show netmode | grep "name='$name'" | cut -d. -f2 | cut -d= -f1)
|
|
uci set "netmode.$idx.value=$value"
|
|
done
|
|
fi
|
|
|
|
uci commit netmode
|
|
|
|
# Apply mode
|
|
echo "Applying mode..."
|
|
service netmode restart
|
|
|
|
# Wait for completion
|
|
sleep 2
|
|
|
|
# Verify
|
|
echo "Verifying configuration..."
|
|
cat /etc/netmodes/.last_mode
|
|
|
|
echo "Mode test complete"
|
|
```
|
|
|
|
Usage:
|
|
```bash
|
|
./test-netmode.sh routed-pppoe "username=test@isp.com,password=secret"
|
|
```
|
|
|
|
### Common Issues and Debugging
|
|
|
|
#### Issue: Mode not switching
|
|
|
|
**Symptoms**: `.last_mode` not updated
|
|
|
|
**Debug**:
|
|
```bash
|
|
# Check if enabled
|
|
uci get netmode.global.enabled
|
|
|
|
# Check if mode exists
|
|
ls /etc/netmodes/<mode>/scripts/
|
|
|
|
# Check script permissions
|
|
ls -la /etc/netmodes/<mode>/scripts/
|
|
```
|
|
|
|
**Solution**:
|
|
```bash
|
|
chmod +x /etc/netmodes/<mode>/scripts/*
|
|
```
|
|
|
|
#### Issue: Required arguments missing
|
|
|
|
**Symptoms**: Mode script exits early
|
|
|
|
**Debug**:
|
|
```bash
|
|
logread | grep "value.*missing"
|
|
```
|
|
|
|
**Solution**: Set all required argument values before switching mode.
|
|
|
|
#### Issue: Environment variables not set
|
|
|
|
**Symptoms**: Mode script cannot access parameters
|
|
|
|
**Debug**:
|
|
```bash
|
|
# Add to mode script:
|
|
env | grep NETMODE | logger -t netmode-debug
|
|
```
|
|
|
|
**Solution**: Verify `dm_parent` references in UCI configuration.
|
|
|
|
#### Issue: UCI configuration not applied
|
|
|
|
**Symptoms**: Network doesn't change after mode switch
|
|
|
|
**Debug**:
|
|
```bash
|
|
# Check if UCI commit succeeded
|
|
uci changes
|
|
|
|
# Verify UCI syntax
|
|
uci show network
|
|
```
|
|
|
|
**Solution**: Check for UCI syntax errors in mode script.
|
|
|
|
---
|
|
|
|
## Advanced Topics
|
|
|
|
### Custom Board Integration
|
|
|
|
If using custom hardware, update board.json parsing in mode scripts:
|
|
|
|
```bash
|
|
if [ -f /etc/board.json ]; then
|
|
json_load_file /etc/board.json
|
|
json_select network
|
|
|
|
# Custom board handling
|
|
json_select custom_wan 2>/dev/null
|
|
json_get_var custom_dev device
|
|
[ -n "$custom_dev" ] && wandev="$custom_dev"
|
|
|
|
json_cleanup
|
|
fi
|
|
```
|
|
|
|
### VLAN Handling
|
|
|
|
All routed modes support VLAN tagging via `vlanid` argument:
|
|
|
|
```bash
|
|
if [ -n "$wandev" ] && echo "$NETMODE_vlanid" | grep -Eq '^[0-9]+$' && [ "$NETMODE_vlanid" -ge 1 ]; then
|
|
vlandev="$wandev.$NETMODE_vlanid"
|
|
vlandev_sec=$(echo $vlandev | tr '.' '_')
|
|
|
|
uci -q set network.${vlandev_sec}=device
|
|
uci -q set network.${vlandev_sec}.type="8021q"
|
|
uci -q set network.${vlandev_sec}.name="$vlandev"
|
|
uci -q set network.${vlandev_sec}.ifname="$wandev"
|
|
uci -q set network.${vlandev_sec}.vid=$NETMODE_vlanid
|
|
|
|
wandev="$vlandev"
|
|
fi
|
|
```
|
|
|
|
### Multicast Configuration
|
|
|
|
**L3 Modes** (routed-*): Use multicast proxy
|
|
```bash
|
|
l3_mcast_config() {
|
|
logger -s -p user.info -t "netmode" "Generating L3 mcast configuration"
|
|
rm -f /etc/config/mcast
|
|
sh /rom/etc/uci-defaults/61-mcast_config_generate
|
|
uci -q commit mcast
|
|
}
|
|
```
|
|
|
|
**L2 Mode** (bridged): Use IGMP/MLD snooping
|
|
```bash
|
|
l2_mcast_config() {
|
|
# IGMP snooping
|
|
uci -q set mcast.igmp_snooping_1=snooping
|
|
uci -q set mcast.igmp_snooping_1.enable='1'
|
|
uci -q set mcast.igmp_snooping_1.proto='igmp'
|
|
uci -q set mcast.igmp_snooping_1.interface='br-lan'
|
|
|
|
# MLD snooping
|
|
uci -q set mcast.mld_snooping_1=snooping
|
|
uci -q set mcast.mld_snooping_1.enable='1'
|
|
uci -q set mcast.mld_snooping_1.proto='mld'
|
|
|
|
uci -q commit mcast
|
|
}
|
|
```
|
|
|
|
### Preserving Configuration During Upgrade
|
|
|
|
**File**: `/lib/upgrade/keep.d/netmode`
|
|
|
|
```
|
|
/etc/config/netmode
|
|
/etc/netmodes/.last_mode
|
|
```
|
|
|
|
Add custom files:
|
|
```bash
|
|
echo "/etc/netmodes/custom-mode/custom.conf" >> /lib/upgrade/keep.d/netmode
|
|
```
|
|
|
|
---
|
|
|
|
## Best Practices
|
|
|
|
### Script Development
|
|
|
|
1. **Always source required libraries**:
|
|
```bash
|
|
. /lib/functions.sh
|
|
. /usr/share/libubox/jshn.sh
|
|
```
|
|
|
|
2. **Use logger for all output**:
|
|
```bash
|
|
logger -s -p user.info -t "netmode" "Message"
|
|
```
|
|
|
|
3. **Validate environment variables**:
|
|
```bash
|
|
if [ -z "$NETMODE_required_arg" ]; then
|
|
logger -s -p user.err -t "netmode" "Missing required argument"
|
|
exit 1
|
|
fi
|
|
```
|
|
|
|
4. **Use `uci -q` for non-critical operations**:
|
|
```bash
|
|
uci -q delete network.wan.old_option
|
|
```
|
|
|
|
5. **Always commit after changes**:
|
|
```bash
|
|
uci -q commit network
|
|
```
|
|
|
|
### Security
|
|
|
|
1. **Clear sensitive environment variables**:
|
|
- Automatic via `cleanup_env_vars()`
|
|
- Mark sensitive parameters as "Secure" in data model
|
|
|
|
2. **Validate input**:
|
|
```bash
|
|
# VLAN ID validation
|
|
echo "$NETMODE_vlanid" | grep -Eq '^[0-9]+$' && [ "$NETMODE_vlanid" -ge 1 ]
|
|
|
|
# IP address validation
|
|
echo "$NETMODE_ipaddr" | grep -Eq '^([0-9]{1,3}\.){3}[0-9]{1,3}$'
|
|
```
|
|
|
|
3. **Avoid command injection**:
|
|
```bash
|
|
# BAD
|
|
eval "uci set network.wan.ip=$NETMODE_ipaddr"
|
|
|
|
# GOOD
|
|
uci set network.wan.ip="$NETMODE_ipaddr"
|
|
```
|
|
|
|
### Performance
|
|
|
|
1. **Minimize reboots**: Use `service reload` when possible
|
|
2. **Batch UCI operations**: Commit once at the end
|
|
3. **Avoid redundant mode switches**: Compare with `.last_mode`
|
|
|
|
---
|
|
|
|
## References
|
|
|
|
- OpenWrt UCI Documentation: https://openwrt.org/docs/guide-user/base-system/uci
|
|
- Procd Init Scripts: https://openwrt.org/docs/guide-developer/procd-init-scripts
|
|
- BBF TR-181 Data Model: https://usp-data-models.broadband-forum.org/
|
|
- iopsys bbfdm: https://dev.iopsys.eu/iopsys/bbfdm
|
|
|
|
---
|
|
|
|
## Support and Contributing
|
|
|
|
For issues and contributions, please contact the iopsys development team.
|
|
|
|
**Package Maintainer**: iopsys
|
|
**License**: GPL-2.0-only
|
|
**Version**: 1.1.11
|