Chinaunix首页 | 论坛 | 博客
  • 博客访问: 291051
  • 博文数量: 71
  • 博客积分: 30
  • 博客等级: 民兵
  • 技术积分: 217
  • 用 户 组: 普通用户
  • 注册时间: 2012-07-31 15:43
文章分类

全部博文(71)

文章存档

2016年(4)

2015年(2)

2014年(2)

2013年(63)

分类: LINUX

2016-05-01 11:08:34

原文地址:网络设备初始化---基础 作者:linuxDOS

    虽然做了很久的网卡驱动,熟悉npai机制,但是一直没有底气去深入内核学习,作为学习的引导书《深入理解linux网络内幕》,写点学习心得.
参考内核 linux   2.6.32.60    kernel/net/core/dev.c  
   在dev.c 中我们知道其实它是作为一个网络中间层,往下接驱动,往上接tcp/ip协议. 它是一个神奇的桥梁. 这里我们简单的分析它的初始化函数:
  static int __init net_dev_init(void)


点击(此处)折叠或打开

  1. /*
  2.  *    Initialize the DEV module. At boot time this walks the device list and
  3.  *    unhooks any devices that fail to initialise (normally hardware not
  4.  *    present) and leaves us with a valid list of present and active devices.
  5.  *
  6.  */

  7. /*
  8.  * This is called single threaded during boot, so no need
  9.  * to take the rtnl semaphore.
  10.  */
  11. static int __init net_dev_init(void)
  12. {
  13.     int i, rc = -ENOMEM;

  14.     BUG_ON(!dev_boot_phase);

  15.     if (dev_proc_init())
  16.         goto out;

  17.     if (netdev_kobject_init())
  18.         goto out;

  19.     INIT_LIST_HEAD(&ptype_all);
  20.     for (i = 0; i < PTYPE_HASH_SIZE; i++)
  21.         INIT_LIST_HEAD(&ptype_base[i]);

  22.     if (register_pernet_subsys(&netdev_net_ops))
  23.         goto out;

  24.     /*
  25.      *    Initialise the packet receive queues.
  26.      */

  27.     for_each_possible_cpu(i) {
  28.         struct softnet_data *queue;

  29.         queue = &per_cpu(softnet_data, i);
  30.         skb_queue_head_init(&queue->input_pkt_queue);
  31.         queue->completion_queue = NULL;
  32.         INIT_LIST_HEAD(&queue->poll_list);

  33.         queue->backlog.poll = process_backlog;
  34.         queue->backlog.weight = weight_p;
  35.         queue->backlog.gro_list = NULL;
  36.         queue->backlog.gro_count = 0;
  37.     }

  38.     dev_boot_phase = 0;

  39.     /* The loopback device is special if any other network devices
  40.      * is present in a network namespace the loopback device must
  41.      * be present. Since we now dynamically allocate and free the
  42.      * loopback device ensure this invariant is maintained by
  43.      * keeping the loopback device as the first device on the
  44.      * list of network devices. Ensuring the loopback devices
  45.      * is the first device that appears and the last network device
  46.      * that disappears.
  47.      */
  48.     if (register_pernet_device(&loopback_net_ops))
  49.         goto out;

  50.     if (register_pernet_device(&default_device_ops))
  51.         goto out;

  52.     open_softirq(NET_TX_SOFTIRQ, net_tx_action);
  53.     open_softirq(NET_RX_SOFTIRQ, net_rx_action);

  54.     hotcpu_notifier(dev_cpu_callback, 0);
  55.     dst_init();
  56.     dev_mcast_init();
  57.     rc = 0;
  58. out:
  59.     return rc;
  60. }

  61. subsys_initcall(net_dev_init);
这里我们做一个简单的分析.

先看dev_proc_init函数  它在/proc/net 下注册3个文件:

Dev  如果cat 表示输出系统所以netdevie 设备的统计信息. 而这些设备都挂着全局设备链表dev_base上.

Softnet :
#cat /proc/net/softnet_stat
0d02effd 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000f43
00010042 00000000 00000000 00000000 00000000 00000000 00000000 00000000 000009b9
000026be 00000000 00000000 00000000 00000000 00000000 00000000 00000000 0000012a
0000113e 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000054

四行表示4个CPU,
 第一列为该CPU所接收到的所有数据包, 第二列为该CPU缺省queue满的时候, 所删除的包的个数,(没有统计对于使用NAPI的adapter, 由于ring 满而导致删除的包),第三列表示time_squeeze, 就是说,一次的软中断的触发还不能处理完目前已经接收的数据,因而要设置下轮软中断,time_squeeze 就表示设置的次数.
第四--第八暂时没用, 最后一个为CPU_collision,cpu 碰撞ci数.(net/sched.c) 这些信息对分析cpu队列性能会有帮助.

ptye:
cat  输出当前内核注册网络处理协议 .

通过dev_add_pack函数注册网络协议,包类型

void dev_add_pack(struct packet_type *pt)

{

              int hash;

 

              spin_lock_bh(&ptype_lock);

              if (pt->type == htons(ETH_P_ALL))

                            list_add_rcu(&pt->list, &ptype_all);

              else {

                            hash = ntohs(pt->type) & PTYPE_HASH_MASK;

                            list_add_rcu(&pt->list, &ptype_base[hash]);

              }

              spin_unlock_bh(&ptype_lock);

}

而我们看到ptype_all 和 ptype_base链表在net_dev_init 初始化.

INIT_LIST_HEAD(&ptype_all);

         for (i = 0; i < PTYPE_HASH_SIZE; i++)

                   INIT_LIST_HEAD(&ptype_base[i]);

....
netdev_kobject_init()  在/sys/class/下注册net类 它和设备模型有关.
接下来我们看 

点击(此处)折叠或打开

  1. /**
  2.  * register_pernet_subsys - register a network namespace subsystem
  3.  *    @ops: pernet operations structure for the subsystem
  4.  *
  5.  *    Register a subsystem which has init and exit functions
  6.  *    that are called when network namespaces are created and
  7.  *    destroyed respectively.
  8.  *
  9.  *    When registered all network namespace init functions are
  10.  *    called for every existing network namespace. Allowing kernel
  11.  *    modules to have a race free view of the set of network namespaces.
  12.  *
  13.  *    When a new network namespace is created all of the init
  14.  *    methods are called in the order in which they were registered.
  15.  *
  16.  *    When a network namespace is destroyed all of the exit methods
  17.  *    are called in the reverse of the order with which they were
  18.  *    registered.
  19.  */
  20. int register_pernet_subsys(struct pernet_operations *ops)
  21. {
  22.     int error;
  23.     mutex_lock(&net_mutex);
  24.     error = register_pernet_operations(first_device, ops);
  25.     mutex_unlock(&net_mutex);
  26.     return error;
  27. }

register_pernet_subsys注册的所有的网络命名空间子系统都加入到 static struct list_head *first_device = &pernet_list;这个链表里.而它的深远意义目前不是很懂.
接着初始化cpu收发队列 ,这里是重点.

点击(此处)折叠或打开

  1. /*
  2.      *    Initialise the packet receive queues.
  3.      */

  4.     for_each_possible_cpu(i) {
  5.         struct softnet_data *queue;

  6.         queue = &per_cpu(softnet_data, i);
  7.         skb_queue_head_init(&queue->input_pkt_queue);
  8.         queue->completion_queue = NULL;
  9.         INIT_LIST_HEAD(&queue->poll_list);

  10.         queue->backlog.poll = process_backlog;
  11.         queue->backlog.weight = weight_p;
  12.         queue->backlog.gro_list = NULL;
  13.         queue->backlog.gro_count = 0;
  14.     }

对于struct softnet_data这个结构体需要单独讲解. cpu队列在以后数据收发时我们会经常见到它,看过NAPI机制的人应该更加熟悉.  
register_pernet_device(&loopback_net_ops)注册lo  回环网络设备.

open_softirq(NET_TX_SOFTIRQ, net_tx_action);
open_softirq(NET_RX_SOFTIRQ, net_rx_action);

注册收发软中断,发送中断和tc有关.  看它的调用机制就明白。 接收中断napi机制有关.
hotcpu_notifier(dev_cpu_callback, 0); 注册cpu通知链,在cpu热插拔的时候,调用回调函数.

dst_init();

注册路由通知链

dev_mcast_init();

proc/net/下创建 dev_mcast  和链路层组播相关.


阅读(2890) | 评论(0) | 转发(0) |
0

上一篇:网络数据包收发流程(一):从驱动到协议栈

下一篇:没有了

给主人留下些什么吧!~~