type
status
date
slug
summary
tags
category
icon
password
迁移自旧站,原始文章发表于2020-05-23,信息可能已部分失效
背景
月初偶然得知padavan固件在linux 3.4.x内核上有高人backport了3.7.x的
SO_REUSEPORT
特性。对于拥有多核CPU的路由器来说,利用该特性可以显著提升SS所能承载的吞吐。手头上正好有个老旧的A3004NS,虽说有点不舍得荒野无灯的精致固件,还是拿来折腾一番。期间学习了一部分padavan固件编写插件的方法,下文以某插件为例,做简单的介绍及记录。准备
按照
hanwckf
的rt-n56u说明准备编译环境。这个固件是在原版的padavan基础上增加了国内常用的一些插件,同时适配了不少常见的padavan兼容路由,在编译配置上做了简化,其他固件可能在一部分配置上有所出入。插件相关文件
trunk/ |-- configs | |-- templates | | |-- A3004NS.config // 路由器适配文件,新增的插件编译选项开关可在此处追加 | | └-- ... | └-- ... |-- user | |-- Makefile // 控制所有插件的编译,和路由器配置联动达到插件可选化编译和打包 | |-- A_PLUGIN | | |-- Makefile // 控制单个插件的编译、打包文件产出,参照其他插件例子即可 | | └-- ... | |-- www // 页面文件,padavan中多数为asp | | |-- Makefile // 新增插件若有相关页面文件,需要调整该文件 | | |-- state.js // 控制页面目录中的插件页面入口,新增插件需要调整该文件 | | |-- dict // i18n实现,按需调整 | | └-- n56u_ribbon_fixed | | |-- PLUGIN_RELATED.asp // 插件页面相关的asp文件 | | └-- ... | |-- httpd | | |-- variables.c // 插件相关nvram持久化数据的变量结构体定义 | | |-- web_ex.c // 处理asp后端逻辑的核心文件,主要关注暴露出来的函数,如update_variables_ex | | |-- common.h // 关注variable,为结构体属性的类型 | | └-- ... | |-- shared | | |-- defaults.c // 定义插件相关变量的默认值 | | └-- ... | └-- ... └-- ...
插件代码
插件核心代码
对应目录中
trunk/user/A_PLUGIN
,主要通过Makefile编译插件并将产出的(部分)二进制文件加入固件。多数情况下需要调整编译选项,参考其他插件例子即可。需要注意的一点是,在整体编译固件时插件时若需要重新运行configure,要删除产出的config_done文件。编译开关
在
trunk/user/Makefile
中关联对应插件的目录,如dir_y += transmission
,即可添加transmission到编译列表。若需要通过路由器适配文件配置插件编译可选,则可以改为
dir_$(CONFIG_FIRMWARE_INCLUDE_TRANSMISSION) += transmission
, 并在trunk/configs/templates/XXX.config
中配置CONFIG_FIRMWARE_INCLUDE_TRANSMISSION=y/n
页面代码
页面代码一般简单插件仅需提供asp文件,若存在额外的js或css文件,同样放在
trunk/user/www
目录下,调整trunk/user/www/Makefile
文件即可。核心流程
页面的核心逻辑是提交的数据通过httpd服务暴露的函数入口更新到nvram或持久化的文件中。对此padavan约定了一套处理的通用流程。
- 页面通过form post提交到
start_apply.htm
start_apply.htm
调用相应的后端update_variables
、asus_nvram_commit
以及notify_services
update_variables
通过参数中的sid_list
找到对应的在trunk/user/httpd/variables.c
中定义的结构体变量,同时将其他参数映射到结构体定义的成员变量上。校验通过后,逐一更新到nvram或写到相应文件(详见trunk/user/httpd/web_ex.c
中的update_variables_ex
函数逻辑)
- 提交变更到nvram(持久化)
- 若需要,通知触发相关关服务,如系统重启等操作
nvram/文件内容输出
- 页面上展示nvram中的变量,使用
<% nvram_get_x("","VARIABLE"); %>
- 页面上输出文件内容,使用
<% nvram_dump("PREFIX.VARIABLE", ""); %>
nvram变量更新
一般情况无需关注,提交的参数名与插件结构体中的变量名相同即可。如:
// trunk/user/httpd/variables.c struct variable variables_dnsforwarderConf[] = { {"dns_forwarder_enable", "", NULL, EVM_RESTART_DNSFORWARDER}, {"dns_forwarder_bind", "", NULL, EVM_RESTART_DNSFORWARDER}, {"dns_forwarder_port", "", NULL, EVM_RESTART_DNSFORWARDER}, {"dns_forwarder_server", "", NULL, EVM_RESTART_DNSFORWARDER}, {0,0,0,0} }; ... struct svcLink svcLinks[] = { ... {"dnsforwarderConf", variables_dnsforwarderConf}, ... }
http提交参数中包含
dns_forwarder_server
,同时sid_list
指定为dnsforwarderConf;
, 即可更新到nvram中的dns_forwarder_server
变量。文件内容更新
关于rom storage中文件内容的更新,是通过将结构体变量单元(
variable
,见trunk/user/httpd/common.h
)中的longname
设置为File
,以在trunk/user/httpd/web_ex.c
的validate_asp_apply
函数改写为对应的文件路径实现更新的。如:// trunk/user/httpd/variables.c {"scripts.start_script.sh", "File", NULL, EVM_BLOCK_UNSAFE},
// trunk/user/httpd/web_ex.c - validate_asp_apply ... } else if (!strncmp(v->name, "scripts.", 8)) { if (write_textarea_to_file(value, STORAGE_SCRIPTS_DIR, file_name)) restart_needed_bits |= event_mask; ...
通过阅读代码可知,文件类型的
variable
有多个预定义的路径(见trunk/user/httpd/httpd.h
),普通插件一般使用scripts
目录即可,变量名格式需要为scripts.xxx
,有如下映射:scripts.FILE_NAME
->/etc/storage/FILE_NAME
- 作者:hackaday
- 链接:https://openai.win/article/how-to-build-a-padavan-plugin
- 声明:本文采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处。