网络子系统22_队列规则传输接口

//	调用路径:
//		1.dev_queue_xmit->qdisc_run
//		2.net_tx_action->qdisc_run

//	对于dev->tx_queue_len !=0 的设备,都会有一个与之关联的队列规则,按照队列规则,调用dev->hard_start_xmit

1.1 static inline void qdisc_run(struct net_device *dev)
{
	//设备传输队列没有被关闭,即__LINK_STATE_XOFF没有被设置
	//结合规则队列完成传输
	while (!netif_queue_stopped(dev) && qdisc_restart(dev) < 0);
}

//	结合设备关联的队列规则,完成数据传输
//	调用路径:qdisc_run->qdisc_restart

//	返回值:	=0  - queue is empty.
//			>0  - queue is not empty, but throttled.
//			<0  - queue is not empty. Device is throttled, if dev->tbusy != 0.

//	函数流程:
//		1.使用队列规则出队skb
//		2.对dev->xmit_lock加锁
//		3.检测死锁与冲突;
//			3.1 死锁:锁已被占用,占用者为本cpu,释放skb,返回
//			3.2 冲突:锁被占用,非本cpu,重入队skb,重调度设备
//		4.设置锁的拥有者为本cpu
//		5.对dev->queue_lock解锁
//		6.向ETH_P_ALL类型l3协议传递此skb
//		7.通过驱动程序hard_start_xmit完成传输
//		8.对dev->queue_lock加锁
//		9.对dev->xmit_lock解锁
1.2 int qdisc_restart(struct net_device *dev)
{
	//与设备相关的队列规则
	struct Qdisc *q = dev->qdisc;
	struct sk_buff *skb;

	//从规则队列出队skb
	if ((skb = q->dequeue(q)) != NULL) {
		//驱动特性:NETIF_F_LLTX,表明驱动在被调用hard_start_xmit时不需要上锁
		unsigned nolock = (dev->features & NETIF_F_LLTX);

		if (!nolock) {//需要上锁
			if (!spin_trylock(&dev->xmit_lock)) {//锁已经被获取
				collision:
					//死锁:
					//	锁被占用,但是拥有者为本cpu,将skb丢掉,直接返回-1
					if (dev->xmit_lock_owner == smp_processor_id()) {
						kfree_skb(skb);
						return -1;
					}

					//冲突:
					//	将skb重新入队
					goto requeue;
			}
			//获取锁,将锁的拥有者设置为本cpu
			dev->xmit_lock_owner = smp_processor_id();
		}

		{
			spin_unlock(&dev->queue_lock);
			if (!netif_queue_stopped(dev)) {//设备可以进行传输
				int ret;
				//netdev_nit表示ETH_P_ALL类型l3协议的个数
				if (netdev_nit)
					dev_queue_xmit_nit(skb, dev);
				//由驱动程序完成传输
				ret = dev->hard_start_xmit(skb, dev);
				if (ret == NETDEV_TX_OK) {
					if (!nolock) {
						dev->xmit_lock_owner = -1;
						spin_unlock(&dev->xmit_lock);
					}
					spin_lock(&dev->queue_lock);
					return -1;
				}
				if (ret == NETDEV_TX_LOCKED && nolock) {
					spin_lock(&dev->queue_lock);
					goto collision;
				}
			}

			if (!nolock) {
				dev->xmit_lock_owner = -1;
				spin_unlock(&dev->xmit_lock);
			}
			spin_lock(&dev->queue_lock);
			q = dev->qdisc;
		}

requeue:
		//将skb重新入队
		q->ops->requeue(skb, q);
		//调度设备
		netif_schedule(dev);
		return 1;
	}
	//返回规则队列中剩余的skb个数
	return q->q.qlen;
}
时间: 2024-08-02 05:53:08

网络子系统22_队列规则传输接口的相关文章

网络子系统5_设备队列规则

// 1.设备描述符与队列规则相关的字段: // 1.1 dev->tx_queue_len 指示驱动程序规则队列的队列长度,在注册设备时使用,通知核心是否为设备提供队列规则机制. // 1.1.1 不适用队列规则=0 // 1.1.2 使用队列规则>0 // 1.2 dev->qdisc,执行设备传输时,qdisc_run,dev_queue_xmit始终通过该字段获取设备当前使用的队列规则. // 1.3 dev->qdisc_sleep, 保存设备具备传输能力时,使用的设备队

网络子系统7_l2、l3接口

// 调用路径: // 1.NAPI设备的poll函数->netif_receive_skb // 2.积压设备的process_backlog函数->netif_receive_skb // 参数: // skb,驱动程序已经去掉了以太帧最后的四字节crc32,skb->mac.raw指向mac头,skb->data,skb->nh指向l3帧头 // 函数主要任务: // 1.处理netpoll衔接点 // 2.更新时间戳,dev的统计信息 // 3.处理bonding衔接

网络子系统21_传输接收软中断的触发

//参考 深入理解linux网络技术内幕 //设备接收数据的调度 //在由驱动程序提供的数据接收中断中: // 1.非napi设备使用netif_rx向上传递skb // 2.napi设备使用netif_rx_schedule //设备发送数据的调度 // 调度只针对具有队列规则的设备,在qdisc_run中如果无法获得xmit_lock锁,则通过规则队列重新入队skb,在net_tx_action中,获取queue_lock失败,调度设备 // 对于不使用队列规则的设备,直接通过dev_que

网络子系统20_传输接收软中断

// 数据帧接收软中断处理函数 // 调用路径:do_softirq->net_rx_action // 函数主要任务: // 1.在关中断情况下检查调度队列poll_list是否有设备接收到入口帧,然后开中断 // 2.单次运行处理的入口帧不能超过netdev_max_backlog=300,运行时间不能超过1个jiffies // 3.依次遍历调度队列poll_list // 4.如果设备配额以用完,或者设备驱动的poll函数表明仍然有入口数据帧 // 4.1 将设备重新添加poll_lis

网络子系统30_桥接子系统通用接口

// 添加网桥设备 // 参数: // name,需要全局唯一 // 调用路径:socket ioctl->br_add_bridge // 函数主要任务: // 1.创建一个新的网络设备 // 2.初始化网络设备的通用字段以及网桥设备的字段 // 3.向系统注册网络设备 1.1 int br_add_bridge(const char *name) { struct net_device *dev;//net_bridge->dev int ret; dev = new_bridge_dev

Linux内核分析(四)----进程管理|网络子系统|虚拟文件系统|驱动简介

原文:Linux内核分析(四)----进程管理|网络子系统|虚拟文件系统|驱动简介 Linux内核分析(四) 两天没有更新了,上次博文我们分析了linux的内存管理子系统,本来我不想对接下来的进程管理子系统.网络子系统.虚拟文件系统在这个阶段进行分析的,但是为了让大家对内核有个整体的把握,今天还是简单的介绍一下剩余的几个子系统,我们对这几个子系统的分析,只要了解其作用和部分内容即可,不必深究,等我们写上几个驱动,到时候按照驱动再来分析这几个子系统我们就清晰多了. 在http://www.cnbl

网络子系统31_网络设备的注册与注销

// 网络设备注册 // 内核中,使用两个全局的hash表,索引net_device,分别为name hash表,index hash表,使用一个链表dev_base,链接所有net_device // 包裹函数,获取rtnl锁,注册任务由register_netdev完成 1.1 int register_netdev(struct net_device *dev) { int err; //获取rtnl锁 rtnl_lock(); //执行注册 err = register_netdevic

Linux TC 带宽管理队列规则

      在着手学习TC之前,请先了解TC采用如下单位来描述带宽:       mbps = 1024 kbps = 1024 * 1024 bps => byte/s       mbit = 1024 kbit => kilo bit/s       mb = 1024 kb = 1024 * 1024 b => byte       mbit = 1024 kbit => kilo bit       内定:数值以bps和b方式储存.但当设置tc输出速率时,使用如下表示:

网络子系统6_设备开启与关闭

// 网络设备开启 // 函数主要任务: // 1.设置dev->state=__LINK_STATE_START // 2.调用驱动程序的回调函数open // 3.设置dev->flags |= IFF_UP表示设备开启 // 4.更新多播列表, // 5.激活设备 // 6.通知监听器,设置dev->flags // 设备开启之后应该具备的特征: // 1.dev->state, 表示设备可以进行传输接收 // 2.dev->flags,表示设备已经开启 // 3.设备