大型门户网站建设方案,百度云建站教程,wordpress the7使用教程,山西建设局网站首页1. 网络数据包接收流程简述 典型的以太网卡网络包接收流程如下#xff1a; 1.网络包通过物理介质传到接收端的phy芯片#xff1b; 2.phy芯片通过RGMII协议传到MAC芯片rx queue fifo中#xff1b; 3.MAC芯片通过专用DMA将网络包搬运到网卡驱动程序预先分配好的rx ringbuffer中…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上的进程*/