linux内核网络收包过程—硬中断与软中断

目录

硬中断处理

软中断处理


        数据通过网络发送过来

硬中断处理

  1. 数据帧首先到达网卡的接收队列,分配RingBuffer
  2. DMA把数据搬运到网卡关联的内存
  3. 网卡向CPU发起硬中断,通知CPU有数据
  4. 调用驱动注册的硬中断处理函数
  5. 启动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;
		}
	}
核⼼逻辑是获取到当前 CPU变量 softnet_data ,对其 poll_list 进⾏遍历 , 然后执⾏到⽹卡驱动注册到的 poll 函数。
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;
}
  1. 从ringbuf中取出数据skb;
  2. 收取完数据以后,对其进⾏⼀些校验
  3. 设置 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: 开发内功修炼

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

为了维护世界和平_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值