dpdk vhost研究(二)

继续本专题的研究,关于本专题前期的内容请参考[这里](http://blog.csdn.net/me_blue/article/details/77854595)。## 消息机制当使用vhost-user时,需要在系统中创建一个unix domain socket server,用来处理qemu发送给host的消息。 如果有新的socket连接,说明guest创建了新的virtio-net设备,vhost驱动
摘要由CSDN通过智能技术生成

继续本专题的研究,关于本专题前期的内容请参考这里

消息机制

当使用vhost-user时,需要在系统中创建一个unix domain socket server,用来处理qemu发送给host的消息。
如果有新的socket连接,说明guest创建了新的virtio-net设备,vhost驱动会为之创建一个vhost设备,之后qemu就可以通过socket和vhost进行通信了;当socket关闭,vhost就会销毁对应的设备。
常用的消息包括:

//driver\net\virtio\virtio_user\vhost_kernel.c
/* vhost kernel ioctls */
#define VHOST_VIRTIO 0xAF
/*返回vhost支持的virtio-net功能子集*/
#define VHOST_GET_FEATURES _IOR(VHOST_VIRTIO, 0x00, __u64)  
/*检查功能掩码,设置vhost和virtio前端共同支持的特性,需要两者同时支持才能生效*/
#define VHOST_SET_FEATURES _IOW(VHOST_VIRTIO, 0x00, __u64)
/*将设备设置为当前进程所有*/
#define VHOST_SET_OWNER _IO(VHOST_VIRTIO, 0x01)
/*当前进程释放对设备的所有权*/
#define VHOST_RESET_OWNER _IO(VHOST_VIRTIO, 0x02)
/*设置内存空间布局信息,用于报文收发时的地址转换*/
#define VHOST_SET_MEM_TABLE _IOW(VHOST_VIRTIO, 0x03, struct vhost_memory_kernel)
/*下面两个宏,用于guest在线迁移*/
#define VHOST_SET_LOG_BASE _IOW(VHOST_VIRTIO, 0x04, __u64)
#define VHOST_SET_LOG_FD _IOW(VHOST_VIRTIO, 0x07, int)
/*vhost记录每个虚拟队列的大小*/
#define VHOST_SET_VRING_NUM _IOW(VHOST_VIRTIO, 0x10, struct vhost_vring_state)
/*由qemu发送virtqueue结构的虚拟地址。vhost将该地址转换成vhost的虚拟地址。*/
#define VHOST_SET_VRING_ADDR _IOW(VHOST_VIRTIO, 0x11, struct vhost_vring_addr)
/*传递初始索引值,vhost通过该索引值找到初始描述符*/
#define VHOST_SET_VRING_BASE _IOW(VHOST_VIRTIO, 0x12, struct vhost_vring_state)
/*将虚拟队列的当前可用索引值发送给qemu*/
#define VHOST_GET_VRING_BASE _IOWR(VHOST_VIRTIO, 0x12, struct vhost_vring_state)
/*传递eventfd文件描述符。当guest有新的数据要发送时,通过该文件描述符通知vhsot接收数据
* 并发送到目的地;vhost使用eventfd代理模块把这个文件描述符从qemu上下文切换到自己的进程
* 上下文
*/
#define VHOST_SET_VRING_KICK _IOW(VHOST_VIRTIO, 0x20, struct vhost_vring_file)
/*也是用来传递eventfd文件描述符。使vhost能够在完成对新的数据包接收时,通过中断方式通知
*guest准备接收数据包。使用eventfd代理模块把这个文件描述符从qemu上下文切换到自己的进程
*上下文
*/
#define VHOST_SET_VRING_CALL _IOW(VHOST_VIRTIO, 0x21, struct vhost_vring_file)
/*代码中仅有定义,未使用*/
#define VHOST_SET_VRING_ERR _IOW(VHOST_VIRTIO, 0x22, struct vhost_vring_file)
/*用来支持virtio-user*/
#define VHOST_NET_SET_BACKEND _IOW(VHOST_VIRTIO, 0x30, struct vhost_vring_file)

地址转换和内存映射

virtqueue和vring进行数据交换的核心是使用一种机制将数据缓冲区实现对guest和host同时可见,从而通过避免数据的拷贝来消耗性能。dpdk vhost在这里使用的是大页内存、内存映射以及相应的地址转换来完成这个功能的。
因此,host端必须由足够的大页空间,同时需要指定内存预分配。为了vhost能访问virtqueue和数据包缓冲区,所有的描述符表、环表地址,其所在页面必须被映射到vhost的进程空间中。
vhost在收到VHOST_SET_MEM_TABLE消息后,会使用消息中的内存分布表来完成内存映射工作:

/*下面的两个数据结构记录guest的物理地址及偏移量*/
/**
 * Information relating to memory regions including offsets to
 * addresses in QEMUs memory file.
 */
struct rte_vhost_mem_region {
    uint64_t guest_phys_addr;
    uint64_t guest_user_addr;
    uint64_t host_user_addr;
    uint64_t size;
    void     *mmap_addr;
    uint64_t mmap_size;
    int fd;
};

/**
 * Memory structure includes region and mapping information.
 */
struct rte_vhost_memory {
    uint32_t nregions;
    struct rte_vhost_mem_region regions[];
};

/*
 *将 QEMU virtual address 转化成 Vhost virtual address. 该函数用来将ring address
 * 转换成host端的virtual address
 */
static uint64_t
qva_to_vva(struct virtio_net *dev, uint64_t qva)
{
    struct rte_vhost_mem_region *reg;
    uint32_t i;

    /* Find the region where the address lives. */
    for (i = 0; i < dev->mem->nregions; i++) {
        reg = &dev->mem->regions[i];

        if (qva >= reg->guest_user_addr &&
            qva <  reg->guest_user_addr + reg->size) {
            return qva - reg->guest_user_addr +
                   reg->host_user_addr;
        }
    }

    return 0;
}

virtio-net 设备管理

一个virtio-net设备的生命周期包括设备创建、配置、服务启动和设备销毁几个阶段。
- 设备创建
vhost-user通过socket连接来创建。当创建一个virtio-net设备是,需要

  • 分配新的virtio-net设备结构,并添加到设备链表中
  • 为该设备分配一个处理处理核并添加设备到数据面的链表中
  • 在vhost上分配一个为virtio-net设备服务的RX\TX队列
  • 配置
    利用VHOST_SET_VRING_*消息通知vhost虚拟队列的大小、基本索引和位置,vhost将虚拟队列映射到自己的虚拟地址空间
  • 服务启动
    vhost利用VHOST_SET_VRING_KICK消息来启动虚拟队列服务。之后,vhost便可以轮询接收队列,并将数据放到virtio-net设备的接收队列上。同时,也可以轮询发送虚拟队列,查看是否有待发送的数据包,如果有,则将其复制到发送队列中。
  • 设备销毁
    vhost利用VHOST_GET_VRING_BASE消息来通知停止提供对接收队列和发送虚拟队列的服务。同时,分配给virtio-net设备的处理和和物理网卡上的RX和TX队列也将被释放。

比较重要的API:

下面从代码角度来理解下前面描述的过程,几个比较重要的API包括:

注册驱动接口

int rte_vhost_driver_register(const char *path, uint64_t flags)

这个函数负责在系统中注册一个vhost driver,path表示socket的路径。flags在最新的17.05版本中(之前的版本中还不支持可设置,只默认支持client,重连)支持下面几个特性:
- RTE_VHOST_USER_CLIENT :以client模式和QEMU相连
- RTE_VHOST_USER_NO_RECONNECT: 默认情况下client会一直尝试自动和server(QEMU)建立连接,当server还没有启动或者重启时,通过此flag可以关闭该特性
- RTE_VHOST_USER_DEQUEUE_ZERO_COPY:用于vm2vm,vm2nic通信的一种优化方案,默认关闭

来读下代码:

int rte_vhost_driver_register(const char *path, uint64_t flags)
{
    int ret = -1;
    ...
    /*创建一个vhost-user socket,并根据不同的flag设置不同的特性*/
    struct vhost_user_socket *vsocket;
    vsocket = malloc(sizeof(struct vhost_user_socket));
    if (!vsocket)
        goto out;
    memset(vsocket, 0, sizeof(struct vhost_user_socket));
    vsocket->path = strdup(path);
    TAILQ_INIT(&vsocket->conn_list);
    pthread_mutex_init(&vsocket->conn_mutex, NULL);
    vsocket->dequeue_zero_copy = flags & RTE_VHOST_USER_DEQUEUE_ZERO_COPY;

    /*
     *设置上内置支持属性,这些特性对用户都是透明的
     */
    vsocket->supported_features = VIRTIO_NET_SUPPORTED_FEATURES;
    vsocket->features           = VIRTIO_NET_SUPPORTED_FEATURES;

    
  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值