######版本为linux4.13.2#########
virtio_init
    bus_register(&virtio_bus)

static struct bus_type virtio_bus = {
    .name  = "virtio",
    .match = virtio_dev_match,
    .dev_groups = virtio_dev_groups,
    .uevent = virtio_uevent,
    .probe = virtio_dev_probe,
    .remove = virtio_dev_remove,
};

virtio_dev_probe //virtio bus的probe
    virtio_add_status(dev, VIRTIO_CONFIG_S_DRIVER) //发现virtio驱动
        dev->config->set_status(dev, dev->config->get_status(dev) | status);
    virtio_finalize_features
        virtio_add_status(dev, VIRTIO_CONFIG_S_FEATURES_OK) //features ok
    drv->probe(dev) //调用驱动的probe,比如virtio net的 virtnet_probe
    virtio_device_ready //设置VIRTIO_CONFIG_S_DRIVER_OK
    virtio_config_enable //配置使能
    
-----------
//virtio net前端驱动入口
virtio_net_driver_init
    register_virtio_driver(&virtio_net_driver)
        driver_register
            bus_add_driver
                driver_attach //bus_for_each_dev(drv->bus, NULL, drv, __driver_attach)
                    __driver_attach    
                        driver_probe_device
                            really_probe
                                dev->bus->probe(dev) 或 drv->probe //一般bus的probe里会调用drv的probe
省略掉device的probe,这里驱动在注册时也会调用probe(这里最好把device的probe分析下,不然始终没连接起来!)
static struct virtio_driver virtio_net_driver = {
    .feature_table = features,
    .feature_table_size = ARRAY_SIZE(features),
    .feature_table_legacy = features_legacy,
    .feature_table_size_legacy = ARRAY_SIZE(features_legacy),
    .driver.name =    KBUILD_MODNAME,
    .driver.owner =    THIS_MODULE,
    .id_table =    id_table,
    .validate =    virtnet_validate,
    .probe =    virtnet_probe,
    .remove =    virtnet_remove,
    .config_changed = virtnet_config_changed,
#ifdef CONFIG_PM_SLEEP
    .freeze =    virtnet_freeze,
    .restore =    virtnet_restore,
#endif
};
virtnet_probe
    dev->netdev_ops = &virtnet_netdev; //此ops回调结构体包含了open、stop、start_xmit、set_mac_address、poll_controller等
    dev->ethtool_ops = &virtnet_ethtool_ops; //ethtool的ops
    INIT_WORK(&vi->config_work, virtnet_config_changed_work); //配置改变工作队列
    init_vqs
        virtnet_alloc_queues
            INIT_DELAYED_WORK(&vi->refill, refill_work); //后面会用到,用于延时填充avail ring
            netif_napi_add //添加virtnet_poll到rq[i].napi
            netif_tx_napi_add //添加virtnet_poll_tx到sq[i].napi
            sg_init_table 
        virtnet_find_vqs
            callbacks[rxq2vq(i)] = skb_recv_done; //接收回调
            callbacks[txq2vq(i)] = skb_xmit_done; //发送回调
            vi->vdev->config->find_vqs(XXX,callbacks,XXX) //回调赋值,中断中会调用此回调

//填充avail ring
refill_work

//接收回调
skb_recv_done
    virtqueue_napi_schedule
        virtnet_poll
        
//接收处理napi
virtnet_poll
    virtnet_poll_cleantx
    virtnet_receive
        {virtqueue_get_buf
            virtqueue_get_buf_ctx //从vring used中取出id、len;从desc_state中取出data?(在virtqueue_add 的时候会进行赋值)
                detach_buf //释放相关内存及指针,这里会有num_free++操作(空闲buffer数,已经处理后释放的buffer数)
        receive_buf
            receive_small[receive_big、receive_mergeable]
                build_skb
            skb_vnet_hdr
            virtio_net_hdr_to_skb
            napi_gro_receive //送给上层处理
        } //循环处理完所有used ring包
        try_fill_recv //条件是:空闲vring数量大于一半;如果失败会启动delaywork

try_fill_recv 添加buffer。主要在receiving路径被调用;也可以在receiving之前的ndo_open中;另一个场景是refill_work(利用napi_disable来关闭receiving)
    {add_recvbuf_mergeable
    add_recvbuf_big
    add_recvbuf_small
        virtqueue_add_inbuf
            virtqueue_add //添加一个buffer到avail ring
    }//循环,每次添加一个,知道把空闲的buffer添加满!
    virtqueue_kick //notify
        virtqueue_kick_prepare
            vring_need_event
                return (__u16)(new_idx - event_idx - 1) < (__u16)(new_idx - old);//简化后就是event_idx+1>old;而event_idx是记录后端处理位置;意思就是后端处理位置超过(加1后超过,其实是等于)了上次添加buffer的位置,就返回真,需要新添加buffer
            //没用event的场景看vring.used->flags判断是否notify
        virtqueue_notify
调用其的函数有:
refill_work //用work队列延时填
virtnet_receive《- virtnet_poll《-virtnet_alloc_queues(netif_napi_add)《- virtnet_netpoll(napi_schedule)《-virtnet_netdev.ndo_poll_controller《-netpoll_poll_dev(ops->ndo_poll_controller)//《-netpoll_send_skb_on_dev《-netpoll_send_skb《-netpoll_send_udp(貌似跟丢了,反正是在napi中调用)
调用try_fill_recv条件:if (rq->vq->num_free > virtqueue_get_vring_size(rq->vq) / 2);vq->num_free为空闲的vring数量(vring_num-avail_num);即空闲vring数量大于一半时就触发添加。
virtnet_open
virtnet_restore_up

总结:guest中virtio网卡驱动在napi中调用接收函数中判断是否应该添加buffer到vring中。当空闲vring数量大于一半时,会调用try_fill_recv来试图添加buffer,因为还得满足vring_need_event条件;如果try_fill_recv失败会利用schedule_delayed_work来延时再调用。pci中断处理程序中会调用,virtio net注册的回调,进而调用napi来处理接收。
------------------------
//发送处理napi
virtnet_poll_tx

//发送回调
skb_xmit_done

=========================
module_pci_driver(virtio_pci_driver)
    module_driver(__pci_driver, pci_register_driver, pci_unregister_driver) //驱动注册宏
        pci_register_driver
            __pci_register_driver
                drv->driver.bus = &pci_bus_type;
                driver_register

struct bus_type pci_bus_type = {
    .name        = "pci",
    .match        = pci_bus_match,
    .uevent        = pci_uevent,
    .probe        = pci_device_probe,
    .remove        = pci_device_remove,
    .shutdown    = pci_device_shutdown,
    .dev_groups    = pci_dev_groups,
    .bus_groups    = pci_bus_groups,
    .drv_groups    = pci_drv_groups,
    .pm        = PCI_PM_OPS_PTR,
    .num_vf        = pci_bus_num_vf,
};

pci_device_probe
    __pci_device_probe
        pci_call_probe
            local_pci_probe
                pci_drv->probe //这里会调用virtio_pci_driver的probe(virtio_pci_probe)

//virtio pci驱动入口
virtio_pci_probe
    virtio_pci_legacy_probe
        vp_dev->ioaddr = pci_iomap(pci_dev, 0, 0) //通过device映射io地址
        vp_dev->isr = vp_dev->ioaddr + VIRTIO_PCI_ISR //获取isr中断寄存器地址
        vp_dev->vdev.config = &virtio_pci_config_ops //包含vp的set、get、vp_find_vqs等
        vp_dev->config_vector = vp_config_vector
        vp_dev->setup_vq = setup_vq
    [virtio_pci_modern_probe]
    register_virtio_device
        device_register

vp_find_vqs //config->find_vqs
    vp_find_vqs_msix //软中断?
        vp_request_msix_vectors
            request_irq(XXX,vp_config_changed,XXX) //pci配置改变中断
            request_irq(XXX,vp_vring_interrupt,XXX) //pci硬件中断?
        vp_setup_vq
            vp_dev->setup_vq
        request_irq(XXX,vring_interrupt,XXX) //pci硬件中断?
    [vp_find_vqs_intx] //常规中断,就一个
        request_irq(XXX,vp_interrupt,XXX)
        vp_setup_vq
            vp_dev->setup_vq
vp_config_vector //设置VIRTIO_MSI_CONFIG_VECTOR寄存器,用来做msi软中断?
setup_vq
    vring_create_virtqueue
        vring_init
        __vring_new_virtqueue
vring_interrupt
    more_used //
    vq->vq.callback //调用virtqueue的接受或发送回调
vp_config_changed
    virtio_config_changed
        __virtio_config_changed
            drv->config_changed
vp_vring_interrupt
    vring_interrupt
vp_interrupt
    ioread8(vp_dev->isr) //读清isr
    vp_config_changed
    vp_vring_interrupt

virtio net前端相关推荐

  1. 《深入浅出DPDK》读书笔记(十二):DPDK虚拟化技术篇(半虚拟化Virtio)

    Table of Contents 半虚拟化Virtio 132.Virtio使用场景 133.Virtio规范和原理 11.2.1 设备的配置 1. 设备的初始化 2. 设备的发现 3. 传统模式v ...

  2. 关于 virtio 的重要知识点总结

    virtio 相关介绍文章很多,这里总结一些自认为一些关键的技术点, 1,virtio ring(vring)队列由 guest 准备(申请内存),vring(split)包含三部分:desc[], ...

  3. virtio 与vhost_net介绍

    1. virtio基本构建模块 virtio是一种I/O半虚拟化解决方案,是一套通用I/O设备虚拟化的程序,是对半虚拟化Hypervisior中的一组通用I/O设备的抽象.是标准化的的开放接口,以使得 ...

  4. OVS DPDK vhost-user详解(十二)

    在软件实现的网络I/O半虚拟化中,vhost-user在性能.灵活性和兼容性等方面达到了近乎完美的权衡.虽然它的提出已经过了四年多,也已经有了越来越多的新特性加入,但是万变不离其宗,那么今天就从整个v ...

  5. x86服务器中网络性能分析与调优(高并发、大流量网卡调优)

    最近在百度云做一些RTC大客户的项目,晚上边缘计算的一台宿主机由于CPU单核耗被打满,最后查到原因是网卡调优没有生效,今天查了一下网卡调优的资料,欢迎大家共同探讨. 一.网卡调优方法 1.Broadc ...

  6. 直播回顾:如何对付臭名昭著的 IO 夯?诊断利器来了 | 龙蜥技术

    简介:听到IO夯总是让人头疼,那有没有可以分析IO夯问题的利器? 编者按:sysAK(system analyse kit),是龙蜥社区(OpenAnolis)系统运维 SIG 下面的一个开源项目,聚 ...

  7. 虚拟化基本知识及virtio-net初探

    QEMU/KVM是在Linux中被广泛使用的虚拟化技术之一,而virtio作为一个半虚拟化I/O事实上的标准[1],是QEMU/KVM在I/O虚拟化部分的默认实现.virtio-net是virtio标 ...

  8. 如何对付臭名昭著的 IO 夯?诊断利器来了

    一.引言 这是作者第二次备战双十一,怀着激动的心情迎接双十一的到来,不曾想迎来的是一枚深水炸弹:赶紧处理一下业务那边出现的 Load 高问题. "为什么 Load 高呢?" &qu ...

  9. linux-cp tap vhost接口

    LCP中接口创建命令如下. vpp# lcp create <sw_if_index>|<if-name> host-if <host-if-name> netns ...

最新文章

  1. React App项目页面进出场动画
  2. mysql常用命令--入门
  3. 屏幕录像专家6.0_迅捷屏幕录像工具和屏幕录像专家哪个更好用?
  4. 老师,你确定注释不会被执行吗?
  5. Java 多线程学习笔记
  6. 滤波电路对服务器的影响,滤波电路到底有什么作用?
  7. vs2017安装勾选哪些_医学图像处理 VS2017配置ITK
  8. C语言中逻辑非和取反的不同
  9. did拼接屏最小拼缝0.88mm
  10. 复习用vue写tabbar
  11. 【系统化学习】CSDN算法技能树测评
  12. 感恩2020,期待2021
  13. allegro artwork设置和颜色设置的导入导出
  14. vue axios介绍
  15. WINFORM时间控件(DATATIMEPICKER)的显示格式设置
  16. SQL Server 为视图或函数 指定的列名比其定义中的列多
  17. 像游戏一样办公,赋能OA系统转型
  18. 计算机基础知识及Linux高级运维基本命令
  19. 2023年推荐几款开源或免费的web应用防火墙
  20. 如何在REST API中使用查阅项的值作为过滤条件

热门文章

  1. 不要污要优雅!国产VR游戏《甜蜜软妹子》上线
  2. 我想起那天夕阳下的奔跑,那是我逝去的青春
  3. python 工业自动化控制_python工业自动化测试教程
  4. 高德地图 2D和3D的区别
  5. 带你全面了解数据库基础
  6. python定制手机套餐_利用Python实现高度定制专属RSS
  7. 手机端访客审核的方案
  8. 企查查、天眼查、启信宝API怎么批量操作调用,API接口应用场景。
  9. 苹果手机里关闭icloud照片图库时,很多视频和照片都没了,怎么恢复
  10. 北邮师哥教新手小白解决xshell无法远程服务器的问题