网络驱动移植之网络子系统设备处理层的初始化

    内核源码:linux-2.6.38.8.tar.bz2

 

    网络子系统设备处理层的初始化大致会完成以下各种任务:

 网络驱动移植之网络子系统设备处理层的初始化_第1张图片

    (1)、在/proc/net目录下创建四个proc条目(分别为dev、softnet_stat、ptype和wireless) 

/* linux-2.6.38.8/net/core/dev.c */
static int __init dev_proc_init(void)
{
	return register_pernet_subsys(&dev_proc_ops);
}

static struct pernet_operations __net_initdata dev_proc_ops = {
	.init = dev_proc_net_init,
	.exit = dev_proc_net_exit,
};

static int __net_init dev_proc_net_init(struct net *net)
{
	int rc = -ENOMEM;

	if (!proc_net_fops_create(net, "dev", S_IRUGO, &dev_seq_fops))
		goto out;
	if (!proc_net_fops_create(net, "softnet_stat", S_IRUGO, &softnet_seq_fops))
		goto out_dev;
	if (!proc_net_fops_create(net, "ptype", S_IRUGO, &ptype_seq_fops))
		goto out_softnet;

	if (wext_proc_init(net))
		goto out_ptype;
	rc = 0;
out:
	return rc;
out_ptype:
	proc_net_remove(net, "ptype");
out_softnet:
	proc_net_remove(net, "softnet_stat");
out_dev:
	proc_net_remove(net, "dev");
	goto out;
}

    其中两个主要函数的定义如下: 

/* linux-2.6.38.8/fs/proc/proc_net.c */
struct proc_dir_entry *proc_net_fops_create(struct net *net,
	const char *name, mode_t mode, const struct file_operations *fops)
{
	return proc_create(name, mode, net->proc_net, fops);
}

void proc_net_remove(struct net *net, const char *name)
{
	remove_proc_entry(name, net->proc_net);
}

    net->proc_net的值在proc文件系统初始化函数proc_root_init所调用的proc_net_init函数中被初始化为字符串”/proc/net”,也就是说这两个函数主要用于在/proc/net目录下创建和删除proc条目。

    (2)、创建sysfs文件系统的net类 

/* linux-2.6.38.8/net/core/net-sysfs.c */
int netdev_kobject_init(void)
{
	kobj_ns_type_register(&net_ns_type_operations);
	register_pernet_subsys(&kobj_net_ops);
	return class_register(&net_class);
}

    即会创建/sys/class/net目录,在此目录下,每个已注册的网络设备都会有一个子目录。

    (3)、接收数据包类型的链表的初始化 

/* linux-2.6.38.8/net/core/dev.c */
	INIT_LIST_HEAD(&ptype_all);
	for (i = 0; i < PTYPE_HASH_SIZE; i++)
		INIT_LIST_HEAD(&ptype_base[i]);

    其中变量ptype_all和ptype_base以及宏PTYPE_HASH_SIZE的定义如下: 

#define PTYPE_HASH_SIZE	(16)
static struct list_head ptype_base[PTYPE_HASH_SIZE] __read_mostly;
static struct list_head ptype_all __read_mostly;

    以下图片来自《Understanding Linux Network Internals》:

 网络驱动移植之网络子系统设备处理层的初始化_第2张图片

    (4)、网络设备全局列表以及两个哈希表的初始化 

/* linux-2.6.38.8/net/core/dev.c */
	if (register_pernet_subsys(&netdev_net_ops))
		goto out;

static struct pernet_operations __net_initdata netdev_net_ops = {
	.init = netdev_init,
	.exit = netdev_exit,
};

static int __net_init netdev_init(struct net *net)
{
	INIT_LIST_HEAD(&net->dev_base_head);

	net->dev_name_head = netdev_create_hash();
	if (net->dev_name_head == NULL)
		goto err_name;

	net->dev_index_head = netdev_create_hash();
	if (net->dev_index_head == NULL)
		goto err_idx;

	return 0;

err_idx:
	kfree(net->dev_name_head);
err_name:
	return -ENOMEM;
}

    根据设备名称和设备索引号搜寻网络设备的哈希表如下图( 图片来自《Understanding Linux NetworkInternals》):

 网络驱动移植之网络子系统设备处理层的初始化_第3张图片

    (5)、初始化数据包接收队列 

/* linux-2.6.38.8/net/core/dev.c */
for_each_possible_cpu(i) {
		struct softnet_data *sd = &per_cpu(softnet_data, i);

		memset(sd, 0, sizeof(*sd));
		skb_queue_head_init(&sd->input_pkt_queue);
		skb_queue_head_init(&sd->process_queue);
		sd->completion_queue = NULL;
		INIT_LIST_HEAD(&sd->poll_list);
		sd->output_queue = NULL;
		sd->output_queue_tailp = &sd->output_queue;
#ifdef CONFIG_RPS
		sd->csd.func = rps_trigger_softirq;
		sd->csd.info = sd;
		sd->csd.flags = 0;
		sd->cpu = i;
#endif

		sd->backlog.poll = process_backlog;
		sd->backlog.weight = weight_p;
		sd->backlog.gro_list = NULL;
		sd->backlog.gro_count = 0;
	}

    对于多CPU的系统来说,每个CPU都有一个各自的接收队列,并且使用各自的softnet_data结构体变量*sd来管理网络数据包的收发流量(通过per_cpu函数)。

    初始化两个sk_buff_head结构体变量process_queue和input_pkt_queue。 

    (6)、注册网络命令空间设备,确保loopback设备在所有网络设备中最先出现和最后消失 

/* linux-2.6.38.8/net/core/dev.c */
	if (register_pernet_device(&loopback_net_ops))
		goto out;

	if (register_pernet_device(&default_device_ops))
		goto out;

    (7)、分别注册网络设备数据包接收和发送的软中断处理程序 

/* linux-2.6.38.8/net/core/dev.c */
	open_softirq(NET_TX_SOFTIRQ, net_tx_action);
	open_softirq(NET_RX_SOFTIRQ, net_rx_action);

    (8)、注册回调处理函数dev_cpu_callback 

/* linux-2.6.38.8/net/core/dev.c */
	hotcpu_notifier(dev_cpu_callback, 0);

    (9)、协议无关目的缓存(Protocol independent destination cache)相关函数的初始化 

/* linux-2.6.38.8/net/core/dst.c */
void __init dst_init(void)
{
	register_netdevice_notifier(&dst_dev_notifier);
}

    (10)、在/proc/net目录下创建proc条目dev_mcast 

/* linux-2.6.38.8/net/core/dev_addr_lists.c */
static int __net_init dev_mc_net_init(struct net *net)
{
	if (!proc_net_fops_create(net, "dev_mcast", 0, &dev_mc_seq_fops))
		return -ENOMEM;
	return 0;
}

static void __net_exit dev_mc_net_exit(struct net *net)
{
	proc_net_remove(net, "dev_mcast");
}

static struct pernet_operations __net_initdata dev_mc_net_ops = {
	.init = dev_mc_net_init,
	.exit = dev_mc_net_exit,
};

void __init dev_mcast_init(void)
{
	register_pernet_subsys(&dev_mc_net_ops);
}

你可能感兴趣的:(网络,struct,list,action,callback,DST)