設備收發包之netif_receive_skb


在設備驅動收包之后,會通過netif_receive_skb將收取的包,按照注冊的協議回調,傳遞到上層進行處理;

  1 /* 將skb傳遞到上層 */
  2 static int __netif_receive_skb_core(struct sk_buff *skb, bool pfmemalloc)
  3 {
  4     struct packet_type *ptype, *pt_prev;
  5     rx_handler_func_t *rx_handler;
  6     struct net_device *orig_dev;
  7     bool deliver_exact = false;
  8     int ret = NET_RX_DROP;
  9     __be16 type;
 10 
 11     /* 記錄收包時間,netdev_tstamp_prequeue為0,表示可能有包延遲 */
 12     net_timestamp_check(!netdev_tstamp_prequeue, skb);
 13 
 14     trace_netif_receive_skb(skb);
 15 
 16     /* 記錄收包設備 */
 17     orig_dev = skb->dev;
 18 
 19     /* 重置各層頭部 */
 20     skb_reset_network_header(skb);
 21     if (!skb_transport_header_was_set(skb))
 22         skb_reset_transport_header(skb);
 23     skb_reset_mac_len(skb);
 24 
 25     /* 
 26         留下一個節點,最后一次向上層傳遞時,
 27         不需要在inc引用,回調中會free
 28         這樣相當於少調用了一次free
 29     */
 30     pt_prev = NULL;
 31 
 32 another_round:
 33 
 34     /* 接收設備索引號 */
 35     skb->skb_iif = skb->dev->ifindex;
 36 
 37     /* 處理包數統計 */
 38     __this_cpu_inc(softnet_data.processed);
 39 
 40     /* vlan包,則去掉vlan頭 */
 41     if (skb->protocol == cpu_to_be16(ETH_P_8021Q) ||
 42         skb->protocol == cpu_to_be16(ETH_P_8021AD)) {
 43 
 44         /*
 45             這里改了三層協議,protocol指向ip等
 46             another_round不會再走這里
 47         */
 48         skb = skb_vlan_untag(skb);
 49         if (unlikely(!skb))
 50             goto out;
 51     }
 52 
 53     /* 不對數據包進行分類 */
 54     if (skb_skip_tc_classify(skb))
 55         goto skip_classify;
 56 
 57     /* prmemalloc */
 58     if (pfmemalloc)
 59         goto skip_taps;
 60 
 61 
 62     /* 下面兩個是未(指定)設備的所有協議傳遞的上層傳遞 */
 63 
 64 
 65     /* 如抓包程序未指定設備 */    
 66     /* 進行未指定設備的全局鏈表對應協議的skb上層傳遞 */
 67     list_for_each_entry_rcu(ptype, &ptype_all, list) {
 68         if (pt_prev)
 69             ret = deliver_skb(skb, pt_prev, orig_dev);
 70         pt_prev = ptype;
 71     }
 72 
 73     /* 如抓包程序指定了設備 */
 74     /* 進行指定設備的協議鏈表的skb上層傳遞 */
 75     list_for_each_entry_rcu(ptype, &skb->dev->ptype_all, list) {
 76         if (pt_prev)
 77             ret = deliver_skb(skb, pt_prev, orig_dev);
 78         pt_prev = ptype;
 79     }
 80 
 81 skip_taps:
 82 #ifdef CONFIG_NET_INGRESS
 83     if (static_key_false(&ingress_needed)) {
 84         skb = sch_handle_ingress(skb, &pt_prev, &ret, orig_dev);
 85         if (!skb)
 86             goto out;
 87 
 88         if (nf_ingress(skb, &pt_prev, &ret, orig_dev) < 0)
 89             goto out;
 90     }
 91 #endif
 92     skb_reset_tc(skb);
 93 skip_classify:
 94 
 95     /* 不支持使用pfmemalloc */
 96     if (pfmemalloc && !skb_pfmemalloc_protocol(skb))
 97         goto drop;
 98 
 99     /* 如果是vlan包 */
100     if (skb_vlan_tag_present(skb)) {
101         /* 處理prev */
102         if (pt_prev) {
103             ret = deliver_skb(skb, pt_prev, orig_dev);
104             pt_prev = NULL;
105         }
106 
107         /* 根據實際的vlan設備調整信息,再走一遍 */
108         if (vlan_do_receive(&skb))
109             goto another_round;
110         else if (unlikely(!skb))
111             goto out;
112     }
113 
114     /* 如果有注冊handler,那么調用,比如網橋模塊 */
115     rx_handler = rcu_dereference(skb->dev->rx_handler);
116     if (rx_handler) {
117         if (pt_prev) {
118             ret = deliver_skb(skb, pt_prev, orig_dev);
119             pt_prev = NULL;
120         }
121         switch (rx_handler(&skb)) {
122             /* 已處理,無需進一步處理 */
123         case RX_HANDLER_CONSUMED:
124             ret = NET_RX_SUCCESS;
125             goto out;
126             /* 修改了skb->dev,在處理一次 */
127         case RX_HANDLER_ANOTHER:
128             goto another_round;
129             /* 精確傳遞到ptype->dev == skb->dev */
130         case RX_HANDLER_EXACT:
131             deliver_exact = true;
132             /* 正常傳遞即可 */
133         case RX_HANDLER_PASS:
134             break;
135         default:
136             BUG();
137         }
138     }
139 
140     /* 還有vlan標記,說明找不到vlanid對應的設備 */
141     if (unlikely(skb_vlan_tag_present(skb))) {
142         /* 存在vlanid,則判定是到其他設備的包 */
143         if (skb_vlan_tag_get_id(skb))
144             skb->pkt_type = PACKET_OTHERHOST;
145         /* Note: we might in the future use prio bits
146          * and set skb->priority like in vlan_do_receive()
147          * For the time being, just ignore Priority Code Point
148          */
149         skb->vlan_tci = 0;
150     }
151 
152     /* 設置三層協議,下面提交都是按照三層協議提交的 */
153     type = skb->protocol;
154 
155     /* deliver only exact match when indicated */
156     /* 未設置精確發送,則向未指定設備的指定協議全局發送一份 */
157     if (likely(!deliver_exact)) {
158         deliver_ptype_list_skb(skb, &pt_prev, orig_dev, type,
159                        &ptype_base[ntohs(type) &
160                            PTYPE_HASH_MASK]);
161     }
162 
163     /* 指定設備的,向原設備上層傳遞  */
164     deliver_ptype_list_skb(skb, &pt_prev, orig_dev, type,
165                    &orig_dev->ptype_specific);
166 
167     /*  當前設備與原設備不同,向當前設備傳遞 */
168     if (unlikely(skb->dev != orig_dev)) {
169         deliver_ptype_list_skb(skb, &pt_prev, orig_dev, type,
170                        &skb->dev->ptype_specific);
171     }
172 
173     if (pt_prev) {
174         if (unlikely(skb_orphan_frags(skb, GFP_ATOMIC)))
175             goto drop;
176         else
177             /*
178                 使用pt_prev這里就不需要deliver_skb來inc應用數了
179                 func執行內部會free,減少了一次skb_free
180             */
181             /* 傳遞到上層*/
182             ret = pt_prev->func(skb, skb->dev, pt_prev, orig_dev);
183     } else {
184 drop:
185         if (!deliver_exact)
186             atomic_long_inc(&skb->dev->rx_dropped);
187         else
188             atomic_long_inc(&skb->dev->rx_nohandler);
189         kfree_skb(skb);
190         /* Jamal, now you will not able to escape explaining
191          * me how you were going to use this. :-)
192          */
193         ret = NET_RX_DROP;
194     }
195 
196 out:
197     return ret;
198 }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM