net_rx_action函数和process_backlog函数解析(转)

网络数据包在上半部的处理通常有两种模式:传统的netif_rx模式和NAPI模式,在这里我们主要讨论网络下半部的内容,对这两种模式的机制不作涉及,但无论上半部采用何种收包模式,都会调用__netif_rx_schedule()函数,其中的调用:

__raise_softirq_irqoff(NET_RX_SOFTIRQ);

 

将触发一个类型为NET_RX_SOFTIRQ的软中断,由do_softirq()函数执行这个软中断,

对于NET_RX_SOFTIRQ类型的软中断来说,系统将其action注册为net_rx_action.

 

net_rx_action函数

 

static void net_rx_action(struct softirq_action *h)

{

       struct softnet_data *queue = &__get_cpu_var(softnet_data);

       unsigned long start_time = jiffies;

       //在这里定义了一次中断处理skb的数目,系统定义为300

       int budget = netdev_budget;

       void *have;

 

       //禁止中断

       local_irq_disable();

 

      //检查poll_list,看是否有准备等待轮询取得数据

       while (!list_empty(&queue->poll_list)) {

              struct net_device *dev;

              //轮询的处理时间不能超过一个时间片,防止一次中断处理占用太多时间

              //同时限制了处理skb的数目,超过300时,中断处理结束

              if (budget <= 0 || jiffies - start_time > 1)

                     goto softnet_break;

              //开启中断

              local_irq_enable();

 

              //取得等待轮询设备的结构

              dev = list_entry(queue->poll_list.next,

                             struct net_device, poll_list);

             

              have = netpoll_poll_lock(dev);

              //调用设备上面的poll方法,如果设备没有注册自己的poll方法,那么系统

              //将poll方法指定为process_backlog()函数

              if (dev->quota <= 0 || dev->poll(dev, &budget)) {

                     netpoll_poll_unlock(have);

                     local_irq_disable();

                     list_move_tail(&dev->poll_list, &queue->poll_list);

                     if (dev->quota < 0)

                            dev->quota += dev->weight;

                     else

                            dev->quota = dev->weight;

              } else {

                     netpoll_poll_unlock(have);

                     dev_put(dev);

                     local_irq_disable();

              }

       }

out:

       local_irq_enable();

………………………………………………………………………………………

softnet_break:

       __get_cpu_var(netdev_rx_stat).time_squeeze++;

       //在这里触发下一次中断处理

__raise_softirq_irqoff(NET_RX_SOFTIRQ);

       goto out;

}

process_backlog函数

 

前面已经说过,中断处理函数net_rx_action调用设备的poll方法(默认为process_backlog),而process_backlog函数将进一步调用netif_receive_skb()将数据包传上协议栈,如果设备自身注册了poll函数,也将调用netif_receive_skb()函数

 

static int process_backlog(struct net_device *backlog_dev, int *budget)

{

       int work = 0;

       int quota = min(backlog_dev->quota, *budget);

       struct softnet_data *queue = &__get_cpu_var(softnet_data);

       unsigned long start_time = jiffies;

      

       backlog_dev->weight = weight_p;

       for (;;) {

              struct sk_buff *skb;

              struct net_device *dev;

 

              local_irq_disable();

              //在这个循环里面,系统将调用__skb_dequeue不断从设备上取出SKB,直到

              //skb处理完为止

              skb = __skb_dequeue(&queue->input_pkt_queue);

              if (!skb)

                     goto job_done;

              local_irq_enable();

 

              dev = skb->dev;

              //netif_receive_skb的调用就在这里了

              netif_receive_skb(skb);

 

             

              dev_put(dev);

             

              //处理的skb数目+1

              work++;

             

              //如果处理的skb数目大于事先预定的最大值,或者处理的时间超过一个

              //时间片,则结束处理

              if (work >= quota || jiffies - start_time > 1)

                     break;

       }

 

       backlog_dev->quota -= work;

       *budget -= work;

       return -1;

………………………………………………………………………………………

}

 

netif_receive_skb函数在前面已经提到过,根据不同的协议调用不同的协议处理函数,

网桥的处理入口netif_receive_skb里面,针对IP协议,ip_rcv函数被调用。

 

你可能感兴趣的:(struct,list,网络,action)