iopsys-feed/netmode/docs/DEVELOPER_GUIDE.md

26 KiB

Netmode Developer Guide

Table of Contents

  1. Development Environment Setup
  2. Package Build System
  3. Code Organization
  4. API Reference
  5. Mode Script Development
  6. UCI Integration
  7. Data Model Development
  8. Debugging Techniques
  9. Testing Framework
  10. Release Process

Development Environment Setup

Prerequisites

# OpenWrt build environment
sudo apt-get install build-essential libncurses5-dev gawk git \
    subversion libssl-dev gettext unzip zlib1g-dev file python3

# Clone iopsys repository
git clone https://dev.iopsys.eu/iopsys/iopsyswrt.git
cd iopsyswrt

# Update feeds
./scripts/feeds update -a
./scripts/feeds install -a

Building netmode Package

# Configure build
make menuconfig
# Navigate to: Utilities -> netmode

# Build package only
make package/feeds/iopsys/netmode/compile V=s

# Build with debug symbols
make package/feeds/iopsys/netmode/compile V=s CONFIG_DEBUG=y

Installing to Device

# Copy to device
scp bin/packages/*/iopsys/netmode_*.ipk root@192.168.1.1:/tmp/

# Install on device
ssh root@192.168.1.1
opkg install /tmp/netmode_*.ipk

Development Workflow

# Make changes to files in feeds/iopsys/netmode/files/

# Clean and rebuild
make package/feeds/iopsys/netmode/clean
make package/feeds/iopsys/netmode/compile V=s

# Test on device
scp bin/packages/*/iopsys/netmode_*.ipk root@192.168.1.1:/tmp/
ssh root@192.168.1.1 "opkg remove netmode; opkg install /tmp/netmode_*.ipk"

Package Build System

Makefile Analysis

PKG_NAME:=netmode
PKG_VERSION:=1.1.11
PKG_RELEASE:=1

Version Scheme: MAJOR.MINOR.PATCH

  • MAJOR: Breaking changes
  • MINOR: New features, backward compatible
  • PATCH: Bug fixes

Build Configuration

define Package/$(PKG_NAME)/config
    config NETMODE_VENDOR_PREFIX
        depends on PACKAGE_netmode
        string "Vendor Extension used for netmode datamodel"
        default ""
endef

Usage in code:

"object": "{BBF_VENDOR_PREFIX}NetMode"

Replaced by BBFDM_REGISTER_SERVICES during build.

Installation Targets

define Package/netmode/install
    $(INSTALL_DIR) $(1)/etc
    $(INSTALL_DIR) $(1)/lib
    $(CP) ./files/etc/* $(1)/etc/
    $(CP) ./files/lib/* $(1)/lib/
    $(BBFDM_REGISTER_SERVICES) -v ${VENDOR_PREFIX} ./bbfdm_service.json $(1) $(PKG_NAME)
    $(BBFDM_INSTALL_MS_DM) -v ${VENDOR_PREFIX} ./files/datamodel.json $(1) $(PKG_NAME)
endef

File Permissions:

  • Scripts in /etc/init.d/: 0755 (executable)
  • UCI configs: 0644 (readable)
  • Mode scripts: Must be made executable in postinst

Code Organization

Module Responsibilities

Module File Responsibility
Init System /etc/init.d/netmode Service lifecycle, mode switching orchestration
Mode Scripts /etc/netmodes/<mode>/scripts/* Mode-specific UCI configuration
Pre-hooks /lib/netmode/pre/* Pre-switch preparation
Post-hooks /lib/netmode/post/* Post-switch cleanup, reboot
UCI Defaults /etc/uci-defaults/* First-boot configuration
Data Model /files/datamodel.json BBF TR-181 mappings
Service Def bbfdm_service.json BBF service registration

Init Script Architecture

/etc/init.d/netmode
├── start_service()           # Main entry point
│   ├── configure_env_vars()  # Setup NETMODE_* vars
│   ├── libnetmode_exec("pre")
│   ├── Copy UCI files
│   ├── libnetmode_exec()     # Generic scripts
│   ├── Execute mode scripts
│   ├── libnetmode_exec("post")
│   └── cleanup_env_vars()
├── service_triggers()        # Procd reload trigger
└── Helper functions:
    ├── _log()
    ├── _get_modes_sec_name()
    ├── _set_env_args()
    └── cleanup_arg_values()

API Reference

Init Script Functions

start_service()

Main service entry point called by procd.

Execution Conditions:

  • /etc/config/netmode exists
  • netmode.global.enabled = 1
  • netmode.global.mode is set
  • Current mode differs from .last_mode

Side Effects:

  • Modifies UCI configuration
  • Exports environment variables
  • Writes .last_mode file
  • May trigger system reboot (via post-hook)

configure_env_vars(mode)

Exports mode arguments as environment variables.

Parameters:

  • mode: Mode name (e.g., "routed-pppoe")

Behavior:

  1. Find UCI section matching mode name
  2. Iterate supported_args with matching dm_parent
  3. Export NETMODE_<name>=<value> if value is non-empty
  4. Exit if required arguments are missing

Example:

configure_env_vars "routed-pppoe"
# Exports:
# NETMODE_username="user@isp.com"
# NETMODE_password="secret123"

cleanup_env_vars(mode)

Unsets NETMODE_* environment variables and clears UCI values.

Parameters:

  • mode: Current mode name

Behavior:

  1. Unset all NETMODE_* environment variables
  2. Clear value field in UCI for all arguments of current mode
  3. Commit UCI changes

Security Note: Prevents leaking credentials to subsequent processes.

libnetmode_exec(when)

Executes hook scripts from /lib/netmode/<when>/.

Parameters:

  • when: Hook type ("pre", "post", or empty for default)

Execution:

  • Scripts executed in lexicographical order
  • Runs in subshell via sh <script>
  • Logs execution to syslog

Example:

libnetmode_exec "pre"
# Executes: /lib/netmode/pre/10-backup
#           /lib/netmode/pre/20-prepare

_log(message)

Logs message to syslog with netmode tag.

Parameters:

  • message: Log message

Implementation:

logger -s -p user.info -t "netmode" "$*"

Mode Script Development

Script Template

#!/bin/sh
#
# Mode: <mode-name>
# Description: <brief description>
# Required Arguments: <list>
# Optional Arguments: <list>
#

. /lib/functions.sh
. /usr/share/libubox/jshn.sh

# Source device-specific info if available
[ -f /etc/device_info ] && source "/etc/device_info"

# Logging function
_log() {
    logger -s -p user.info -t "netmode-<mode>" "$*"
}

# Main configuration function
configure_network() {
    _log "Starting network configuration"

    # Get WAN device
    wandev="$(uci -q get network.WAN.ifname)"
    [ -z "$wandev" ] && wandev="eth0"  # Fallback

    # Validate required arguments
    if [ -z "$NETMODE_required_arg" ]; then
        _log "ERROR: Missing required argument: required_arg"
        return 1
    fi

    # Configure network interface
    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'

    # Mode-specific WAN configuration
    uci -q set network.wan=interface
    uci -q set network.wan.device="$wandev"
    # Add mode-specific settings here

    uci -q commit network

    _log "Network configuration complete"
}

# Configure DHCP server
configure_dhcp() {
    _log "Configuring DHCP"

    uci -q set dhcp.lan.ignore=0
    uci -q set dhcp.wan.ignore=1
    uci -q commit dhcp
}

# Configure firewall
configure_firewall() {
    _log "Configuring firewall"

    uci -q set firewall.globals.enabled="1"
    uci -q commit firewall
}

# Configure multicast
configure_multicast() {
    _log "Configuring multicast"

    # L3 or L2 multicast config
    rm -f /etc/config/mcast
    sh /rom/etc/uci-defaults/61-mcast_config_generate
    uci -q commit mcast
}

# Update service dependencies
configure_services() {
    _log "Updating service configurations"

    # CWMP WAN interface
    uci -q set cwmp.cpe.default_wan_interface="wan"
    uci -q commit cwmp

    # Gateway WAN interface
    uci -q set gateway.global.wan_interface="wan"
    uci -q commit gateway

    # SSDPD
    uci -q set ssdpd.ssdp.enabled="1"
    uci -q commit ssdpd
}

# Main execution
configure_network || exit 1
configure_dhcp
configure_firewall
configure_multicast
configure_services

_log "Mode configuration complete"
exit 0

Common Patterns

VLAN Configuration

configure_vlan() {
    local wandev="$1"

    # Delete existing VLANs
    for vlandev_sec in $(uci show network | grep "type=.*8021q" | cut -d'.' -f1,2); do
        uci -q delete $vlandev_sec
    done

    # Create new VLAN if vlanid provided
    if [ -n "$wandev" ] && echo "$NETMODE_vlanid" | grep -Eq '^[0-9]+$' && [ "$NETMODE_vlanid" -ge 1 ]; then
        local vlandev="$wandev.$NETMODE_vlanid"
        local 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

        echo "$vlandev"
    else
        echo "$wandev"
    fi
}

# Usage
wandev="$(uci -q get network.WAN.ifname)"
wandev=$(configure_vlan "$wandev")
uci -q set network.wan.device="$wandev"

DNS Server Configuration

configure_dns() {
    uci -q delete network.wan.dns

    if [ -n "$NETMODE_dns_servers" ]; then
        local dns_servers="$(echo $NETMODE_dns_servers | tr ',' ' ')"
        for server in $dns_servers; do
            # Validate IP address format
            if echo "$server" | grep -Eq '^([0-9]{1,3}\.){3}[0-9]{1,3}$'; then
                uci add_list network.wan.dns="$server"
            else
                _log "WARNING: Invalid DNS server: $server"
            fi
        done
    fi
}

Bridge Port Configuration

configure_bridge_ports() {
    uci -q delete network.br_lan.ports
    uci -q set network.br_lan.bridge_empty='1'

    add_port_to_br_lan() {
        local port="$1"
        [ -n "$port" -a -d /sys/class/net/$port ] || return
        uci add_list network.br_lan.ports="$port"
        _log "Added $port to br-lan"
    }

    if [ -f /etc/board.json ]; then
        json_load_file /etc/board.json
        json_select network

        # LAN ports
        json_select lan
        if json_is_a ports array; then
            json_for_each_item add_port_to_br_lan ports
        else
            json_get_var device device
            [ -n "$device" ] && add_port_to_br_lan "$device"
        fi
        json_select ..

        # WAN ports (for bridged mode)
        if [ "$1" = "bridged" ]; then
            json_select wan 2>/dev/null
            json_get_var device device
            [ -n "$device" ] && add_port_to_br_lan "$device"
        fi

        json_cleanup
    fi
}

Error Handling

# Validate critical operations
configure_network() {
    if ! uci -q get network.WAN >/dev/null; then
        _log "ERROR: WAN interface not found in board config"
        return 1
    fi

    if [ -z "$NETMODE_required_param" ]; then
        _log "ERROR: Required parameter missing"
        return 1
    fi

    # Perform configuration
    uci -q set network.wan.setting="$NETMODE_required_param" || {
        _log "ERROR: Failed to set UCI option"
        return 1
    }

    uci -q commit network || {
        _log "ERROR: Failed to commit network config"
        return 1
    }

    return 0
}

# Check return value
if ! configure_network; then
    _log "Configuration failed, aborting mode switch"
    exit 1
fi

UCI Integration

Reading UCI Values

# Get single value
enabled=$(uci -q get netmode.global.enabled)

# Get with default
mode=$(uci -q get netmode.global.mode || echo "routed-dhcp")

# Check if option exists
if uci -q get network.wan >/dev/null; then
    echo "WAN interface exists"
fi

# Iterate sections
config_load netmode
config_foreach handle_mode supported_modes

handle_mode() {
    local section="$1"
    local name
    config_get name "$section" name
    echo "Found mode: $name"
}

Writing UCI Values

# Set option
uci set network.wan.proto='dhcp'

# Delete option
uci delete network.wan.username

# Delete section
uci delete network.wan6

# Add list item
uci add_list network.wan.dns='8.8.8.8'

# Delete all list items
uci delete network.wan.dns

# Always commit after changes
uci commit network

UCI Section References

# Reference by index
uci set netmode.@supported_modes[0].name='routed-dhcp'

# Reference by name (if section is named)
uci set netmode.global.mode='routed-pppoe'

# Get section index
idx=$(uci show netmode | grep "name='routed-pppoe'" | cut -d. -f2 | cut -d= -f1)
uci set "netmode.$idx.description='PPPoE Mode'"

Advanced UCI Operations

# Create anonymous section
uci add netmode supported_modes

# Rename section
uci rename netmode.@supported_modes[0]=pppoe_mode

# Reorder sections
uci reorder netmode.pppoe_mode=1

# Batch operations
uci batch <<EOF
set network.wan=interface
set network.wan.proto='dhcp'
set network.wan.device='eth0'
delete network.wan.ipaddr
commit network
EOF

Data Model Development

Adding New Parameters

1. Update datamodel.json

{
    "Device.{BBF_VENDOR_PREFIX}NetMode.SupportedModes.{i}.": {
        "NewParameter": {
            "type": "string",
            "read": true,
            "write": true,
            "description": "New parameter description",
            "protocols": ["cwmp", "usp"],
            "mapping": [
                {
                    "type": "uci_sec",
                    "data": "@Parent",
                    "key": "new_param"
                }
            ]
        }
    }
}

2. Update UCI Schema

Add to /etc/config/netmode:

config supported_modes
    option name 'mode-name'
    option new_param 'default-value'

3. Handle in Mode Script

#!/bin/sh
new_value="$NETMODE_new_param"
if [ -n "$new_value" ]; then
    uci set some_config.section.option="$new_value"
fi

Data Type Mappings

BBF Type UCI Type Shell Validation
string text [ -n "$var" ]
unsignedInt integer echo "$var" | grep -Eq '^[0-9]+$'
boolean 0/1 [ "$var" = "1" ]
dateTime timestamp date -d "$var"
base64 base64 echo "$var" | base64 -d

Mapping Types

uci Mapping (Static Section)

{
    "mapping": [
        {
            "type": "uci",
            "uci": {
                "file": "netmode",
                "section": {
                    "name": "global"
                },
                "option": {
                    "name": "enabled"
                }
            }
        }
    ]
}

uci_sec Mapping (Dynamic Section)

{
    "mapping": [
        {
            "type": "uci_sec",
            "data": "@Parent",
            "key": "name"
        }
    ]
}

Special Flags

Flag Purpose Example
Linker Reference target Mode name for linking
Reference Reference source Mode selection
Unique Value must be unique Mode names
Secure Hidden from GET Passwords

Debugging Techniques

Enable Verbose Logging

# In mode script
set -x  # Enable shell tracing
trap 'set +x' EXIT

# Or use logger extensively
_log() {
    logger -s -p user.debug -t "netmode-debug" "$*"
}

Live Log Monitoring

# Terminal 1: Monitor logs
logread -f | grep -E "netmode|network|firewall"

# Terminal 2: Trigger mode switch
service netmode restart

Capture Environment State

#!/bin/sh
# Add to mode script for debugging

DEBUG_DIR="/tmp/netmode-debug"
mkdir -p "$DEBUG_DIR"

# Save environment
env > "$DEBUG_DIR/env.txt"

# Save UCI state
uci export network > "$DEBUG_DIR/network.uci"
uci export netmode > "$DEBUG_DIR/netmode.uci"

# Save script output
exec 2>&1 | tee "$DEBUG_DIR/script-output.log"

Interactive Testing

# Manually execute mode script
sh -x /etc/netmodes/routed-pppoe/scripts/10-routed-pppoe

# Set environment manually
export NETMODE_username="test"
export NETMODE_password="test123"
sh /etc/netmodes/routed-pppoe/scripts/10-routed-pppoe

# Check UCI changes without commit
uci changes

Common Debug Commands

# Check last mode
cat /etc/netmodes/.last_mode

# Check netmode UCI
uci show netmode

# Check network UCI
uci show network | grep -E "lan|wan"

# Check process environment
cat /proc/$(pgrep netmode)/environ | tr '\0' '\n' | grep NETMODE

# Check procd service status
ubus call service list '{"name":"netmode"}'

Procd Debugging

# Check procd service state
procd_status() {
    ubus call service list '{"name":"netmode"}' | jsonfilter -e '@.netmode'
}

# Manual procd trigger
ubus call service event '{"type":"config.change","data":{"package":"netmode"}}'

# Check init script syntax
sh -n /etc/init.d/netmode

Testing Framework

Unit Test Template

#!/bin/sh
# test-mode-routed-dhcp.sh

. /lib/functions.sh

PASSED=0
FAILED=0

assert_equal() {
    local expected="$1"
    local actual="$2"
    local test_name="$3"

    if [ "$expected" = "$actual" ]; then
        echo "✓ PASS: $test_name"
        PASSED=$((PASSED + 1))
    else
        echo "✗ FAIL: $test_name"
        echo "  Expected: $expected"
        echo "  Actual:   $actual"
        FAILED=$((FAILED + 1))
    fi
}

assert_exists() {
    local path="$1"
    local test_name="$2"

    if [ -e "$path" ]; then
        echo "✓ PASS: $test_name"
        PASSED=$((PASSED + 1))
    else
        echo "✗ FAIL: $test_name (path not found: $path)"
        FAILED=$((FAILED + 1))
    fi
}

test_mode_applied() {
    local expected_mode="$1"
    local actual_mode=$(cat /etc/netmodes/.last_mode 2>/dev/null)
    assert_equal "$expected_mode" "$actual_mode" "Mode applied"
}

test_wan_proto() {
    local expected_proto="$1"
    local actual_proto=$(uci -q get network.wan.proto)
    assert_equal "$expected_proto" "$actual_proto" "WAN protocol"
}

test_dhcp_enabled() {
    local expected="$1"
    local actual=$(uci -q get dhcp.lan.ignore)
    [ "$expected" = "enabled" ] && expected="0" || expected="1"
    assert_equal "$expected" "$actual" "DHCP server state"
}

# Run tests
echo "Testing routed-dhcp mode..."

test_mode_applied "routed-dhcp"
test_wan_proto "dhcp"
test_dhcp_enabled "enabled"
assert_exists "/etc/config/network" "Network config exists"

echo ""
echo "Results: $PASSED passed, $FAILED failed"
[ $FAILED -eq 0 ] && exit 0 || exit 1

Integration Test Script

#!/bin/sh
# test-mode-switch.sh

MODE="$1"
[ -z "$MODE" ] && { echo "Usage: $0 <mode>"; exit 1; }

echo "=== Mode Switch Test: $MODE ==="

# Backup config
cp /etc/config/network /tmp/network.backup
cp /etc/config/netmode /tmp/netmode.backup

# Set mode
echo "Setting mode to $MODE..."
uci set netmode.global.mode="$MODE"
uci commit netmode

# Trigger switch
echo "Applying mode..."
service netmode restart
sleep 2

# Verify
echo "Verifying..."
LAST_MODE=$(cat /etc/netmodes/.last_mode)

if [ "$LAST_MODE" = "$MODE" ]; then
    echo "✓ Mode switch successful"

    # Run mode-specific tests
    case "$MODE" in
        routed-dhcp)
            [ "$(uci -q get network.wan.proto)" = "dhcp" ] && echo "✓ WAN proto correct"
            ;;
        routed-pppoe)
            [ "$(uci -q get network.wan.proto)" = "pppoe" ] && echo "✓ WAN proto correct"
            ;;
        bridged)
            [ -z "$(uci -q get network.wan)" ] && echo "✓ WAN interface removed"
            ;;
    esac
else
    echo "✗ Mode switch failed"
    echo "  Expected: $MODE"
    echo "  Actual:   $LAST_MODE"
fi

# Restore config
echo "Restoring config..."
cp /tmp/network.backup /etc/config/network
cp /tmp/netmode.backup /etc/config/netmode
uci commit

Automated Test Suite

#!/bin/sh
# run-all-tests.sh

TESTS_DIR="$(dirname $0)/tests"
RESULTS_DIR="/tmp/netmode-test-results"

mkdir -p "$RESULTS_DIR"

TOTAL=0
PASSED=0
FAILED=0

for test_script in "$TESTS_DIR"/test-*.sh; do
    [ -f "$test_script" ] || continue

    TOTAL=$((TOTAL + 1))
    test_name=$(basename "$test_script" .sh)

    echo "Running $test_name..."
    if sh "$test_script" > "$RESULTS_DIR/$test_name.log" 2>&1; then
        echo "✓ $test_name PASSED"
        PASSED=$((PASSED + 1))
    else
        echo "✗ $test_name FAILED"
        FAILED=$((FAILED + 1))
        cat "$RESULTS_DIR/$test_name.log"
    fi
done

echo ""
echo "=== Test Summary ==="
echo "Total:  $TOTAL"
echo "Passed: $PASSED"
echo "Failed: $FAILED"

[ $FAILED -eq 0 ] && exit 0 || exit 1

Release Process

Version Bump Procedure

  1. Update version in Makefile:

    PKG_VERSION:=1.2.0
    PKG_RELEASE:=1
    
  2. Update changelog:

    # Create CHANGELOG.md if not exists
    echo "## [1.2.0] - $(date +%Y-%m-%d)" >> CHANGELOG.md
    echo "### Added" >> CHANGELOG.md
    echo "- New feature description" >> CHANGELOG.md
    
  3. Test on target hardware:

    make package/feeds/iopsys/netmode/clean
    make package/feeds/iopsys/netmode/compile V=s
    # Deploy and test
    
  4. Commit changes:

    git add Makefile CHANGELOG.md
    git commit -m "netmode: update to version 1.2.0"
    
  5. Tag release:

    git tag -a netmode-1.2.0 -m "Release version 1.2.0"
    git push origin netmode-1.2.0
    

Pre-release Checklist

  • All tests passing
  • Documentation updated
  • CHANGELOG.md updated
  • Version numbers bumped
  • Tested on at least 2 different hardware platforms
  • Backward compatibility verified
  • Data model compatibility checked
  • No hardcoded paths or device-specific code
  • Logging is appropriate (not too verbose)
  • UCI defaults handle upgrade scenarios

Package Validation

# Check package structure
tar -tzf netmode_*.ipk

# Verify file permissions
tar -xzf netmode_*.ipk -O ./data.tar.gz | tar -tzv

# Check dependencies
opkg info netmode_*.ipk | grep Depends

# Validate UCI config syntax
tar -xzf netmode_*.ipk -O ./data.tar.gz | tar -xz ./etc/config/netmode
uci import netmode < netmode

Best Practices Summary

Code Quality

  1. Always use shellcheck:

    shellcheck /etc/init.d/netmode
    shellcheck /etc/netmodes/*/scripts/*
    
  2. Use set -e for critical scripts:

    #!/bin/sh
    set -e  # Exit on error
    
  3. Quote all variables:

    # Good
    uci set network.wan.device="$wandev"
    
    # Bad
    uci set network.wan.device=$wandev
    
  4. Check return values:

    if ! configure_network; then
        logger -t netmode "Configuration failed"
        exit 1
    fi
    

Performance Optimization

  1. Minimize UCI commits:

    # Bad: Multiple commits
    uci set network.lan.ipaddr='192.168.1.1'
    uci commit network
    uci set network.lan.netmask='255.255.255.0'
    uci commit network
    
    # Good: Single commit
    uci set network.lan.ipaddr='192.168.1.1'
    uci set network.lan.netmask='255.255.255.0'
    uci commit network
    
  2. Avoid unnecessary mode switches:

    # Check .last_mode before proceeding
    [ "$mode" = "$(cat /etc/netmodes/.last_mode)" ] && return
    
  3. Use batch UCI operations:

    uci batch <<EOF
    set network.wan=interface
    set network.wan.proto='dhcp'
    commit network
    EOF
    

Security Hardening

  1. Validate all input:

    # VLAN ID validation
    if ! echo "$NETMODE_vlanid" | grep -Eq '^[0-9]+$'; then
        logger -t netmode "Invalid VLAN ID"
        return 1
    fi
    
  2. Clear sensitive data:

    # Automatic via cleanup_env_vars()
    # But also clear from UCI
    uci set netmode.@supported_args[X].value=''
    
  3. Use secure file permissions:

    # Scripts should be 0755
    # Configs should be 0644
    # Never 0777
    

Troubleshooting

Build Issues

Issue: Package fails to build

Solution:

# Clean build
make package/feeds/iopsys/netmode/clean
rm -rf build_dir/target-*/netmode-*

# Rebuild with verbose output
make package/feeds/iopsys/netmode/compile V=s

Issue: Data model registration fails

Solution:

# Check vendor prefix
grep BBF_VENDOR_PREFIX .config

# Verify bbfdm is installed
opkg list-installed | grep bbfdm

Runtime Issues

Issue: Mode not switching

Debug:

# Check service status
service netmode status

# Check logs
logread | grep netmode

# Verify UCI
uci show netmode

Issue: Environment variables not set

Debug:

# Check dm_parent references
uci show netmode | grep dm_parent

# Verify argument values
uci show netmode | grep value

Contributing Guidelines

Code Style

  • Use tabs for indentation (OpenWrt standard)
  • Max line length: 120 characters
  • Function names: lowercase_with_underscores
  • Variables: lowercase or UPPERCASE for constants

Commit Messages

netmode: brief description (max 50 chars)

Detailed explanation of changes (wrap at 72 chars).
- Bullet points for multiple changes
- Reference issue numbers if applicable

Signed-off-by: Your Name <email@example.com>

Pull Request Process

  1. Fork the repository
  2. Create feature branch: git checkout -b feature/my-feature
  3. Make changes and test thoroughly
  4. Update documentation
  5. Submit PR with clear description
  6. Address review comments

Resources


Maintainer: iopsys Development Team License: GPL-2.0-only Version: 1.1.11