目录
1.调试
1.1 gdb调试
如下所示,修改配置(问题:有些东西打印不出来,比如ifname,提示 ifname = <error reading variable>)
1.2 D打印
在/etc/init.d/network中增加如下内容就能使用“logread -e netifd”看到D打印的内容,“-d 15"表示打开以下所有模块的打印,如果”-d 1",那就只打印DEBUG_SYSTEM:
enum {
DEBUG_SYSTEM = 0,
DEBUG_DEVICE = 1,
DEBUG_INTERFACE = 2,
DEBUG_WIRELESS = 3,
};
注意:D打印的内容是"daemon.err netifd[10824]"开头的,而netifd使用的syslog级别为L_CRIT,L_WARNING,L_NOTICE,L_INFO,L_DEBUG,感觉是特意避开err级别,避免跟D混淆。
1.3 syslog打印
如果将上面的启动参数修改为“procd_set_param command /sbin/netifd -l 5 -d 15”,则代码及对应的打印内容如下所示:
DPRINTF("connected as %08x\n", ubus_ctx->local_id);
netifd_log_message(L_DEBUG, "connected as %08x\n", ubus_ctx->local_id);
netifd_log_message(L_INFO, "connected as %08x\n", ubus_ctx->local_id);
netifd_log_message(L_NOTICE, "connected as %08x\n", ubus_ctx->local_id);
netifd_log_message(L_WARNING, "connected as %08x\n", ubus_ctx->local_id);
netifd_log_message(L_CRIT, "connected as %08x\n", ubus_ctx->local_id);
daemon.err netifd[17096]: netifd_ubus_init(1364): connected as 0d6fc15a
daemon.debug netifd: connected as 0d6fc15a
daemon.info netifd: connected as 0d6fc15a
daemon.notice netifd: connected as 0d6fc15a
daemon.warn netifd: connected as 0d6fc15a
daemon.crit netifd: connected as 0d6fc15a
1.4 命令行获取IP
ifstatus WAN1 | jsonfilter -e '@["ipv4-address"][0].address'
2 初始化过程分析(BPI-R64)
2.1 创建CPU口和mdio驱动初始化
kernel_init->kernel_init_freeable->do_basic_setup->do_initcalls->do_one_initcall
->mtk_driver_init(mtk_eth_soc.c中通过module_platform_driver注册)
->platform_driver_register->__platform_driver_register->driver_register->bus_add_driver->driver_attach->bus_for_each_dev
->__driver_attach->device_driver_attach->driver_probe_device->really_probe
->platform_drv_probe(paltform.c中通过__platform_driver_register注册)->mtk_probe
2.1.1 创建CPU口
- 创建CPU口
mtk_probe->mtk_add_mac->alloc_etherdev->alloc_etherdev_mq->alloc_etherdev_mqs->alloc_netdev_mqs(此时接口名称为'eth%d')
- 将netdev与DTS关联起来
mtk_probe->mtk_add_mac(其中eth->netdev[id]->dev.of_node = np;关联起来,在设备初始化时match)
2.1.2 mdio驱动初始化
mtk_probe->mtk_mdio_init(读DTS)->of_mdiobus_register->of_mdiobus_register_device->mdio_device_register->device_add
->bus_probe_device->device_initial_probe->__device_attach->bus_for_each_drv->__device_attach_driver
->driver_probe_device->really_probe->mdio_probe(mdio.h中通过mdio_module_init注册)
->mt7530_probe(drivers\net\dsa\mt7530.c中通过mdio_module_driver(mt7530_mdio_driver)注册)
->dsa_register_switch->dsa_switch_probe->dsa_switch_parse_of->dsa_switch_parse_ports_of->dsa_port_parse_of
->of_find_net_device_by_node(DTS中port@6调用,因为此时接口没有注册,所以class_find_device返回NULL,进而dsa_port_parse_of返回-EPROBE_DEFER,驱动初始化完成)
2.1.3 注册CPU口
注册时,会自动给CPU口命名为命名为eth0和eth1
mtk_probe->register_netdev->register_netdevice->dev_get_valid_name->dev_alloc_name_ns->__dev_alloc_name
2.2 创建用户口(mdio设备初始化)
获取接口名称
deferred_probe_work_func(具体何时调用不清楚)->bus_probe_device->device_initial_probe->__device_attach->bus_for_each_drv
->__device_attach_driver->driver_probe_device->really_probe->mdio_probe(mdio.h中通过mdio_module_init注册)
->mt7530_probe(drivers\net\dsa\mt7530.c中通过mdio_module_driver(mt7530_mdio_driver)注册)
->dsa_register_switch->dsa_switch_probe
其中->dsa_switch_parse_of->dsa_switch_parse_ports_of->dsa_port_parse_of->dsa_port_parse_user(从DTS中读取接口名称)
另外->dsa_tree_setup->dsa_tree_setup_switches->dsa_port_setup->dsa_slave_create(创建lan1~lan4及wan口。)
2.3 生成/etc/config/network
config_generate根据target\linux\mediatek\mt7622\base-files\etc\board.d\02_network生成/etc/config/network,具体实现的参考链接如下:OpenWrt file/bin/config_generate network初始化分析
3 支持的device类型
LuCI类型 | UCI类型 | 对应结构体 | 使用场景 |
Network device | N/A | simple_device_type | 对应真实物理端口,好像不创建也不影响功能。。。 |
Bridge device | bridge | bridge_device_type | 基于桥设备创建桥接口,比如br-lan |
VLAN(802.1q) | 8021q | vlan8021q_device_type | 基于802.1q设备创建接口,比如创建802.1q的路由连接 |
VLAN(802.1ad) | 8021ad | vlan8021ad_device_type | 基于802.1ad设备创建接口,比如创建802.1ad的路由连接 |
MAC VLAN | macvlan | macvlan_device_type | |
Virtual Ethernet | veth | veth_device_type |
所有类型都通过device_type_add来添加。
3.1 802.1q
- 创建带VLAN的device
- 创建interface,这样在WAN侧抓到的报文就是带VLAN 100的
- 对应的UCI配置如下:
config device
option type '8021q'
option ifname 'wan'
option vid '100'
option name 'wan.100'
config interface 'WAN'
option proto 'dhcp'
option device 'wan.100'
3.2 MAC VLAN
- 创建带MAC VLAN的device,wanmac1也用同样方法创建
- 创建interface,WAN1使用相同方法创建
- 对应的UCI配置如下:
config device
option type 'macvlan'
option ifname 'wan'
option mode 'bridge'
option name 'wanmac0'
config device
option type 'macvlan'
option ifname 'wan'
option mode 'bridge'
option name 'wanmac1'
config interface 'WAN0'
option proto 'dhcp'
option device 'wanmac0'config interface 'WAN1'
option proto 'dhcp'
option device 'wanmac1'
- 两个MAC VLAN桥模式的WAN连接通信
执行如下命令,参考链接:https://unix.stackexchange.com/questions/398671/communication-problem-between-macvlan-interfaces-when-sockets-are-bound-to-devic
device0=`ifstatus WAN0 | jsonfilter -e '@["device"]'`
device1=`ifstatus WAN1 | jsonfilter -e '@["device"]'`
ip0=`ifstatus WAN0 | jsonfilter -e '@["ipv4-address"][0].address'`
ip1=`ifstatus WAN1 | jsonfilter -e '@["ipv4-address"][0].address'`
ip route del default
ip route del `ip route|grep "$device0"`
ip route del `ip route|grep "$device1"`
ip rule del pref 0
ip rule add pref 200 to "$ip1" lookup 100
ip rule add pref 200 to "$ip0" lookup 101
ip route add default dev "$device0" table 100
ip route add default dev "$device1" table 101
ip rule add pref 1000 lookup local
ip rule add pref 100 to "$ip0" iif "$device0" lookup local
ip rule add pref 100 to "$ip1" iif "$device1" lookup local
ping -I $device0 $ip1 #此时能ping通
4 监听内核接口状态的变化
- 1、system_init中调用create_event_socket创建监听netlink的socket
- 2、当接口link up或者link down时,在内核中调用netif_carrier_on,最终会走到netdev_state_change,再通过rtmsg_ifinfo发出netlink消息。
- 3、在system_init中注册的cb_rtnl_event监听到消息之后,做相应的处理。