转载:http://blog.csdn.net/quqi99/article/details/47321023

X86体系早期没有在硬件设计上对虚拟化提供支持,因此虚拟化完全通过软件实现。一个典型的做法是通过优先级压缩(Ring Compression)和二进制代码翻译(Binary Translation)相结合,VMM在特权级ring 0, Guest操作系统在非特权级ring 1, Guest应用程序在ring 3。由于Guest操作系统工作在非特权级ring 1中,这样当它执行特权指令时就会触发异常,由VMM截获异常并采用软件方式模拟指令并返回。但由于X86体系在设计之初没有考虑虚拟化,所以一小部分特权指令在ring 1下没有引发异常,所以需要对操作系统的二进制代码进行扫描,一旦发现不友好的指令,将就其换成支持虚拟化的指令块,这些指令块与VMM合作访问受限的虚拟资源,或者显式地触发异常让VMM进一步处理。这种打补丁的方式很难在构架上保证其完整性。于是,下层的硬件加入了虚拟化功能,硬件截获操作系统对敏感指令的执行或者对敏感资源的访问后通过异常的方式报告给VMM,这样就解决了虚拟化的问题。Intel VTx技术是这一方向的代表,它引入了一个新的特殊执行模式用于运行虚拟机,这个模式会将特权指令统统截取并报告给VMM,VMM本身工作在正常模式下,在接收到处理的报告后,通过对目标指令的解码,找到相应的虚拟化模块进行模拟
    对于内存的虚拟化则需要用硬件实现从GVA(Guest Virtual Address)到GPA(Guest Physical Address)再到HPA(Host Physical Address)的两次地址转换。传统非虚拟化的操作系统只通过硬件MMU完成一次从GVA到GPA的虚拟化。
    在I/O的虚拟化方面,VTd技术在北桥引入DMA重映射硬件来提供设备重映射和设备直接分配的功能。设备所有的DMA传输都会被DMA重映射硬件截取,然后根据设备对应的I/O页表,对DMA中的地址进行转换,使设备只能访问特定的内存。这样,设备就可以直接分配给Guest机使用,驱动提供给设备的GPA经过重映射,变为HPA,使得DMA操作得以完成。
    在网络虚拟化方面,VTd技术可以将一个物理网卡直接分配给一个虚机使用,但扩展性差,因为一台服务支持的PCI设备数是有限的,远远不能满足越来越来的Guest机数量。因此SRIOV(Single
Root I/O Virtualization)被引入来解决这个问题。SRIOV是PCIe(PCI
Express)规范的一个扩展,定义了本质上可以共享的设备。它允许一个PCIe设备,通过是网卡,为每个与其相连的客户机复制一份资源(例如内存资源、中断和DMA数据流),使得数据处理不再依赖VMM。
    在GPU虚拟化方面,如XenGT,它是由Intel在Xen基础上开发的GPU虚拟化开源方案。客户机操作系统不需要任何改动,特权操作会被Xen截获,并且转发到中介(Mediator),中介为每个客户机创建一个GPU上下文(Context),并且在其中模拟特权操作。

1, 普通虚拟化

传统的KVM实现中,kvm.ko是内核的一个模块主要用来捕获虚机的是上述的针对CPU、内存MMU的特权指令然后负责模拟,对I/O的模拟则是再通过用户态的Qemu进程模拟的,Qemu负责解释I/O指令流,并通过系统调用让Host操作系统上的驱动去完成真正的I/O操作。这其中用户态与内核态切换了两次,数据也需要复制


   用户态的Qemu在启动Guest操作系统时,可以先通过KVM在用户态的字符接口/dev/kvm获取Guest的地址空间(fd_vm)
和KVM本身(fd_kvm),然后通过fd_vm将Guest的物理空间mmap到Qemu进程的虚拟空间(虚机就是一个进程,虚机进程的用户虚拟空间就是Guest的物理空间,映射之后Qemu的虚拟设备就可以很方便的存取Guest地址空间里的数据了),并根据配置信息创建vcpu[N]线程(对虚机来说,虚机进程的线程对应着Guest的处理器),然后Qemu将操作fd_vcpu[N]在自己的进程空间mmap一块KVM的数据结构区域(即下图的shared,包括:Guest的IO信息,如端口号,读写方向,内存地址)。该数据结构用于Qemu和kvm.ko交互,Qemu通过它调用虚拟设备注册的回调函数来模拟设备的行为,并将Guest IO的请求换成系统请求发给Host系统。

图中vm-exit代表处理器进入host模式,执行kvm和Qemu的逻辑。vm-entry代表处理器进入Guest模式,执行整个Guest系统的逻辑。Qemu通过三个文件描述符同kvm.ko交互,然后kvm.ko通过vmcs这个数据结构同处理器交互,最终达到控制Guest系统的效果。其中fd_kvm主要用于Qemu同KVM本身的交互,比如获取KVM的版本号,创建地址空间、vcpu等fd_vcpu主要用于控制处理器的模式切换,设置进入Guest

mode前的处理器状态等等(内存寻址模式,段寄存器、控制寄存器、指令指针等),同时Qemu需要通过fd_vcpu来mmap一块KVM的数据结构区域。fd_vm主要用于Qemu控制Guest的地址空间,向Guest注入虚拟中断等。

2, VirtIO

VirtIO通过共享内存的方式为Guest和Qemu提供了高速的硬盘与网络I/O通道(因为Guest的地址空间早就mmap到Qemu的进程空间)。VirtIO只需要增加VirtIO
Driver和VirtIO Device即可直接读写共享内存。如下图,Guest
VirtIO驱动通过访问port地址空间向Qemu的VirtIO设备发送IO发起消息。而设备通过读写irqfd或者IOCTL
fd_vm将I/O的完成情况通知给Guest的驱动。irqfd和ioeventfd是KVM为用户程序基于内核eventfd机制提供的通知机制,以实现异步的IO处理(这样发起IO请求的vcpu将不会阻塞)。之所以使用PIO而不是MMIO,是因为KVM处理PIO的速度快于MMIO。


3, vhost
   VirtIO通过共享内存减小了Guest与Qemu之间数据复制的开销,但Qemu到内核的系统调用还是跑不了。有必要将模拟I/O的逻辑将VirtIO Device挪到内核空间避免系统调用。
   vhost在内核态再增加一个vhost-net.ko模
块, vhost client与vhost backend通过共享内存(virtqueues, unit socket), 文件描述符(ioeventfds), (中断号)irqfds实现快速交换数据的机制。


4, vhost-user
   vhost使用了内核态TCP/IP栈导致从Guest到kvm.ko仍然有一个用户态内核态的切换以及数据的拷贝。一些用户态栈议栈如openonload直接在用户态实现网卡驱动再实现BSD兼容的socket接口供上层应用使用,vhost-user(需要将vhost-backend移到用户态)的共享内存技术用于将这些用户态网络设备(又如snabb switch)和用户态的Guest连接起来

5, DPDK support for vhost-user [3]
   DPDK便是一个在用户态可以直接操作物理网卡的库函数,它和vhost-user结合便可以实现类似于snabb
switch一样性能强劲的用户态交换机了。2015年6月16日dpdk vhost-user ports特性合并到了ovs社区[1],
dpdkvhostuser port将创建unix socket将虚机的virtio-net虚拟网卡的网卡缓冲区共享给物理机上的ovs
port设备。

理论部分结束,下面开始安配置配置dpdk + vhost-user
1, sudo apt-get install fuse libfuse-dev dh-autoreconf openssl libssl-dev
   Git clone git://dpdk.org/dpdk
2, 检查硬件网卡是否支持dpdk,在lib/librte_eal/common/include/rte_pci_dev_ids.h文件中搜索0x153A能搜到。
   hua@hua-ThinkPad-T440p:/bak/OpenStack$ sudo lspci -nn|grep Ethernet
   00:19.0 Ethernet controller [0200]: Intel Corporation Ethernet Connection I217-LM [8086:153a] (rev 04)
3, 修改文件config/common_linuxapp
   CONFIG_RTE_BUILD_COMBINE_LIBS=y  #产生单个库文件
   CONFIG_RTE_LIBRTE_VHOST=y        #enable对vhost的支持
4, 编译,安装。DPDK IVSHMEM可以在host-to-guest或guest-to-guest之间采用零拷贝技术
   make config T=x86_64-ivshmem-linuxapp-gcc
   make install T=x86_64-ivshmem-linuxapp-gcc
5, 编译eventfd模块
   cd $DPDK/lib/librte_vhost/eventfd_link/
   make
   sudo insmod eventfd_link.ko
6, uio提供了用户态驱动开发的框架, dpdk中的uid驱动需要定期去poll/select

/dev/uioX检查设备是否有中断产生。uio也是通过mmap将设备的内存映射到用户空间,当然用户态也可以通过/sys/class/uio/uioX/maps/mapX来实现对设备内存的访问,所以发送和接受数据是通过操作设备的内存来完成的。
   DPDK除了可以使用uio驱动,还可以使用VFIO驱动。VFIO是用户态的PCI设备驱动开发的框架,它向用户态提供访问硬件设备的接口,也向用户态提供配置IOMMU的接口。它需要内核与BIOS的支持。
   sudo modprobe uio
   sudo insmod x86_64-ivshmem-linuxapp-gcc/kmod/igb_uio.ko
   $ sudo ./tools/dpdk_nic_bind.py --status
    Network devices using DPDK-compatible driver
    ============================================
    <none>
    Network devices using kernel driver
    ===================================
    0000:00:19.0 'Ethernet Connection I217-LM' if=eth0 drv=e1000e unused=igb_uio *Active*
    Other network devices
    =====================
    <none>
   $ sudo ./tools/dpdk_nic_bind.py --force --bind=igb_uio eth0
   $ sudo tools/dpdk_nic_bind.py -u 0000:00:19.0  # 恢复

7, 大页支持,添加/etc/default/grub后执行update-grub
(centos是执行:grub2-mkconfig --output=/boot/grub2/grub.cfg),
通过mount一个大页文件系统,然后通过mmap的文件映射,使得该文件系统中的内存操作实现大页调度,从而解决TLB shrashing的问题。
   GRUB_CMDLINE_LINUX=iommu=pt intel_iommu=on default_hugepagesz=1G hugepagesz=1G hugepages=8
   之后mount它,mount -t hugetlbfs -o pagesize=1G none /dev/hugepages

8, 编译ovs
   git clone https://github.com/openvswitch/ovs.git
   cd ovs && ./boot.sh
  
./configure --prefix=/usr --sysconfdir=/etc --localstatedir=/var
--with-dpdk=/bak/openstack/dpdk/x86_64-ivshmem-linuxapp-gcc/
--enable-ssl
   但报错“cannot link with dpdk”,无法继续了。

opendp是一个基于DPDK的用户态协议栈,当需要三层VPN或者NAT时或者其他应用时需要它,https://github.com/opendp/dpdk-odp/wiki

DPDK support for vhost-user的更多相关文章

  1. 译文:ovs+dpdk中的“vHost User NUMA感知”特性

    本文描述了"vHost User NUMA感知"的概念,该特性的测试表现,以及该特性为ovs+dpdk带来的性能提升.本文的目标受众是那些希望了解ovs+dpdk底层细节的人,如果 ...

  2. ovs+dpdk numa感知特性验证

    0.介绍 本测试是为了验证这篇文章中提到的DPDK的NUMA感知特性. 简单来说,在ovs+dpdk+qemu的环境中,一个虚拟机牵涉到的内存共有三部分: DPDK为vHost User设备分配的De ...

  3. DPDK在OpenStack中的实现

    随着云计算与大数据的快速发展,其对数据中心网络的性能和管理提出了更高的要求,但传统云计算架构存在多个I/O瓶颈,由于云平台基本上是采用传统的X86服务器加上虚拟化方式组建,随着40G.100G高速网卡 ...

  4. VNF网络性能提升解决方案及实践

    VNF网络性能提升解决方案及实践 2016年7月 作者:    王智民 贡献者:     创建时间:    2016-7-20 稳定程度:    初稿 修改历史 版本 日期 修订人 说明 1.0 20 ...

  5. vyatta的fork开源版本

    https://www.reddit.com/r/networking/comments/3dvwfy/who_here_is_using_vyos/ Vyatta came in two flavo ...

  6. OVS 总体架构、源码结构及数据流程全面解析

    在前文「从 Bridge 到 OVS」中,我们已经对 OVS 进行了一番探索.本文决定从 OVS 的整体架构到各个组件都进行一个详细的介绍. OVS 架构 OVS 是产品级的虚拟交换机,大量应用在生产 ...

  7. vyatta的fork开源版本vyos

    vyatta的fork开源版本vyos 来源: https://www.reddit.com/r/networking/comments/3dvwfy/who_here_is_using_vyos/ ...

  8. SRS之RTMP的TCP线程(即监听线程)

    本文分析的是 SRS 针对 rtmp 的端口建立的 tcp 线程.具体建立过程: SRS之监听端口的管理:RTMP RTMP 的 TCP 线程中各个类之间 handler 的关系图 1. RTMP之T ...

  9. DPDK之(八)——vhost库

    转:http://www.cnblogs.com/danxi/p/6652725.html vhost库实现了一个用户空间的virtio net server,允许用户直接处理virtio ring队 ...

随机推荐

  1. The Native POSIX Thread Library for Linux - 设计文档

    nptl-design

  2. 用jQuery的ajax的功能实现输入自动提示的功能

    注意事项:要使用jQuery首先要把它的包引用进来( <script type="text/javascript" language="javascript&quo ...

  3. 字符串json转换为xml xml转换json

    原文:字符串json转换为xml xml转换json // To convert an XML node contained in string xml into a JSON string XmlD ...

  4. 熔断器C#实现

    关键词1:保险丝.电闸跳闸.输入密码错误3次则在指定的时间之内禁止登录 关键词2:保护性架构.防御性代码.软件可靠性 实现:https://github.com/fecktty/Circuit_Bre ...

  5. 如何使用SetTimer MFC 不够具体

    转会:http://blog.csdn.net/ellor/article/details/1714741 Timer事件,即定时器事件,是在游戏编程中.常常使用的一个事件.借助它能够产生定时运行动作 ...

  6. Oracle笔试题库 附参考答案

    1.  下列不属于ORACLE的逻辑结构的是(C) 区 段 数据文件 表空间 2. 下面哪个用户不是ORACLE缺省安装后就存在的用户(A) A . SYSDBA B. SYSTEM C. SCOTT ...

  7. 网页启动Windows服务

    如何在网页启动Windows服务   由于公司有许多windows服务进行业务的处理,所谓对服务的维护也是一个比较头痛的问题,因为自己也不知道服务什么时候自动停了,而且更主要的原因是服务都是由运维部门 ...

  8. C#事件与委托的区别

    C#事件与委托的区别 1. 委托 事件是利用委托来定义的,因此先解释委托.委托是一个类,它与其他类如int,string等没有本质区别,int代表的是所有的整形,而string代表的是字符串,委托则代 ...

  9. iOS基础 - 数据库-SQLite

    一.iOS应用数据存取的常用方式 XML属性列表 —— PList NSKeyedArchiver 归档 Preference(偏好设置) SQLite3 Core Data(以面向对象的方式操作数据 ...

  10. HttpClient的使用-爬虫学习(一)

    Apache真是伟大,为我们提供了HttpClient.jar,这个HttpClient是客户端的http通信实现库,这个类库的作用是接受和发送http报文,引进这个类库,我们对于http的操作会变得 ...