# Netmode Developer Guide ## Table of Contents 1. [Development Environment Setup](#development-environment-setup) 2. [Package Build System](#package-build-system) 3. [Code Organization](#code-organization) 4. [API Reference](#api-reference) 5. [Mode Script Development](#mode-script-development) 6. [UCI Integration](#uci-integration) 7. [Data Model Development](#data-model-development) 8. [Debugging Techniques](#debugging-techniques) 9. [Testing Framework](#testing-framework) 10. [Release Process](#release-process) --- ## Development Environment Setup ### Prerequisites ```bash # 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 ```bash # 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 ```bash # 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 ```bash # 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 ```makefile 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 ```makefile 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**: ```json "object": "{BBF_VENDOR_PREFIX}NetMode" ``` Replaced by `BBFDM_REGISTER_SERVICES` during build. ### Installation Targets ```makefile 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//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_=` if value is non-empty 4. Exit if required arguments are missing **Example**: ```bash 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//`. **Parameters**: - `when`: Hook type ("pre", "post", or empty for default) **Execution**: - Scripts executed in lexicographical order - Runs in subshell via `sh