dpdk vhost

消息機制

當使用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 

/*返回vhost支持的virtio-net功能子集*/
#define VHOST_GET_FEATURES 

/*檢查功能掩碼,設置vhost和virtio前端共同支持的特性,需要兩者同時支持才能生效*/
#define VHOST_SET_FEATURES

/*將設備設置爲當前進程所有*/
#define VHOST_SET_OWNER 

/*當前進程釋放對設備的所有權*/
#define VHOST_RESET_OWNER 

/*設置內存空間佈局信息,用於報文收發時的地址轉換*/
#define VHOST_SET_MEM_TABLE 

/*下面兩個宏,用於guest在線遷移*/
#define VHOST_SET_LOG_BASE
#define VHOST_SET_LOG_FD 

/*vhost記錄每個虛擬隊列的大小*/
#define VHOST_SET_VRING_NUM //設置vring size

/*由qemu發送virtqueue結構的虛擬地址。vhost將該地址轉換成vhost的虛擬地址。*/
#define VHOST_SET_VRING_ADDR 

/*傳遞初始索引值,vhost通過該索引值找到初始描述符*/
#define VHOST_SET_VRING_BASE  //VirtQueue.last_avail_idx

/*將虛擬隊列的當前可用索引值發送給qemu*/
#define VHOST_GET_VRING_BASE 

/*傳遞eventfd文件描述符。當guest有新的數據要發送時,通過該文件描述符通知vhost接收數據併發送到目的地;vhost使用eventfd代理模塊把這個文件描述符從qemu上下文切換到自己的進程上下文*/
#define VHOST_SET_VRING_KICK  //設置kick fd (guest -> vhost) 


/*也是用來傳遞eventfd文件描述符。使vhost能夠在完成對新的數據包接收時,通過中斷方式通知guest準備接收數據包。使用eventfd代理模塊把這個文件描述符從qemu上下文切換到自己的進程上下文*/
#define VHOST_SET_VRING_CALL //設置call fd (vhost -> guest) 

/*代碼中僅有定義,未使用*/
#define VHOST_SET_VRING_ERR 

/*用來支持virtio-user*/
#define VHOST_NET_SET_BACKEND 

地址轉換和內存映射

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隊列也將被釋放。

設置使能特性

/*顯式設置支持新特性*/
int rte_vhost_driver_set_features(const char *path, uint64_t features)
/*使能相關特性*/
int rte_vhost_driver_enable_features(const char *path, uint64_t features)
/*去使能相關特性*/
int rte_vhost_driver_disable_features(const char *path, uint64_t features)

以上的操作都是針對socket->features做軟件特性的設置,原理大同小異;這些接口可以用來在driver註冊後,對該driver的特性進行微調。

比如當支持mergeable特性時,可以調用rte_vhost_driver_enable_features(file,1ULL << VIRTIO_NET_F_MRG_RXBUF)來進行設置。 當前支持的特性包括:

/* The feature bitmap for virtio net */
#define VIRTIO_NET_F_CSUM   0   /* Host handles pkts w/ partial csum */
#define VIRTIO_NET_F_GUEST_CSUM 1   /* Guest handles pkts w/ partial csum */
#define VIRTIO_NET_F_MTU    3   /* Initial MTU advice. */
#define VIRTIO_NET_F_MAC    5   /* Host has given MAC address. */
#define VIRTIO_NET_F_GUEST_TSO4 7   /* Guest can handle TSOv4 in. */
#define VIRTIO_NET_F_GUEST_TSO6 8   /* Guest can handle TSOv6 in. */
#define VIRTIO_NET_F_GUEST_ECN  9   /* Guest can handle TSO[6] w/ ECN in. */
#define VIRTIO_NET_F_GUEST_UFO  10  /* Guest can handle UFO in. */
#define VIRTIO_NET_F_HOST_TSO4  11  /* Host can handle TSOv4 in. */
#define VIRTIO_NET_F_HOST_TSO6  12  /* Host can handle TSOv6 in. */
#define VIRTIO_NET_F_HOST_ECN   13  /* Host can handle TSO[6] w/ ECN in. */
#define VIRTIO_NET_F_HOST_UFO   14  /* Host can handle UFO in. */
#define VIRTIO_NET_F_MRG_RXBUF  15  /* Host can merge receive buffers. */
#define VIRTIO_NET_F_STATUS 16  /* virtio_net_config.status available */
#define VIRTIO_NET_F_CTRL_VQ    17  /* Control channel available */
#define VIRTIO_NET_F_CTRL_RX    18  /* Control channel RX mode support */
#define VIRTIO_NET_F_CTRL_VLAN  19  /* Control channel VLAN filtering */
#define VIRTIO_NET_F_CTRL_RX_EXTRA 20   /* Extra RX mode control support */
#define VIRTIO_NET_F_GUEST_ANNOUNCE 21  /* Guest can announce device on the
                     * network */
#define VIRTIO_NET_F_MQ     22  /* Device supports Receive Flow
                     * Steering */
#define VIRTIO_NET_F_CTRL_MAC_ADDR 23   /* Set MAC address */
/* Do we get callbacks when the ring is completely used, even if we've
 * suppressed them? */
#define VIRTIO_F_NOTIFY_ON_EMPTY    24
/* Can the device handle any descriptor layout? */
#define VIRTIO_F_ANY_LAYOUT     27
/* We support indirect buffer descriptors */
#define VIRTIO_RING_F_INDIRECT_DESC 28
#define VIRTIO_F_VERSION_1      32
#define VIRTIO_F_IOMMU_PLATFORM 33

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章