IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 系统运维 -> linux硬件中断处理流程2----netif_rx -> 正文阅读

[系统运维]linux硬件中断处理流程2----netif_rx

1 netif_rx简介

netif_rx函数由常规非NAPI网络设备驱动程序在接受中断将数据包从设备缓冲区拷贝到内核空间后调用,他的主要任务是把数据帧添加到CPU的输入队列input_pkt_queue中。随后标记软中断来处理后续上传数据帧给TCP/IP协议栈。

netif_rx函数调用场合有以下三种:

  • 网络设备驱动程序接受中断的执行现场
  • 处理CPU掉线时间的回调函数dev_cpu_callback中
  • loopback设备的接受数据帧函数

dev_cpu_callback函数是网络子系统注册到CPU时间通知链中的回调函数,在对称多任务系统SMP中,当一个CPU掉线时,会向其事件通知链发送时间消息,调用所有注册到CPU事件通知链中的回调函数来对时间做出反应。dev_cpu_callback函数就将掉线CPU的struct softnet_data数据结构实力中的发送数据帧完成队列,输出设备队列,input_pkt_queue加入到其他CPU的struct softnet_data数据结构实力相关队列中。将输入数据帧从掉线的输入队列转移到其他CPU输入队列也由netif_rx函数实现。

常规情况下,netif_rx函数在网络设备驱动程序的中断执行现场被调用。但是对于loopback设备,不存在中断执行现场,因为loopback设备不是真是的网络设备,所以开始执行netif_rx函数时要关闭本地CPU中断,等netif_rx执行完成后在开中断。

netif_rx可以在不同CPU上同时运行,每个CPU有自己的struct softnet_data数据结构实例来维护状态,所以对struct softnet_data数据结构实例的访问不会出现问题。

2 netif_rx详情

netif_rx主要做以下三件事情

  • 初始化skb_buff数据结构的某些数据域,如接受数据帧的时间
  • 将接受到的数据帧放入CPU的私有输入队列,通过标记通知内核有数据帧到达
  • 更新CPU的接受统计信息

netif_rx实际调用netif_rx_internal

int netif_rx(struct sk_buff *skb)
{
	trace_netif_rx_entry(skb);

	return netif_rx_internal(skb);
}

2. 1 netif_rx_internal

netif_rx_internal的输入参数只有一个:存放网络设备接受到的数据帧Socket Buffer。如果数据帧成功放入到CPU的输入队列就返回NET_RX_SUCCESS;如果数据帧被扔掉就返回NET_RX_DROP。

netif_rx_internal代码如下:

  • 首先设置skb的接受时间
  • 获取当前CPU的标识ID
  • 调用enqueue_to_backlog继续处理
static int netif_rx_internal(struct sk_buff *skb)
{
	int ret;

	net_timestamp_check(netdev_tstamp_prequeue, skb); //设置数据包的时间

	trace_netif_rx(skb);
#ifdef CONFIG_RPS
	if (static_key_false(&rps_needed)) {
		struct rps_dev_flow voidflow, *rflow = &voidflow;
		int cpu;

		preempt_disable();
		rcu_read_lock();

		cpu = get_rps_cpu(skb->dev, skb, &rflow);  //取当前cpu的id
		if (cpu < 0)
			cpu = smp_processor_id();

		ret = enqueue_to_backlog(skb, cpu, &rflow->last_qtail); //继续处理

		rcu_read_unlock();
		preempt_enable();
	} else
#endif
	{
		unsigned int qtail;
		ret = enqueue_to_backlog(skb, get_cpu(), &qtail);
		put_cpu();
	}
	return ret;
}

2.2?enqueue_to_backlog

enueue_to_backlog主要做以下事情:

  • 获取CPU的softnet_data
  • 保存本地中断信息,并禁止本地中断
  • 将skb添加到CPU的输入队列input_pkt_queue
  • 恢复本地中断
  • 如果CPU的输入队列input_pkt_queu为空,说明当前时收到第一个数据帧,应该标记软件中断,并且将backlog添加到poll_list中,backlog也就是初始化的process_backlog。如果CPU输入队列不为空说明当前已经标记过软件中断,只需要将数据帧加入到CPU的输入队列中。
  • 如果当前CPU输入队列已经满了,那么netif_rx就会扔掉数据帧,释放缓冲区只能用的内存空间,更行CPU的扔包统计信息。
static int enqueue_to_backlog(struct sk_buff *skb, int cpu,
			      unsigned int *qtail)
{
	struct softnet_data *sd;
	unsigned long flags;
	unsigned int qlen;

	sd = &per_cpu(softnet_data, cpu); //获取cpu的softnet_data

	local_irq_save(flags);			//禁止本地CPU中断,并保存本地中断信息

	rps_lock(sd);
	if (!netif_running(skb->dev))
		goto drop;
	qlen = skb_queue_len(&sd->input_pkt_queue);
	if (qlen <= netdev_max_backlog && !skb_flow_limit(skb, qlen)) {		//判断队列是否超过最大值
		if (skb_queue_len(&sd->input_pkt_queue)) {
enqueue:
			__skb_queue_tail(&sd->input_pkt_queue, skb);		//将skb添加到cpu输入队列input_pkt_queue
			input_queue_tail_incr_save(sd, qtail);
			rps_unlock(sd);
			local_irq_restore(flags);	//恢复本地CPU中断
			return NET_RX_SUCCESS;
		}

		/* Schedule NAPI for backlog device
		 * We can use non atomic operation since we own the queue lock
		 */
		if (!__test_and_set_bit(NAPI_STATE_SCHED, &sd->backlog.state)) {
			if (!rps_ipi_queued(sd))
				____napi_schedule(sd, &sd->backlog);   //如果NAPI_STATE_SCHED标志没有设置表示当前没有软中断在处理数据包,
		}											   //将backlog添加到poll_list中,backlog也就是初始化的process_backlog
		goto enqueue;
	}

drop:
	sd->dropped++;
	rps_unlock(sd);

	local_irq_restore(flags);

	atomic_long_inc(&skb->dev->rx_dropped);
	kfree_skb(skb);
	return NET_RX_DROP;
}

如果NAPI_STATE_SCHED标志没有设置表示当前没有软中断在处理数据包,调用函数____napi_schedule将backlog添加到poll_list中,backlog也就是初始化的process_backlog。

static inline void ____napi_schedule(struct softnet_data *sd,
				     struct napi_struct *napi)
{
	list_add_tail(&napi->poll_list, &sd->poll_list); //将软中断处理函数添加到CPU的poll_list
	__raise_softirq_irqoff(NET_RX_SOFTIRQ);			//标记软件中断
}

  系统运维 最新文章
配置小型公司网络WLAN基本业务(AC通过三层
如何在交付运维过程中建立风险底线意识,提
快速传输大文件,怎么通过网络传大文件给对
从游戏服务端角度分析移动同步(状态同步)
MySQL使用MyCat实现分库分表
如何用DWDM射频光纤技术实现200公里外的站点
国内顺畅下载k8s.gcr.io的镜像
自动化测试appium
ctfshow ssrf
Linux操作系统学习之实用指令(Centos7/8均
上一篇文章      下一篇文章      查看所有文章
加:2022-07-05 23:43:39  更:2022-07-05 23:46:15 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/18 22:06:01-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码