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