网络设备

PCI设备

很多网络设备都是基于PCI接口的。因此尽管网络设备驱动比较特殊,但也要作为PCI驱动注册到内核中。

PCI接口等定义、网络设备驱动相关定义涉及以下文件:

include/linux/mod_devicetable.h 定义导出到用户控件的PCI设备信息

include/linux/pci.h 定义PCI接口驱动相关的结构、宏等

include/linux/netdevice.h 定义网络设备结构、宏等

include/linux/inetdevice.h 定义IPV4专用的网络设备相关的结构、宏等

net/core/dev.c 网络设备注册、输入和输出等接口

net/ethernet/eth.c 以太网网络设备驱动程序专用接口

net/core/link_watch.c 网络设备连接状态通知

drivers/net/e100.c e100驱动程序

PCI驱动程序相关结构

1、pci_device_id结构

#define PCI_ANY_ID (~0)

struct pci_device_id {
	__u32 vendor, device;		/* Vendor and device ID or PCI_ANY_ID*/
	__u32 subvendor, subdevice;	/* Subsystem ID's or PCI_ANY_ID */
	__u32 class, class_mask;	/* (class,subclass,prog-if) triplet */
	kernel_ulong_t driver_data;	/* Data private to the driver */
};

标准PCI设备中都有一个配置寄存器,用来存放各种参数,其中的vendorID(厂商ID)、deviceID(设备ID)、class(类代号)、subsystem vendorID(子系统厂商ID)和subsystem deviceID(子系统设备ID)是我们关注的。

vendor为厂商ID,用于标识硬件制造商。PCI Special Interest Group维护一个全球厂商的编号注册表,制造商必须申请一个唯一的编号并写入到设备的vendorID寄存器中。例如,每个Intel设备都会被标识为相同的厂商编号0x8086

device为设备ID,由制造商自己设置。

设备ID与厂商ID配对生成一个唯一的32位硬件设备标识符,驱动程序通常依靠此标识符来识别设备。

2、pci_driver结构

struct pci_driver {
	struct list_head node;
	char *name;
	const struct pci_device_id *id_table;	/* must be non-NULL for probe to be called */
	int  (*probe)  (struct pci_dev *dev, const struct pci_device_id *id);	/* New device inserted */
	void (*remove) (struct pci_dev *dev);	/* Device removed (NULL if not a hot-plug capable driver) */
	int  (*suspend) (struct pci_dev *dev, u32 state);	/* Device suspended */
	int  (*resume) (struct pci_dev *dev);	                /* Device woken up */
	int  (*enable_wake) (struct pci_dev *dev, u32 state, int enable);   /* Enable wake event */

	struct device_driver	driver;
	struct pci_dynids dynids;
};

pci_driver结构用来描述一个PCI设备,因此所有的PCI驱动都必须创建一个pci_driver结构的实例,用来向PCI设备管理模块描述PCI驱动程序。

name 驱动程序名,在内核中所有PCI驱动程序名都是唯一的,通常被设置为和驱动程序模块相同的名字

id_table 指向pci_device_id结构数组的指针

probe 指向PCI驱动中的probe函数指针。当有驱动被添加到内核时,会调用此接口进行设备的初始化。

以e100为例来说明驱动程序的注册过程。

static struct pci_device_id e100_id_table[] = {
	{0x8086, 0x1229, PCI_ANY_ID, PCI_ANY_ID, 0, 0, },
	{0x8086, 0x2449, PCI_ANY_ID, PCI_ANY_ID, 0, 0, },
	{0x8086, 0x1059, PCI_ANY_ID, PCI_ANY_ID, 0, 0, },
	{0x8086, 0x1209, PCI_ANY_ID, PCI_ANY_ID, 0, 0, },
  	{0x8086, 0x1029, PCI_ANY_ID, PCI_ANY_ID, 0, 0, },
	{0x8086, 0x1030, PCI_ANY_ID, PCI_ANY_ID, 0, 0, },
	{0x8086, 0x1031, PCI_ANY_ID, PCI_ANY_ID, 0, 0, },
	{0x8086, 0x1032, PCI_ANY_ID, PCI_ANY_ID, 0, 0, },
	{0x8086, 0x1033, PCI_ANY_ID, PCI_ANY_ID, 0, 0, },
	{0x8086, 0x1034, PCI_ANY_ID, PCI_ANY_ID, 0, 0, },
	{0x8086, 0x1038, PCI_ANY_ID, PCI_ANY_ID, 0, 0, },
	{0x8086, 0x1039, PCI_ANY_ID, PCI_ANY_ID, 0, 0, },
	{0x8086, 0x103A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, },
	{0x8086, 0x103B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, },
	{0x8086, 0x103C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, },
	{0x8086, 0x103D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, },
	{0x8086, 0x103E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, },
	{0x8086, 0x1050, PCI_ANY_ID, PCI_ANY_ID, 0, 0, },
	{0x8086, 0x1051, PCI_ANY_ID, PCI_ANY_ID, 0, 0, },
	{0x8086, 0x1052, PCI_ANY_ID, PCI_ANY_ID, 0, 0, },
	{0x8086, 0x1053, PCI_ANY_ID, PCI_ANY_ID, 0, 0, },
	{0x8086, 0x1054, PCI_ANY_ID, PCI_ANY_ID, 0, 0, },
	{0x8086, 0x1055, PCI_ANY_ID, PCI_ANY_ID, 0, 0, },
	{0x8086, 0x2459, PCI_ANY_ID, PCI_ANY_ID, 0, 0, },
	{0x8086, 0x245D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, },
	{0,} /* This has to be the last entry*/
};
MODULE_DEVICE_TABLE(pci, e100_id_table);

static struct pci_driver e100_driver = {
	.name         = "e100",
	.id_table     = e100_id_table,
	.probe        = e100_found1,
	.remove       = __devexit_p(e100_remove1),
#ifdef CONFIG_PM
	.suspend      = e100_suspend,
	.resume       = e100_resume,
#endif
};

static int __init
e100_init_module(void)
{
	int ret;
        ret = pci_module_init(&e100_driver);

	if(ret >= 0) {
#ifdef CONFIG_PM
		register_reboot_notifier(&e100_notifier_reboot);
#endif
	}

	return ret;
}

static void __exit
e100_cleanup_module(void)
{
#ifdef CONFIG_PM
	unregister_reboot_notifier(&e100_notifier_reboot);
#endif 

	pci_unregister_driver(&e100_driver);
}

module_init(e100_init_module);
module_exit(e100_cleanup_module);

e100_id_table是e100驱动程序的pci_device_id结构类型列表。由module_init可知,e100_init_module()为e100驱动的初始化接口,在模块装载到内核中时被调用。

与网络设备相关的数据结构

1、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.
	 */
	char			name[IFNAMSIZ];
	/*
	 *	I/O specific fields
	 *	FIXME: Merge these and struct ifmap into one
	 */
	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;	/* Selectable AUI, TP,..*/
	unsigned char		dma;		/* DMA channel		*/
	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;
	int			iflink;
	struct net_device_stats* (*get_stats)(struct net_device *dev);
        ...
}

net_device结构是网络驱动及接口层中最重要的结构,其中不但描述了接口方面的信息,还包括硬件信息,致使该结构很大很复杂。将接口和驱动完全整合在一起也许是设计上的失误。

net_device结构的成员大致可以分为以下几类:

硬件信息成员变量:与网络设备相关的底层硬件信息,如果是虚拟网络设备驱动,则这部分信息无效。

接口信息成员变量:本节介绍有关接口方面的信息,这些信息主要是为其他硬件类型的setup()而设置的。对以太网来说是ether_setup(),以太网设备利用该函数设置大部分成员。

设备操作接口变量:设备的接口主要提供操作数据或控制设备的一些功能,如发送数据包的接口、激活和关闭设备的接口等。在这些接口中,有些是必须的,而有些是可选的,这与设备提供的特性有关。

辅助成员变量

每个设备都是自定义的私有数据结构,net_device结构全局链表可能链接不同长度的结点。

分配说明如下:

1、当调用alloc_netdev()分配net_device结构时,与具体驱动程序有关的驱动程序私有数据块长度被传递给alloc_netdev(),alloc_netdev()追加私有数据块到net_device接口实例的尾部。

2、dev_base和net_device的next指针指向net_device接口的开始,而不是指向已分配块的开始。初始填充长度保存在dev->padded字段,该字段允许内核在适当的时候释放整个内存块。

网络设备的注册

设备注册的时机

1、加载网络设备驱动程序

2、插入可热插拔网络设备

分配net_device结构空间

1、alloc_netdev()

网络设备由net_device结构定义,每个net_device结构实例代表一个网络设备,该结构的实例由alloc_netdev()分配空间

/**
 *	alloc_netdev - allocate network device
 *	@sizeof_priv:	size of private data to allocate space for
 *	@name:		device name format string
 *	@setup:		callback to initialize device
 *
 *	Allocates a struct net_device with private data area for driver use
 *	and performs basic initialization.
 */
struct net_device *alloc_netdev(int sizeof_priv, const char *name,
		void (*setup)(struct net_device *))
{
	void *p;
	struct net_device *dev;
	int alloc_size;

	/* ensure 32-byte alignment of both the device and private area */
	alloc_size = (sizeof(*dev) + NETDEV_ALIGN_CONST) & ~NETDEV_ALIGN_CONST;
	alloc_size += sizeof_priv + NETDEV_ALIGN_CONST;

	p = kmalloc(alloc_size, GFP_KERNEL);
	if (!p) {
		printk(KERN_ERR "alloc_dev: Unable to allocate device.\n");
		return NULL;
	}
	memset(p, 0, alloc_size);

	dev = (struct net_device *)
		(((long)p + NETDEV_ALIGN_CONST) & ~NETDEV_ALIGN_CONST);
	dev->padded = (char *)dev - (char *)p;

	if (sizeof_priv)
		dev->priv = netdev_priv(dev);

	setup(dev);
	strcpy(dev->name, name);
	return dev;
}

2、ether_setup()

绝大多数普通的网络设备类型,都会用一个特定的xxx_setup()初始化net_device实例的配置函数字段,这对所有的设备都是一样的。在alloc_etherdev()中,将ether_setup()作为第三个输入参数传给alloc_netdev(),ether_setup()就是以太网设备的xxx_setup()

/*
 * Fill in the fields of the device structure with ethernet-generic values.
 */
void ether_setup(struct net_device *dev)
{
	dev->change_mtu		= eth_change_mtu;
	dev->hard_header	= eth_header;
	dev->rebuild_header 	= eth_rebuild_header;
	dev->set_mac_address 	= eth_mac_addr;
	dev->hard_header_cache	= eth_header_cache;
	dev->header_cache_update= eth_header_cache_update;
	dev->hard_header_parse	= eth_header_parse;

	dev->type		= ARPHRD_ETHER;
	dev->hard_header_len 	= ETH_HLEN;
	dev->mtu		= 1500; /* eth_mtu */
	dev->addr_len		= ETH_ALEN;
	dev->tx_queue_len	= 1000;	/* Ethernet wants good queues */
	dev->flags		= IFF_BROADCAST|IFF_MULTICAST;

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

}

网络设备注册过程

以e100为例

注册过程并不是简单地把net_device结构实例插入到全局链表或相关散列表中,还包括初始化net_device结构实例的部分成员,产生一个广播形式通知通知其他内核组件其已经注册的消息,以及其他任务。

最终调用register_netdevice注册网络设备,并将网络设备描述符注册到系统中。完成注册后,会发送NETDEV_REGISTER消息到netdev_chain通知连中,使得所有对注册感兴趣的模块都能接收消息。

注册设备的状态迁移

网络设备通过regiseter_netdev()和unregister_netdev()注册与注销。在注册、注销以及释放过程中,伴随着网络设备注册状态的迁移。

1、网络设备的初始化状态为UNINITIALIZED,在调用register_netdev()完成注册后,状态便迁移到REGISTERED

2、处于REGISTERED状态的网络设备,通过unregister_netdev()注销后,迁移到UNREGISTERING状态。同时net_device的两个虚拟init()和uninit()在注册和注销后分别初始化和清除私有数据。

3、在衔接操作中,设备真正被注销要到所有对该实例的相关引用都释放时才执行,netdev_wait_allrefs()直到条件满足才会返回,此时状态迁移到UNINITIALIZED。

4、注销后的网络设备在调用free_netdev()后,释放之前,状态迁移到RELEASED。

设备注册状态通知

内核其他模块和用户空间应用程序可能都想知道网络设备注册、注销、打开、关闭的时间,因此提供两个产生时间通知的途径,即netdev_chain通知链和netlink的RTMGRP_LINK组播组。内核模块只要注册到netdev_chain通知链上,网络设备的相关事件都会通知该模块,而用户控件应用程序只要注册到netlink的RTMGRP_LINK组播组,网络设备事件也会通知到该应用程序。

1、netdev_chain通知链

内核模块可以通过register_netdevice_notifier()将处理网络设备事件的函数注册到netdev_chain通知链中,之后可以通过unregister_netdevice_notifier()注销。并且可以对一个或多个事件感兴趣。需要注意的是,注册到通知链时,register_netdevice_notifier()会将以前的NETDEV_REGISTER和NETDEV_UP通知重发给系统中当前注册的模块

2、netlink链接通知

当设备状态或配置改变时,通知被发送到连接组播组RTMGRP_LINK。事实上,那些发送到组播组RTMGRP_LINK的通知也是由netdev_chain通知链驱动的,为了能及时通知netlink链,在netdev_chain通知链页注册了一个实例,通过该实例发送通知到netlink链上

网络设备的注销

设备注销时机

1、卸载网络设备驱动程序

2、移除热插拔网络设备

网络设备注销过程

1、unregister_netdevice()

为例注销网络设备,内核和相关的网络设备驱动程序需要撤销所有注册时执行的操作,以及下列操作:

a)通过dev_close()禁止网络设备

b)释放所有分配的资源,如IRQ、I/O内存、I/O端口等

c)从全局队列dev_base、dev_name_head和dev_index_head散列表中移除net_device实例

d)一旦实例的引用为0,就释放net_device实例、驱动程序私有数据结构及其他连接到它的内存块。netdevice实例由free_netdev()释放,如果内核编译支持sysfs,free_netdev()会让sysfs来负责释放。

e)移除添加到proc和sys文件系统的任何文件

2、衔接操作:netdev_run_todo()

net_device结构实例的改变受rtnl_mutex原子变量的保护,在修改net_device实例前后需要调用rtnl_lock()和rtnl_unlock()。

一旦unregister_netdevice()完成了它的工作,会通过net_set_todo()将完成注销的net_device结构加入到net_todo_list中,这个链表包含了注销已经结束的设备。由于互斥变量net_todo_run_mutex控制了其串行化,因此在同一时刻仅能有一个CPU运行netdev_run_todo()。

netdev_run_todo函数用来处理队列net_todo_list上的网络设备,继续处理相关的注销事物。主要是注销sysfs中该设备的节点。注销时,等待设备的引用计数为0,在调用设备自身的destructor,完成注销过程

网络设备的启用

设备一旦注册后即可使用,但必须在用户或用户空间应用程序使能后才能收发数据。因为注册到系统中的网络设备初始状态是关闭的,此时是不能传输数据的,必须激活后,网络设备才能进行数据的传输。在应用层,可以通过ifconfig up命令(最终是通过ioctl的SIOCSIFFLAGS)来激活网络设备。而SIOCSIFFLAGS命令是通过dev_change_flags()调用dev_open()来激活网络设备。

dev_open将网络设备从关闭状态转到激活状态,并发送一个NETDEV_UP消息到网络设备状态改变通知链上。

/**
 *	dev_open	- prepare an interface for use.
 *	@dev:	device to open
 *
 *	Takes a device from down to up state. The device's private open
 *	function is invoked and then the multicast lists are loaded. Finally
 *	the device is moved into the up state and a %NETDEV_UP message is
 *	sent to the netdev notifier chain.
 *
 *	Calling this function on an active interface is a nop. On a failure
 *	a negative errno code is returned.
 */
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
	 */
	set_bit(__LINK_STATE_START, &dev->state);
	if (dev->open) {
		ret = dev->open(dev);
		if (ret)
			clear_bit(__LINK_STATE_START, &dev->state);
	}

 	/*
	 *	If it went open OK then:
	 */

	if (!ret) {
		/*
		 *	Set the flags.
		 */
		dev->flags |= IFF_UP;

		/*
		 *	Initialize multicasting status
		 */
		dev_mc_upload(dev);

		/*
		 *	Wakeup transmit queue engine
		 */
		dev_activate(dev);

		/*
		 *	... and announce new interface.
		 */
		notifier_call_chain(&netdev_chain, NETDEV_UP, dev);
	}
	return ret;
}

网络设备的禁用

网络设备一旦关闭后就不能传输数据了,网络设备能被用户命令明确地或被其他事件隐含地禁止。在应用层,可以通过ifconfig down命令(最终是通过ioctl的SIOCSIFFLAGS)来关闭设备,或者在网络设备注销时被禁止。SIOCSIFFLAGS命令通过dev_change_flags(),根据网络设备当前状态来确定调用dev_close()关闭网络设备。

dev_close()将网络设备从激活状态转换到关闭状态,并发送NETDEV_GOING_DOWN和NETDEV_DOWN消息到网络设备状态改变通知链上

/**
 *	dev_close - shutdown an interface.
 *	@dev: device to shutdown
 *
 *	This function moves an active device into down state. A
 *	%NETDEV_GOING_DOWN is sent to the netdev notifier chain. The device
 *	is then deactivated and finally a %NETDEV_DOWN is sent to the notifier
 *	chain.
 */
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);

	/* Synchronize to scheduled poll. We cannot touch poll list,
	 * it can be even on different cpu. So just clear netif_running(),
	 * and wait when poll really will happen. Actually, the best place
	 * for this is inside dev->stop() after device stopped its irq
	 * engine, but this requires more changes in devices. */

	smp_mb__after_clear_bit(); /* Commit netif_running(). */
	while (test_bit(__LINK_STATE_RX_SCHED, &dev->state)) {
		/* No hurry. */
		current->state = TASK_INTERRUPTIBLE;
		schedule_timeout(1);
	}

	/*
	 *	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;

	/*
	 * Tell people we are down
	 */
	notifier_call_chain(&netdev_chain, NETDEV_DOWN, dev);

	return 0;
}

网络设备

时间: 2024-09-28 23:01:57

网络设备的相关文章

网络设备-批量自动配置备份软件Kiwi cattools使用介绍

先说下,以往常见配置备份和变更后,运维工程师的痛点.维护的设备越多越容易出错.几台还勉强能做好,一旦体量超过20台以上后,很多配置备份都会或多或少出现不少问题. 所以这里也特意挑了一款软件,简单的聊聊这工具确实不错.上菜,各位注意!! 安装文档,和安装软件,暂时不贴出来.拒绝伸手党.!!!! Kiwi cattools 网络设备配置备份管理软件操作文档 第一步:如下为打开界面一览. 第二步:现在开始新增设备(Juniper-SSG140)为例:点击Add PS:还是能支持很多类型的,如下所示 D

zabbix自动监控网络设备juniper防火墙

1.配置juniper防火墙SNMP 登陆到juniper页面或使用SSH链接配置,此处使用web界面配置 1)定位到Configuration > Report Settings > SNMP,配置端口管理信息如图 2)点击New Community创建团体名,配置版本等,如图: 3)在Host IP Address/Netmask填写链接IP地址和子网,选择版本,点击Add添加 4)定位到Network > Interfaces (List)选择链接接口编辑,勾选允许snmp链接 到

物理层、数据链路层网络设备工作原理

物理层网络设备有中继器.集线器. 中继器的功能是将接收到的信号进行再放大然后传输出去,作用是将扩展网络设备信号传输的物理范围,缺点是扩大数据信号的同时也扩大的噪声,不能够进行广播隔离,网络利用率很低,现在基本上已经被淘汰. 集线器实际上可以理解为有多个端口的中继器,集线器的所有端口共享一条背板总线,故所有端口都在同一个冲突域,网络利用率低,基本已经淘汰. 数据链路层网络设备有网桥.交换机. 网桥工作在数据链路层,能够通过源主机的mac地址,自学习创建自己的"mac-端口"表,一旦这个&

浅谈 Linux 内核开发之网络设备驱动

网络设备介绍 网络设备是计算机体系结构中必不可少的一部分,处理器如果想与外界通信,通常都会选择网络设备作为通信接口.众所周知,在 OSI(Open Systems Interconnection,开放网际互连)中,网络被划分为七个层次,从下到上分别是物理层.数据链路层.网络层.传输层.会话层.表示层和应用层.我们所讲的网络设备也包括两个层次,一层叫做 MAC(Media Access Control)层,对应于 OSI 的数据链路层:另一层叫做 PHY(Physical Layer)层,对应于物

zabbix通过自动发现功能实现自动识别网络设备接口

由于之前网络设备不是很多,监控网络设备接口就直接使用模版中的item来实现了,可是现在公司上线了一大批网络设备,如果要每个网络设备都做模板,添加item......那就该废了,于是迫于压力今天来测试使用zabbix的自动发现功能实现自动发现网络设备接口,并且自动获取接口的流量值,生成流量图等功能. 这样的话就能节省大量时间,时间就是生命啊,把时间浪费在枯燥的添加网络接口的工作上就是在浪费生命!好了,废话不多说,进入正题: 首先,在交换机上面配置好snmp协议,为了简单,这里目前使用的是snmp

从veth看虚拟网络设备的qdisc

背景 前段时间在测试docker的网络性能的时候,发现了一个veth的性能问题,后来给docker官方提交了一个PR,参考set tx_queuelen to 0 when create veth device,引起了一些讨论.再后来,RedHat的网络专家Jesper Brouer 出来详细的讨论了一下这个问题. 可以看到,veth设备qdisc队列,而环回设备/桥接设备是没qdisc队列的,参考br_dev_setup函数. 内核实现 在注册(创建)设备时,qdisc设置为noop_qdis

网络设备驱动程序框架

1网络设备驱动程序框架可以分为四层 网络协议接口层----------------------------------------------------------------------------------------------------------数据的发送                                                                数据的接收                      hard_start_xmit(struct

Zabbix如何监控网络设备

最近一直在做网络设备的监控,包括switch,firewall,netscaler等网络设备的流量和性能监控.所有的监控软件(nagios,zenoss,zabbix等)监控网络设备都是通过SNMP协议进行监控的,提起SNMP协议,大家首先要明白几个关于SNMP概念: 1)SNMP(Simple Network Management Protocol)简单网络管理协议.由一组网络管理的标准组成,网络管理员可以通过SNMP协议采集和查看网络设备运行信息.目前SNMP版本有SNMPv1,SNMPv2

网络设备之侦测连接状态

通常,网络设备会定时地侦测设备是否处于可传递状态.当状态发生变化时,会调用netif_carrier_on或者netif_carrier_off来通知内核: 从网上设备插拔网线或者另一端的设备关闭或禁止,都会导致连接状态改变: netif_carrier_on----设备驱动侦测到设备传递信号时调用 netif_carrier_off----设备驱动侦测到设备丢失信号时调用 上述两个状态改变函数均会调用linkwatch_fire_event将事件加入到事件队列进行调度: (netif_carr

linux网络设备无法启动问题处理

之前安装了一台CentOS操作系统测试Nginx负载均衡,后来很久没用.有一次同事升级了VM,最近又想在上面测试KeepAlived,于是,服务里连接不上了. 开始查找原因,一直傻傻的更改ifcfg-eth0配置文件,重启 network 的时候确总是提示 找不到设备 eth0,于是使用 ifconfig -a 命令查看了下当前所有的网络设备,发现确实不存在 eth0,但是确多出来一个 eth1,难道名称变了?不管这么多了,重新配吧. 于是乎我直接修改ifcfg-eth0的配置,将device更