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);
}
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;
}