OpenWrt network 啓動過程
/etc/config/network
networt 配置文件爲 /etc/config/network
關於/etc/config/network 的生成可以看我的上一篇博文:OpenWrt /etc/config/network 的生成過程
config interface 'loopback'
option ifname 'lo'
option proto 'static'
option ipaddr '127.0.0.1'
option netmask '255.0.0.0'
config globals 'globals'
option ula_prefix 'fd20:4754:ca54::/48'
config interface 'lan'
option ifname 'eth0.1'
option force_link '1'
option macaddr 'ff:ff:ff:ff:ff:ff'
option type 'bridge'
option proto 'dhcp'
option ipaddr '192.168.1.1'
option netmask '255.255.255.0'
option ip6assign '60'
config interface 'wan'
option force_link '1'
option macaddr 'ff:ff:ff:ff:ff:ff'
option proto 'dhcp'
option ifname 'apcli0'
config interface 'wan6'
option ifname 'eth0.2'
option proto 'dhcpv6'
config switch
option name 'switch0'
option reset '1'
option enable_vlan '1'
config switch_vlan
option device 'switch0'
option vlan '1'
option ports '0 6t'
config switch_vlan
option device 'switch0'
option vlan '2'
option ports '1 6t'
/etc/init.d/network
openWrt 網絡啓動腳本爲/etc/init.d/network, 以MT7688 爲例內容如下:
#!/bin/sh /etc/rc.common
START=20
STOP=90
USE_PROCD=1 # 表示由 procd 進程管理
# 更多說明:https://openwrt.org/start?id=docs/guide-developer/procd-init-scripts
init_switch() {
setup_switch() { return 0; }
include /lib/network
setup_switch # 調用的是 /lib/network 裏定義的 setup_switch
}
start_service() {
init_switch
#初始化 switch
procd_open_instance
# 創建一個實例
# ubus call service list 可以查看實例
procd_set_param command /sbin/netifd
# 執行的命令是 /sbin/netifd
procd_set_param respawn
# 定義respawn參數,告知procd當程序退出後嘗試進行重啓
procd_set_param watch network.interface
# 監控的ubs 名字
[ -e /proc/sys/kernel/core_pattern ] && {
procd_set_param limits core="unlimited"
echo '/tmp/%e.%p.%s.%t.core' > /proc/sys/kernel/core_pattern
}
procd_close_instance
# 關閉一個實例
}
reload_service() {
init_switch
ubus call network reload
/sbin/wifi reload_legacy
}
...
start_service 中主要做了兩件事情:
- init_switch
- /sbin/netifd
init_switch
init_switch -> setup_switch ,找到 setup_switch 的定義在 /lib/network/switch.sh
/lib/network 下有兩個文件
config.sh
switch.sh
#!/bin/sh
# Copyright (C) 2009 OpenWrt.org
setup_switch_dev() {
local name
config_get name "$1" name
name="${name:-$1}"
[ -d "/sys/class/net/$name" ] && ifconfig "$name" up
swconfig dev "$name" load network
}
setup_switch() {
config_load network # 讀取 /etc/config/network ,config_load 在/lib/functions.sh 中定義
config_foreach setup_switch_dev switch
}
config_foreach setup_switch_dev switch 最終執行 swconfig dev switch0 load network
swconfig
swconfig 是 openWrt 下用於配置 switch 的 工具,工具是基於 genl (Generic Netlink)接口與內核通信實現的。usage 如下。
~# swconfig --help
swconfig list
swconfig dev <dev> [port <port>|vlan <vlan>] (help|set <key> <value>|get <key>|load <config>|show)
swconfig dev switch0 load network 會讀取 /etc/config/network ,根據裏面的配置信息對swicth 進行配置。所涉及的配置有:
- vlan 的使能
- port 的劃分,如上,有port0 和port1 兩個端口,port0 歸valn1 ,port1 歸vlan2
netifd
netifd是openWrt中用於進行網絡配置的守護進程。netifd 讀取 /etc/config/network 和/etc/config/wireless並在ubus 上創建如下對象:
# ubus list network*
network
network.device
network.interface
network.interface.lan
network.interface.loopback
network.interface.wan
network.interface.wan6
network.wireless
同時可看到 /sys/class/net 下面創建了虛擬網卡,也可以 ifconfig 查看到
ls -l /sys/class/net/*
lrwxrwxrwx 1 root root 0 May 11 15:52 /sys/class/net/apcli0 -> ../../devices/virtual/net/apcli0
lrwxrwxrwx 1 root root 0 May 12 09:29 /sys/class/net/apcli1 -> ../../devices/virtual/net/apcli1
lrwxrwxrwx 1 root root 0 May 11 15:52 /sys/class/net/br-lan -> ../../devices/virtual/net/br-lan
lrwxrwxrwx 1 root root 0 Jan 1 1970 /sys/class/net/eth0 -> ../../devices/10100000.ethernet/net/eth0
lrwxrwxrwx 1 root root 0 May 12 09:29 /sys/class/net/eth0.1 -> ../../devices/virtual/net/eth0.1
lrwxrwxrwx 1 root root 0 May 12 09:29 /sys/class/net/eth0.2 -> ../../devices/virtual/net/eth0.2
lrwxrwxrwx 1 root root 0 Jan 1 1970 /sys/class/net/lo -> ../../devices/virtual/net/lo
lrwxrwxrwx 1 root root 0 May 11 15:52 /sys/class/net/ra0 -> ../../devices/virtual/net/ra0
netifd 如何通知內核創建虛擬網卡的?
netifd
main
config_init_all
config_init_interfaces
config_parse_interface
interface_add
__interface_add
vlist_add(&interfaces, &iface->node, iface->name);
tree->update // = interfaces.update
interface_update
interface_claim_device
device_get
get_vlan_device_chain
get_vlan_device
vldev->dev.set_state = vlan_set_device_state // 設置set_state 方法
interface_set_device_config(iface, dev)
device_apply_config
dev->set_state() // 調用set_state 方法
vlan_set_device_state
system_vlan_add
system_vlan
ioctl(sock_ioctl, SIOCSIFVLAN, &ifr); // 通過socket 給內核發消息 ifr.cmd = ADD_VLAN_CMD
kernel
// linux-3.18.21\net\8021q\vlan.c
vlan_ioctl_handler
case ADD_VLAN_CMD:
err = register_vlan_device(dev, args.u.VID);
break;
小結
- 網絡配置文件 /etc/config/network
- 網絡初始化腳本/etc/init.d/network
- swconfig 用於配置 switch
- netifd 進行更復雜的網絡管理,創建虛擬網卡,dhcp 等