- 论坛徽章:
- 0
|
- static void net_rx_action(struct softirq_action *h)
- {
- /*取得当前CPU上的队列*/
- struct softnet_data *queue = &__get_cpu_var(softnet_data);
- unsigned long start_time = jiffies;
- /*netdev_max_backlog是一个sysctl常量,它决定了最大的排队等候的数据包*/
- int budget = netdev_max_backlog;
-
- local_irq_disable();
- /*处理每一个设备上接收到的数据包,直接遍历完所有的设备,其中之一,就是netif_rx函数添加进的伪设备:backlog_dev*/
- while (!list_empty(&queue->poll_list)) {
- struct net_device *dev;
- 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);
- netpoll_poll_lock(dev);
- /*调用设备的poll函数*/
- if (dev->quota <= 0 || dev->poll(dev, &budget)) {
- netpoll_poll_unlock(dev);
- local_irq_disable();
- list_del(&dev->poll_list);
- list_add_tail(&dev->poll_list, &queue->poll_list);
- if (dev->quota < 0)
- dev->quota += dev->weight;
- else
- dev->quota = dev->weight;
- } else {
- netpoll_poll_unlock(dev);
- dev_put(dev);
- local_irq_disable();
- }
- }
- out:
- local_irq_enable();
- return;
- softnet_break:
- __get_cpu_var(netdev_rx_stat).time_squeeze++;
- __raise_softirq_irqoff(NET_RX_SOFTIRQ);
- goto out;
- }
复制代码
对于软中断函数,我们主要关心的是:
遍历设备列表,取得每一个设备的poll函数,在netif_rx函数中,添加进队列的是back_log设备,它的poll函数是process_backlog。
二、process_backlog
- static int process_backlog(struct net_device *backlog_dev, int *budget)
- {
- int work = 0;
- int quota = min(backlog_dev->quota, *budget);
- /*同样地,取得当前CPU的队列*/
- 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 = __skb_dequeue(&queue->input_pkt_queue);
- if (!skb)
- goto job_done;
- local_irq_enable();
- dev = skb->dev;
- /*将从队列中取出的数据包,进一步交给上层函数处得*/
- netif_receive_skb(skb);
- dev_put(dev);
- work++;
- if (work >= quota || jiffies - start_time > 1)
- break;
- }
- backlog_dev->quota -= work;
- *budget -= work;
- return -1;
- job_done:
- backlog_dev->quota -= work;
- *budget -= work;
- list_del(&backlog_dev->poll_list);
- smp_mb__before_clear_bit();
- netif_poll_enable(backlog_dev);
- if (queue->throttle)
- queue->throttle = 0;
- local_irq_enable();
- return 0;
- }
复制代码
三、netif_receive_skb
netif_receive_skb函数最重要的工作,就是把数据包交给上层协议栈:
int netif_receive_skb(struct sk_buff *skb)
{
/*ptype和pt_prev用来遍历packet_type结构的链表,我们前面讨论过上层协议的封装与注册*/
struct packet_type *ptype, *pt_prev;
int ret = NET_RX_DROP;
unsigned short type;
/* 处理NAPI的情况*/
if (skb->dev->poll && netpoll_rx(skb))
return NET_RX_DROP;
if (!skb->stamp.tv_sec)
net_timestamp(&skb->stamp);
skb_bond(skb);
/*接收计数器累加*/
__get_cpu_var(netdev_rx_stat).total++;
/*更新传输层头和网络层头指针*/
skb->h.raw = skb->nh.raw = skb->data;
skb->mac_len = skb->nh.raw - skb->mac.raw;
pt_prev = NULL;
rcu_read_lock();
#ifdef CONFIG_NET_CLS_ACT
if (skb->tc_verd & TC_NCLS) {
skb->tc_verd = CLR_TC_NCLS(skb->tc_verd);
goto ncls;
}
#endif
/*处理混杂模式的情况*/
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;
}
}
#ifdef CONFIG_NET_CLS_ACT
if (pt_prev) {
ret = deliver_skb(skb, pt_prev);
pt_prev = NULL; /* noone else should process this after*/
} else {
skb->tc_verd = SET_TC_OK2MUNGE(skb->tc_verd);
}
ret = ing_filter(skb);
if (ret == TC_ACT_SHOT || (ret == TC_ACT_STOLEN)) {
kfree_skb(skb);
goto out;
}
skb->tc_verd = 0;
ncls:
#endif
handle_diverter(skb);
/*进入网桥*/
if (handle_bridge(&skb, &pt_prev, &ret))
goto out;
/*取得上层协议类型,这个类型值,是在网卡驱动中设置的*/
type = skb->protocol;
/*遍历每一个注册协议,调用deliver_skb函数来调用协议封装的处理函数*/
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;
}
}
if (pt_prev) {
ret = pt_prev->func(skb, skb->dev, pt_prev);
} else {
kfree_skb(skb);
/* Jamal, now you will not able to escape explaining
* me how you were going to use this.
*/
ret = NET_RX_DROP;
}
out:
rcu_read_unlock();
return ret;
}
对于IP协议而言,早已注册的处理函数是ip_recv……
未完,待续! |
|