linux内核网络收包过程—硬中断与软中断
目录
硬中断处理
软中断处理
数据通过网络发送过来
硬中断处理
- 数据帧首先到达网卡的接收队列,分配RingBuffer
- DMA把数据搬运到网卡关联的内存
- 网卡向CPU发起硬中断,通知CPU有数据
- 调用驱动注册的硬中断处理函数
- 启动NAPI,触发软中断
上一分析说到网卡硬中断注册的函数igb_msix_ring
static irqreturn_t igb_msix_ring(int irq, void *data)
{struct igb_q_vector *q_vector = data;/* Write the ITR value calculated from the previous interrupt. */igb_write_itr(q_vector);napi_schedule(&q_vector->napi);return IRQ_HANDLED;
}
igb_write_itr仅记录硬件中断频率
static inline void ____napi_schedule(struct softnet_data *sd,struct napi_struct *napi)
{list_add_tail(&napi->poll_list, &sd->poll_list);//触发一个软中断NET_RX_SOFTIRQ__raise_softirq_irqoff(NET_RX_SOFTIRQ);
}
- list_add_tail修改了napi的poll_list(双向链表,数据帧等着被处理),
- 触发一个软中断NET_RX_SOFTIRQ
- 网络包硬中断的工作到此结束。
软中断处理
判断softirq_pending标志
static int ksoftirqd_should_run(unsigned int cpu)
{return local_softirq_pending();
}
执行run_ksoftirqd->__do_softirq
asmlinkage __visible void __softirq_entry __do_softirq(void)
{while ((softirq_bit = ffs(pending))) {trace_softirq_entry(vec_nr);h->action(h);trace_softirq_exit(vec_nr);wakeup_softirqd();}
...
}
调用action中断函数
static __latent_entropy void net_rx_action(struct softirq_action *h)
{struct softnet_data *sd = this_cpu_ptr(&softnet_data);unsigned long time_limit = jiffies +usecs_to_jiffies(netdev_budget_usecs);int budget = netdev_budget;for (;;) {struct napi_struct *n;n = list_first_entry(&list, struct napi_struct, poll_list);//变量sd,调用poll函数budget -= napi_poll(n, &repoll);//budget 与 time_limit控制退出if (unlikely(budget <= 0 ||time_after_eq(jiffies, time_limit))) {sd->time_squeeze++;break;}}
static int igb_poll(struct napi_struct *napi, int budget)
{if (q_vector->tx.ring)clean_complete = igb_clean_tx_irq(q_vector, budget);if (q_vector->rx.ring) {int cleaned = igb_clean_rx_irq(q_vector, budget);}}static int igb_clean_rx_irq(struct igb_q_vector *q_vector, const int budget)
{while (likely(total_packets < budget)) {union e1000_adv_rx_desc *rx_desc;struct igb_rx_buffer *rx_buffer;unsigned int size;rx_buffer = igb_get_rx_buffer(rx_ring, size);igb_put_rx_buffer(rx_ring, rx_buffer);cleaned_count++;/* fetch next buffer in frame if non-eop */if (igb_is_non_eop(rx_ring, rx_desc))continue;/* verify the packet layout is correct */if (igb_cleanup_headers(rx_ring, rx_desc, skb)) {skb = NULL;continue;}/* probably a little skewed due to removing CRC */total_bytes += skb->len;/* populate checksum, timestamp, VLAN, and protocol */igb_process_skb_fields(rx_ring, rx_desc, skb);napi_gro_receive(&q_vector->napi, skb);/* update budget accounting */total_packets++;}return total_packets;
}
- 从ringbuf中取出数据skb;
- 收取完数据以后,对其进⾏⼀些校验
- 设置 sbk 变量的 timestamp, VLAN id, protocol
gro_result_t napi_gro_receive(struct napi_struct *napi, struct sk_buff *skb)
{skb_gro_reset_offset(skb);ret = napi_skb_finish(napi, skb, dev_gro_receive(napi, skb));trace_napi_gro_receive_exit(ret);}
napi_gro_receive函数代表的是⽹卡 GRO 特性,可以简单理解成把相关的⼩包合并成⼀个⼤包。
/* Pass the currently batched GRO_NORMAL SKBs up to the stack. */
static void gro_normal_list(struct napi_struct *napi)
{if (!napi->rx_count)return;netif_receive_skb_list_internal(&napi->rx_list);INIT_LIST_HEAD(&napi->rx_list);napi->rx_count = 0;
}/* Queue one GRO_NORMAL SKB up for list processing. If batch size exceeded,* pass the whole batch up to the stack.*/
static void gro_normal_one(struct napi_struct *napi, struct sk_buff *skb)
{list_add_tail(&skb->list, &napi->rx_list);if (++napi->rx_count >= gro_normal_batch)gro_normal_list(napi);
}static gro_result_t napi_skb_finish(struct napi_struct *napi,struct sk_buff *skb,gro_result_t ret)
{switch (ret) {case GRO_NORMAL:gro_normal_one(napi, skb);break;...
}
最终调用 gro_normal_list将数据发送到网络协议栈。
参考
GitHub - yanfeizhang/coder-kung-fu: 开发内功修炼
linux内核网络收包过程—硬中断与软中断相关推荐
- 代码学习-Linux内核网卡收包过程(NAPI)
本文通过学习RealTek8169/8168/8101网卡的驱动代码(drivers/net/r8169.c).梳理一下Linux下网卡的收包过程. 在下水平相当有限,有不当之处,还请大家斧正^_^ ...
- Linux内核网络数据包处理流程
Linux内核网络数据包处理流程 from kernel-4.9: 0. Linux内核网络数据包处理流程 - 网络硬件 网卡工作在物理层和数据链路层,主要由PHY/MAC芯片.Tx/Rx FIFO. ...
- Linux内核网络数据包发送(一)
Linux内核网络数据包发送(一) 1. 前言 2. 数据包发送宏观视角 3. 协议层注册 4. 通过 socket 发送网络数据 4.1 `sock_sendmsg`, `__sock_sendms ...
- 如何快速优化 Linux 内核 UDP 收包效率? | CSDN 博文精选
作者 | dog250 责编 | 郭芮 出品 | CSDN 博客 现在很多人都在诟病Linux内核协议栈收包效率低,不管他们是真的懂还是一点都不懂只是听别人说的,反正就是在一味地怼Linux内核协议栈 ...
- Linux内核UDP收包为什么效率低?能做什么优化?
现在很多人都在诟病Linux内核协议栈收包效率低,不管他们是真的懂还是一点都不懂只是听别人说的,反正就是在一味地怼Linux内核协议栈,他们的武器貌似只有DPDK. 但是,即便Linux内核协议栈收包 ...
- Linux内核网络数据包发送(四)——Linux netdevice 子系统
Linux内核网络数据包发送(四)--Linux netdevice 子系统 1. 前言 2. `dev_queue_xmit` and `__dev_queue_xmit` 2.1 `netdev_ ...
- Linux内核网络数据包发送(三)——IP协议层分析
Linux内核网络数据包发送(三)--IP协议层分析 1. 前言 2. `ip_send_skb` 3. `ip_local_out` and `__ip_local_out` 3.1 netfilt ...
- Linux内核网络数据包发送(二)——UDP协议层分析
Linux内核网络数据包发送(二)--UDP协议层分析 1. 前言 2. `udp_sendmsg` 2.1 UDP corking 2.2 获取目的 IP 地址和端口 2.3 Socket 发送:b ...
- linux网络收包过程
记录一下linux数据包从网卡进入协议栈的过程,不涉及驱动,不涉及其他层的协议处理. 内核是如何知道网卡收到数据的,这就涉及到网卡和内核的交互方式: 轮询(poll):内核周期性的检查网卡,查看是否收 ...
最新文章
- spring elasticsearch 按条件删除_Elasticsearch系列之Query DSL
- Jquery高亮显示文本中重要的关键字
- 怎么修改linux用户名密码忘记,linux passwd命令设置或修改用户忘记密码
- node.js 下载安装及gitbook环境安装、搭建
- 北京大学 微软:预训练模型(Transformer)中的知识神经元
- C++学习成长的四个层次
- NLP产品级系统设计模式
- ORA-01017: invalid username/password; logon denied
- 天敏盒子系统停止服务器,天敏网络机顶盒今天怎么停服了?
- 一键GHOST v2019.08.12优盘教程
- 聊聊docker的使用心得
- 手把手学习Vue3.0:开发工具WebStorm和Vue模板文件介绍
- BS和CS架构的区别
- Emacs的日常生活
- 教小师妹学多线程,看完我写的例子,脸红成那样!
- Note: further occurrences of HTTP header parsing errors will be logged at DEBUG level.
- 看看同一种字体是如何对应不同的字体文件的
- 一万八的M1 iPad Pro ,怎么就成了“期货”
- 项目管理心得--第一篇
- 软件工程——结构化分析方法