Linux 内核virtio 收发包实现浅析

发包

内核协议栈
dev_hard_start_xmit  //net\core\dev.c
    xmit_one
        netdev_start_xmit   //include/linux/netdevice.h
            __netdev_start_xmit
                ops->ndo_start_xmit(skb, dev);  到virtio_net.c 中
    ||
    \/
virtio_net.c中
static const struct net_device_ops virtnet_netdev = {
    .ndo_start_xmit      = start_xmit,     
start_xmit
    xmit_skb        // 把skb放到vqueue中
        virtqueue_add_outbuf
         
            //把数据写到队列中
            virtqueue_add       //virtio_ring.c
            virtqueue_add_split
                virtqueue_kick  //virtio_ring.c
    ||
    \/
virtqueue_kick     
    virtqueue_notify
        vq->notify(_vq)      // agile_nic.c中notify函数,通知板卡驱动给队列中写数据了,然后板卡收到notify后,读取数据

发包没什么好说的,在经历linux 内核协议栈qos后,dev_hard_start_xmit 传递下来的skb 要映射到scatterlist,才能给到后端。因为skb 是gva 地址,只在虚拟机中用。
核心逻辑只是准备sg,更新avail index。

收包:
数据接收流程:

数据接收流程:
napi_gro_receive(&rq->napi, skb);
                netif_receive_skb
                    __netif_receive_skb         // 传输skb给网络层
    /\
    ||
驱动 virtio_net.c 中poll方法 napi_poll(n, &repoll); 即virtio_net.c 中 virtnet_poll()
virtnet_poll
     virtnet_receive
         receive_buf                 // 接收到的数据转换成skb
             //根据接收类型XDP_PASS、XDP_TX等对 virtqueue 中的数据进行不同的处理
             skb = receive_mergeable(dev, vi, rq, buf, ctx, len, xdp_xmit,stats); or
             skb = receive_big(dev, vi, rq, buf, len, stats);  or
             skb = receive_small(dev, vi, rq, buf, ctx, len, xdp_xmit, stats);              
             napi_gro_receive(&rq->napi, skb);   // 把skb上传到上层协议栈
                 
                     
         schedule_delayed_work                  //通过你延迟队列接收数据
             refill_work
                 try_fill_recv(vi, rq, GFP_KERNEL);
                 如果检测到本次中断 receive 数据完成,则重新开启中断                                
                local_bh_enable                 //enable 软中断 等待下一次中断接收数据
    /\
    ||
中断下半步
执行软中断回调函数 net_rx_action(), 调用 virtio_net.c 中 virtnet_poll()
    /\
    ||
检查poll队列上是否有设备在等待轮询
napi_schedule ->__napi_schedule  ->   list_add_tail(&napi->poll_list, &sd->poll_list); //把 NAPI 加入到本地cpu的 softnet_data 的 poll_list链表头
        __raise_softirq_irqoff(NET_RX_SOFTIRQ);          // 调度收包软中断
                     
    /\
    ||
skb_recv_done           //virtio_net.c 中 virtnet_find_vqs() 中,数据接收完成回调函数
    virtqueue_napi_schedule
        调用 napi_schedule
    /\
    ||
每个vq 对应一个数据接收函数 vring_interrupt()
vring_interrupt()       //virtio_ring.c
    vq->vq.callback(&vq->vq);   即virtio_net.c 中 skb_recv_done
    /\
    ||
中断上半步
pcie网卡发送数据给host时,会触发pci msix硬中断,然后host driver agile_nic.c 中执行回调函数vring_interrupt

收包会复杂点,涉及中断上半部和下半部。
上半部由硬中断触发,回调是vring_interrupt;上半部回调很简单,什么也没做,就是挂个napi 到本地cpu的softnet_data->poll_list链表,并通过raise_softirq;触发网络收包软中断。其软中断的实际回调是通过open_softirq(NET_RX_SOFTIRQ, net_rx_action);注册的。后续在合适时机,内核会调用本地cpu对应的软中断回调,以定期清理链表;
下半部走软中断,回调是 net_rx_action()->napi_poll()通过napi->poll指针指向驱动特定回调,丢与virtio来说是virtnet_poll,从而获取对应网卡接收队列中的数据包。期间,有两个比较有趣的点:禁用硬中断剪切sd->poll_list的操作,比较有趣;另一个是gro 收到完整报文后,再上送协议栈的hook,等于在驱动层做了个缓冲区。

我做了一张图:
在这里插入图片描述
参考文档:
https://blog.csdn.net/wangquan1992/article/details/120649182

Linux上,virtio的具体实现涉及到几个关键的结构和函数。首先,在virtio驱动中,使用了virtio_device_id结构来匹配设备,并在virtio_driver结构中含了支持的virtio_device_id列表。\[1\]其次,对于特定的虚拟设备,比如virtio-net网卡驱动,它的实现括了网卡驱动virtio操作。\[2\]在创建virtqueue时,核心流程括了一系列的操作,其中重点是核心流程的梳理。\[2\]最后,对于挂接在virtio总线上的设备,对应了struct virtio_device结构。对于virtio-net设备,它提供了自己的驱动即struct virtio_driver virtio_net_driver。当virtio-net设备挂接到virtio总线上或者virtio_net_driver注册到virtio总线上时,会调用virtio bus的探测函数virtio_dev_probe来找到驱动探测函数virtnet_probe。最终,通过register_netdev()函数将网络设备注册到Linux网络协议栈中。\[3\]这些是virtioLinux上的具体实现的一些关键点。 #### 引用[.reference_title] - *1* *2* [virtio-net 实现机制【一】(图文并茂)](https://blog.csdn.net/m0_74282605/article/details/128114444)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] - *3* [Linux virtio-net driver](https://blog.csdn.net/lingshengxiyou/article/details/127771119)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值