主要查看一下virtio-user的工作思路,个人觉得他主要是用来替换KNI或者OVS的TAP设备,更好的用法应该是给container来用,主要是通过操作/dev/vhost-net创建kernel的tap设备用,然后kernel和virtio-user进行内存映射,便于收发报文。
| 更正一下:目前来说container用virtio-user还不太合适,因为如果TAP设备加入到namespace的话,重启virtio-user就因为在当前的宿主机找不到TAP设备,会生成一个新的TAP设备。这块目前没有解决。
官方图
以上就是virtio-user的结构图,我们可以看到virtio-user驱动会在内核生成一个tap设备,然后另一端连接DPDK,报文通过内核发送到用户态。
virtio-user创建tap端口流程
接下来详细看一下,函数路径如下,就是初始化的时候,根据参数设置初始化虚拟设备。
rte_eal_init-->rte_bus_probe-->vdev_probe-->vdev_probe_all_drivers-->virtio_user_pmd_probe
主要是两个操作
- 首先会解析一些参数,用来配置tap口,支持的参数为queues,cq,mac,path,queue_size,iface,这里面path是必备的,但是mac和iface我们可能也常用。
- 如果进程是primary的话,调用
virtio_user_dev_init
初始化设备 - 如果进程是secondary的话,调用
rte_eth_dev_attach_secondary
绑定设备,这里所做的就是简单的获取端口,默认就是由primary进行端口的配置了。 eth_virtio_dev_init
初始化vhost-user或者vhost-net设备
virtio_user_dev_init-->virtio_user_dev_setup
主要是根据支持对端为vhost-user和vhost-net,并且配置通知和中断,另外我们接下来主要关心一下vhost-net。
virtio_user_dev_setup
- 当是vhost-user时,得到vhost-user相关的ops,vhost-net时,得到kernel相关的vhost的ops,接下来就看kernel的vhost-net,不管vhost-user。
- 首先申请vhostfds和tapfds的内存相关空间。
- 调用
vhost_kernel_setup
打开相关的设备,比如我们打开的是dev/vhost-net
。 - 调用
virtio_user_dev_init_notify
去初始化通知。 - 调用
virtio_user_fill_intr_handle
创建中断。
eth_virtio_dev_init
virtio_init_device
初始化设备rte_intr_callback_register
注册中断回调
virtio_init_device
vtpci_reset
重置设备vtpci_set_status
告诉host,注意到设备,并且知道怎么去驱动它了virtio_alloc_queues
为设备创建队列virtio_configure_intr
配置中断vtpci_reinit_complete
实际调用vtpci_set_status
告诉host,驱动完成。
vtpci_set_status-->virtio_user_set_status
- 如果驱动完成了,调用
virtio_user_start_device
驱动设备 - 如果是重置标志,调用
virtio_user_reset
重置设备 - 如果其他状态,则将状态记录在设备中
virtio_user_start_device
virtio_user_queue_setup
调用virtio_user_create_queue
,最终调用ioctl告知kernel的vhost,创建队列。dev->ops->send_request
调用vhost_kernel_ioctl
配置共享内存virtio_user_queue_setup
调用virtio_user_kick_queue
配置队列的vringdev->ops->enable_qp
调用vhost_kernel_enable_queue_pair
创建并且配置tap设备
vhost_kernel_enable_queue_pair
vhost_kernel_open_tap
创建tap设备,并且进行配置。vhost_kernel_set_backend
配置tap设备
数据传递流程
Kernel部分
接下来我们看一下数据的传递路径,主要看一个流向,就是pktgen通过tap口进行流量发送,然后最终会传递给virtio-user的接收。pktgen发送直接调用的是tap的ndo_start_xmit
,即tun_net_xmit
。
tun_net_xmit-->vhost_poll_wakeup-->vhost_poll_queue-->vhost_work_queue-->wake_up_process
会唤醒vhost_worker
。
vhost_worker-->handle_rx_kick-->handle_rx-->tun_recvmsg-->tun_do_read
会进行报文的收取,然后发送到用户态,而virtio-user处会轮询收取报文,所以我们略过了消息通知机制,其实是我没有找到。
DPDK部分
rte_eth_rx_burst-->virtio_recv_pkts_vec
会从相应的队列中读取数据。
目前问题
- virtio-user创建的tap设备是down的状态,需要手动up,up之前,virtio-user是不知道设备是down的,如果有别的类型的端口的报文,可能就会向virtio-user端口转发。最后就是tap设备up或者down的状态目前还不能通知virtio-user。
- mvs重启后tap设备丢失,tap设备重新生成后,是down状态,并且Mac会变化,创建时并不能指定,tap设备丢失的问题会在DPDK-18.05中加入,但是这个功能稳定性和可用性还需要再验证。
- virtio-user创建的tap设备的mac地址不能指定。