亚洲av成人无遮挡网站在线观看,少妇性bbb搡bbb爽爽爽,亚洲av日韩精品久久久久久,兔费看少妇性l交大片免费,无码少妇一区二区三区

  免費注冊 查看新帖 |

Chinaunix

  平臺 論壇 博客 文庫
最近訪問板塊 發(fā)新帖
查看: 4544 | 回復: 5
打印 上一主題 下一主題

[內核入門] ip_rcv函數中調用skb_share_check克隆skb疑問 [復制鏈接]

論壇徽章:
0
跳轉到指定樓層
1 [收藏(0)] [報告]
發(fā)表于 2012-11-06 16:42 |只看該作者 |倒序瀏覽
本帖最后由 ljbphoebe 于 2012-11-06 16:51 編輯

問:原來的skb哪去了?  
    ip_rcv函數處理從鏈路層來的skb數據包,該函數會檢查skb是否被共享,如果被共享就clone一個skb,原來的skb的user引用計數減1。
    如果skb的user引用數為3的話,那么就會進入skb_share_check中的if (skb_shared(skb)) 段中執(zhí)行,就會clone 一個新的skb,然后kfree_skb(skb)將舊的skb的引用計數減1,user為2,
    struct sk_buff *nskb = skb_clone(skb, pri);
                kfree_skb(skb);
                skb = nskb;
從代碼上看,skb指針指向了新clone的skb,kfree_skb(skb)并沒有真正釋放原來skb,那么原來的skb哪去了呢?豈不是內核內存泄露了?誰知道這是為什么?謝謝~
  1. int ip_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt)
  2. {
  3.         struct iphdr *iph;

  4.         /* When the interface is in promisc. mode, drop all the crap
  5.          * that it receives, do not try to analyse it.
  6.          */
  7.         if (skb->pkt_type == PACKET_OTHERHOST)
  8.                 goto drop;

  9.         IP_INC_STATS_BH(IPSTATS_MIB_INRECEIVES);

  10.         if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL) {
  11.                 IP_INC_STATS_BH(IPSTATS_MIB_INDISCARDS);
  12.                 goto out;
  13.         }
  14. ......

  15. }

  16. static inline struct sk_buff *skb_share_check(struct sk_buff *skb, int pri)
  17. {
  18.         might_sleep_if(pri & __GFP_WAIT);
  19.         if (skb_shared(skb)) {
  20.                 struct sk_buff *nskb = skb_clone(skb, pri);
  21.                 kfree_skb(skb);
  22.                 skb = nskb;
  23.         }
  24.         return skb;
  25. }

  26. static inline void kfree_skb(struct sk_buff *skb)
  27. {
  28.         if (atomic_read(&skb->users) == 1 || atomic_dec_and_test(&skb->users))
  29.                 __kfree_skb(skb);
  30. }
復制代碼

論壇徽章:
0
2 [報告]
發(fā)表于 2012-11-06 17:23 |只看該作者
按照你的假設skb的user傳進來時就是3,表明有其他地方使用這個skb,使用的地方會負責釋放的

論壇徽章:
0
3 [報告]
發(fā)表于 2012-11-06 17:57 |只看該作者
本帖最后由 ljbphoebe 于 2012-11-06 17:59 編輯

我查看了原來的skb的出處,調用路徑是這樣的:
process_backlog函數中,skb = __skb_dequeue(&queue->input_pkt_queue);   此時的skb是孤立的個體,沒有其他指針指向它
然后調用netif_receive_skb(skb);       將skb和所有的已注冊的協議相比較,
然后調用deliver_skb(skb, pt_prev);       對user引用計數遞增,調用上層協議處理函數處理此skb,對于ip層,就直接調用ip_rcv函數了

多謝提醒啊,我明白了。感覺應該是這樣:
int netif_receive_skb(struct sk_buff *skb)
{
    ......

        list_for_each_entry_rcu(ptype, &ptype_all, list) {
                if (!ptype->dev || ptype->dev == skb->dev) {
                        if (pt_prev)
                                ret = deliver_skb(skb, pt_prev);
                        pt_prev = ptype;
                }
        }
     ........
        list_for_each_entry_rcu(ptype, &ptype_base[ntohs(type)&15], list) {
                if (ptype->type == type &&
                    (!ptype->dev || ptype->dev == skb->dev)) {
                        if (pt_prev)
                                ret = deliver_skb(skb, pt_prev);
                        pt_prev = ptype;
                }
        }
   .......
}

在每次比較協議的時候,都會調用相應協議的處理函數來對之前的skb操作,所以除了在ip層的ip_rcv函數之外,還有其他協議的處理函數操作此skb,應該是這樣了

論壇徽章:
0
4 [報告]
發(fā)表于 2012-11-08 10:23 |只看該作者
路過看看,求更深入分析

論壇徽章:
0
5 [報告]
發(fā)表于 2012-11-08 18:39 |只看該作者
本帖最后由 ljbphoebe 于 2012-11-08 20:32 編輯

從linux網絡內核源碼看,我也只是看大概的流程,沒有細看具體的細節(jié)

      每個網卡在linux啟動之初都跟內核相關聯上,硬件是內核函數pci_init()內部通過層層調用,最后通過pci_scan_device()函數將網卡結構掛著pci_devices全局變量上。網卡驅動程序是通過pci_register_driver ()函數將網卡驅動掛入全局驅動鏈表pci_drivers中,并且將驅動和對應的device相關聯。在網卡驅動結構struct pci_driver中,是一些函數指針,最主要的是probe,指向具體類型網卡相應的初始化函數,如rtl8139_init_one,這個函數是真正和具體網卡有直接關系的驅動程序,主要負責建立網卡設備結構net_device,申請中斷號,映射內存IO端口等任務。而在net_device結構中就是內核可以直接操作網卡的一系列函數指針open,hard_start_xmit,poll等等,net_device結構比較大,不能全列出來
struct net_device{
    ........
     int        (*open)(struct net_device *dev);
     int        (*stop)(struct net_device *dev);
     int        (*hard_start_xmit) (struct sk_buff *skb, struct net_device *dev);
     int        (*poll) (struct net_device *dev, int *quota);
   ........
}
      open指向rtl8139_open,hard_start_xmit指向rtl8139_start_xmit,poll指向rtl8139_poll,stop指向rtl8139_close函數,分別是打開設備,發(fā)送數據包,輪訓設備接收數據包,關閉設備。顯然打開和關閉設備分別在系統(tǒng)啟動和系統(tǒng)關閉時的操作;發(fā)送和接收是隨時的操作。在open操作中驅動程序會為此網卡申請一個中斷號,并且關聯上中斷服務程序。對于網絡接收數據包有兩種方式:1.中斷方式;2.輪訓方式
1.中斷方式:
      在2.4及2.4之前的內核是以中斷方式接收的,即中斷服務程序通過將接收到的數據拷貝到內核緩沖包結構skb中,然后通過netif_rx()函數將skb掛入軟中斷數據結構softnet_data結構中的input_pkt_queue隊列上,再通過netif_rx_schedule()函數將設備poll_list加入softnet_data的poll_list列表中并標記軟中斷,等待內核處理。這部分是硬中斷處理部分。
      內核在軟中斷處理時機,net_rx_action()函數調用process_backlog函數(也是poll,是blog_dev的poll,2.6中是backlog_dev)將skb從input_pkt_queue隊列取出,然后調用netif_receive_skb()函數將skb數據包提交給網絡上層。
struct softnet_data
{
   ……
        struct sk_buff_head        input_pkt_queue;
        struct list_head        poll_list;
   ……
};
2.輪訓方式:
      在2.6內核中增加了輪訓機制。這種機制,從我看內核源碼中發(fā)現,它不再將skb掛入input_pkt_queue了(不知道我看的對不對,有高手給予指正),在中斷服務程序中就不一樣了。當中斷到來時,它是先將對應設備的poll_list掛入struct softnet_data的poll_list列表中,然后打軟中斷標記,先不對數據包進行接收,把接收數據包的任務給軟中斷了。
      在軟中斷執(zhí)行時機,net_rx_action()調用poll函數將網卡數據交給skb,然后直接調用netif_receive_skb()函數交給上層。
      我感覺中斷和輪訓處理方式不同的是在接收skb數據包的時機不同了(雖然都用poll,但是poll處理數據包時機不同),中斷方式是在硬中斷過程中接收的,而輪訓方式是在軟中斷過程中接收的;另一個就是輪訓方式是不將skb保存在input_pkt_queue隊列中。對于這一點,我還不確定我看的對不對,希望大家討論一下

      接下來,netif_receive_skb()得到skb包之后就處理該數據包。先檢查包的正確性(netpoll_rx函數檢查),打時間戳,……,再之后就是掃描ptype_all鏈表與ptype_base哈希表。ptype_base是各種已經注冊的協議的哈希表,根據每個數據包協議不同分派給不同的協議來處理,在這里遞增skb進行索引計數,然后會在后續(xù)的操作中對skb進行拷貝。我們討論的是IP協議,所以就通過ETH_P_IP標志傳給IP層處理函數ip_rcv(),這是通過struct packet_type的func函數指針調用的(ip_rcv是在內核初始化時通過ip_init函數與func指針關聯的)。
      在ip_rcv函數中通過skb_share_check函數對skb進行拷貝,接下來調整IP層的data起始位置,最后通過ip_rcv_finish處理路由轉發(fā)還是繼續(xù)往上層傳遞。
      在ip_rcv_finish中也是對skb包進行一系列檢查,調用ip_route_input函數處理路由,設置此數據包的路由出口,接下來調用dst_input函數處理轉發(fā)還是向上傳。如果是轉發(fā)則調用ip_forward,如果是向上傳則調用ip_local_deliver。

      這是大概的包流程,寫出來和大家一起探討,互相進步。不一定對啊,僅供參考。

論壇徽章:
0
6 [報告]
發(fā)表于 2014-11-24 17:18 |只看該作者
這個論壇的同志就是叼
您需要登錄后才可以回帖 登錄 | 注冊

本版積分規(guī)則 發(fā)表回復

  

北京盛拓優(yōu)訊信息技術有限公司. 版權所有 京ICP備16024965號-6 北京市公安局海淀分局網監(jiān)中心備案編號:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年舉報專區(qū)
中國互聯網協會會員  聯系我們:huangweiwei@itpub.net
感謝所有關心和支持過ChinaUnix的朋友們 轉載本站內容請注明原作者名及出處

清除 Cookies - ChinaUnix - Archiver - WAP - TOP