linux 内核 网络设备接口数据结构

1.net_device{}结构

网络设备接口使用数据结构net_device,系统中所有网络接口都有一个对应的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
	 * the interface.
	 */
   /*
    *网络接口名字。在系统中网络接口有独一无二的名称。如果name的第一个字符为NULL,name系统就会在
    *register_netdev函数中给他分配一个序号,而针对不同类型的名称前缀,整合起来就是整个网络接口的
    *名称。比如说对以太网接口设备来说,所有以太网接口的前缀都是‘eth’,如果序号为0(就是第一个接
    *口),name它的名称就是‘eth0’。
    */
	char			name[IFNAMSIZ];
	/*
	 *	I/O specific fields
	 *	FIXME: Merge these and struct ifmap into one
	 */
    //这些都是IO操作需要的成员变量
	unsigned long		rmem_end;	/* shmem "recv" end	*/
	unsigned long		rmem_start;	/* shmem "recv" start	*/
	unsigned long		mem_end;	/* shared mem end	*/
	unsigned long		mem_start;	/* shared mem start	*/
	unsigned long		base_addr;	/* device I/O address	*/
	unsigned int		irq;		/* device IRQ number	*/

	/*
	 *	Some hardware also needs these fields, but they are not
	 *	part of the usual set specified in Space.c.
	 */

	unsigned char		if_port;	/* 一般用来区分相同类型的网卡的不同网络类型*/
	unsigned char		dma;		/*表示目前在使用的DMA通道,		*/

	unsigned long		state;//网卡的状态

	struct net_device	*next;//构建链表使用的
	
	/* The device initialization function. Called only once. */
    /* 检测网络接口的存在,并且做一些初始化操作。如果这个函数调用不成功,
     * 表示网络设备不存在,或者没有检测到,如果成功,表示可以正常使用。
     * 编写网络接口驱动程序的第一步就是实现这个函数指针,用来探测网络接口。
     */
	int			(*init)(struct net_device *dev);

	/* ------- Fields preinitialized in Space.c finish here ------- */

	struct net_device	*next_sched;//指向下一个准备接受调度的网卡接口设备

	/* Interface index. Unique device identifier	*/
	int			ifindex;//在系统中网络接口具有唯一的表示索引,使用dev_new_index函数生成这些索引。
	int			iflink;//如果生成了索引,iflink也设置成ifindex的值,否则ifindex为-1,表示该结构没有通过索引进行管理。

    /*获取网络接口状态的函数指针。这些状态信息主要用于统计接口数据。在系统运行时,网络接口的一些
     *信息,如接收的字节数、发送的字节数、丢包的数据包个数等等信息,都存放在一个私有的数据结构中
     *(下面会讲到priv成员),这些数据可以通过netstat -i 命令获取这些信息。因为对于无线连接的接
     *口,需要测定的状态信息与一般网络接口有很大不同,因此还有get_wireless_stats函数来获取这
     *些数据信息。
     */
	struct net_device_stats* (*get_stats)(struct net_device *dev);
	struct iw_statistics*	(*get_wireless_stats)(struct net_device *dev);

	/*
	 * This marks the end of the "visible" part of the structure. All
	 * fields hereafter are internal to the system, and may change at
	 * will (read: may be cleaned up at will).
	 */

	/* These may be needed for future network-power-down code. */
	unsigned long		trans_start;	/* 最后一次发送数据的时间*/
	unsigned long		last_rx;	/* 最后一个接收数据的时间	*/

	unsigned short		flags;	/* 网络接口的特性。IFF_LOOPBACK	*/
	unsigned short		gflags;
	unsigned		mtu;	/* 是该接口可以接受的MTU值		*/
	unsigned short		type;	/* 接口的媒质类型	*/
	unsigned short		hard_header_len;	/* 数据包中硬件头的大小, 16字节 对齐	*/
	void			*priv;	/* 保存接口私有数据的指针	*/

	struct net_device	*master; /* Pointer to master device of a group,
					  * which this device is member of.
					  */

	/* Interface address info. */
    //接口的地址信息
	unsigned char		broadcast[MAX_ADDR_LEN];	/* hw bcast add	*/
	unsigned char		pad;		/* make dev_addr aligned to 8 bytes */
	unsigned char		dev_addr[MAX_ADDR_LEN];	/* hw address	*/
	unsigned char		addr_len;	/* hardware address length	*/
    //多播的Mac地址
	struct dev_mc_list	*mc_list;	/* Multicast mac addresses	*/
	int			mc_count;	/* Number of installed mcasts	*/
	int			promiscuity;//表示该接口是否工作在混杂模式
	int			allmulti;//是否是接收所有的多播数据包

	int			watchdog_timeo;//监控定时器相关
	struct timer_list	watchdog_timer;

	/* Protocol specific pointers */
	/*与具体协议相关的指针.表示与该网络接口相关的上层处理网络协议是哪个。如果说在IP层如果使用
     *ipv4的网络协议传输的话,将ip_ptr初始化(in_device结构)
     */
	void 			*atalk_ptr;	/* AppleTalk link 	*/
	void			*ip_ptr;	/* IPv4 specific data	*/  
	void                    *dn_ptr;        /* DECnet specific data */
	void                    *ip6_ptr;       /* IPv6 specific data */
	void			*ec_ptr;	/* Econet specific data	*/
    //服务质量,对网络传输的排队做了多种排列方法
	struct Qdisc		*qdisc;
	struct Qdisc		*qdisc_sleeping;
	struct Qdisc		*qdisc_list;
	struct Qdisc		*qdisc_ingress;
	unsigned long		tx_queue_len;	/* Max frames per queue allowed */

	/* hard_start_xmit synchronizer */
	spinlock_t		xmit_lock;
	/* cpu id of processor entered to hard_start_xmit or -1,
	   if nobody entered there.
	 */
	int			xmit_lock_owner;
	/* device queue lock */
	spinlock_t		queue_lock;
	/* Number of references to this device */
	atomic_t		refcnt;
	/* The flag marking that device is unregistered, but held by an user */
	int			deadbeaf;

	/* Net device features */
	int			features;//表示网络接口可能在硬件实现的一些特殊功能
#define NETIF_F_SG		1	/* Scatter/gather IO. */
#define NETIF_F_IP_CSUM		2	/* Can checksum only TCP/UDP over IPv4. */
#define NETIF_F_NO_CSUM		4	/* Does not require checksum. F.e. loopack. */
#define NETIF_F_HW_CSUM		8	/* Can checksum all the packets. */
#define NETIF_F_DYNALLOC	16	/* Self-dectructable device. */
#define NETIF_F_HIGHDMA		32	/* Can DMA to high memory. */
#define NETIF_F_FRAGLIST	1	/* Scatter/gather IO. */

	/* Called after device is detached from network. */
	void			(*uninit)(struct net_device *dev);
	/* Called after last user reference disappears. */
	void			(*destructor)(struct net_device *dev);

	/* Pointers to interface service routines.	*/
	int			(*open)(struct net_device *dev);
	int			(*stop)(struct net_device *dev);
	int			(*hard_start_xmit) (struct sk_buff *skb,
						    struct net_device *dev);//发送数据函数指针
	int			(*hard_header) (struct sk_buff *skb,
						struct net_device *dev,
						unsigned short type,
						void *daddr,
						void *saddr,
						unsigned len);
	int			(*rebuild_header)(struct sk_buff *skb);
#define HAVE_MULTICAST			 
	void			(*set_multicast_list)(struct net_device *dev);
#define HAVE_SET_MAC_ADDR  		 
	int			(*set_mac_address)(struct net_device *dev,
						   void *addr);
#define HAVE_PRIVATE_IOCTL
	int			(*do_ioctl)(struct net_device *dev,
					    struct ifreq *ifr, int cmd);
#define HAVE_SET_CONFIG
	int			(*set_config)(struct net_device *dev,
					      struct ifmap *map);
#define HAVE_HEADER_CACHE
	int			(*hard_header_cache)(struct neighbour *neigh,
						     struct hh_cache *hh);
	void			(*header_cache_update)(struct hh_cache *hh,
						       struct net_device *dev,
						       unsigned char *  haddr);
#define HAVE_CHANGE_MTU
	int			(*change_mtu)(struct net_device *dev, int new_mtu);

#define HAVE_TX_TIMEOUT
	void			(*tx_timeout) (struct net_device *dev);

	int			(*hard_header_parse)(struct sk_buff *skb,
						     unsigned char *haddr);
	int			(*neigh_setup)(struct net_device *dev, struct neigh_parms *);
	int			(*accept_fastpath)(struct net_device *, struct dst_entry*);

	/* open/release and usage marking */
	struct module *owner;//指向该网络设备使用的模块方式的驱动程序的module结构。

	/* bridge stuff */
	struct net_bridge_port	*br_port;//网桥的设置

#ifdef CONFIG_NET_FASTROUTE
#define NETDEV_FASTROUTE_HMASK 0xF
	/* Semi-private data. Keep it at the end of device struct. */
	rwlock_t		fastpath_lock;
	struct dst_entry	*fastpath[NETDEV_FASTROUTE_HMASK+1];//快速转发的信息
#endif
#ifdef CONFIG_NET_DIVERT
	/* this will get initialized at each interface type init routine */
	struct divert_blk	*divert;
#endif /* CONFIG_NET_DIVERT */
};

2.net_device对应操作函数

注册与注销

注册与注销过程分别通过register_netdev和unregister_netdev函数完成。

register_netdev

/*用来向系统登记网络接口的函数,在这个函数中需要分配给网络接口在系统中惟一的名称,并且将该网络接口
 *设备添加到系统管理的链表dev_base中进行管理
 */
int register_netdev(struct net_device *dev)
{
	int err;

	rtnl_lock();//并发控制

	/*
	 *	If the name is a format string the caller wants us to
	 *	do a name allocation
	 */
	 
	if (strchr(dev->name, '%'))
	{
		err = -EBUSY;
        /*
         *给该设备分配一个合适的索引名称。基本原理是在当前已经注册的网络接口链表中寻找第一个没有
         *被分配的适合该网络接口的设备索引号,然后根据这个索引和传入的前缀结合,成为网络接口名
         *称。
         */
		if(dev_alloc_name(dev, dev->name)<0)
			goto out;
	}
	
	/*
	 *	Back compatibility hook. Kill this one in 2.5
	 */
	//兼容操作,如果第一个字符为0或者空格,就假定传给dev_alloc_name的参数前缀为eth,即以太网卡类型
	if (dev->name[0]==0 || dev->name[0]==' ')
	{
		err = -EBUSY;
		if(dev_alloc_name(dev, "eth%d")<0)
			goto out;
	}
		
		
	err = -EIO;
	if (register_netdevice(dev))//完成这个网络接口添加到dev_base链表中的任务。
		goto out;

	err = 0;

out:
	rtnl_unlock();
	return err;
}

register_netdev=>register_netdevice

/*
 * 实际的注册设备过程
 */
int register_netdevice(struct net_device *dev)
{
	struct net_device *d, **dp;
#ifdef CONFIG_NET_DIVERT
	int ret;
#endif

	spin_lock_init(&dev->queue_lock);
	spin_lock_init(&dev->xmit_lock);
	dev->xmit_lock_owner = -1;
#ifdef CONFIG_NET_FASTROUTE
	dev->fastpath_lock=RW_LOCK_UNLOCKED;
#endif
    /*判断全局变量dev_boot_phase的值。默认值为1,在系统启动的时候调用net_dev_init已经将变量
     *设为0了,说明在内核启动初始化的过程已经结束。在为1的情况下才会执行这段代码。在内核启动检测
     *时,对dev_base中的每一个节点都检测一遍,不存在的网络设备节点删除,不存在在内核启动的方式
     *下在dev_base中增加节点的情况。为了开发者方便,register_netdev并不是专门为模块方式设计
     *的。在开发驱动程序时,可以在内核启动检测结束之前,自己增加代码,检测特殊网卡,然后调用
     *register_netdev将这种新的网络接口设备结构注册。这种情况下才会进入到这段代码。
     */
	if (dev_boot_phase) {
#ifdef CONFIG_NET_DIVERT
		ret = alloc_divert_blk(dev);
		if (ret)
			return ret;
#endif /* CONFIG_NET_DIVERT */
		
		/* This is NOT bug, but I am not sure, that all the
		   devices, initialized before netdev module is started
		   are sane. 

		   Now they are chained to device boot list
		   and probed later. If a module is initialized
		   before netdev, but assumes that dev->init
		   is really called by register_netdev(), it will fail.

		   So that this message should be printed for a while.
		 */
        //打印提前检测网络设备的信息
		printk(KERN_INFO "early initialization of device %s is deferred\n", dev->name);

		/* Check for existence, and append to tail of chain */
        //遍历dev_base链表,检查是否已存在,存在报错。
		for (dp=&dev_base; (d=*dp) != NULL; dp=&d->next) {
			if (d == dev || strcmp(d->name, dev->name) == 0) {
				return -EEXIST;
			}
		}
        //插入链表,尾部
		dev->next = NULL;
		write_lock_bh(&dev_base_lock);
		*dp = dev;
		dev_hold(dev);
		write_unlock_bh(&dev_base_lock);

		/*
		 *	Default initial state at registry is that the
		 *	device is present.
		 */

		set_bit(__LINK_STATE_PRESENT, &dev->state);//将state置位

		return 0;
	}

#ifdef CONFIG_NET_DIVERT
	ret = alloc_divert_blk(dev);
	if (ret)
		return ret;
#endif /* CONFIG_NET_DIVERT */
	
	dev->iflink = -1;

	/* Init, if this function is available */
	if (dev->init && dev->init(dev) != 0)//调用该接口的init函数来检测和初始化网络接口
		return -EIO;

	dev->ifindex = dev_new_index();//初始化接口索引
	if (dev->iflink == -1)
		dev->iflink = dev->ifindex;//拷贝索引

	/* Check for existence, and append to tail of chain */
    //逻辑和特殊网络设备一样
	for (dp=&dev_base; (d=*dp) != NULL; dp=&d->next) {
		if (d == dev || strcmp(d->name, dev->name) == 0) {
			return -EEXIST;
		}
	}
	/*
	 *	nil rebuild_header routine,
	 *	that should be never called and used as just bug trap.
	 */

	if (dev->rebuild_header == NULL)
		dev->rebuild_header = default_rebuild_header;

	/*
	 *	Default initial state at registry is that the
	 *	device is present.
	 */

	set_bit(__LINK_STATE_PRESENT, &dev->state);

	dev->next = NULL;
	dev_init_scheduler(dev);
	write_lock_bh(&dev_base_lock);
	*dp = dev;
	dev_hold(dev);
	dev->deadbeaf = 0;
	write_unlock_bh(&dev_base_lock);

	/* Notify protocols, that a new device appeared. */
    //通知链相关。通知所有的协议,新增加了一个网络设备接口
	notifier_call_chain(&netdev_chain, NETDEV_REGISTER, dev);
	net_run_sbin_hotplug(dev, "register");

	return 0;
}

unregister_netdev

void unregister_netdev(struct net_device *dev)
{
	rtnl_lock();
	unregister_netdevice(dev);//注销一个网络接口设备
	rtnl_unlock();
}

unregister_netdev=>unregister_netdevice


/**
 *	用来停止一个网络接口设备的工作,并且把它从dev_base链表中删除
 */
int unregister_netdevice(struct net_device *dev)
{
	unsigned long now, warning_time;
	struct net_device *d, **dp;

	/* If device is running, close it first. */
	if (dev->flags & IFF_UP)//如果这个设备是激活状态,调用dev_close先关闭这个设备
		dev_close(dev);

	BUG_TRAP(dev->deadbeaf==0);
	dev->deadbeaf = 1;

	/* And unlink it from device chain. */
	for (dp = &dev_base; (d=*dp) != NULL; dp=&d->next) {//从链表中删除
		if (d == dev) {
			write_lock_bh(&dev_base_lock);
			*dp = d->next;
			write_unlock_bh(&dev_base_lock);
			break;
		}
	}
	if (d == NULL) {//不存在,打印错误信息,返回。
		printk(KERN_DEBUG "unregister_netdevice: device %s/%p never was registered\n", dev->name, dev);
		return -ENODEV;
	}

	/* Synchronize to net_rx_action. */
	br_write_lock_bh(BR_NETPROTO_LOCK);
	br_write_unlock_bh(BR_NETPROTO_LOCK);
    //在dev_boot_phase 为0的情况下才能运行这段代码。表示在启动初始化完成之后才能继续这段注销网卡设备的过程。
	if (dev_boot_phase == 0) {
#ifdef CONFIG_NET_FASTROUTE
		dev_clear_fastroute(dev);
#endif

		/* Shutdown queueing discipline. */
		dev_shutdown(dev);//将接口关闭

		net_run_sbin_hotplug(dev, "unregister");

		/* Notify protocols, that we are about to destroy
		   this device. They should clean all the things.
		 */
        //调用notifier_call_chain通知netdev_chain上所有元素该接口已经注销。
		notifier_call_chain(&netdev_chain, NETDEV_UNREGISTER, dev);

		/*
		 *	Flush the multicast chain
		 */
		dev_mc_discard(dev);//更新整个多播链表
	}

	if (dev->uninit)
		dev->uninit(dev);//一般是将dev->priv中保存的和系统其他部分数据相关的指针关闭。

	/* Notifier chain MUST detach us from master device. */
	BUG_TRAP(dev->master==NULL);

#ifdef CONFIG_NET_DIVERT
	free_divert_blk(dev);
#endif
    //网卡有NETIF_F_DYNALLOC特性,不要验证refcnt的值,直接将dev空间释放就可以了
	if (dev->features & NETIF_F_DYNALLOC) {
#ifdef NET_REFCNT_DEBUG
		if (atomic_read(&dev->refcnt) != 1)
			printk(KERN_DEBUG "unregister_netdevice: holding %s refcnt=%d\n", dev->name, atomic_read(&dev->refcnt)-1);
#endif
		dev_put(dev);
		return 0;
	}

	/* Last reference is our one */
	if (atomic_read(&dev->refcnt) == 1) {
		dev_put(dev);//没有引用,直接释放
		return 0;
	}

#ifdef NET_REFCNT_DEBUG
	printk("unregister_netdevice: waiting %s refcnt=%d\n", dev->name, atomic_read(&dev->refcnt));
#endif

	/* EXPLANATION. If dev->refcnt is not now 1 (our own reference)
	   it means that someone in the kernel still has a reference
	   to this device and we cannot release it.

	   "New style" devices have destructors, hence we can return from this
	   function and destructor will do all the work later.  As of kernel 2.4.0
	   there are very few "New Style" devices.

	   "Old style" devices expect that the device is free of any references
	   upon exit from this function.
	   We cannot return from this function until all such references have
	   fallen away.  This is because the caller of this function will probably
	   immediately kfree(*dev) and then be unloaded via sys_delete_module.

	   So, we linger until all references fall away.  The duration of the
	   linger is basically unbounded! It is driven by, for example, the
	   current setting of sysctl_ipfrag_time.

	   After 1 second, we start to rebroadcast unregister notifications
	   in hope that careless clients will release the device.

	 */

	now = warning_time = jiffies;
	while (atomic_read(&dev->refcnt) != 1) {//循环将引用计数减一
		if ((jiffies - now) > 1*HZ) {//1秒检测
			/* Rebroadcast unregister notification */
			notifier_call_chain(&netdev_chain, NETDEV_UNREGISTER, dev);
		}
		current->state = TASK_INTERRUPTIBLE;
		schedule_timeout(HZ/4);
		current->state = TASK_RUNNING;
		if ((jiffies - warning_time) > 10*HZ) {//10秒检测
			printk(KERN_EMERG "unregister_netdevice: waiting for %s to "
					"become free. Usage count = %d\n",
					dev->name, atomic_read(&dev->refcnt));
			warning_time = jiffies;
		}
	}
	dev_put(dev);//释放
	return 0;
}

net_device{}基本操作

dev_put

static inline void dev_put(struct net_device *dev)
{
	if (atomic_dec_and_test(&dev->refcnt))//引用计数减一
		netdev_finish_unregister(dev);//注销dev
}

dev_put=>netdev_finish_unregister

int netdev_finish_unregister(struct net_device *dev)
{
    //保证三个指针都为空
	BUG_TRAP(dev->ip_ptr==NULL);
	BUG_TRAP(dev->ip6_ptr==NULL);
	BUG_TRAP(dev->dn_ptr==NULL);

	if (!dev->deadbeaf) {//还没有注销部分函数,打印告警,返回
		printk(KERN_ERR "Freeing alive device %p, %s\n", dev, dev->name);
		return 0;
	}
#ifdef NET_REFCNT_DEBUG
	printk(KERN_DEBUG "netdev_finish_unregister: %s%s.\n", dev->name,
	       (dev->features & NETIF_F_DYNALLOC)?"":", old style");
#endif
	if (dev->destructor)//对于某些新的网卡设备,会初始化他自己的destructor函数指针。特殊处理
		dev->destructor(dev);
	if (dev->features & NETIF_F_DYNALLOC)//有NETIF_F_DYNALLOC特性,直接释放
		kfree(dev);
	return 0;
}

通知链

在系统中网络接口的设备的数据做更新的时候,会将netdev_chain链表中的所有的元素都通知到。实现通知的方法是通知链。这里分析netdev_chain通知链。

系统中调用notifier_call_chain函数完成通知的过程,系统中调用函数register_netdevice_notifier更新netdev_chain链表的内容。这里介绍和路由相关的一些东西。fib_netdev_notifier元素的添加和更新。

struct notifier_block fib_netdev_notifier = {
	fib_netdev_event,
	NULL,
	0
};

void __init ip_fib_init(void)
{
#ifdef CONFIG_PROC_FS
	proc_net_create("route",0,fib_get_procinfo);
#endif		/* CONFIG_PROC_FS */

#ifndef CONFIG_IP_MULTIPLE_TABLES
	local_table = fib_hash_init(RT_TABLE_LOCAL);
	main_table = fib_hash_init(RT_TABLE_MAIN);
#else
	fib_rules_init();
#endif

	register_netdevice_notifier(&fib_netdev_notifier);//将fib_netdev_notifier注册到netdev_chain中
	register_inetaddr_notifier(&fib_inetaddr_notifier);
}

ip_fib_init=>register_netdevice_notifier

int register_netdevice_notifier(struct notifier_block *nb)
{
	return notifier_chain_register(&netdev_chain, nb);
}

ip_fib_init=>register_netdevice_notifier=>notifier_chain_register

int notifier_chain_register(struct notifier_block **list, struct notifier_block *n)
{
	write_lock(&notifier_lock);
	while(*list)
	{
		if(n->priority > (*list)->priority)//根据优先级添加到通知链中
			break;
		list= &((*list)->next);
	}
	n->next = *list;
	*list=n;
	write_unlock(&notifier_lock);
	return 0;
}

notifier_call_chain

int notifier_call_chain(struct notifier_block **n, unsigned long val, void *v)
{
	int ret=NOTIFY_DONE;
	struct notifier_block *nb = *n;

	while(nb)//循环遍历链表中的所有元素
	{
		ret=nb->notifier_call(nb,val,v);//调用每个元素的notifier_call函数指针,完成对本节点对应于通知的动作。
		if(ret&NOTIFY_STOP_MASK)//如果返回值中设置了NOTIFY_STOP_MASK,停止循环返回。
		{
			return ret;
		}
		nb=nb->next;
	}
	return ret;
}

notifier_call_chain=>fib_netdev_event

static int fib_netdev_event(struct notifier_block *this, unsigned long event, void *ptr)
{
	struct net_device *dev = ptr;//对应于net_device结构的指针
	struct in_device *in_dev = __in_dev_get(dev);

	if (!in_dev)
		return NOTIFY_DONE;

	switch (event) {//通知事件
	case NETDEV_UP://如果接口启动,对该dev对应的in_device结构增加对应的fib项,更新路由缓存
		for_ifa(in_dev) {
			fib_add_ifaddr(ifa);
		} endfor_ifa(in_dev);
#ifdef CONFIG_IP_ROUTE_MULTIPATH
		fib_sync_up(dev);
#endif
		rt_cache_flush(-1);
		break;
	case NETDEV_DOWN://删除fib项
		fib_disable_ip(dev, 0);
		break;
	case NETDEV_UNREGISTER://删除fib项
		fib_disable_ip(dev, 1);
		break;
	case NETDEV_CHANGEMTU:
	case NETDEV_CHANGE:
		rt_cache_flush(0);
		break;
	}
	return NOTIFY_DONE;
}

这里在NETDEV_REGISTER通知的时候,对fib_netdev_notifier并没有对应的事件发生,后面分析dev_open时可以知道,在dev_open的时候,会通知fib_netdev_notifier一个NETDEV_UP事件,更新fib项。

打开和关闭函数

dev_open


/**
 *	对所有网络接口设备打开的通用过程 
 */
int dev_open(struct net_device *dev)
{
	int ret = 0;

	/*
	 *	Is it already up?
	 */

	if (dev->flags&IFF_UP)//已经打开,直接返回
		return 0;

	/*
	 *	Is it even present?
	 */
	if (!netif_device_present(dev))//设备是否存在
		return -ENODEV;

	/*
	 *	Call device private open method
	 */
	if (try_inc_mod_count(dev->owner)) {
		if (dev->open) {
			ret = dev->open(dev);
			if (ret != 0 && dev->owner)//open失败,返回
				__MOD_DEC_USE_COUNT(dev->owner);
		}
	} else {
		ret = -ENODEV;
	}

	/*
	 *	If it went open OK then:
	 */
	 
	if (ret == 0) //open 成功
	{
		/*
		 *	Set the flags.
		 */
		dev->flags |= IFF_UP;//设置up标志

		set_bit(__LINK_STATE_START, &dev->state);//设置可以进行传输的状态

		/*
		 *	Initialize multicasting status 
		 */
		dev_mc_upload(dev);//初始化多播的地址列表

		/*
		 *	Wakeup transmit queue engine
		 */
		dev_activate(dev);//激活该设备上进行传输的数据包队列

		/*
		 *	... and announce new interface.
		 */
        //发送NETDEV_UP通知时间,表示设备打开动作完成。与前面对应
		notifier_call_chain(&netdev_chain, NETDEV_UP, dev);
	}
	return(ret);
}

dev_close

int dev_close(struct net_device *dev)
{
	if (!(dev->flags&IFF_UP))//已经关闭,返回
		return 0;

	/*
	 *	Tell people we are going down, so that they can
	 *	prepare to death, when device is still operating.
	 */
	notifier_call_chain(&netdev_chain, NETDEV_GOING_DOWN, dev);

	dev_deactivate(dev);

	clear_bit(__LINK_STATE_START, &dev->state);

	/*
	 *	Call the device specific close. This cannot fail.
	 *	Only if device is UP
	 *
	 *	We allow it to be called even after a DETACH hot-plug
	 *	event.
	 */
	 
	if (dev->stop)
		dev->stop(dev);

	/*
	 *	Device is now down.
	 */

	dev->flags &= ~IFF_UP;//清除IFF_UP标志
#ifdef CONFIG_NET_FASTROUTE
	dev_clear_fastroute(dev);
#endif

	/*
	 *	Tell people we are down
	 */
	notifier_call_chain(&netdev_chain, NETDEV_DOWN, dev);//发送NETDEV_DOWN通知事件

	/*
	 * Drop the module refcount
	 */
	if (dev->owner)
		__MOD_DEC_USE_COUNT(dev->owner);//如果网络接口是通过模块方式启动的,那么需要将这个模块的使用计数减一。

	return(0);
}

Guess you like

Origin blog.csdn.net/guoguangwu/article/details/118631942