kernel version:2.6.32.61
对于没有自己实现poll的驱动,统一使用的是process_backlog, 这个函数会取出处于CPU队列中的包,然后执行netif_receive_skb。
对于没有自己实现poll的驱动,统一使用的是process_backlog, 这个函数会取出处于CPU队列中的包,然后执行netif_receive_skb。
这里需要注意的是,对于CPU队列操作时,需要关闭中断,因为这个队列是共享的。
net/core/dev.c
2725 static int process_backlog(struct napi_struct *napi, int quota)
2726 {
2727 int work = 0;
2728 struct softnet_data *queue = &__get_cpu_var(softnet_data);
2729 unsigned long start_time = jiffies;
2730
2731 napi->weight = weight_p;
2732 do {
2733 struct sk_buff *skb;
2734
// 出队列前关闭中断
2735 local_irq_disable();
2736 skb = __skb_dequeue(&queue->input_pkt_queue);
2737 if (!skb) {
2738 __napi_complete(napi);
2739 local_irq_enable();
2740 break;
2741 }
2742 local_irq_enable();
2743
2744 netif_receive_skb(skb);
2745 } while (++work < quota && jiffies == start_time);
2746
2747 return work;
2748 }
netif_receive_skb函数主要处理的是在进入三层协议栈之前的动作,包括入口QoS,网桥等处理,最后进入三层协议栈。
net/core/dev.c
2304 int netif_receive_skb(struct sk_buff *skb)
2305 {
2306 struct packet_type *ptype, *pt_prev;
2307 struct net_device *orig_dev;
2308 struct net_device *null_or_orig;
2309 int ret = NET_RX_DROP;
2310 __be16 type;
2311
2312 if (!skb->tstamp.tv64)
2313 net_timestamp(skb);
2314
2315 if (skb->vlan_tci && vlan_hwaccel_do_receive(skb))
2316 return NET_RX_SUCCESS;
2317
2318 /* if we've gotten here through NAPI, check netpoll */
2319 if (netpoll_receive_skb(skb))
2320 return NET_RX_DROP;
2321
2322 if (!skb->iif)
2323 skb->iif = skb->dev->ifindex;
2324
2325 null_or_orig = NULL;
2326 orig_dev = skb->dev;
2327 if (orig_dev->master) {
2328 if (skb_bond_should_drop(skb))
2329 null_or_orig = orig_dev; /* deliver only exact match */
2330 else
2331 skb->dev = orig_dev->master;
2332 }
2333
2334 __get_cpu_var(netdev_rx_stat).total++;
2335
2336 skb_reset_network_header(skb);
2337 skb_reset_transport_header(skb);
2338 skb->mac_len = skb->network_header - skb->mac_header;
2339
2340 pt_prev = NULL;
2341
2342 rcu_read_lock();
2343
// 入口QoS处理
2344 #ifdef CONFIG_NET_CLS_ACT
2345 if (skb->tc_verd & TC_NCLS) {
2346 skb->tc_verd = CLR_TC_NCLS(skb->tc_verd);
2347 goto ncls;
2348 }
2349 #endif
2350
2351 list_for_each_entry_rcu(ptype, &ptype_all, list) {
2352 if (ptype->dev == null_or_orig || ptype->dev == skb->dev ||
2353 ptype->dev == orig_dev) {
2354 if (pt_prev)
2355 ret = deliver_skb(skb, pt_prev, orig_dev);
2356 pt_prev = ptype;
2357 }
2358 }
2359
2360 #ifdef CONFIG_NET_CLS_ACT
2361 skb = handle_ing(skb, &pt_prev, &ret, orig_dev);
2362 if (!skb)
2363 goto out;
2364 ncls:
2365 #endif
2366
// 网桥处理
2367 skb = handle_bridge(skb, &pt_prev, &ret, orig_dev);
2368 if (!skb)
2369 goto out;
2370 skb = handle_macvlan(skb, &pt_prev, &ret, orig_dev);
2371 if (!skb)
2372 goto out;
2373
2374 type = skb->protocol;
2375 list_for_each_entry_rcu(ptype,
2376 &ptype_base[ntohs(type) & PTYPE_HASH_MASK], list) {
2377 if (ptype->type == type &&
2378 (ptype->dev == null_or_orig || ptype->dev == skb->dev ||
2379 ptype->dev == orig_dev)) {
2380 if (pt_prev)
2381 ret = deliver_skb(skb, pt_prev, orig_dev);
2382 pt_prev = ptype;
2383 }
2384 }
2385
2386 if (pt_prev) {
// 进入三层协议栈
2387 ret = pt_prev->func(skb, skb->dev, pt_prev, orig_dev);
2388 } else {
2389 kfree_skb(skb);
2390 /* Jamal, now you will not able to escape explaining
2391 * me how you were going to use this. :-)
2392 */
2393 ret = NET_RX_DROP;
2394 }
2395
2396 out:
2397 rcu_read_unlock();
2398 return ret;
2399 }