Chinaunix首页 | 论坛 | 博客
  • 博客访问: 539730
  • 博文数量: 120
  • 博客积分: 3030
  • 博客等级: 中校
  • 技术积分: 1445
  • 用 户 组: 普通用户
  • 注册时间: 2006-03-05 01:00
文章存档

2011年(1)

2009年(2)

2008年(32)

2007年(33)

2006年(52)

我的朋友

分类: LINUX

2006-04-06 18:20:47

  从分析uip代码,到学习设备驱动 ,到分析linux网络原码,俺这么些天这么辛苦 ,其实是为了解决如何将自己的私有协议栈跟linux系统紧密的进行衔接的问题 ,这其中涉及网卡的收发数据 ,阻塞的处理 ,协议的实现(基本就是状态机)等。今天终于觉得好像可以将这些东东贯穿到一起了 。
  底层协议栈跟驱动的接口是netif_rx ,实际的数据处理是在botton half 函数net_rx_action 函数中进行的 ,下面我们对net_rx_action 进行分析 。不好意思不知道netif_rx的,看不懂什么是botton_half的恕俺不详细解答 。说了也没有用呵呵 ,不是一下子能够说明白的 ,虽然俺也不太懂呵呵
  首先还是有必要介绍一下net_device结构 ,这个结构包含了网络设备的各种信息 ,有些类似于一个类 ,其中有很多属性和方法 ,其中有一个poll方法要特别注意
 
 static void net_rx_action(struct softirq_action *h)
{
 int this_cpu = smp_processor_id();
 struct softnet_data *queue = &softnet_data[this_cpu];
 unsigned long start_time = jiffies;
 int budget = netdev_max_backlog;  ;/*表示队列的最大长度*/
 br_read_lock(BR_NETPROTO_LOCK);
/*禁止中断*/
 local_irq_disable();
/*检查POLL队列(poll_list)上是否有设备在准备等待轮询取得数据*/
 while (!list_empty(&queue->poll_list)) {
  struct net_device *dev;
/*这里保证执行当前的 POLL 过程的时间不超过一个时间片,这样不至于被软中断占用太多的时间*/
  if (budget <= 0 || jiffies - start_time > 1)
   goto softnet_break;
//开中断
  local_irq_enable();
/*从公共的 softnet_data 数据结构中的轮循队列上获得等待轮循的设备结构*/
  dev = list_entry(queue->poll_list.next, struct net_device,
poll_list);
 
   /*调用设备的POLL方法从NIC上的Ring Buffer中读入数据*/
  if (dev->quota <= 0 || dev->poll(dev, &budget)) {
   //因为要对poll_list进行操作这个操作也不能被中断所以要关中断
   local_irq_disable();
   /*完成一次POLL过程的数据的接收,重新定义设备接收数据的"配额"
(事实上就是sk_buff缓冲区的数量,每次调用POLL方法的时候可以创建并且最
多可以向上层提交的sk_buff缓冲区数目,这个参数很重要在高速处理的时候有需要慎重优化这个数值,在有大量数据接收的情况下,需要增加该数值)*/

   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 {
   dev_put(dev);
   local_irq_disable();
  }
 }
 
 local_irq_enable();
 //完成更新放开中断

 br_read_unlock(BR_NETPROTO_LOCK);
 return;
softnet_break: //如果上次操作被中断 ,再来一次
 netdev_rx_stat[this_cpu].time_squeeze++;
 __cpu_raise_softirq(this_cpu, NET_RX_SOFTIRQ);
 local_irq_enable();
 br_read_unlock(BR_NETPROTO_LOCK);
}
 
dev->poll_list好像是指向第几个设备
真正的数据处理是在poll中进行的 。poll方法在net_dev_init的时候被指定为process_backlog ,这个函数就在net_rx_action紧挨的上方,它调用netif_receive_skb对skb数据进行了接收
  这个是俺第一次的分析 ,可能有些地方不清楚或者错误的地方 ,以后会慢慢的修改
希望大家指出问题呵呵
 
增加1 :
/*#define list_entry(ptr, type, member) \
 ((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))
如果将函数定义写成
#define list_entry(ptr, type, member) \
 ((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member -0))) 将好理解很多 ,对于一个固定的结构体,其各个成员之间偏移是固定的,该函数用在知道一个结构体的成员地址 ,需要得到这个结构体的地址的时候 ,此处用来得到ptr的所有者的地址
*/
 
 
阅读(3925) | 评论(4) | 转发(2) |
给主人留下些什么吧!~~