Chinaunix首页 | 论坛 | 博客
  • 博客访问: 771111
  • 博文数量: 370
  • 博客积分: 2334
  • 博客等级: 大尉
  • 技术积分: 3222
  • 用 户 组: 普通用户
  • 注册时间: 2012-05-06 16:56
文章分类

全部博文(370)

文章存档

2013年(2)

2012年(368)

分类:

2012-05-18 11:47:44

------------------------------------------

本文系本站原创,欢迎转载!

转载请注明出处:http://ericxiao.cublog.cn/

-------------------------------------------

注意到这么庞大的结构中,有个成员叫: struct net_device  *next,呵呵,很熟悉吧,就是用它来建立网络设备的链表。

每一个网络设备启动的时候,都会调用register_netdev() (drivers/net/net_init.c)

跟踪这个函数:

int register_netdev(struct net_device *dev)

{

     int err;

 

     rtnl_lock();

 

     /*

      *   If the name is a format string the caller wants us to

      *   do a name allocation

      */

      

     if (strchr(dev->name, '%'))

     {

         err = dev_alloc_name(dev, dev->name);

         if (err < 0)

              goto out;

     }

    

     /*

      *   Back compatibility hook. Kill this one in 2.5

      */

    

     if (dev->name[0]==0 || dev->name[0]==' ')

     {

         err = dev_alloc_name(dev, "eth%d");

         if (err < 0)

              goto out;

     }

 

     err = register_netdevice(dev);

 

out:

     rtnl_unlock();

     return err;

}

 

跟踪至: register_netdevice(struct net_device *dev)  (net/core/dev.c)

int register_netdevice(struct net_device *dev)

{

     struct hlist_head *head;

     struct hlist_node *p;

     int ret;

 

     BUG_ON(dev_boot_phase);

     ASSERT_RTNL();

 

     /* When net_device's are persistent, this will be fatal. */

     BUG_ON(dev->reg_state != NETREG_UNINITIALIZED);

 

     spin_lock_init(&dev->queue_lock);

     spin_lock_init(&dev->xmit_lock);

     dev->xmit_lock_owner = -1;

#ifdef CONFIG_NET_CLS_ACT

     spin_lock_init(&dev->ingress_lock);

#endif

 

     ret = alloc_divert_blk(dev);

     if (ret)

         goto out;

 

     dev->iflink = -1;

 

     /* Init, if this function is available */

     //如果dev -> init 被赋值,那么调用此函数

     if (dev->init) {

         ret = dev->init(dev);

         if (ret) {

              if (ret > 0)

                   ret = -EIO;

              goto out_err;

         }

     }

 

     //判断name 是否合法

     if (!dev_valid_name(dev->name)) {

         ret = -EINVAL;

         goto out_err;

     }

     //为此设备分配一个index

     dev->ifindex = dev_new_index();

     if (dev->iflink == -1)

         dev->iflink = dev->ifindex;

 

     /* Check for existence of name */

 

     //所有网络设备,以名字作为哈希主键存在dev_name_head中,该变量是一个哈希数组

     //找到该名字对应的链表

     //如果内核中已经含有此名字的网络设备,出错退出

     head = dev_name_hash(dev->name);

     hlist_for_each(p, head) {

         struct net_device *d

              = hlist_entry(p, struct net_device, name_hlist);

         if (!strncmp(d->name, dev->name, IFNAMSIZ)) {

              ret = -EEXIST;

              goto out_err;

         }

     }

 

     /* Fix illegal SG+CSUM combinations. */

     if ((dev->features & NETIF_F_SG) &&

         !(dev->features & (NETIF_F_IP_CSUM |

                     NETIF_F_NO_CSUM |

                     NETIF_F_HW_CSUM))) {

         printk("%s: Dropping NETIF_F_SG since no checksum feature.\n",

                dev->name);

         dev->features &= ~NETIF_F_SG;

     }

 

     /*

      *   nil rebuild_header routine,

      *   that should be never called and used as just bug trap.

      */

 

     //rebuild_header赋默认值

     if (!dev->rebuild_header)

         dev->rebuild_header = default_rebuild_header;

 

     /*

      *   Default initial state at registry is that the

      *   device is present.

      */

 

     set_bit(__LINK_STATE_PRESENT, &dev->state);

 

     dev->next = NULL;

     dev_init_scheduler(dev);

     write_lock_bh(&dev_base_lock);

     //初始化的时候,有struct net_device **dev_tail = &dev_base;

     //这段代码的意思实际就是:把dev加入dev_base为首结点队链表的尾部

     *dev_tail = dev;

     dev_tail = &dev->next;

     //把此结点加入到以名字为哈希主键的链表数组dev_name_head

     hlist_add_head(&dev->name_hlist, head);

     //把此结点加到以序号为主键的链表数组dev_index_head

     hlist_add_head(&dev->index_hlist, dev_index_hash(dev->ifindex));

     dev_hold(dev);

     dev->reg_state = NETREG_REGISTERING;

     write_unlock_bh(&dev_base_lock);

 

     /* Notify protocols, that a new device appeared. */

     //在通知链表上发送事件

     notifier_call_chain(&netdev_chain, NETDEV_REGISTER, dev);

 

     /* Finish registration after unlock */

     net_set_todo(dev);

     ret = 0;

 

out:

     return ret;

out_err:

     free_divert_blk(dev);

     goto out;

}

 

从此可以看出。新加入一个设备时,会插入三个位置:以名字为哈希值组织的dev_name_head ,以序号为主链的哈希数组dev_index_head.还有dev_base.它为快速查找网络设备提供了基础。事实上。在内核中,经常要根据index找到dev. 或者根据name找到dev.我们遇到的时候再分析

 

到现在,我们可以在内核中顺藤摸瓜的找到每一个网络设备了。

还有很重要的。设备更改了配置,要怎么通知跟他相关的子系统呢?例如,网卡更新了IP,如何使路由得到更新?

接着往下看:

注意到上面注册代码中所调用的一个函数notifier_call_chain(&netdev_chain, NETDEV_REGISTER, dev).

该函数的作用是,在通知链表上netdev_chain上发送NETDEV_REGISTER消息,所有在与该通知链表关联的子系统都可以收到此消息。以此,可以快速的更新整个系统的配置消息。

以路由子系统为例,来讲述该过程:

IPV4子系统加载的时候,加调用ip_init(),接着调用fib_init(),然后再调用ip_fib_init()

跟踪一下此函数:

void __init ip_fib_init(void)

{

#ifndef CONFIG_IP_MULTIPLE_TABLES

     ip_fib_local_table = fib_hash_init(RT_TABLE_LOCAL);

     ip_fib_main_table  = fib_hash_init(RT_TABLE_MAIN);

#else

     fib_rules_init();

#endif

 

     register_netdevice_notifier(&fib_netdev_notifier);

     register_inetaddr_notifier(&fib_inetaddr_notifier);

}

register_netdevice_notifier是做什么的呢?往下跟踪:

int register_netdevice_notifier(struct notifier_block *nb)

{

     struct net_device *dev;

     int err;

 

     rtnl_lock();

     //注册通知链

     err = notifier_chain_register(&netdev_chain, nb);

     if (!err) {

         for (dev = dev_base; dev; dev = dev->next) {

              nb->notifier_call(nb, NETDEV_REGISTER, dev);

 

              if (dev->flags & IFF_UP)

                   nb->notifier_call(nb, NETDEV_UP, dev);

         }

     }

     rtnl_unlock();

     return err;

}

呵呵,它在netdev_chain上注册了通知链,当此链上有事件发生时,会调用fib_netdev_notifiers中的相关信息处理,看一下fib_netdev_notifier的信息:

 

struct notifier_block fib_netdev_notifier = {

     .notifier_call =fib_netdev_event,

};

 

OK,现在越来越具体了,如果netdev_chain有事件,会调用fib_netdev_event处理。继续跟踪:

static int fib_netdev_event(struct notifier_block *this, unsigned long event, void *ptr)

{

     struct net_device *dev = ptr;

     struct in_device *in_dev = __in_dev_get(dev);

     //设备注销

     if (event == NETDEV_UNREGISTER) {

         fib_disable_ip(dev, 2);

         return NOTIFY_DONE;

     }

 

     if (!in_dev)

         return NOTIFY_DONE;

 

     switch (event) {

     //设备UP

     case NETDEV_UP:

         for_ifa(in_dev) {

              fib_add_ifaddr(ifa);

         } endfor_ifa(in_dev);

#ifdef CONFIG_IP_ROUTE_MULTIPATH

         fib_sync_up(dev);

#endif

         rt_cache_flush(-1);

         break;

     //设备DOWN

     case NETDEV_DOWN:

         fib_disable_ip(dev, 0);

         break;

     //设备参数改变

     case NETDEV_CHANGEMTU:

     case NETDEV_CHANGE:

         rt_cache_flush(0);

         break;

     }

     return NOTIFY_DONE;

}

 

路由部份的代码将在后续的笔记中给出。至此,整个网络设备的架构非常的清晰了!

阅读(586) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~