当前位置: 首页 > news >正文

网络数据包接收流程

1. 网络数据包接收流程简述

        典型的以太网卡网络包接收流程如下:

        1.网络包通过物理介质传到接收端的phy芯片;

        2.phy芯片通过RGMII协议传到MAC芯片rx queue fifo中;

        3.MAC芯片通过专用DMA将网络包搬运到网卡驱动程序预先分配好的rx ringbuffer中,当一个网络包搬运完后,给CPU触发中断;

        4.CPU响应网卡中断(同时关网卡dma中断),执行网卡驱动程序的中断处理函数,触发NET_RX软中断;

        5.NET_RX软中断中通过napi_poll接口轮询调用网卡的接收函数将数据从rx ringbuffer中搬运到网络协议栈中处理,取空rx ringbuffer后使能网卡dma中断;

        6.网络协议栈层层处理后(网络接口层--->网络层--->传输层),将数据放到socket接收缓冲区;

        7.用户态通过read/recv系列接口从socket接收缓冲区中取走数据

2. 触发网卡硬中断前      

1.网卡interface up时,会为每个rx queue在system memory中申请dma ring buffer。
2.初始化网卡寄存器,包括dma/mtl/mac/mmc,启动dma传输;
3.申请网卡中断;
4.启动queue;

3. 响应网卡硬中断

        在网卡中断处理函数中,检查网卡的中断状态寄存器,检查到有RX interrupt时,会先清该中断,关闭网卡dma中断,在raise NET_RX的软中断后退出,实际的收包工作在软中断中处理。

4. 网络软中断定义

        软中断通过open_softirq函数(定义在kernel/softirq.c文件中)来注册的。open_softirq注册一个软中断处理函数,即在软中断向量表softirq_vec数组中添加新的软中断处理action函数。

        我们可以从start_kernel函数开始,该函数定义在init/main.c中。会调用softirq_init(),该函数会调用open_softirq函数来注册相关的软中断,但是并没有注册网络相关的软中断:

void __init softirq_init(void)
{int cpu;for_each_possible_cpu(cpu) {per_cpu(tasklet_vec, cpu).tail =&per_cpu(tasklet_vec, cpu).head;per_cpu(tasklet_hi_vec, cpu).tail =&per_cpu(tasklet_hi_vec, cpu).head;}open_softirq(TASKLET_SOFTIRQ, tasklet_action);open_softirq(HI_SOFTIRQ, tasklet_hi_action);}

        那么网络相关的软中断在哪里呢?其也是在startup_kernel函数中的中,调用链路如下:

startup_kernel->rest_init->kernel_init->kernel_init_freeable->do_basic_setup();

        而do_basic_setup函数会进行驱动设置。会通过调用net_dev_init函数。net_dev_init函数(定义在net/core/dev.c),最注册软中断,如下:

static int __init net_dev_init(void)
{int i, rc = -ENOMEM;BUG_ON(!dev_boot_phase);if (dev_proc_init())goto out;if (netdev_kobject_init())goto out;INIT_LIST_HEAD(&ptype_all);for (i = 0; i < PTYPE_HASH_SIZE; i++)INIT_LIST_HEAD(&ptype_base[i]);INIT_LIST_HEAD(&offload_base);if (register_pernet_subsys(&netdev_net_ops))goto out;for_each_possible_cpu(i) {struct work_struct *flush = per_cpu_ptr(&flush_works, i);struct softnet_data *sd = &per_cpu(softnet_data, i);INIT_WORK(flush, flush_backlog);skb_queue_head_init(&sd->input_pkt_queue);skb_queue_head_init(&sd->process_queue);INIT_LIST_HEAD(&sd->poll_list);sd->output_queue_tailp = &sd->output_queue;#ifdef CONFIG_RPSsd->csd.func = rps_trigger_softirq;sd->csd.info = sd;sd->cpu = i;
#endifsd->backlog.poll = process_backlog;sd->backlog.weight = weight_p;}dev_boot_phase = 0;if (register_pernet_device(&loopback_net_ops))goto out;if (register_pernet_device(&default_device_ops))goto out;open_softirq(NET_TX_SOFTIRQ, net_tx_action);//注册网络发送的软中断,关联net_tx_action函数open_softirq(NET_RX_SOFTIRQ, net_rx_action);//注册网络接收的软中断,关联net_rx_action函数rc = cpuhp_setup_state_nocalls(CPUHP_NET_DEV_DEAD, "net/dev:dead",NULL, dev_cpu_dead);WARN_ON(rc < 0);rc = 0;
out:return rc;
}//软中断注册
void open_softirq(int nr, void (*action)(struct softirq_action *))
{softirq_vec[nr].action = action;
}//软中断向量表
static struct softirq_action softirq_vec[NR_SOFTIRQS] __cacheline_aligned_in_smp;

5. NET_RX软中断执行流程

        在调度到ksoftirqd/x线程处理NET_RX的软中断时,以stmmac网卡驱动为例,有如下的调用关系:

net_rx_actionnapi_pollstmmac_napi_poll_rx /*网卡驱动注册的rx napi回调*/stmmac_rx /*实际接收数据的函数*/skb_copy_to_linear_data   /*将数据包从rx ringbuffer中拷贝到skb结构体中*/napi_gro_receive /*网络接口层处理数据包*/dev_gro_receive napi_skb_finishnetif_receive_skb_internaldeliver_skb   /*将数据送到网络层*/ip_rcv /*网络层IP协议核心函数*/ip_rcv_coreip_rcv_finish  /* 处理netfiler和iptables规则*/ip_local_deliver_finish /*将数据送到传输层*/udp_rcv /*根据协议调用传输层回调,以下以UDP协议为例*/udp_queue_rcv_skb /*校验udp数据*/__udp_queue_rcv_skb /*将网络包送到socket接收队列中*/sk_data_ready /*唤醒所有等待在该socket上的进程*/

http://www.lryc.cn/news/12944.html

相关文章:

  • CSAPP学习笔记——虚拟内存(二)
  • 面试sql
  • Python编程自动化办公案例(2)
  • Vulnhub 渗透练习(七)—— FRISTILEAKS: 1.3
  • 阶段二10_面向对象高级_分类分包思想和案例环境搭建
  • 关于打印工具print-js的使用
  • Doxygen使用
  • MySQL数据库调优————表结构设计优化
  • set对象和map对象
  • stream()流的使用
  • C++学习笔记-常量
  • JavaScript系列之实现继承的几种方式
  • java面试准备
  • kafka-6-python单线程操作kafka
  • 【Spring教程】1.Spring概述
  • 设计模式-代理模式
  • DPDK — MALLOC(librte_malloc,Memory Manager,内存管理组件)
  • 【Java开发】Spring 12 :Spring IOC控制反转和依赖注入(解决单接口多实现类调用)
  • 【C++学习】基础语法(三)
  • k8s自动化安装脚本(kubeadm-1.23.7)
  • 面试题记录
  • 链式前向星介绍以及原理
  • jenkins 安装 -适用于在线安装 后续写个离线安装的
  • 【C++】再谈vscode界面调试C++程序(linux) - 知识点目录
  • 蚂蚁感冒---第五届蓝桥杯真题
  • 常见排序算法--Java实现
  • 算法笔记(九)—— 暴力递归
  • Flask框架学习记录
  • 【Opencv 系列】 第6章 人脸检测(Haar/dlib) 关键点检测
  • 信源分类及数学模型