Linux虚拟化之mdev框架

Linux虚拟化之mdev框架

  • 引言
  • 1 用户接口
  • 2 内核实现
    • 2.1 mdev框架初始化
    • 2.2 mdev父设备注册
    • 2.3 mdev设备创建

引言

sriov是设备虚拟化的一种很好的实现方式,但是它也有一些问题:

  • 需要设备硬件去实现相关的虚拟功能号等逻辑;
  • 需要PCI配置搓开虚拟设备的bus号和设备号,这样导致总线资源不够;
  • 不支持热迁移。

mdev提供了一种不用硬件设备提供虚拟功能相关实现,由软件去模拟虚拟设备的机制。linux中mdev框架是结合vfio实现的。

注:后述源码mdev框架结合mtty为例讲解

1 用户接口

首先,通过uuid工具生成一组序列,假设为:53b2f4fa-80af-632a-3a1e-b6bfe1fa1221。

  1. 执行如下命令创建mtty上面对应的虚拟设备

echo "53b2f4fa-80af-632a-3a1e-b6bfe1fa1221" > /sys/devices/virtual/mtty/mtty/mdev_supported_types/mtty-2/create

  1. 打开/etc/libvirt/qemu/ubuntu20.04-01.xml在devices节点追加如下子节点:
<hostdev mode='subsystem' type='mdev' managed='no' model='vfio-pci' display='off'>
	<source>
		<address uuid='53b2f4fa-80af-632a-3a1e-b6bfe1fa1221'/>
	</source>
</hostdev>

最后,就成功将创建的虚拟设备配置给虚拟机

2 内核实现

在mtty_dev_init函数中,创建了一个mtty的字符设备mtty_dev.dev;然后再将该设备通过函数mdev_register_device注册到mdev框架中,其回调为struct mdev_parent_ops mdev_fops。该回调实现了将虚拟设备模拟为PCI设备。mdev_fops定义如下:

// dev_attr_groups定义
static DEVICE_ATTR_RO(sample_mtty_dev);

static struct attribute *mtty_dev_attrs[] = {
	&dev_attr_sample_mtty_dev.attr,
	NULL,
};

static const struct attribute_group mtty_dev_group = {
	.name  = "mtty_dev",
	.attrs = mtty_dev_attrs,
};

static const struct attribute_group *mtty_dev_groups[] = {
	&mtty_dev_group,
	NULL,
};

// mdev_attr_groups定义
static DEVICE_ATTR_RO(sample_mdev_dev);

static struct attribute *mdev_dev_attrs[] = {
	&dev_attr_sample_mdev_dev.attr,
	NULL,
};

static const struct attribute_group mdev_dev_group = {
	.name  = "vendor",
	.attrs = mdev_dev_attrs,
};

static const struct attribute_group *mdev_dev_groups[] = {
	&mdev_dev_group,
	NULL,
};

// supported_type_groups定义
static MDEV_TYPE_ATTR_RO(name);
static MDEV_TYPE_ATTR_RO(available_instances);
static MDEV_TYPE_ATTR_RO(device_api);

static struct attribute_group mdev_type_group1 = {
	.name  = "1",
	.attrs = mdev_types_attrs,
};

static struct attribute_group mdev_type_group2 = {
	.name  = "2",
	.attrs = mdev_types_attrs,
};

static struct attribute_group *mdev_type_groups[] = {
	&mdev_type_group1,
	&mdev_type_group2,
	NULL,
};

// mdev设备回调
static const struct mdev_parent_ops mdev_fops = {
	.owner                  = THIS_MODULE,
	.dev_attr_groups        = mtty_dev_groups,
	.mdev_attr_groups       = mdev_dev_groups,
	.supported_type_groups  = mdev_type_groups,
	.create                 = mtty_create,
	.remove			= mtty_remove,
	.open                   = mtty_open,
	.release                = mtty_close,
	.read                   = mtty_read,
	.write                  = mtty_write,
	.ioctl		        = mtty_ioctl,
};

注:mtty_*系列回调实现了pci配置空间、BAR空间的模拟

2.1 mdev框架初始化

在vfio_mdev_init函数中,直接通过mdev_register_driver注册了一个设备驱动vfio_mdev_driver;在mdev_register_driver内部,将vfio_mdev_driver.driver.bus设置为mdev_bus_type。

  1. 首先,mdev_bus_type匹配到一个mdev设备的时候(也就是用户层通过create文件生成设备的时候),就会创建一个mdev设备,并调用mdev_bus_type.probe回调;mdev设备移除的时候也会调用mdev_bus_type.remove;
  2. mdev_bus_type的probe和remove回调为mdev_probe和mdev_remove。前者是将mdev设备attach到IOMMU后,调用vfio_mdev_driver.probe;后者是前者的反操作,也是会调用vfio_mdev_driver.remove。

2.2 mdev父设备注册

需要明确,mdev_register_device是对host端的真实设备的注册、而非对mdev设备的注册。在mdev_register_device函数内:

  • 首先,基于真实设备dev创建struct mdev_parent *parent,本质上就是parent->dev指向dev;
  • 通过函数parent_create_sysfs_files在设备目录下创建mdev_supported_types文件夹:
    通过parent_create_sysfs_files->add_mdev_supported_type_groups->add_mdev_supported_type->kobject_init_and_add调用链在mdev_supported_types目录下创建mdev虚拟设备组目录mtty-1和mtty-2;
    同时通过parent_create_sysfs_files->add_mdev_supported_type_groups->add_mdev_supported_type->sysfs_create_file调用链在mtty-1和mtty-2目录下创建create文件;
    同时通过parent_create_sysfs_files->add_mdev_supported_type_groups->add_mdev_supported_type->kobject_create_and_add调用链在mtty-1和mtty-2目录下创建devices目录;

2.3 mdev设备创建

当执行echo uuid > /sys/devices/virtual/mtty/mtty/mdev_supported_types/mtty-2/create时,在回调中会调用mdev_device_create实现mdev设备创建:

  • 首先,基于真实设备(或者说父设备)创建虚拟设备mdev;
  • 调用父设备注册的create方法;
  • 调用device_add将mdev注册,会触发总线probe方法,依次执行mdev_probe->vfio_mdev_probe->vfio_add_group_dev;
  • 在vfio_add_group_dev将mdev注册到vfio框架中,设备回调为struct vfio_device_ops vfio_mdev_dev_ops函数集;
  • 通过函数mdev_create_sysfs_files创建mdev设备的remove回调,会在sys目录的mdev设备目录创建remove文件接口。

注:vfio_mdev_dev_ops各个函数集是对父设备注册的函数集合的调用包装。

你可能感兴趣的:(Linux内幕,linux,服务器,运维)