net_device

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

struct net init_net;
EXPORT_SYMBOL(init_net);

struct net定义了一个链表头以及两个hash表头用于快速寻找相应的net_device数据结构

struct net {
    atomic_t        passive;    /* To decided when the network
                         * namespace should be freed.
                         */
    atomic_t        count;      /* To decided when the network
                         *  namespace should be shut down.
                         */
#ifdef NETNS_REFCNT_DEBUG
    atomic_t        use_count;  /* To track references we
                         * destroy on demand
                         */
#endif
    spinlock_t      rules_mod_lock;

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

    struct proc_dir_entry   *proc_net;
    struct proc_dir_entry   *proc_net_stat;

#ifdef CONFIG_SYSCTL
    struct ctl_table_set    sysctls;
#endif

    struct sock         *rtnl;          /* rtnetlink socket */
    struct sock     *genl_sock;

    struct list_head    dev_base_head;
    struct hlist_head   *dev_name_head;
    struct hlist_head   *dev_index_head;
    unsigned int        dev_base_seq;   /* protected by rtnl_mutex */

    /* core fib_rules */
};

对应的net_device的分量如下:

struct net_device {

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

    struct pm_qos_request_list pm_qos_req;

    /* device name hash chain */
    struct hlist_node   name_hlist;
    struct list_head    dev_list;
    struct hlist_node   index_hlist;
    int         ifindex;
    ...
};

dev_base_head用于遍历:

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

struct net_device *dev_get_by_name_rcu(struct net *net, const char *name)
{
    struct hlist_node *p;
    struct net_device *dev;
    struct hlist_head *head = dev_name_hash(net, name);

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

    return NULL;
}
EXPORT_SYMBOL(dev_get_by_name_rcu);

struct net_device *dev_get_by_index_rcu(struct net *net, int ifindex)
{
    struct hlist_node *p;
    struct net_device *dev;
    struct hlist_head *head = dev_index_hash(net, ifindex);

    hlist_for_each_entry_rcu(dev, p, head, index_hlist)
        if (dev->ifindex == ifindex)
            return dev;

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

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

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

struct net_device数据结构一般在网卡驱动程序中申请注册以及卸载,卸载加载后index可能改变,

如卸载eth0对应的驱动后再重新加载后:

[ 3135.110849] dev name=lo,index=1
[ 3135.110854] dev name=wlan0,index=3
[ 3135.110858] dev name=eth0,index=4

以r8169驱动为例,调用 dev = alloc_etherdev(sizeof (*tp))函数分配net_device

struct net_device *alloc_etherdev_mqs(int sizeof_priv, unsigned int txqs,
                      unsigned int rxqs)
{
    return alloc_netdev_mqs(sizeof_priv, "eth%d", ether_setup, txqs, rxqs);
}

void ether_setup(struct net_device *dev)
{
    dev->header_ops     = ð_header_ops;
    dev->type       = ARPHRD_ETHER;
    dev->hard_header_len    = ETH_HLEN;
    dev->mtu        = ETH_DATA_LEN;
    dev->addr_len       = ETH_ALEN;
    dev->tx_queue_len   = 1000; /* Ethernet wants good queues */
    dev->flags      = IFF_BROADCAST|IFF_MULTICAST;
    dev->priv_flags     |= IFF_TX_SKB_SHARING;

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

}

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

static int list_netdevice(struct net_device *dev)
{
    struct net *net = dev_net(dev);

    ASSERT_RTNL();

    write_lock_bh(&dev_base_lock);
    list_add_tail_rcu(&dev->dev_list, &net->dev_base_head);
    hlist_add_head_rcu(&dev->name_hlist, dev_name_hash(net, dev->name));
    hlist_add_head_rcu(&dev->index_hlist,
               dev_index_hash(net, dev->ifindex));
    write_unlock_bh(&dev_base_lock);

    dev_base_seq_inc(net);

    return 0;
}


你可能感兴趣的:(linux网络)