1、netifd简介
1.1 netifd简介
OpenWRT为网络接口管理和配置创建了一个单独的项目——netifd。不同于其他发行版上针对同样问题领域采用的方案,netifd的目标是更适合在嵌入式家庭网关上使用,因此也具有一些特点。
1.2 netifd包含下面这些组件
程序 | |
---|---|
Shell脚本 | /sbin/ifup,/sbin/ifdown,/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守护进程 | /sbin/netifd |
1.3 netifd组件分析
下面对这些组件,逐一进行分析,希望以此来理解netifd的基本工作机制。
1.3.1 ifup和ifdown脚本
ifup和ifdown脚本都被存放在/sbin目录下,ifdown实际上是指向ifup的符号链接。所以,这两个脚本实际上是同一个脚本文件。查看过程如下所示:
root@OpenWrt:~# ls -l /sbin/ifup -rwxrwxr-x 1 root root 1286 Sep 1 09:27 /sbin/ifup root@OpenWrt:~# root@OpenWrt:~# ls -l /sbin/ifdown lrwxrwxrwx 1 root root 4 Sep 1 09:27 /sbin/ifdown -> ifup root@OpenWrt:~#
ifup和ifdown的语法格式如下所示:
ifup [-a] [-w] <interface> ifdown [-a] [-w] <interface>
下面是对ifup/ifdown命令选项的简介。
选项 | 作用 |
---|---|
-a | 对所有接口均执行相同的操作,此时interface被忽略.此参数默认为false |
-w | 是否执行wifi up操作。如果此参数被指定,则wifi up操作不会被执行。如果未指定,则在ifup的时候,wifi up会被执行 |
interface | 指定down/up操作的目标接口 |
ifup的脚本里面,关于wifi的操作是通过/sbin/wifi这个脚本来执行的,所以在这里暂时不讨论。关于普通的ifdown或ifup操作,这个脚本都是通过ubus命令来实现的。在/sbin/ifup脚本中定义了一个if_call()函数,具体如下所示:
if_call() { local interface="$1" for mode in $modes; do ubus call network.interface $mode "{ \"interface\" : \"$interface\" }" done }
可以看到这个函数有一个名为interface的参数,然后还使用了一个全局参数。而参数modes则被定义在ifup脚本里面,具体如下所示:
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
命令。
2、ubus和ubusd简介
OpenWRT提供了一个ubus系统,它类似于桌面Linux系统中的dbus。主要目的也是提供系统级的IPC和RPC。ubus在设计理念上与dbus基本保持一致,区别在于简化的API和简练的模型,以适应于嵌入式路由器的特殊环境。
2.1 ubus的组件
OpenWRT的ubus组主要由ubus和ubus组成,具体见下表。
组件 | |
---|---|
ubusd | 这个是ubus系统的后台进程,负责注册unix domain socket,分派ubus消息和事件等。 |
ubus | 这是一个CLI utility,可以通过它访问ubus系统。 |
ubus的各个应用程序 | 这些应用程序可以在ubus系统中注册RPC接口,提供相应的服务。而其他程序可以通过使用这些接口来访问这些服务。 |
ubus的帮助信息如下所示:
Usage: ubus [<options>] <command> [arguments...] Options: -s <socket>: Set the unix domain socket to connect to -t <timeout>: Set the timeout (in seconds) for a command to complete -S: Use simplified output (for scripts) -v: More verbose output -m <type>: (for monitor): include a specific message type (can be used more than once) -M <r|t> (for monitor): only capture received or transmitted traffic Commands: - list [<path>] List objects - call <path> <method> [<message>] Call an object method - subscribe <path> [<path>...] Subscribe to object(s) notifications - listen [<path>...] Listen for events - send <type> [<message>] Send an event - wait_for <object> [<object>...] Wait for multiple objects to appear on ubus - monitor Monitor ubus traffic
ubus提供了6种子命令,其中常用的子命令有4种,分别为list、call、listen以及send。通过使用这四种子命令,我们就可以轻松的访问注册到ubus系统中的服务了。
2.2 netifd的ubus RPC接口
在OpenWRT中使用如下命令可以查看netifd在ubus系统中注册了的所有对象。具体演示过程如下所示:
'dhcp' @f7f1dc29 "ipv4leases":{} "ipv6leases":{} "add_lease":{"ip":"String","mac":"String","duid":"String","hostid":"String","leasetime":"String","name":"String"} 'dnsmasq' @9143135f "metrics":{} 'file' @8925e8d9 "read":{"path":"String","base64":"Boolean","ubus_rpc_session":"String"} "write":{"path":"String","data":"String","append":"Boolean","mode":"Integer","base64":"Boolean","ubus_rpc_session"} "list":{"path":"String","ubus_rpc_session":"String"} "stat":{"path":"String","ubus_rpc_session":"String"} "md5":{"path":"String","ubus_rpc_session":"String"} "remove":{"path":"String","ubus_rpc_session":"String"} "exec":{"command":"String","params":"Array","env":"Table","ubus_rpc_session":"String"} 'hostapd' @4e9102ab "config_add":{"iface":"String","config":"String"} "config_remove":{"iface":"String"} 'hotplug.dhcp' @1c0f1fef "call":{"env":"Array"} 'hotplug.ieee80211' @270baa6c "call":{"env":"Array"} 'hotplug.iface' @d8ed4c69 "call":{"env":"Array"} 'hotplug.neigh' @cbb19dd5 "call":{"env":"Array"} 'hotplug.net' @eea39d9a "call":{"env":"Array"} 'hotplug.ntp' @7a836d9d "call":{"env":"Array"} 'hotplug.tftp' @b0f9191c "call":{"env":"Array"} 'hotplug.usb' @d4aee266 "call":{"env":"Array"} 'iwinfo' @d97cdc95 "devices":{} "info":{"device":"String"} "scan":{"device":"String"} "assoclist":{"device":"String","mac":"String"} "freqlist":{"device":"String"} "txpowerlist":{"device":"String"} "countrylist":{"device":"String"} "survey":{"device":"String"} "phyname":{"section":"String"} 'log' @11411906 "read":{"lines":"Integer","stream":"Boolean","oneshot":"Boolean"} "write":{"event":"String"} 'luci' @bbc5ddfd "getMountPoints":{} "getFeatures":{} "setBlockDetect":{} "getSwconfigFeatures":{"switch":"String"} "setPassword":{"username":"String","password":"String"} "getConntrackHelpers":{} "getUSBDevices":{} "getInitList":{"name":"String"} "getProcessList":{} "getBlockDevices":{} "getRealtimeStats":{"device":"String","mode":"String"} "getSwconfigPortState":{"switch":"String"} "getLEDs":{} "getConntrackList":{} "setLocaltime":{"localtime":"Integer"} "getTimezones":{} "setInitAction":{"name":"String","action":"String"} "getLocaltime":{} 'luci-rpc' @a0a88098 "getNetworkDevices":{} "getWirelessDevices":{} "getHostHints":{} "getDUIDHints":{} "getBoardJSON":{} "getDHCPLeases":{"family":"Integer"} 'network' @32f01ebb "restart":{} "reload":{} "add_host_route":{"target":"String","v6":"Boolean","interface":"String"} "get_proto_handlers":{} "add_dynamic":{"name":"String"} "netns_updown":{"jail":"String","pid":"Integer","start":"Boolean"} 'network.device' @75f4ab54 "status":{"name":"String"} "set_alias":{"alias":"Array","device":"String"} "set_state":{"name":"String","defer":"Boolean","auth_status":"Boolean"} 'network.interface' @0e4d1c10 "up":{} "down":{} "renew":{} "status":{} "prepare":{} "dump":{} "add_device":{"name":"String","link-ext":"Boolean","vlan":"Array"} "remove_device":{"name":"String","link-ext":"Boolean","vlan":"Array"} "notify_proto":{} "remove":{} "set_data":{} 'network.interface.lan' @d822397a "up":{} "down":{} "renew":{} "status":{} "prepare":{} "dump":{} "add_device":{"name":"String","link-ext":"Boolean","vlan":"Array"} "remove_device":{"name":"String","link-ext":"Boolean","vlan":"Array"} "notify_proto":{} "remove":{} "set_data":{} 'network.interface.loopback' @afbe04c1 "up":{} "down":{} "renew":{} "status":{} "prepare":{} "dump":{} "add_device":{"name":"String","link-ext":"Boolean","vlan":"Array"} "remove_device":{"name":"String","link-ext":"Boolean","vlan":"Array"} "notify_proto":{} "remove":{} "set_data":{} 'network.interface.wan' @ec3fd869 "up":{} "down":{} "renew":{} "status":{} "prepare":{} "dump":{} "add_device":{"name":"String","link-ext":"Boolean","vlan":"Array"} "remove_device":{"name":"String","link-ext":"Boolean","vlan":"Array"} "notify_proto":{} "remove":{} "set_data":{} 'network.interface.wan6' @43cb9475 "up":{} "down":{} "renew":{} "status":{} "prepare":{} "dump":{} "add_device":{"name":"String","link-ext":"Boolean","vlan":"Array"} "remove_device":{"name":"String","link-ext":"Boolean","vlan":"Array"} "notify_proto":{} "remove":{} "set_data":{} 'network.rrdns' @01950e10 "lookup":{"addrs":"Array","timeout":"Integer","server":"String","port":"(unknown)","limit":"Integer"} 'network.wireless' @99c526f5 "up":{} "down":{} "reconf":{} "status":{} "notify":{} "get_validate":{} 'rc' @dcd62cdb "list":{} "init":{"name":"String","action":"String"} 'service' @79a2b8b2 "set":{"name":"String","script":"String","instances":"Table","triggers":"Array","validate":"Array","autostart":"Bo} "add":{"name":"String","script":"String","instances":"Table","triggers":"Array","validate":"Array","autostart":"Bo} "list":{"name":"String","verbose":"Boolean"} "delete":{"name":"String","instance":"String"} "signal":{"name":"String","instance":"String","signal":"Integer"} "update_start":{"name":"String"} "update_complete":{"name":"String"} "event":{"type":"String","data":"Table"} "validate":{"package":"String","type":"String","service":"String"} "get_data":{"name":"String","instance":"String","type":"String"} "state":{"spawn":"Boolean","name":"String"} "watchdog":{"mode":"Integer","timeout":"Integer","name":"String","instance":"String"} 'session' @96b0fd45 "create":{"timeout":"Integer"} "list":{"ubus_rpc_session":"String"} "grant":{"ubus_rpc_session":"String","scope":"String","objects":"Array"} "revoke":{"ubus_rpc_session":"String","scope":"String","objects":"Array"} "access":{"ubus_rpc_session":"String","scope":"String","object":"String","function":"String"} "set":{"ubus_rpc_session":"String","values":"Table"} "get":{"ubus_rpc_session":"String","keys":"Array"} "unset":{"ubus_rpc_session":"String","keys":"Array"} "destroy":{"ubus_rpc_session":"String"} "login":{"username":"String","password":"String","timeout":"Integer"} 'system' @7962cd42 "board":{} "info":{} "reboot":{} "watchdog":{"frequency":"Integer","timeout":"Integer","magicclose":"Boolean","stop":"Boolean"} "signal":{"pid":"Integer","signum":"Integer"} "validate_firmware_image":{"path":"String"} "sysupgrade":{"path":"String","force":"Boolean","backup":"String","prefix":"String","command":"String","options":"} 'uci' @8b03b234 "configs":{} "get":{"config":"String","section":"String","option":"String","type":"String","match":"Table","ubus_rpc_session":"} "state":{"config":"String","section":"String","option":"String","type":"String","match":"Table","ubus_rpc_session"} "add":{"config":"String","type":"String","name":"String","values":"Table","ubus_rpc_session":"String"} "set":{"config":"String","section":"String","type":"String","match":"Table","values":"Table","ubus_rpc_session":"S} "delete":{"config":"String","section":"String","type":"String","match":"Table","option":"String","options":"Array"} "rename":{"config":"String","section":"String","option":"String","name":"String","ubus_rpc_session":"String"} "order":{"config":"String","sections":"Array","ubus_rpc_session":"String"} "changes":{"config":"String","ubus_rpc_session":"String"} "revert":{"config":"String","ubus_rpc_session":"String"} "commit":{"config":"String","ubus_rpc_session":"String"} "apply":{"rollback":"Boolean","timeout":"Integer","ubus_rpc_session":"String"} "confirm":{"ubus_rpc_session":"String"} "rollback":{"ubus_rpc_session":"String"} "reload_config":{} 'wpa_supplicant' @3632b31c "config_add":{"driver":"String","iface":"String","bridge":"String","hostapd_ctrl":"String","ctrl":"String","config} "config_remove":{"iface":"String"}
每个对象所提供的RPC接口名称以及接口的参数类型都可以通过ubus得到。
2.3 netifd interface RPC
在2021-07-26-440eb064版本的netifd源码的ubus.c文件中为每个接口对象注册了一组相同的方法(或者说函数,不过习惯上称之为方法),如下所示:
static struct ubus_method iface_object_methods[] = { { .name = "up", .handler = netifd_handle_up }, { .name = "down", .handler = netifd_handle_down }, { .name = "renew", .handler = netifd_handle_renew }, { .name = "status", .handler = netifd_handle_status }, { .name = "prepare", .handler = netifd_handle_iface_prepare }, { .name = "dump", .handler = netifd_handle_dump }, UBUS_METHOD("add_device", netifd_iface_handle_device, dev_link_policy ), UBUS_METHOD("remove_device", netifd_iface_handle_device, dev_link_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的形式提供。
2.4 netifd protocol handler插件
netifd的protocol handler插件位于/lib/netifd/proto/目录下,名称统一为*.sh。