本文包含網絡接口的硬件基本原理和VxWorks 6.6網絡協議棧/驅動的分析,適用于VxWorks6.6以及之前的版本,并可用作其他版本協議棧的參考。
0. 概述
0.1 網絡接口
以太網目前有兩種模型,即ISO(國際標準化組織)定義的的OSI七層模型和IETF(互聯網工程任務組)的TCP/IP五層模型,具體可參考TCP/IP協議詳解。目前,TCP/IP為互聯網的事實標準,具體分層如下所示:
OSI | TCP/IP | 實體 |
---|---|---|
應用層 | ||
表示層 | 應用層 | FTP/HTTP等 |
會話層 | ||
傳輸層 | 傳輸層 | TCP/UDP |
網絡層 | 網絡層 | IP |
鏈路層 | 鏈路層 | MAC(介質訪問控制器) |
物理層 | 物理層 | PHY(物理層) |
上表中:
-
以太網報文格式與上表的分層對應:
物理層 鏈路層 網絡層 傳輸層 應用層 鏈路層 前導位、起始標志 以太網頭 IP頭 TCP/UDP頭等 FTP/HTTP數據等 CRC校驗 - MAC又稱為以太網控制器,既具有獨立的鏈路層地址(MAC地址,又稱為以太網地址),也就是通常意義上或者狹義上的網口,用于控制鏈路層數據的傳輸;
- PHY用于控制物理層傳輸,用于物理鏈路與MAC之間數據的編解碼、物理鏈路控制、載波偵聽、線序交換等功能,通常只包含PCS(物理編碼子層)、PMD(物理介質相關子層)、PMA(物理介質附加子層)等,但是1000Mbps以上的高速鏈路需要更多的子層(DTE XGXS、PHY XGXS);
- MAC通過MII(狹義上的介質獨立接口)/RGMII(簡化的千兆介質無關接口)/SGMII(串行千兆介質無關接口)/XGMII(超高速介質無關接口)總線等連接到PHY上;
- 每個MAC通常只需要一個PHY,但是1000Mbps以上的高速網口的PHY設備需要可能還需要先通過內部PHY將TBI接口轉換成SGMII接口或者將XGMII接口轉換成XAUI接口,再連接到外部PHY,從而降低外部PHY的布線難度;
- TBI、XAUI和MII、RGMII、SGMII、XGMII、GMII、QGMII等接口都屬于廣義上的MII接口,對應于MII總線;
- PHY必須掛在MII總線上,通過MII控制器訪問;
- MII接口有MDIO22和MIDO45兩種標準,分別定義在802.3ap clasue22和Clasue 45中, 前者支持5位PHY地址和5位寄存器地址,后者增加了5位設備地址,允許控制PHY的不同子層;因此,每個MII控制器最多通過MII總線支持32個PHY設備;
- 廣義上的網口指的是MAC、MII控制器和PHY的綜合體。
0.2 約定
- socket即套接字,是BSD協議棧提出的網絡接口,包含一個接收緩沖區,用于收發數據和控制數據傳輸;
-
MBLK/Cluster/data是BSD協議棧提出的緩沖區模型,每個數據區
data
對應一個Cluster
,每個Cluster
關聯到1個MBLK
上;MBLK
作為以太網報文的代表,可以將多個以太網報文分片串成一個鏈表,用以提升數據收發效率; - 分析以VxWorks6.6上的MPC5200 FEC網口為例,適用于VxWorks6.6以及之前的版本,并可用作其他版本協議棧的參考;
- 流程圖中的非關鍵函數參數和非關鍵流程被省略以突出重點和降低工作量;
1. END驅動架構
END驅動整體架構如下所示:
Snipaste_2022-08-13_11-59-17.png
其中:
- 用戶可以通過3種接口訪問協議棧接口:
-
socket:由sockLib庫提供,包括
socket/bind/connect/listen/accept/getsockopt/setsockopt/recv/recvfrom/recvmsg/send/sendmsg/sendto()
等;其中: -
通用IO接口:由sockLib庫提供,包括
close/ioctl/write/ioctl()
; -
ipcom/ipnet接口:由ipcom/ipnet提供,包括
ifconfig
等;
-
socket:由sockLib庫提供,包括
-
sockLib庫位于
vxworks-6.6/target/src/wrn/coreip/sysdep/os/vxWorks/socket
,提供socket接口,并調用iosDrvInstall()
接口安裝IO設備驅動,從而為每個socket套接字創建描述符以提供通用IO接口,其中:-
socket/accept接口除了調用ipcom/ipnet注冊的
socketRtn/acceptRtn()
鉤子函數,還需要調用iosLib庫接口創建IO設備作為socket描述符; - 其余socket接口在進行簡單的參數檢查后直接調用ipcom/ipnet注冊的對應鉤子函數;
-
通用IO接口對應于sockLib庫在安裝IO設備驅動時注冊的
socketClose/socketRead/socketWrite/socketIoctl()
接口,這些接口在進行簡單的參數檢查后直接調用ipcom/ipnet注冊的對應鉤子函數;
-
socket/accept接口除了調用ipcom/ipnet注冊的
-
ipnet/ipcom位于
components/ip_net2-6.6
,使用sockLibAdd()將AF_NET/AF_PACKET等協議棧及包含socket/bind/connect/listen/accept/getsockopt/setsockopt/recv/recvfrom/recvmsg/send/sendmsg/sendto()
等鉤子的功能列表注冊到sockLib的sockLibMap[];其中:-
ipcom提供OS封裝層,用于屏蔽OS的不同,并綁定到MUX層,主要代碼位于
components/ip_net2-6.6、ipcom/port/vxworks
; -
ipnet/ipcom調用
muxLib
提供的muxDevStart/muxDevStop/muxIoctl/muxSend/muxDevLoad/muxDevUnload/muxBind/muxUnbind()
接口來完成協議棧綁定、、驅動加載、網口控制和數據收發功能;
-
ipcom提供OS封裝層,用于屏蔽OS的不同,并綁定到MUX層,主要代碼位于
-
muxLib位于
vxworks-6.6/target/src/wrn/coreip/common/mux
,用于將協議棧綁定到不同的網口上,并提供網卡控制接口,包括:-
muxDevStart/muxDevStop/muxIoctl接口:主要通過調用
endLib
封裝的網口驅動功能列表中相應的start/stop/ioctl
鉤子來完成; -
muxSend接口:首先通過
endLib
封裝的網口驅動功能列表中的formAddress
鉤子生成地址,然后調用endLib
封裝的網口驅動功能列表中的packetDataGet
鉤子和muxBind
接口安裝的stackRcvRtn
來過濾本地數據包,最后調用endLib
封裝的網口驅動功能列表中的send/formAddress/packetDataGet
鉤子來完成發送功能; -
muxReceive接口:通過
muxBind
接口安裝的stackRcvRtn
將數據上傳到ipnet/ipcom; -
muxDevLoad接口:調用驅動提供的
xxxEndLoad
接口加載網口驅動,然后調用endLib
提供的endFlagsSet
設置END_MIB_2233標志(m5200FecEnd不支持2233 MIB),并使用ioctl判斷end類型以設置pEnd->receiveRtn
為muxReceive
(m5200FecEnd類型為END_STYLE_END);
-
muxDevStart/muxDevStop/muxIoctl接口:主要通過調用
- end層用于提供網卡驅動的封裝結構和公用代碼。
2. 網卡驅動全工作流程
2.1 初始化流程
網卡驅動初始化入口為usrNetworkInit():
-
usrNetworkInit:該位于
<工程目錄>/prjConfig.c
中,調用usrNetEndLibInit()
,用于初始化網卡驅動; -
usrNetEndLibInit:該接口位于
vxworks-6.6/target/src/config/usrNetwork.c
或vxworks-6.6/target/config/comps/src/net/coreip/usrNetEndLib.c
中,關鍵流程如下所示:
Snipaste_2022-08-13_11-55-29.png
其中:- vxbDevMethodRun()遍歷VxBus驅動,調用所有提供muxDevConnect接口的網卡驅動,不適用于lite5200b的Legacy網卡驅動;
-
endDevTbl[]數組包含Legacy網卡驅動,定義于BSP目錄的configNet.h中:
#define FEC_LOAD_FUNC m5200FecEndLoad ... #define FEC_LOAD_STR "-1:0x0:-1:-1:0x40:0x30:0x0:0xff:2:0x4:" \ FEC_CLOCK_SPEED(IPB_CLOCK_LITERAL) #define FEC_BUFF_LOAN 1 ... END_TBL_ENTRY endDevTbl [] = { #ifdef INCLUDE_FEC_END { 0, FEC_LOAD_FUNC, FEC_LOAD_STR, FEC_BUFF_LOAN, NULL, FALSE}, #endif /* INCLUDE_FEC_END */ ... };
- endPollStatsInit()用于初始化網口驅動的統計信息。
-
muxDevLoad():位于
vxworks-6.6/target/src/wrn/coreip/common/mux/muxLib.c
中,用于調用endDevTbl[]數組中Legacy網口驅動的初始化函數endLoad
,關鍵流程如下所示:
Snipaste_2022-08-13_11-56-17.png
其中:- 第一次調用endLoad時參數為空字符串,用于獲取網口名稱,例如'fec';
- 第二次調用endLoad時參數為網口單元號與初始化字符串的組合,用于正式加載網口;
-
muxDevStart():位于
vxworks-6.6/target/src/wrn/coreip/common/mux/muxLib.c
中,用于調用驅動注冊的pEnd->pFuncTable->start()接口啟動網口,并將網口設置為IFF_UP | IFF_RUNNING狀態
; -
m5200FecEndLoad():驅動接口,主要功能是注冊到
endLib
:- 分配驅動信息結構和PHY信息結構;
- 調用
m5200FecInitParse
解析初始化字符串并保存在驅動信息結構中; - 調用
m5200FecInitMem
申請臨時發送緩沖區,并創建netpool網絡緩沖池; - 調用
m5200FecSdmaTaskInit
創建Bestcomm SDMA任務; - 調用
END_OBJ_INIT
即endObjInit
初始化END結構,注冊網口驅動功能列表; - 調用
END_FLAGS_SET
設置多播和廣播標志;
-
m5200FecStart():驅動接口,主要功能是啟動網口:
- 調用
m5200FecReset
復位以太網控制器; - 調用
m5200FecTbdInit/m5200FecRbdInit
初始化收發緩沖區描述符環; - 調用
SYS_FEC_INT_CONNECT
即intConnect
掛接BestComm發送和接收任務中斷以及通用中斷處理函數; - 調用
SYS_FEC_INT_ENABLE
即intEnable
使能中斷; - 調用
m5200FecPrePhyConfig
初始化MAC地址、設置中斷事件掩碼、清除中斷事件、配置內部MII控制器接口等; - 調用
m5200FecPhyPreInit
根據驅動信息結構中的標志設置PHY信息結構中的工作模式標志; - 調用
_func_m5200FecPhyInit
即m5200FecPhyInit
初始化PHY,并根據PHY信息結構中的工作模式標志選擇自協商模式或強制模式; - 調用
TaskIntClear
清除Bsetcomm接收任務中斷; - 調用
TaskStart
啟動Bsetcomm接收任務; - 調用
FEC_END_ETH_ENABLE
使能以太網控制器; - 調用
END_FLAGS_SET
將網口標志為IFF_UP | IFF_RUNNING
,即工作狀態; - 調用
netJobAdd
將muxTxRestart
添加到tNet0任務維護的netJobQueueId
隊列,進而調用綁定在網口上的協議棧的stackTxRestartRtn
接口以復位協議棧。
- 調用
2.2 發送流程
發送流程的入口為socket庫提供的send/sendto/sendmsg()和ios子系統提供的write():
- send/sendto/sendmsg():調用協議棧利用sockLibAdd()注冊的SOCK_FUNC指針中的sendRtn/sendtoRtn/sendmsgRtn(),即ipcom_windnet_send/sendto/sendmsg()位于
vxworks-6.6/target/src/wrn/coreip/sysdep/os/vxWorks/socket/sockLib.c
; - write():調用socket庫安裝到ios子系統的socket驅設備的socketWrite()鉤子,進而調用協議棧利用sockLibAdd()注冊的SOCK_FUNC指針中的socketwriteRtn(),即ipcom_windnet_socketwrite(),位于
vxworks-6.6/target/src/wrn/coreip/sysdep/os/vxWorks/socket/sockLib.c
; - ipcom_windnet_send/sendto/sendmsg/socketwrite():調用ipcom_send/sendto/sendmsg/send(),位于
components/ip_net2-6.6/ipnet2/src/ipnet_sock.c
; - ipcom_send/sendto/sendmsg/send():調用ipcom_sendmsg(),位于
components/ip_net2-6.6/ipnet2/src/ipnet_sock.c
; - ipcom_sendmsg():調用sock->ops->send(),即ipnet_init()注冊并由socket()接口使用ipcom_socket()安裝的iptcp_send和ipnet_sock_udp_send接口;
- iptcp_send和ipnet_sock_udp_send():
- UDP分支:
- ipnet_sock_udp_send():調用ops->i.network_send(),即ipnet_ip4_sendto(),位于
components/ip_net2-6.6/ipnet2/src/ipnet_udp.c
;
- ipnet_sock_udp_send():調用ops->i.network_send(),即ipnet_ip4_sendto(),位于
- TCP分支:
- iptcp_send():調用iptcp_create_output_seg(),位于
components/ip_net2-6.6/ipnet2/src/iptcp.c
; - iptcp_create_output_seg():調用iptcp_output(),位于
components/ip_net2-6.6/ipnet2/src/iptcp.c
; - iptcp_output():調用iptcp_sendto(),位于
components/ip_net2-6.6/ipnet2/src/iptcp.c
; - iptcp_sendto():調用sock->ops->network_send(),即ipnet_ip4_sendto(),位于
components/ip_net2-6.6/ipnet2/src/iptcp.c
;
7.ipnet_ip4_sendto():調用netif->link_ip4_output(),即ipnet_eth_if_init安裝的ipnet_eth_ip4_output(),位于components/ip_net2-6.6/ipnet2/src/ipnet_ip4.c
;
- iptcp_send():調用iptcp_create_output_seg(),位于
- UDP分支:
- ipnet_eth_ip4_output():調用ipnet_if_output(),位于
components/ip_net2-6.6/ipnet2/src/ipnet_eth.c
; - ipnet_if_output():調用ipnet_if_drv_output(),位于
components/ip_net2-6.6/ipnet2/src/ipnet_netif.c
; - ipnet_if_drv_output():調用netif->ipcom.drv_output(),即ipcom_drv_eth_init安裝的ipcom_drv_eth_output(),位于
components/ip_net2-6.6/ipnet2/src/ipnet_netif.c
; - ipcom_drv_eth_output():調用muxSend(),位于
components/ip_net2-6.6/ipcom/port/vxworks/src/ipcom_drv_eth.c
; - muxSend():位于
components/ip_net2-6.6/ipcom/port/vxworks/src/ipcom_drv_eth.c
,使用pEnd->pFuncTable->send()
作為參數調用_muxTkSendEnd
進行通用處理,參數檢查失敗則直接釋放pMBlk
發送緩沖區; -
_muxTkSendEnd
:位于components/ip_net2-6.6/ipcom/port/vxworks/src/ipcom_drv_eth.c
,進行通用處理:- 更新2233 MIB中的發包統計信息;
- 如果目的MAC地址非空,則調用
pEnd->pFuncTable->formAddress
即m5200FecEndLoad
安裝的endEtherAddressForm
構造以太網頭并放到pMBlk
發送緩沖區; - 如果網口已綁定協議棧,則調用
pEnd->pFuncTable->packetDataGet
即endEtherPacketDataGet
獲取pMBlk
發送緩沖區的數據指針,然后調用muxEndRcvRtn
接收數據到協議棧; - 調用
muxSend
傳遞過來鉤子調用pEnd->pFuncTable->send()
,即m5200FecEndLoad
函數安裝的m5200FecSend()
; - 如果發送阻塞即網口忙,則從
pMBlk
發送緩沖區移除以太網頭,返回錯誤信息等待協議棧再次發送;
- m5200FecSend():驅動接口,將數據寫入發送緩沖區并發送,
- 檢查參數和工作模式,失敗則返回;
- 計算
pMBlk
發送緩沖區的分片數; - 如果發送緩沖區描述符個數為0,則調用
m5200FecTbdClean
清理發送緩沖區; - 如果送緩沖區描述符個數大于
pMBlk
發送緩沖區的分片數、緩沖區地址滿足對齊要求且m5200FecForceCopy
為false,則調用m5200FecPktTransmit
;否則,調用m5200FecPktCopyTransmit
;
- m5200FecPktTransmit():驅動接口,使用
pMBlk
發送緩沖區進行零拷貝傳輸:- 調用
m5200FecTbdListSet
獲取發送緩沖區描述符列表; - 使用將
pMBlk
發送緩沖區各分片對應的數據指針設置發送緩沖區描述符的緩沖區指針并更新發送緩沖區描述符標志; - 調用
TaskStart
啟動BestComm發送任務; - 調用
CACHE_PIPE_FLUSH
刷新寫緩沖;
- 調用
- m5200FecPktCopyTransmit():驅動接口,從驅動創建的netpool中申請新的
MBLK
用于保存pMBlk
發送緩沖區中的所有數據,然后發送:- 調用
NET_BUF_ALLOC
申請cluster即數據緩沖區,申請失敗則使用臨時發送緩沖區,仍然失敗則返回發送阻塞; - 對齊發送緩沖區數據地址到32字節;
- 調用
m5200FecTbdListSet
獲取發送緩沖區描述符列表; - 使用將
pMBlk
發送緩沖區各分片對應的數據拷貝到申請的新發送緩沖區中; - 使用新發送緩沖區的指針設置發送緩沖區描述符的緩沖區指針并更新發送緩沖區描述符標志;
- 調用
TaskStart
啟動BestComm發送任務; - 調用
CACHE_PIPE_FLUSH
刷新寫緩沖;
- 調用
- m5200FecWdmaInt():驅動接口,BestComm發送任務完成后會觸發BestComm發送任務中斷,并調用該函數:
- 調用
SDMA_INT_DISABLE
關閉BestComm發送任務中斷; - 調用
TaskIntClear
清除BestComm發送任務中斷; - 調用
CACHE_PIPE_FLUSH
刷新寫緩沖; - 調用
netJobAdd
將m5200FecTxHandle
添加到tNet0任務維護的netJobQueueId
隊列,失敗則調用SDMA_INT_ENABLE
使能BestComm發送任務
退出;
- 調用
- m5200FecTxHandle():清理發送緩沖區描述符和BestComm發送任務:
- 調用
m5200FecTbdClean
清理發送緩沖區; - 調用
intLock
鎖中斷; - 如果BestComm發送任務狀態非空,則清除當前BestComm發送任務狀態,調用
intUnlock
解鎖中斷,再次回到調用m5200FecTbdClean
清理發送緩沖區,直到BestComm發送任務狀態為空再調用intUnlock
解鎖中斷并退出。
- 調用
2.3 接收流程
接收流程的用戶程序入口為socket庫提供的recv/recvfrom/recvmsg()和ios子系統提供的read():
- recv/recvfrom/recvmsg():調用協議棧利用sockLibAdd()注冊的SOCK_FUNC指針中的recvRtn/recvfromRtn/recvmsgRtn(),即ipcom_windnet_recv/recvfrom/recvmsg()位于
vxworks-6.6/target/src/wrn/coreip/sysdep/os/vxWorks/socket/sockLib.c
; - read():調用socket庫安裝到ios子系統的socket驅設備的socketRead()鉤子,進而調用協議棧利用sockLibAdd()注冊的SOCK_FUNC指針中的socketresdRtn(),即ipcom_windnet_socketread(),位于
vxworks-6.6/target/src/wrn/coreip/sysdep/os/vxWorks/socket/sockLib.c
; - ipcom_windnet_recv/socketread():調用ipcom_recv(),進而調用
ipcom_recvfrom
,位于components/ip_net2-6.6/ipnet2/src/ipnet_sock.c
; - ipcom_windnet_recvfrom/recvmsg():調用ipcom_recvfrom/recvmsg(),位于
components/ip_net2-6.6/ipnet2/src/ipnet_sock.c
; - ipcom_recvfrom():調用ipcom_recvmsg(),位于
components/ip_net2-6.6/ipnet2/src/ipnet_sock.c
; - ipcom_recvmsg():調用sock->ops->recv(),即ipnet_init()注冊并由socket()接口使用ipcom_socket()安裝的iptcp_recv和ipnet_sock_pkt_recv接口;
- iptcp_recv/ipnet_sock_pkt_recv():如果socket的接收緩沖區中沒有報文,則根據用戶傳入的標志決定直接返回或者掛起任務等待報文到來;否則,則取出報文,處理后返還給用戶程序入口。
接收流程的驅動程序入口為驅動的m5200FecRdmaInt:
- m5200FecRdmaInt():調用
m5200FecRxHandle
接收數據:- 讀取接收FIFO狀態并打印調試信息;
- 調用
intLock
鎖中斷; - 調用
SDMA_INT_DISABLE
關閉接收DMA任務中斷; - 調用
TaskIntClear
清除BestComm接收任務中斷; - 調用
intUnlock
解鎖中斷; - 調用
CACHE_PIPE_FLUSH
刷新寫緩沖; - 調用
netJobAdd
將m5200FecRxHandle
添加到tNet0任務維護的netJobQueueId
隊列并退出;
- m5200FecRxHandle():處理BestComm接收任務中斷,
- 調用
m5200FecHandleRecvInt
接收數據; - 調用
intLock
鎖中斷; - 如果仍有BestComm接收任務中斷待處理,則調用
TaskIntClear
清除BestComm接收任務中斷,調用intUnlock
解鎖中斷,調用netJobAdd
將m5200FecRxHandle
添加到tNet0任務維護的netJobQueueId
隊列,調用intLock
鎖中斷,并再次回到第一步調用m5200FecHandleRecvInt
接收數據,直到沒有BestComm接收任務中斷需要處理,才調用SDMA_INT_ENABLE
使能BestComm接收任務中斷
并退出;
- 調用
- m5200FecHandleRecvInt():遍歷接收緩沖區描述符環形隊列,調用
m5200FecReceive
接收數據并上送協議棧; - m5200FecReceive():接收數據并上送協議棧,
- 如果接收緩沖區描述符有錯誤,則調用
m5200FecRbdClean
清除接收緩沖區描述符并退出; - 從驅動的netpool緩沖池申請MBLK和cluster,并關聯到接收緩沖區描述符的緩沖區指針,同時從驅動的netpool緩沖池申請新的緩沖區用以更新接收緩沖描述符的緩沖區指針;
- 調用
m5200FecRbdClean
清除接收緩沖區描述符; - 調用
END_RCV_RTN_CALL
上傳數據到協議棧。
- 如果接收緩沖區描述符有錯誤,則調用
- END_RCV_RTN_CALL:調用
pEnd->receiveRtn
即muxReceive
,失敗則調用netMblkClChainFree
釋放發送緩沖區pMBLK
; - muxReceive():接收數據上傳協議棧:
- 調用
pEnd->pFuncTable->packetDataGet
即endEtherPacketDataGet
獲取pMBlk
接收緩沖區的數據指針; - 獲取以太網頭中的報文類型;
- 遍歷綁定在網口上的協議棧,若匹配則調用協議棧的接收函數
pProto->rr.endRcv
即muxEndRcvRtn
將數據放入協議棧的緩沖區; - 更新2233 MIB接收統計信息;
- 調用
netMblkClChainFree
釋放發送緩沖區`pMBLK。
- 調用
- muxEndRcvRtn():調用pBinding->stackRcvRtn,即協議棧調用
muxBind
綁定的dengstackRcvRtn
函數指針將數據上傳到協議棧的緩沖區。
3. ifconfig up/down流程
ifconfig的入口位于vxworks-6.6/target/src/wrn/coreip/wrapper/utilslib/ifconfig.c
,主要流程如下所示:
- ifconfig():調用ipnet_cmd_ifconfig(),位于
vxworks-6.6/target/src/wrn/coreip/wrapper/utilslib/ifconfig.c
; - ipnet_cmd_ifconfig():調用ipcom_socket()創建socket,然后使用IP_TRUE和IP_FALSE調用ipnet_ifconfig_if_change_state(),位于
components/ip_net2-6.6/ipnet2/src/ipnet_cmd_ifconfig.c
; - ipnet_ifconfig_if_change_state():使用IP_SIOCSIFFLAGS,并設置或清除IP_IFF_UP來調用ipcom_socketioctl(),位于
components/ip_net2-6.6/ipnet2/src/ipnet_ioctl.c
; - ipcom_socketioctl():調用ipnet_do_ioctl(),位于
components/ip_net2-6.6/ipnet2/src/ipnet_ioctl.c
; - ipnet_do_ioctl():調用ipnet_ioctl_if(),位于
components/ip_net2-6.6/ipnet2/src/ipnet_ioctl.c
; - ipnet_ioctl_if():使用IP_SIOCXOPEN或IP_SIOCXCLOSE調用ipnet_if_link_ioctl(),位于
components/ip_net2-6.6/ipnet2/src/ipnet_netif.c
; - ipnet_if_link_ioctl():調用netif->link_ioctl(),即通過ipnet_eth_if_init()安裝的ipnet_eth_ioctl(),位于
components/ip_net2-6.6/ipnet2/src/ipnet_netif.c
; - ipnet_eth_ioctl():調用ipnet_if_drv_ioctl(),位于
components/ip_net2-6.6/ipnet2/src/ipnet_eth.c
; - ipnet_if_drv_ioctl():調用ipnet_if_clean_snd_queue()清理并復位當前接口上的隊列,然后調用netif->ipcom.drv_ioctl(),即通過ipcom_drv_eth_init()安裝的ipcom_drv_eth_ioctl(),位于
components/ip_net2-6.6/ipnet2/src/ipnet_netif.c
; - ipcom_drv_eth_ioctl():為IP_SIOCXOPEN調用ipnet_drv_eth_sync_with_end_flags(),為IP_SIOCXCLOSE調用netif->link_ioevent即ipnet_eth_ioevent()通知協議棧網口處于IP_EIOXSTOP,位于
components/ip_net2-6.6/ipnet2/src/ipnet_eth.c
; - ipnet_drv_eth_sync_with_end_flags():調用muxIoctl獲取網口標志和狀態,若網口處于活動狀態度,則調用netif->link_ioevent即ipnet_eth_ioevent()通知協議棧網口處于IP_EIOXRUNNING狀態。
綜上所述,ifconfig up/down不會真正操作網口驅動,只是清理并復位當前網口上的隊列,然后通知協議棧網口處于IP_EIOXRUNNING或IP_EIOXSTOP狀態。