顧燕飛, 鄒維軍, 王子劍, 張慶松
(中國(guó)電子科技集團(tuán)公司第三十二研究所, 上海 201808)
Netlink作為一種進(jìn)程間通信機(jī)制, 除了提供內(nèi)核不同模塊間通信, 還能實(shí)現(xiàn)內(nèi)核態(tài)與用戶態(tài)進(jìn)程間通信.相較于傳統(tǒng)的用戶進(jìn)程與內(nèi)核通信的機(jī)制(如ioctl方法和proc文件系統(tǒng))的單向性, Netlink可以實(shí)現(xiàn)全雙工通信[1].
1553B總線全稱為數(shù)字時(shí)分命令/響應(yīng)型多路傳輸數(shù)據(jù)總線.最早應(yīng)用于美軍航空電子綜合系統(tǒng)之上, 各種航電設(shè)備基于MIL-STD-1553B總線完成設(shè)備間通信[2].但隨著其不斷的發(fā)展, 線性局域網(wǎng)絡(luò)結(jié)構(gòu)使得1553B總線成為航空系統(tǒng)或地面車輛系統(tǒng)中分布式設(shè)備的理想連接方式.與點(diǎn)對(duì)點(diǎn)連接相比, 它減少了所需電纜、所需空間和系統(tǒng)的重量.便于維護(hù), 易于增加或刪除節(jié)點(diǎn), 提高了設(shè)計(jì)靈活性, 冗余容錯(cuò)能力等特點(diǎn),在航空、航天、航海和民用等領(lǐng)域都得到廣泛的使用[3].
Socket 1553B協(xié)議是在Linux下1553B協(xié)議實(shí)現(xiàn)的一種方法.Linux下一般使用1553B協(xié)議的方法是基于字符設(shè)備來(lái)實(shí)現(xiàn)的, 與之不同的是Socket 1553B使用Netlink的socket接口和linux網(wǎng)絡(luò)協(xié)議棧, 這種方法使得1553B設(shè)備驅(qū)動(dòng)可以通過(guò)網(wǎng)絡(luò)接口來(lái)調(diào)用.Socket 1553B的接口被設(shè)計(jì)的盡量接近TCP/IP的協(xié)議, 讓那些熟悉網(wǎng)絡(luò)編程的程序員能夠比較容易的學(xué)習(xí)和使用.
整個(gè)系統(tǒng)環(huán)境的最底層是PCIE-1553B接口卡, 在操作系統(tǒng)中為1553B設(shè)備創(chuàng)建網(wǎng)絡(luò)驅(qū)動(dòng), 負(fù)責(zé)配置和收發(fā)操作.在收發(fā)網(wǎng)絡(luò)包過(guò)程中對(duì)其進(jìn)行解析報(bào)文, 根據(jù)協(xié)議類型判斷是否為1553B數(shù)據(jù)包, 遞交給Netlink內(nèi)核層中的接收函數(shù)處理[4].利用內(nèi)核提供的Netlink接口層, 創(chuàng)建新的網(wǎng)絡(luò)協(xié)議, 屏蔽了底層實(shí)現(xiàn)的差異, 為上層socket應(yīng)用提供了統(tǒng)一的應(yīng)用接口.系統(tǒng)總體架構(gòu)如圖1.

圖1 系統(tǒng)總體架構(gòu)
1553B總線系統(tǒng)包括串行傳輸電纜、總線控制器BC、遠(yuǎn)程終端RT、總線監(jiān)控器MT[5].其組成如圖2所示.
本文以BC與RT之間的通信為例, 來(lái)說(shuō)明該總線系統(tǒng)的工作過(guò)程.該過(guò)程如下:
(1) 總線控制器BC通過(guò)初始化完成數(shù)據(jù)傳輸?shù)臏?zhǔn)備工作.
(2) BC通過(guò)向總線發(fā)送命令字來(lái)決定參與本次數(shù)據(jù)傳輸?shù)倪h(yuǎn)程終端和采用的消息格式.命令字分為發(fā)送命令字(要求RT向總線上發(fā)送數(shù)據(jù)), 接收命令字(要求RT接收總線上的數(shù)據(jù)), 方式代碼命令字(要求RT完成特殊操作).

圖2 1553B 總線通信系統(tǒng)組成
(3) RT檢測(cè)到BC傳來(lái)的命令字與自己地址匹配時(shí), 將按照命令字的要求參與到數(shù)據(jù)傳輸過(guò)程中, 完成數(shù)據(jù)傳輸后RT將在規(guī)定時(shí)間內(nèi)返回狀態(tài)字[6].
(4) BC通過(guò)檢測(cè)RT返回的狀態(tài)字來(lái)判斷本次數(shù)據(jù)傳輸完成情況.如果數(shù)據(jù)正確傳輸將結(jié)束本消息傳輸.
其中字格式如圖3所示.

圖3 1553B 協(xié)議字格式
1553B協(xié)議驅(qū)動(dòng)實(shí)現(xiàn)BC與RT之間的通信.BC和RT的通信過(guò)程可以分為BC發(fā)送RT接收和RT發(fā)送BC接收兩種情況.
2.1.1 BC 讀 RT
BC讀RT表示RT發(fā)送BC接收, 如圖4所示.如圖4所示, 整個(gè)過(guò)程如下:
(1) RT將數(shù)據(jù)寫入本地DMA發(fā)送緩存, 等待BC來(lái)讀取.
(2) BC發(fā)送BC讀RT的命令給目的RT, 告訴目的RT, BC需要從RT的哪個(gè)子地址(sa)讀取多長(zhǎng)的數(shù)據(jù)(len), 同時(shí)BC開始計(jì)時(shí), 在一定的時(shí)間內(nèi)若沒(méi)有收到RT返回的狀態(tài)(幀), 則產(chǎn)生超時(shí)中斷.

圖4 BC 讀 RT 數(shù)據(jù)原理框圖
(3) RT接收到BC的命令后RT啟動(dòng)本地定時(shí)器(RT需要在規(guī)定的時(shí)間內(nèi)向BC發(fā)送狀態(tài)幀), 根據(jù)本地情況返回不同的狀態(tài)幀給BC, 具體情況如下:
1) 如果BC要求讀取的目的子地址沒(méi)有數(shù)據(jù),則返回busy幀給BC, 并產(chǎn)生一次正常數(shù)據(jù)發(fā)送中斷.
2) 如果BC要求讀取的目的子地址有數(shù)據(jù),則返回“狀態(tài)+數(shù)據(jù)”給BC, 并產(chǎn)生一次正常數(shù)據(jù)發(fā)送中斷.
3) 在 1), 2)的過(guò)程中, 如果定時(shí)時(shí)間到, 則會(huì)產(chǎn)生一個(gè)“RT返回狀態(tài)超時(shí)”的中斷[7].
(4) BC在規(guī)定的時(shí)間內(nèi)收到RT返回的狀態(tài)(busy幀或數(shù)據(jù)幀), BC將RT返回的狀態(tài)寫入特定寄存器保存起來(lái), 如果返回的狀態(tài)后面跟有數(shù)據(jù), 則將數(shù)據(jù)存入BC特定的DMA接收緩存中, 供驅(qū)動(dòng)程序獲取, 并產(chǎn)生一次正常數(shù)據(jù)接收中斷.
(5) 驅(qū)動(dòng)程序根據(jù)返回的狀態(tài)內(nèi)容, 將busy狀態(tài)或接收到的數(shù)據(jù)返回給用戶.
2.1.2 BC寫 RT
BC寫RT表示BC發(fā)送RT接收, 如圖5所示.如圖5所示, 整個(gè)過(guò)程如下:
(1) BC將用戶數(shù)據(jù)寫入本地特定DMA發(fā)送緩存.

圖5 BC 寫 RT 數(shù)據(jù)原理框圖
(2) BC將目的RT號(hào)、目的子地址號(hào)、數(shù)據(jù)長(zhǎng)度信息寫入特定寄存器, 供硬件組“命令字”使用.
(3) 啟動(dòng)命令發(fā)送.
(4) BC以命令字+數(shù)據(jù)字(可以有多個(gè))的形式往外發(fā)送數(shù)據(jù), 在最后一個(gè)數(shù)據(jù)字發(fā)送完后, 啟動(dòng)定時(shí).
(5) RT收到BC寫命令進(jìn)行解析, 當(dāng)BC向RT所寫的子地址中有數(shù)據(jù)時(shí), 返回busy幀發(fā)送BC;當(dāng)BC向RT所寫的子地址中無(wú)數(shù)據(jù)時(shí), RT接收數(shù)據(jù), 并產(chǎn)生正常接收的狀態(tài)發(fā)送BC[8].
(6) 如果在一定時(shí)間內(nèi)沒(méi)有收到RT返回的狀態(tài)(表征busy或正常接收), 則產(chǎn)生一次發(fā)送超時(shí);否則產(chǎn)生一次正常發(fā)送中斷.
(7) RT 將根據(jù)狀態(tài), 反饋給用戶.
Netlink機(jī)制用戶層的套接字采用標(biāo)準(zhǔn)的套接字接口來(lái)定義的, 其中包括 socket、bind、sendto、recvfrom、close等[9].
int socket( int domain, int type, int protocol);
socket函數(shù), 指定期望的通信協(xié)議類型和傳輸方式.domain:地址域, 在 Netlink 機(jī)制下應(yīng)為 AF_NETLINK;type:SOCK_DGRAM 或 SOCK_RAW 兩種類型;protocol:協(xié)議使用NETLINK_1553B_EVENT, 自定義協(xié)議號(hào)為NETLINK_1553B_EVENT=17.
int bind ( int sockfd, struct sockaddr *maddr,socklen_t addrlen);
bind函數(shù), 用來(lái)綁定一個(gè)套接字的地址、協(xié)議、端口號(hào)[10].在Netlink機(jī)制下綁定地址的結(jié)構(gòu)體如下:

sendto是向套接字發(fā)送消息給內(nèi)核的Netlink層.Netlink套接字消息包括消息頭和數(shù)據(jù)兩部分.Netlink套接字所傳遞的消息都有一個(gè)固定的消息頭,結(jié)構(gòu)體如下[11]:

nlmsg_len表示該消息的總長(zhǎng)度;nlmsg_type表示消息類型, 該值與Netlink選用的通信協(xié)議相關(guān), 本文設(shè)置為NLMSG_1553B_TYPE=0x12, 表示1553B協(xié)議消息類型;nlmsg_flags為控制信息, 如標(biāo)志設(shè)為NLM_F_REQUEST或 NLM_F_ACK, NLM_F_ACK 表示要求消息接收方發(fā)回一個(gè)確認(rèn)消息給消息發(fā)送方;nlmsg_seq表示序列號(hào);nlmsg_pid表示發(fā)出消息進(jìn)程的進(jìn)程號(hào).

close表示關(guān)閉一個(gè)Netlink網(wǎng)絡(luò)套接字, 具體操作是把套接字鏈表中對(duì)應(yīng)的套接字刪除, 同時(shí)釋放套接字的接收緩存和發(fā)送緩存, 清除套接字的使用內(nèi)存,設(shè)置套接字的傳輸狀態(tài)為關(guān)閉.
在Netlink內(nèi)核初始化時(shí), 通過(guò)netlink_kernel_create函數(shù)來(lái)創(chuàng)建內(nèi)核套接字, 并將自定義協(xié)議號(hào)為NETLINK_1553B_EVENT=17, 消息類型為 NLMSG_1553B_TYPE=0x12進(jìn)行注冊(cè).

net表示網(wǎng)絡(luò)名字空間, 一般使用init_net這個(gè)全局變量;unit表示使用的協(xié)議號(hào), 這里為 NETLINK_1553B_EVENT=17;cb_mutex 為 NULL;module為THIS_MODULE.
input()函數(shù)為具體的消息處理函數(shù)[12].內(nèi)核中為某一個(gè)通信協(xié)議使用netlink_kernel_create函數(shù)創(chuàng)建了一個(gè)Netlink套接字, 所有該通信協(xié)議的用戶方Netlink消息都將發(fā)送給內(nèi)核空間的這個(gè)Netlink套接字, 由該套接字再調(diào)用創(chuàng)建時(shí)注冊(cè)的input()函數(shù)來(lái)統(tǒng)一處理所有的消息.這里在自定義消息處理函數(shù)為msg1553b_receive中, 會(huì)判斷消息類型、長(zhǎng)度等, 以及1553B協(xié)議整個(gè)收發(fā)過(guò)程, 包含BC讀RT, BC寫RT,RT讀數(shù)據(jù), RT寫數(shù)據(jù)等.
基于Netlink機(jī)制的用戶態(tài)與內(nèi)核態(tài)之間的通信如圖6所示.

圖6 1553B協(xié)議在內(nèi)核態(tài)與用戶態(tài)的通信流程
用戶態(tài)中使用Netlink套接字socket創(chuàng)建時(shí), 需要設(shè)置協(xié)議號(hào)為NETLINK_1553B_EVENT=17.在Netlink套接字封裝消息時(shí), 需要將消息類型設(shè)置為NLMSG_1553B_TYPE=0x12.并且在消息數(shù)據(jù)中規(guī)定了以下幾種模式:
DEV_INIT:表示設(shè)備的初始化, 規(guī)定該設(shè)備的角色, 是BC還是RT.
BC_RD_RT:表示 BC 讀 RT, 即 BC需要從 RT的某個(gè)子地址中讀取數(shù)據(jù).
BC_WR_RT:表示BC寫RT, 即BC需要向RT的某個(gè)子地址中寫入數(shù)據(jù).
RT_RD_DATA:表示 RT 讀數(shù)據(jù), 即 RT 從某個(gè)子地址中讀取數(shù)據(jù).
RT_WR_DATA:表示 RT 寫數(shù)據(jù), 即 RT向某個(gè)子地址中寫入數(shù)據(jù).
內(nèi)核態(tài)中使用Netlink套接字socket創(chuàng)建時(shí), 需要注冊(cè)協(xié)議號(hào)NETLINK_1553B_EVENT=17, 并指明接收處理函數(shù)msg1553b_receive.在msg1553b_receive函數(shù)中會(huì)判斷消息類型是否為NLMSG_1553B_TYPE,如果是, 繼續(xù)處理消息;如果不是則返回錯(cuò)誤.對(duì)應(yīng)的消息處理函數(shù)中針對(duì)以上這幾種模式會(huì)做出不同的響應(yīng):
(1) 當(dāng)收到DEV_INIT模式時(shí), 將判斷是BC還是RT, 分別進(jìn)行對(duì)應(yīng)的初始化.
(2) 當(dāng)收到 BC_RD_RT模式時(shí), 將 1553B的狀態(tài)字發(fā)送給RT, 并讀取RT返回的數(shù)據(jù)或狀態(tài), 再返回給用戶態(tài).若超時(shí)或無(wú)數(shù)據(jù), 則返回對(duì)應(yīng)的狀態(tài)給用戶態(tài).
(3) 當(dāng)收到 BC_WR_RT 模式時(shí), 將 1553B的“狀態(tài)字+數(shù)據(jù)”發(fā)送給RT, 并讀取RT返回狀態(tài), 再返回給用戶態(tài).若超時(shí)或無(wú)法寫數(shù)據(jù), 則返回對(duì)應(yīng)的狀態(tài)給用戶態(tài).
(4) 當(dāng)收到 RT_RD_DATA 模式時(shí), 將從底層RT對(duì)應(yīng)子地址中的讀取數(shù)據(jù), 并返回給用戶態(tài).若超時(shí)或無(wú)數(shù)據(jù), 則返回對(duì)應(yīng)的狀態(tài)給用戶態(tài).
(5) 當(dāng)收到 RT_WR_DATA 模式時(shí), 將向底層RT對(duì)應(yīng)子地址中的寫入數(shù)據(jù), 并返回給用戶態(tài).若超時(shí)或無(wú)法寫入數(shù)據(jù), 則返回對(duì)應(yīng)的狀態(tài)給用戶態(tài).
搭建測(cè)試環(huán)境, 測(cè)試設(shè)備連線示意圖如圖7所示.
按圖7所示連接開發(fā)機(jī)、測(cè)試計(jì)算機(jī)、1553B監(jiān)控設(shè)備(監(jiān)控1553B總線上的數(shù)據(jù)).測(cè)試計(jì)算機(jī)上, 通過(guò)測(cè)試軟件打開1553B監(jiān)控設(shè)備, 對(duì)整個(gè)通信過(guò)程進(jìn)行監(jiān)控;Linux軟件開發(fā)機(jī)上加載1553B驅(qū)動(dòng)模塊;分別打開測(cè)試機(jī)上RT設(shè)備Netlink套接字測(cè)試程序和Linux開發(fā)機(jī)上BC設(shè)備Netlink套接字測(cè)試程序, 進(jìn)行BC和RT設(shè)備間1553B數(shù)據(jù)通信測(cè)試.本測(cè)試以BC讀RT數(shù)據(jù)為例, 具體測(cè)試步驟如下.

圖7 設(shè)備連線關(guān)系示意圖
(1) BC向0號(hào)RT設(shè)備發(fā)送請(qǐng)求模式字命令, 以獲知當(dāng)前0號(hào)RT設(shè)備的哪些子地址擁有數(shù)據(jù).
(2) RT在收到BC的矢量請(qǐng)求命令后回復(fù)一個(gè)數(shù)據(jù)字, 告知BC此時(shí)自身?yè)碛袛?shù)據(jù)的子地址號(hào), 如果沒(méi)有返回0.
(3) BC根據(jù)RT返回的結(jié)果, 向當(dāng)前RT的擁有數(shù)據(jù)的某個(gè)子地址發(fā)送“RT發(fā)送數(shù)據(jù)”命令字, 來(lái)獲取該子地址的數(shù)據(jù).
(4) RT 在收到“RT發(fā)送數(shù)據(jù)”命令字后, 將相應(yīng)子地址的數(shù)據(jù)發(fā)送給BC, 記錄此時(shí)發(fā)送的數(shù)據(jù).
測(cè)試結(jié)果如下表所示.
通過(guò)表1可見(jiàn), BC發(fā)送給RT命令為0x0410, 而RT可以接收到0x0410;RT回復(fù)狀態(tài)和數(shù)據(jù)表示1子地址有數(shù)據(jù);BC發(fā)送給RT命令0x0412表示從RT的1子地址上取兩個(gè)數(shù)據(jù);RT回復(fù)狀態(tài)和數(shù)據(jù)表示1子地址上的1, 2數(shù)據(jù)傳給了BC.以上的每個(gè)步驟在記錄表中的數(shù)據(jù)與1553B監(jiān)控設(shè)備監(jiān)控的數(shù)據(jù)一致, 由此可見(jiàn), 利用Netlink套接字編程可以實(shí)現(xiàn)BC與RT之間正常通信.

表1 1553B 接口測(cè)試記錄表
針對(duì)1553B協(xié)議提供了基于Netlink機(jī)制的通用socket接口, 給熟悉網(wǎng)絡(luò)編程的程序員帶來(lái)了極大的方便, 并且移植性好.本文采用的是基于linux的1553B協(xié)議的實(shí)現(xiàn), 但是就協(xié)議本身而言, 與操作系統(tǒng)相關(guān)性不是很大.下一步工作是對(duì)1553B協(xié)議的優(yōu)化以及多平臺(tái), 多系統(tǒng)上的移植, 進(jìn)一步完成在工程上的實(shí)現(xiàn).