云桌面(VDI)spice协议优化的关键技术——外设篇

spice协议原生的USB外设重定向支持已经相当优秀,相比usbip对复合型设备兼容性更好。对于热插拔的支持有两种机制-gudev和libusb。从1.0.16开始libusb支持hotplug事件侦听,可以使用接口libusb_hotplug_register_callback注册插拔回调,从而不依赖于udev,这在不支持udev的某些嵌入式Linux内核平台上更适用。

    一. 提高USB重定向传输速度

    用3.0总线替代2.0和1.1总线,需要qemu 2.9.0以上,-device nec-usb-xhci会在虚拟机设备管理器中出现新的通用串行总线,驱动可以使用renesas通用3.0驱动,注意不要与2.0或1.1总线并存,且去掉-usb参数。usb-hub的注册属性中增加3.0对应的MASK_SUPER,当用于重定向传输的字符设备小于等于3个时只有Root Hub,超过则会生成新的Hub。同时开启usb通道的lz4压缩有助于进一步提高传输速度。多线程下达到20MB/S以上的传输速度并不难(注意usbredir并非线程安全,某些接口需要加锁),由于usb重定向的传输速度还与cpu主频、存储和usb设备的IO性能、网络带宽等相关,具体场景下提高多少还需实测,由于某些ARM终端还是百兆网口,软件的优化已经不再是瓶颈。上述所指均为bulk传输机制下,如果在同步传输机制下,传输速度还会大幅提高,但可能有一定误码率,这时制约因素更多的是网络带宽。

    二. 精确过滤键鼠设备

    usb设备中,特别的如键盘,既可以重定向使用(usbredir channel传递key event),也可以非重定向使用(inputs channel传递key event);如鼠标,客户端模式下必须非重定向使用,同时需要借助vdagent模拟鼠标事件,服务端模式下类似键盘。一般的,都以非重定向方式使用键鼠,以获得较好的响应体验。这就需要将其从usb设备中过滤出来,避免自动重定向。原生spice以device class 0x03为标志,会过滤所有HID设备,其实更为精确的做法是获取interface的class和protocol,不但class 0x03属于HID设备,而且protocol为1或2代表键鼠,具体含义可以参见lsusb -v,需要注意的是复合设备有多个interface。interface class还可以帮助我们按类别控制USB重定向的黑白名单功能。

    三. 控制重定向的USB设备的读写权限

    windows系统传统的usb权限控制是修改注册表,这种方法很容易被破解,在云桌面我们有更彻底更安全的控制方法。以常见的对于存储类usb设备的读写控制为例,USB协议urb指令有四种传输方式,存储类usb设备数据传输使用bulk transaction。重定向成功只需要control packets和interrupt packets,修改客户端usbredir,不发送bulk packets,即控制了对存储类usb设备的读操作;修改服务端usbredir,不发送bulk packets,即控制了对存储类usb设备的写操作。控制标志可以通过spice调用usbredir接口动态设置。

    四. 串口重定向

    两种方式实现:1)虚拟机内创建虚拟串口设备,与终端串口借助TCP实现双向通讯,comtotcp是有成熟例子的,很容易实现;2)用qemu虚拟一个串口设备,同样与终端串口借助TCP实现双向通讯,因为有-serial参数的存在,比方法1更方便,而且通讯两端都是Linux系统可以更方便的使用socat工具映射。需要注意的是整个通路上映射指定的串口参数需要一致,这就要求qemu通过虚拟串口抓取用户在虚拟机内打开串口指定的参数,传递到终端再建立相应的tcp映射。

    五. 摄像头/高拍仪重定向

    将摄像头作为普通USB设备重定向也可以正常使用,缺陷是采集的图像数据未经压缩传输会大量占用带宽,通常2592×1944的分辨率即使以3帧/秒的速度采集,也会占用150Mbps以上的带宽。尤其大量云终端使用时对服务器网卡造成极大压力。实际上视频传输大多采用H.264编码,可以大大降低带宽占用,难点在于如何不改变虚拟机内应用程序和用户使用习惯的情况下,既重定向摄像头设备,又重定向流媒体。类似串口重定向的思路,首先需要在虚拟机内形成一个设备管理器内可见的虚拟摄像头,该摄像头的各项参数(vip,pid,class,protocol等等)都与接在终端上的真实摄像头完全一致。windows虚拟机内生成虚拟摄像头有一些成熟的方案,首先要生成一个专用于摄像头的虚拟USB总线(涉及总线驱动开发),再开发一个符合UVC标准的USB模拟数据包来作为虚拟摄像头。这里需要参阅UVC官方文档,同时借助USBLyzer分析真实USB摄像头的通讯数据包,另外因为是标准协议,linux内核源码也可以作为参考(include/uapi/linux/usb/video.h)。终端这边利用v4l2框架实时采集图像数据,再经过H.264编码后做成RTSP服务。虚拟摄像头则按RTSP地址直接拉取码流(RTP包形式)作为视频源,解码每一帧后转成YUV2格式分段拷贝到usb hdr的缓冲区,模拟成iso packets。真实摄像头的参数和RTSP地址都会在真实摄像头插入时通过spice的main channel作为agent消息由vdagent写入虚拟机(注意要屏蔽class 0x0e设备的普通重定向)。此外可以通过调节H.264码流的码率、质量,在带宽和实时性上取得一个平衡。这么做,即使最高分辨率的高拍仪重定向,带宽占用也不会超过2Mbps。

原文链接:https://blog.csdn.net/xx306/article/details/80150099

猜你喜欢

转载自blog.csdn.net/u014022631/article/details/81079128