Openwrt netifd解析
Overview
Openwrt为网络接口管理和配置创建了一个单独的project,netifd。不同于其他发行版上针对同样问题领域采用的方案,netifd的目标是更适合在嵌入式的home-gateway上使用,因此也具有一些特点。
Package组成
netifd包含下面这些组件:
- Shell脚本:/sbin/ifup, /sbin/ifdown(link to ifup), /sbin/ifstatus, /sbin/devstatus
- init.d脚本:/etc/init.d/network
- hotplug2脚本:/etc/hotplug.d/iface/00-netstate, /etc/hotplug.d/iface/10-sysctl
- udhcpc脚本:/usr/share/udhcpc/default.script
- netifd守护进程binary: /sbin/netifd
下面对这些组件,逐一进行分析,以期理解netifd的基本工作机制.
Shell脚本
/sbin/ifup
如前所述,ifdown实际上是指向ifup的符号链接,因此这两个脚本由同一个文件ifup实现。下面是其语法:
|
1
2
3
4
|
syntax: /sbin/{ifup|ifdown} [-a] [-w] [interface]
-a选项指明对所有接口均执行相同的操作,此时interface被忽略.此参数默认为false
-w选项指定是否执行wifi up操作。如果此参数被指定,则wifi up操作不会被执行。如果未指定,则在ifup的时候,wifi up会被执行
interface指定down/up操作的目标接口
|
ifup的脚本里面,关于wifi的操作是通过/sbin/wifi脚本执行的,所以在这里暂时不讨论。关于normal的if down/up操作,这个脚本是通过ubus命令来实现的。下面是一个if_call() function:
|
1
2
3
4
5
6
|
if_call(){
localinterface="$1"
formodein$modes;do
ubuscall$interface$mode
done
}
|
可以看到这个function有一个参数,是interface,然后还使用了一个全局参数, modes, 在ifup脚本里面被定义,如下:
|
1
2
3
4
5
6
7
8
|
case "$0" in
*ifdown) modes=down;;
*ifup)
modes="down up"
setup_wifi=1
;;
*) echo "Invalid command: $0";;
esac
|
所以当执行ifdown lan时,对应的ubus命令为”ubus call network.interface.lan down”;执行ifup lan时,ubus命令为两条,先执行”ubus call network.interface.lan down”,然后是”ubus call network.interface.lan up”.
ubus & ubusd
Openwrt提供了一个ubus系统,它类似于桌面linux系统的dbus,目标也是提供系统级的IPC和RPC。ubus在设计理念上与dbus基本保持一致,区别在于简化的API和简练的模型,以适应于embedded router的特殊环境。
基本上来说, openwrt的ubus由下面几个组件组成:
- ubusd,这个是ubus系统的后台进程,负责注册unix domain socket,分派ubus消息和事件等;
- ubus,这是一个CLI utility,可以通过它访问ubus系统. ubus的帮助信息如下:
1234567891011Usage:ubus[options]<command></command>[arguments...]Options:-s:Settheunixdomainsockettoconnectto-t:Setthetimeout(inseconds)foracommandtocomplete-S:Usesimplifiedoutput(forscripts)-v:MoreverboseoutputCommands:-list[]Listobjects-call[]Callanobjectmethod-listen[...]Listenforevents-send[]Sendanevent
ubus提供的command有4种: list, call, listen & send, 通过这四种command,可以访问注册到ubus系统的服务 - 最后是使用ubus的各个应用程序。这些应用程序可以在ubus系统中注册RPC接口,提供相应的服务。而其他程序可以使用这些接口,来访问这些服务。
netifd的ubus RPC接口
netifd在ubus系统中注册了的object如下:
12345678910111213141516171819202122232425262728293031323334353637383940root@OpenWrt:/# ubus list -v'network'@25a06dad"restart":{}"reload":{}"add_host_route":{"target":"String","v6":"Boolean"}"get_proto_handlers":{}'network.device'@9d97d655"status":{"name":"String"}"set_alias":{"alias":"(unknown)","device":"String"}"set_state":{"name":"String","defer":"Boolean"}'network.interface.lan'@f9e7258b"up":{}"down":{}"status":{}"prepare":{}"add_device":{"name":"String"}"remove_device":{"name":"String"}"notify_proto":{}"remove":{}"set_data":{}'network.interface.loopback'@6d026db0"up":{}"down":{}"status":{}"prepare":{}"add_device":{"name":"String"}"remove_device":{"name":"String"}"notify_proto":{}"remove":{}"set_data":{}'network.interface.wan'@ade92c65"up":{}"down":{}"status":{}"prepare":{}"add_device":{"name":"String"}"remove_device":{"name":"String"}"notify_proto":{}"remove":{}"set_data":{}每个object所提供的RPC接口名称,以及接口参数类型都可以通过ubus得到。
netifd interface RPC
netifd为每个interface object注册了一组相同的methods,如下:
1234567891011static struct ubus_method iface_object_methods[] = {{ .name = "up", .handler = netifd_handle_up },{ .name = "down", .handler = netifd_handle_down },{ .name = "status", .handler = netifd_handle_status },{ .name = "prepare", .handler = netifd_handle_iface_prepare },UBUS_METHOD("add_device", netifd_iface_handle_device, dev_policy ),UBUS_METHOD("remove_device", netifd_iface_handle_device, dev_policy ),{ .name = "notify_proto", .handler = netifd_iface_notify_proto },{ .name = "remove", .handler = netifd_iface_remove },{ .name = "set_data", .handler = netifd_handle_set_data },};然后可以发现,netifd里面还有一个protocol handler的概念,也就是对不同的interface protocol,可以提供不同的handler,来响应各种可能的事件。最常见的static类型的protocol,内置在netifd中。而dhcp,pppoe等类型的协议,则以shell script的形式提供。
netifd protocol handler插件
netifd的protocol handler插件位于/lib/netifd/proto/目录下,名称统一为*.sh

浙公网安备 33010602011771号