virtio net前端
######版本为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前端相关推荐
- 《深入浅出DPDK》读书笔记(十二):DPDK虚拟化技术篇(半虚拟化Virtio)
Table of Contents 半虚拟化Virtio 132.Virtio使用场景 133.Virtio规范和原理 11.2.1 设备的配置 1. 设备的初始化 2. 设备的发现 3. 传统模式v ...
- 关于 virtio 的重要知识点总结
virtio 相关介绍文章很多,这里总结一些自认为一些关键的技术点, 1,virtio ring(vring)队列由 guest 准备(申请内存),vring(split)包含三部分:desc[], ...
- virtio 与vhost_net介绍
1. virtio基本构建模块 virtio是一种I/O半虚拟化解决方案,是一套通用I/O设备虚拟化的程序,是对半虚拟化Hypervisior中的一组通用I/O设备的抽象.是标准化的的开放接口,以使得 ...
- OVS DPDK vhost-user详解(十二)
在软件实现的网络I/O半虚拟化中,vhost-user在性能.灵活性和兼容性等方面达到了近乎完美的权衡.虽然它的提出已经过了四年多,也已经有了越来越多的新特性加入,但是万变不离其宗,那么今天就从整个v ...
- x86服务器中网络性能分析与调优(高并发、大流量网卡调优)
最近在百度云做一些RTC大客户的项目,晚上边缘计算的一台宿主机由于CPU单核耗被打满,最后查到原因是网卡调优没有生效,今天查了一下网卡调优的资料,欢迎大家共同探讨. 一.网卡调优方法 1.Broadc ...
- 直播回顾:如何对付臭名昭著的 IO 夯?诊断利器来了 | 龙蜥技术
简介:听到IO夯总是让人头疼,那有没有可以分析IO夯问题的利器? 编者按:sysAK(system analyse kit),是龙蜥社区(OpenAnolis)系统运维 SIG 下面的一个开源项目,聚 ...
- 虚拟化基本知识及virtio-net初探
QEMU/KVM是在Linux中被广泛使用的虚拟化技术之一,而virtio作为一个半虚拟化I/O事实上的标准[1],是QEMU/KVM在I/O虚拟化部分的默认实现.virtio-net是virtio标 ...
- 如何对付臭名昭著的 IO 夯?诊断利器来了
一.引言 这是作者第二次备战双十一,怀着激动的心情迎接双十一的到来,不曾想迎来的是一枚深水炸弹:赶紧处理一下业务那边出现的 Load 高问题. "为什么 Load 高呢?" &qu ...
- linux-cp tap vhost接口
LCP中接口创建命令如下. vpp# lcp create <sw_if_index>|<if-name> host-if <host-if-name> netns ...
最新文章
- 图解 Java 垃圾回收机制,写得非常好!
- 基于STM32分析栈、堆、全局区、常量区、代码区、RAM、ROM
- Java_StringBuffer类
- 傻瓜都能看懂的高并发量服务器架构
- rtsp直接转http fmp4
- PyCUDA Documentation
- 博图买什么样配置的笔记本_3dsmax需要什么样的笔记本配置?
- MYSQL 存储过程和函数 案例 例子
- 还贷的那些事VI——自由贷的设想
- Frammer X for mac(mac高清视频截图工具)
- 给Intel AX200装上个Killer 1650X驱动
- 【MATLAB imagesc 背景色】
- 计算机系统如何恢复出厂设置路由器,斐讯p.to怎么恢复出厂设置?-斐讯路由器设置...
- 008九九乘法表(详解)
- 猿创征文|OneOS 万耦启物TB6612驱动电机
- jq将数据库数据显示在select标签上
- 【Vscode】tab键失效的解决方案
- 【纯净版windows系统】U盘启动制作图文教程
- 斜率优化之凸包优化与李超线段树
- 企业网站友情链接有什么作用,毫无保留的给大家分析
热门文章
- Python画3D足球2
- nginx根据域名二级目录进行转发实现负载均衡
- C. Planar Reflections
- Swift 简介 - 苹果最新的编程语言
- win10电脑发现不了华为share_win10无法正常发现网上邻居怎么解决_win10网上邻居看不到别的电脑解决方法...
- ubuntu14.04 u盘安装教程
- Linux系统下,智能中文车牌识别系统EasyPR的配置
- 第三届中国高校智能机器人创意大赛ROS挑战赛-迷宫夺宝机器人
- Beta分布及其应用
- mysql和数据库的区别是什么意思_同样是数据库 SQL和MySQL的区别是什么?