W3Cschool
恭喜您成為首批注冊(cè)用戶
獲得88經(jīng)驗(yàn)值獎(jiǎng)勵(lì)
從網(wǎng)絡(luò)上接收?qǐng)?bào)文比發(fā)送它要難一些, 因?yàn)楸仨毞峙湟粋€(gè) sk_buff 并從一個(gè)原子性上下文中遞交給上層. 網(wǎng)絡(luò)驅(qū)動(dòng)可以實(shí)現(xiàn) 2 種報(bào)文接收的模式: 中斷驅(qū)動(dòng)和查詢. 大部分驅(qū)動(dòng)采用中斷驅(qū)動(dòng)技術(shù), 這是我們首先要涉及的. 有些高帶寬適配卡的驅(qū)動(dòng)也可能采用查詢技術(shù); 我們?cè)?接收中斷緩解"一節(jié)中了解這個(gè)方法.
snull 的實(shí)現(xiàn)將"硬件"細(xì)節(jié)從設(shè)備獨(dú)立的常規(guī)事務(wù)中分離. 因此, 函數(shù) snull_rx 在硬件收到報(bào)文后從 snull 的"中斷"處理中調(diào)用, 并且報(bào)文現(xiàn)在已經(jīng)在計(jì)算機(jī)的內(nèi)存中. snull_rx 收到一個(gè)數(shù)據(jù)指針和報(bào)文長度; 它唯一的責(zé)任是發(fā)走這個(gè)報(bào)文和運(yùn)行附加信息給上層的網(wǎng)絡(luò)代碼. 這個(gè)代碼獨(dú)立于獲得數(shù)據(jù)指針和長度的方式.
void snull_rx(struct net_device *dev, struct snull_packet *pkt)
{
struct sk_buff *skb;
struct snull_priv *priv = netdev_priv(dev);
/*
*
The packet has been retrieved from the transmission
*
medium. Build an skb around it, so upper layers can handle it
*/
skb = dev_alloc_skb(pkt->datalen + 2);
if (!skb) {
if (printk_ratelimit())
printk(KERN_NOTICE "snull rx: low on mem - packet dropped\n"); priv->stats.rx_dropped++; goto out;
}
memcpy(skb_put(skb, pkt->datalen), pkt->data, pkt->datalen);
/* Write metadata, and then pass to the receive level */
skb->dev = dev;
skb->protocol = eth_type_trans(skb, dev);
skb->ip_summed = CHECKSUM_UNNECESSARY; /* don't check it */
priv->stats.rx_packets++;
priv->stats.rx_bytes += pkt->datalen;
netif_rx(skb);
out:
return;
}
這個(gè)函數(shù)足夠普通以作為任何網(wǎng)絡(luò)驅(qū)動(dòng)的一個(gè)模板, 但是在你有信心重用這個(gè)代碼段前需要一些解釋.
第一步是分配一個(gè)緩存區(qū)來保存報(bào)文. 注意緩存分配函數(shù) (dev_alloc_skb) 需要知道數(shù)據(jù)長度. 函數(shù)用這些信息來給緩存區(qū)分配空間. dev_alloc_skb 使用 atomic 優(yōu)先級(jí)調(diào)用 kmalloc , 因此它可以在中斷時(shí)間安全使用. 內(nèi)核提供了其他接口給 socket 緩存分配, 但是它們不值得在此介紹; socket 緩存在"socket 緩存"一節(jié)中詳細(xì)介紹.
當(dāng)然, dev_alloc_skb 的返回值必須檢查, snull 這樣做了. 我們調(diào)用 printk_ratelimit 在抱怨失敗之前, 但是. 每秒鐘產(chǎn)生成百上千的控制臺(tái)消息是完全陷死系統(tǒng)和隱藏問題的真正源頭的好方法; printk_ratelimit 幫助阻止這個(gè)問題, 通過在有太多輸出到了控制臺(tái)時(shí)返回 0, 事情需要慢下來一點(diǎn).
一旦有一個(gè)有效的 skb 指針, 通過調(diào)用 memcpy, 報(bào)文數(shù)據(jù)被拷貝到緩存區(qū); skb_put 函數(shù)更新緩存中的數(shù)據(jù)末尾指針并返回指向新建空間的指針.
如果你在編寫一個(gè)高性能驅(qū)動(dòng), 為一個(gè)可以進(jìn)行完全總線占據(jù) I/O 的接口, 一個(gè)可能的優(yōu)化值得在此考慮下. 一些驅(qū)動(dòng)在報(bào)文接收前分配 sokcet 緩存, 接著使接口將報(bào)文數(shù)據(jù)直接放入 socket 緩存空間. 網(wǎng)絡(luò)層通過在可 DMA 的空間( 如果你的設(shè)備設(shè)置了 NETIF_F_HIGHDMA 標(biāo)志, 這個(gè)空間有可能在高端內(nèi)存)中分配所有 socket 緩存來配合這個(gè)策略. 這樣避免了單獨(dú)的填充 socket 緩存的拷貝操作, 但是需要小心緩存區(qū)的大小, 因?yàn)槟銦o法提前知道進(jìn)來的報(bào)文大小. change_mtu 方法的實(shí)現(xiàn)在這種情況下也重要, 因?yàn)樗试S驅(qū)動(dòng)對(duì)最大報(bào)文大小改變作出響應(yīng).
網(wǎng)絡(luò)層在搞懂報(bào)文的意思前需要清楚一些事情. 為此, dev 和 protocol 成員必須在緩存向上傳遞前賦值. 以太網(wǎng)支持代碼輸出一個(gè)幫助函數(shù)( eth_type_trans ), 它發(fā)現(xiàn)一個(gè)合適值來賦給 protocol. 接著我們需要指出校驗(yàn)和要如何進(jìn)行或者已經(jīng)在報(bào)文上完成( snull 不需要做任何校驗(yàn)和 ). 對(duì)于 skb->ip_summed 可能的策略有:
CHECKSUM_HW
設(shè)備已經(jīng)在硬件里做了校驗(yàn). 一個(gè)硬件校驗(yàn)的例子使 APARC HME 接口.
CHECKSUM_NONE
校驗(yàn)和還沒被驗(yàn)證, 必須由系統(tǒng)軟件來完成這個(gè)任務(wù). 這個(gè)是缺省的, 在新分配的緩存中.
CHECKSUM_UNNECESSARY
不要做任何校驗(yàn). 這是 snull 和 環(huán)回接口的策略.
你可能奇怪為什么校驗(yàn)和狀態(tài)必須在這里指定, 當(dāng)我們已經(jīng)在我們的 net_device 結(jié)構(gòu)的特性成員中設(shè)置了標(biāo)志. 答案是特性標(biāo)志告訴內(nèi)核我們的設(shè)備如何對(duì)待外出的報(bào)文. 它不用于進(jìn)入的報(bào)文, 相反, 進(jìn)入報(bào)文必須單獨(dú)標(biāo)記.
最后, 驅(qū)動(dòng)更新它的統(tǒng)計(jì)計(jì)數(shù)來記錄收到一個(gè)報(bào)文。 統(tǒng)計(jì)結(jié)構(gòu)由幾個(gè)成員組成; 最重要的是 rx_packet, rx_bytes, 和 tx_bytes, 分別含有收到的報(bào)文數(shù)目, 發(fā)送的數(shù)目, 和發(fā)送的字節(jié)總數(shù). 所有的成員在"統(tǒng)計(jì)信息"一節(jié)中完全描述.
報(bào)文接收的最后一步由 netif_rx 進(jìn)行, 它遞交 socket 緩存給上層. 實(shí)際上 netif_rx 返回一個(gè)整數(shù); NET_RX_SUCCESS(0) 意思是報(bào)文成功接收; 任何其他值指示錯(cuò)誤. 有 3 個(gè)返回值 (NET_RX_CN_LOW, NET_RX_CN_MOD, 和 NET_RX_CN_HIGH )指出網(wǎng)絡(luò)子系統(tǒng)的遞增的擁塞級(jí)別; NET_RX_DROP 意思是報(bào)文被丟棄. 一個(gè)驅(qū)動(dòng)在擁塞變高時(shí)可能使用這些值來停止輸送報(bào)文給內(nèi)核, 但是, 實(shí)際上, 大部分驅(qū)動(dòng)忽略從 netif_rx 的返回值. 如果你在編寫一個(gè)高帶寬設(shè)備的驅(qū)動(dòng), 并且希望正確處理擁塞, 最好的辦法是實(shí)現(xiàn) NAPI, 我們?cè)诳焖儆懻撝袛嗵幚砗笥懻撍?
Copyright©2021 w3cschool編程獅|閩ICP備15016281號(hào)-3|閩公網(wǎng)安備35020302033924號(hào)
違法和不良信息舉報(bào)電話:173-0602-2364|舉報(bào)郵箱:jubao@eeedong.com
掃描二維碼
下載編程獅App
編程獅公眾號(hào)
聯(lián)系方式:
更多建議: