Chinaunix首页 | 论坛 | 博客
  • 博客访问: 85720
  • 博文数量: 15
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 210
  • 用 户 组: 普通用户
  • 注册时间: 2014-01-05 15:27
文章分类

全部博文(15)

文章存档

2014年(15)

我的朋友

分类: LINUX

2014-01-07 22:54:08

以r8169为例

分配初始化net_device

struct net_device表示一个网卡,通过init_net串在一起(不考虑net namespace)

  1. struct net init_net;
  2. EXPORT_SYMBOL(init_net);
struct net定义了一个链表头以及两个hash表头用于快速寻找相应的net_device数据结构

  1. struct net {
  2.     atomic_t passive; /* To decided when the network
  3.                          * namespace should be freed.
  4.                          */
  5.     atomic_t count; /* To decided when the network
  6.                          * namespace should be shut down.
  7.                          */
  8. #ifdef NETNS_REFCNT_DEBUG
  9.     atomic_t use_count; /* To track references we
  10.                          * destroy on demand
  11.                          */
  12. #endif
  13.     spinlock_t rules_mod_lock;

  14.     struct list_head list; /* list of network namespaces */
  15.     struct list_head cleanup_list; /* namespaces on death row */
  16.     struct list_head exit_list; /* Use only net_mutex */

  17.     struct proc_dir_entry *proc_net;
  18.     struct proc_dir_entry *proc_net_stat;

  19. #ifdef CONFIG_SYSCTL
  20.     struct ctl_table_set sysctls;
  21. #endif

  22.     struct sock *rtnl; /* rtnetlink socket */
  23.     struct sock *genl_sock;

  24.     struct list_head dev_base_head;
  25.     struct hlist_head *dev_name_head;
  26.     struct hlist_head *dev_index_head;
  27.     unsigned int dev_base_seq; /* protected by rtnl_mutex */

  28.     /* core fib_rules */
  29. }

对应的net_device的分量如下:



  1. struct net_device {

  2.     /*
  3.      * This is the first field of the "visible" part of this structure
  4.      * (i.e. as seen by users in the "Space.c" file). It is the name
  5.      * of the interface.
  6.      */
  7.     char name[IFNAMSIZ];

  8.     struct pm_qos_request_list pm_qos_req;

  9.     /* device name hash chain */
  10.     struct hlist_node name_hlist;
  11.     struct list_head dev_list;
  12.     struct hlist_node index_hlist;
  13.     int ifindex;
  14.     ...
  15. }
dev_base_head用于遍历:

  1. #define for_each_netdev(net, d) \
  2.         list_for_each_entry(d, &(net)->dev_base_head, dev_list)
dev_name_head以及dev_index_head用于根据设备名或者index获取net_device数据结构

  1. struct net_device *dev_get_by_name_rcu(struct net *net, const char *name)
  2. {
  3.     struct hlist_node *p;
  4.     struct net_device *dev;
  5.     struct hlist_head *head = dev_name_hash(net, name);

  6.     hlist_for_each_entry_rcu(dev, p, head, name_hlist)
  7.         if (!strncmp(dev->name, name, IFNAMSIZ))
  8.             return dev;

  9.     return NULL;
  10. }

  1. struct net_device *dev_get_by_index_rcu(struct net *net, int ifindex)
  2. {
  3.     struct hlist_node *p;
  4.     struct net_device *dev;
  5.     struct hlist_head *head = dev_index_hash(net, ifindex);

  6.     hlist_for_each_entry_rcu(dev, p, head, index_hlist)
  7.         if (dev->ifindex == ifindex)
  8.             return dev;

  9.     return NULL;
  10. }
通过驱动的方式可以获取当前系统net_device的情况:

  1. struct net_device *dev_tmp;
  2.     for_each_netdev(&init_net, dev_tmp)
  3.         printk("dev name=%s,index=%d\n",dev_tmp->name,dev_tmp->ifindex)
输出如下:

  1. [ 2472.696920] dev name=lo,index=1
  2. [ 2472.696926] dev name=eth0,index=2
  3. [ 2472.696929] dev name=wlan0,index=3

struct net_device数据结构一般在网卡驱动程序中申请注册以及卸载,卸载加载后index可能改变,如卸载eth0对应的驱动后再重新加载后:

  1. [ 3135.110849] dev name=lo,index=1
  2. [ 3135.110854] dev name=wlan0,index=3
  3. [ 3135.110858] dev name=eth0,index=4
对于r8169驱动,调用 dev = alloc_etherdev(sizeof (*tp))函数分配net_device


  1. struct net_device *alloc_etherdev_mqs(int sizeof_priv, unsigned int txqs,
  2.                       unsigned int rxqs)
  3. {
  4.     return alloc_netdev_mqs(sizeof_priv, "eth%d", ether_setup, txqs, rxqs);
  5. }

  6. void ether_setup(struct net_device *dev)
  7. {
  8.     dev->header_ops = ?_header_ops;
  9.     dev->type = ARPHRD_ETHER;
  10.     dev->hard_header_len = ETH_HLEN;
  11.     dev->mtu = ETH_DATA_LEN;
  12.     dev->addr_len = ETH_ALEN;
  13.     dev->tx_queue_len = 1000; /* Ethernet wants good queues */
  14.     dev->flags = IFF_BROADCAST|IFF_MULTICAST;
  15.     dev->priv_flags |= IFF_TX_SKB_SHARING;

  16.     memset(dev->broadcast, 0xFF, ETH_ALEN);

  17. }
调用register_netdev注册,加入到链表中:

  1. static int list_netdevice(struct net_device *dev)
  2. {
  3.     struct net *net = dev_net(dev);

  4.     ASSERT_RTNL();

  5.     write_lock_bh(&dev_base_lock);
  6.     list_add_tail_rcu(&dev->dev_list, &net->dev_base_head);
  7.     hlist_add_head_rcu(&dev->name_hlist, dev_name_hash(net, dev->name));
  8.     hlist_add_head_rcu(&dev->index_hlist,
  9.                dev_index_hash(net, dev->ifindex));
  10.     write_unlock_bh(&dev_base_lock);

  11.     dev_base_seq_inc(net);

  12.     return 0;
  13. }

分配初始化in_device

也是在register_netdev函数中,该函数调用register_netdevice,除了分配网卡名字和索引,进行其它的初始化外,还通知NETDEV_REGISTER事件

  1. int register_netdevice(struct net_device *dev)
  2. {
  3.     int ret;
  4.     struct net *net = dev_net(dev);

  5.     BUG_ON(dev_boot_phase);
  6.     ASSERT_RTNL();

  7.     might_sleep();

  8.     /* When net_device's are persistent, this will be fatal. */
  9.     BUG_ON(dev->reg_state != NETREG_UNINITIALIZED);
  10.     BUG_ON(!net);

  11.     spin_lock_init(&dev->addr_list_lock);
  12.     netdev_set_addr_lockdep_class(dev);

  13.     dev->iflink = -1;

  14.     ret = dev_get_valid_name(dev, dev->name);
  15.     if (ret < 0)
  16.         goto out;

  17.     /* Init, if this function is available */
  18.     if (dev->netdev_ops->ndo_init) {
  19.         ret = dev->netdev_ops->ndo_init(dev);
  20.         if (ret) {
  21.             if (ret > 0)
  22.                 ret = -EIO;
  23.             goto out;
  24.         }
  25.     }

  26.     dev->ifindex = dev_new_index(net);
  27.     if (dev->iflink == -1)
  28.         dev->iflink = dev->ifindex;

  29.     /* Transfer changeable features to wanted_features and enable
  30.      * software offloads (GSO and GRO).
  31.      */
  32.     dev->hw_features |= NETIF_F_SOFT_FEATURES;
  33.     dev->features |= NETIF_F_SOFT_FEATURES;
  34.     dev->wanted_features = dev->features & dev->hw_features;

  35.     /* Turn on no cache copy if HW is doing checksum */
  36.     dev->hw_features |= NETIF_F_NOCACHE_COPY;
  37.     if ((dev->features & NETIF_F_ALL_CSUM) &&
  38.      !(dev->features & NETIF_F_NO_CSUM)) {
  39.         dev->wanted_features |= NETIF_F_NOCACHE_COPY;
  40.         dev->features |= NETIF_F_NOCACHE_COPY;
  41.     }

  42.     /* Make NETIF_F_HIGHDMA inheritable to VLAN devices.
  43.      */
  44.     dev->vlan_features |= NETIF_F_HIGHDMA;

  45.     ret = call_netdevice_notifiers(NETDEV_POST_INIT, dev);
  46.     ret = notifier_to_errno(ret);
  47.     if (ret)
  48.         goto err_uninit;

  49.     ret = netdev_register_kobject(dev);
  50.     if (ret)
  51.         goto err_uninit;
  52.     dev->reg_state = NETREG_REGISTERED;

  53.     __netdev_update_features(dev);

  54.     /*
  55.      *    Default initial state at registry is that the
  56.      *    device is present.
  57.      */

  58.     set_bit(__LINK_STATE_PRESENT, &dev->state);

  59.     dev_init_scheduler(dev);
  60.     dev_hold(dev);
  61.     list_netdevice(dev);

  62.     /* Notify protocols, that a new device appeared. */
  63.     ret = call_netdevice_notifiers(NETDEV_REGISTER, dev);
  64.     ret = notifier_to_errno(ret);
  65.     if (ret) {
  66.         rollback_registered(dev);
  67.         dev->reg_state = NETREG_UNREGISTERED;
  68.     }
  69.     /*
  70.      *    Prevent userspace races by waiting until the network
  71.      *    device is fully setup before sending notifications.
  72.      */
  73.     if (!dev->rtnl_link_ops ||
  74.      dev->rtnl_link_state == RTNL_LINK_INITIALIZED)
  75.         rtmsg_ifinfo(RTM_NEWLINK, dev, ~0U);

  76. out:
  77.     return ret;

  78. err_uninit:
  79.     if (dev->netdev_ops->ndo_uninit)
  80.         dev->netdev_ops->ndo_uninit(dev);
  81.     goto out;
  82. }
devinet_init函数中注册了ip_netdev_notifier,该数据结构如下:

  1. static struct notifier_block ip_netdev_notifier = {
  2.     .notifier_call = inetdev_event,
  3. };
如果是初次调用的话,调用inetdev_init初始化in_device数据结构
  1. static int inetdev_event(struct notifier_block *this, unsigned long event,
  2.              void *ptr)
  3. {
  4.     struct net_device *dev = ptr;
  5.     struct in_device *in_dev = __in_dev_get_rtnl(dev);

  6.     ASSERT_RTNL();

  7.     if (!in_dev) {
  8.         if (event == NETDEV_REGISTER) {
  9.             in_dev = inetdev_init(dev);
  10.             if (!in_dev)
  11.                 return notifier_from_errno(-ENOMEM);
  12.             if (dev->flags & IFF_LOOPBACK) {
  13.                 IN_DEV_CONF_SET(in_dev, NOXFRM, 1);
  14.                 IN_DEV_CONF_SET(in_dev, NOPOLICY, 1);
  15.             }
  16.         } else if (event == NETDEV_CHANGEMTU) {
  17.             /* Re-enabling IP */
  18.             if (inetdev_valid_mtu(dev->mtu))
  19.                 in_dev = inetdev_init(dev);
  20.         }
  21.         goto out;
  22.     }

  1. static struct in_device *inetdev_init(struct net_device *dev)
  2. {
  3.     struct in_device *in_dev;

  4.     ASSERT_RTNL();

  5.     in_dev = kzalloc(sizeof(*in_dev), GFP_KERNEL);
  6.     if (!in_dev)
  7.         goto out;
  8.     memcpy(&in_dev->cnf, dev_net(dev)->ipv4.devconf_dflt,
  9.             sizeof(in_dev->cnf));
  10.     in_dev->cnf.sysctl = NULL;
  11.     in_dev->dev = dev;
  12.     in_dev->arp_parms = neigh_parms_alloc(dev, &arp_tbl);
  13.     if (!in_dev->arp_parms)
  14.         goto out_kfree;
  15.     if (IPV4_DEVCONF(in_dev->cnf, FORWARDING))
  16.         dev_disable_lro(dev);
  17.     /* Reference in_dev->dev */
  18.     dev_hold(dev);
  19.     /* Account for reference dev->ip_ptr (below) */
  20.     in_dev_hold(in_dev);

  21.     devinet_sysctl_register(in_dev);
  22.     ip_mc_init_dev(in_dev);
  23.     if (dev->flags & IFF_UP)
  24.         ip_mc_up(in_dev);

  25.     /* we can receive as soon as ip_ptr is set -- do this last */
  26.     rcu_assign_pointer(dev->ip_ptr, in_dev);
  27. out:
  28.     return in_dev;
  29. out_kfree:
  30.     kfree(in_dev);
  31.     in_dev = NULL;
  32.     goto out;
  33. }













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

上一篇:没有了

下一篇:源设备以及源地址的选择

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