小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

Linux內(nèi)核分析 - 網(wǎng)絡(luò)[一]:收發(fā)數(shù)據(jù)包的調(diào)用

 杰的個(gè)人圖書(shū)館 2012-04-11
內(nèi)核版本:Linux-2.6.34
網(wǎng)卡驅(qū)動(dòng):B4401

 

 

什么是NAPI

NAPI 是linux一套最新的處理網(wǎng)口數(shù)據(jù)的API,linux 2.5引入的,所以很多驅(qū)動(dòng)并不支持這種操作方式。簡(jiǎn)單來(lái)說(shuō),NAPI是綜合中斷方式與輪詢(xún)方式的技術(shù)。數(shù)據(jù)量很低與很高時(shí),NAPI可以發(fā)揮中斷方式與 輪詢(xún)方式的優(yōu)點(diǎn),性能較好。如果數(shù)據(jù)量不穩(wěn)定,且說(shuō)高不高說(shuō)低不低,則NAPI會(huì)在兩種方式切換上消耗不少時(shí)間,效率反而較低一些。

 

下面會(huì)用到netdev_priv()這個(gè)函數(shù),這里先講解下,每個(gè)網(wǎng)卡驅(qū)動(dòng)都有自己的私有的數(shù)據(jù),來(lái)維持網(wǎng)絡(luò)的正常運(yùn)行,而這部分私有數(shù)據(jù)放在網(wǎng)絡(luò)設(shè)備數(shù)據(jù)后面(內(nèi)存概念上),這個(gè)函數(shù)就是通過(guò)dev來(lái)取得這部分私有數(shù)據(jù),注間這部分私有數(shù)據(jù)不在dev結(jié)構(gòu)體中,而是緊接在dev內(nèi)存空間后。

static inline void *netdev_priv(const struct net_device *dev)

{

  return (char *)dev + ALIGN(sizeof(struct net_device), NETDEV_ALIGN);

}

 

弄清這個(gè)函數(shù)還得先清楚dev這個(gè)結(jié)構(gòu)的分配

alloc_netdev() -> alloc_netdev_mq()

struct net_device *alloc_netdev_mq(int sizeof_priv, const char *name,

              void (*setup)(struct net_device *), unsigned int queue_count)

{

     ……

 

     alloc_size = sizeof(struct net_device);

     if (sizeof_priv) {

              /* ensure 32-byte alignment of private area */

              alloc_size = ALIGN(alloc_size, NETDEV_ALIGN);

              alloc_size += sizeof_priv;

     }

     /* ensure 32-byte alignment of whole construct */

     alloc_size += NETDEV_ALIGN - 1;

 

     p = kzalloc(alloc_size, GFP_KERNEL);

     if (!p) {

              printk(KERN_ERR "alloc_netdev: Unable to allocate device./n");

              return NULL;

     }

 

     ……….

}

可以看到,dev在分配時(shí),即在它的后面分配了private的空間,需要注意的是,這兩部分都是4字節(jié)對(duì)齊的,如下圖所示,padding是加入的的補(bǔ)齊字節(jié):

  

 

舉個(gè)例子,假設(shè)sizeof(net_device)大小為31Bprivate大小45B,則實(shí)際分配空間如圖所示:

 

   

    b44_interrupt():當(dāng)有數(shù)據(jù)包收發(fā)或發(fā)生錯(cuò)誤時(shí),會(huì)產(chǎn)生硬件中斷,該函數(shù)被觸發(fā)

struct b44 *bp = netdev_priv(dev);

取出網(wǎng)卡驅(qū)動(dòng)的私有數(shù)據(jù)private,該部分?jǐn)?shù)據(jù)位于dev數(shù)據(jù)后面

istat = br32(bp, B44_ISTAT);

imask = br32(bp, B44_IMASK);

讀出當(dāng)前中斷狀態(tài)和中斷屏蔽字

     if (istat) {

              ……

              if (napi_schedule_prep(&bp->napi)) {

                       bp->istat = istat;

                       __b44_disable_ints(bp);

                       __napi_schedule(&bp->napi);

              }

設(shè)置NAPISCHED狀態(tài),記錄當(dāng)前中斷狀態(tài),關(guān)閉中斷,執(zhí)行調(diào)度

void __napi_schedule(struct napi_struct *n)

{

     unsigned long flags;

 

     local_irq_save(flags);

     list_add_tail(&n->poll_list, &__get_cpu_var(softnet_data).poll_list);

     __raise_softirq_irqoff(NET_RX_SOFTIRQ);

     local_irq_restore(flags);

}

__get_cpu_var():得到當(dāng)前CPU的偏移量,與多CPU有關(guān)

napipoll_list加入到softnet_data隊(duì)列尾部,然后引起軟中斷NET_RX_SOFTIRQ。

 

似乎還沒(méi)有真正的收發(fā)函數(shù)出現(xiàn),別急;關(guān)于軟中斷的機(jī)制請(qǐng)參考資料,在net_dev_init()[dev.c]中,注冊(cè)了兩個(gè)軟中斷處理函數(shù),所以引起軟中斷后,最終調(diào)用了net_rx_action()。

open_softirq(NET_TX_SOFTIRQ, net_tx_action);

open_softirq(NET_RX_SOFTIRQ, net_rx_action);

下面來(lái)看下net_rx_action()函數(shù)實(shí)現(xiàn):

static void net_rx_action(struct softirq_action *h)

{

     struct list_head *list = &__get_cpu_var(softnet_data).poll_list;  // [1]

     ……

     n = list_first_entry(list, struct napi_struct, poll_list);     // [2]

     ……

     work = 0;

     if (test_bit(NAPI_STATE_SCHED, &n->state)) {

              work = n->poll(n, weight);        // [3]

              trace_napi_poll(n);

     }

……

}

__get_cpu_var是不是很熟悉,在b44_interrupt()中才向它的poll_list中加入了一個(gè)napi_struct;代碼[2]很簡(jiǎn)單了,從poll_list的頭中取出一個(gè)napi_struct,然后執(zhí)行代碼[3],調(diào)用poll()函數(shù);注意到這里在interrupt時(shí),會(huì)向poll_list尾部加入一個(gè)napi_struct,并引起軟中斷,在軟中斷處理函數(shù)中,會(huì)從poll_list頭部移除一個(gè)napi_struct,進(jìn)行處理,理論上說(shuō),硬件中斷加入的數(shù)據(jù)在其引起的軟中斷中被處理。

poll函數(shù)實(shí)際指向的是b44_poll(),這是顯而易見(jiàn)的,但具體怎樣調(diào)用的呢?在網(wǎng)卡驅(qū)動(dòng)初始化函數(shù)b44_init_one()有這樣一行代碼:

netif_napi_add(dev, &bp->napi, b44_poll, 64);

netif_napi_add()中初始化napi并將其加入dev的隊(duì)列,

     napi->poll = poll;

這行代碼就是b44_poll賦給napi_poll,所以在NET_RX_SOFTIRQ軟中斷處理函數(shù)net_rx_action()中執(zhí)行的b44_poll()。

怎么到這里都還沒(méi)有收發(fā)數(shù)據(jù)包的函數(shù)呢!b44_poll()就是輪詢(xún)中斷向量,查找出引起本次操作的中斷;

static int b44_poll(struct napi_struct *napi, int budget)

{

     ……

     if (bp->istat & (ISTAT_TX | ISTAT_TO))

              b44_tx(bp);

     ……

     if (bp->istat & ISTAT_RX)

              work_done += b44_rx(bp, budget);

     if (bp->istat & ISTAT_ERRORS)

              ……

}

可以看到,查詢(xún)了四種中斷:ISTAT_TX、ISTAT_TO、ISTAT_RXISTAT_ERRORS

#define  ISTAT_TO               0x00000080 /* General Purpose Timeout */

#define  ISTAT_RX               0x00010000 /* RX Interrupt */

#define  ISTAT_TX                0x01000000 /* TX Interrupt */

#define ISTAT_ERRORS (ISTAT_DSCE|ISTAT_DATAE|ISTAT_DPE|ISTAT_RDU|ISTAT_RFO|ISTAT_TFU)

如果是TX中斷,則調(diào)用b44_tx發(fā)送數(shù)據(jù)包;如果是RX中斷,則調(diào)用b44_rx接收數(shù)據(jù)包。至此,從網(wǎng)卡驅(qū)動(dòng)收發(fā)數(shù)據(jù)包的調(diào)用就是如此了。

最后,給個(gè)總結(jié)性的圖:

  

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶(hù)發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買(mǎi)等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶(hù) 評(píng)論公約

    類(lèi)似文章 更多