以r8169为例
分配初始化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;
-
}
-
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;
-
}
分配初始化in_device
也是在
register_netdev函数中,该函数调用
register_netdevice,除了分配网卡名字和索引,进行其它的初始化外,还通知NETDEV_REGISTER事件
devinet_init函数中注册了ip_netdev_notifier,该数据结构如下:
-
static struct notifier_block ip_netdev_notifier = {
-
.notifier_call = inetdev_event,
-
};
如果是初次调用的话,调用
inetdev_init初始化in_device数据结构
-
static int inetdev_event(struct notifier_block *this, unsigned long event,
-
void *ptr)
-
{
-
struct net_device *dev = ptr;
-
struct in_device *in_dev = __in_dev_get_rtnl(dev);
-
-
ASSERT_RTNL();
-
-
if (!in_dev) {
-
if (event == NETDEV_REGISTER) {
-
in_dev = inetdev_init(dev);
-
if (!in_dev)
-
return notifier_from_errno(-ENOMEM);
-
if (dev->flags & IFF_LOOPBACK) {
-
IN_DEV_CONF_SET(in_dev, NOXFRM, 1);
-
IN_DEV_CONF_SET(in_dev, NOPOLICY, 1);
-
}
-
} else if (event == NETDEV_CHANGEMTU) {
-
/* Re-enabling IP */
-
if (inetdev_valid_mtu(dev->mtu))
-
in_dev = inetdev_init(dev);
-
}
-
goto out;
-
}
-
static struct in_device *inetdev_init(struct net_device *dev)
-
{
-
struct in_device *in_dev;
-
-
ASSERT_RTNL();
-
-
in_dev = kzalloc(sizeof(*in_dev), GFP_KERNEL);
-
if (!in_dev)
-
goto out;
-
memcpy(&in_dev->cnf, dev_net(dev)->ipv4.devconf_dflt,
-
sizeof(in_dev->cnf));
-
in_dev->cnf.sysctl = NULL;
-
in_dev->dev = dev;
-
in_dev->arp_parms = neigh_parms_alloc(dev, &arp_tbl);
-
if (!in_dev->arp_parms)
-
goto out_kfree;
-
if (IPV4_DEVCONF(in_dev->cnf, FORWARDING))
-
dev_disable_lro(dev);
-
/* Reference in_dev->dev */
-
dev_hold(dev);
-
/* Account for reference dev->ip_ptr (below) */
-
in_dev_hold(in_dev);
-
-
devinet_sysctl_register(in_dev);
-
ip_mc_init_dev(in_dev);
-
if (dev->flags & IFF_UP)
-
ip_mc_up(in_dev);
-
-
/* we can receive as soon as ip_ptr is set -- do this last */
-
rcu_assign_pointer(dev->ip_ptr, in_dev);
-
out:
-
return in_dev;
-
out_kfree:
-
kfree(in_dev);
-
in_dev = NULL;
-
goto out;
-
}
阅读(2271) | 评论(0) | 转发(0) |