Библиотека сайта rus-linux.net
Virtio: Фреймворк виртуализации ввода-вывода для Linux
Оригинал: "Virtio: An I/O virtualization framework for Linux"Автор: M. Tim Jones
Дата публикации: 29 Jan 2010
Перевод: Н.Ромоданов
Дата перевода: 22 марта 2010 г.
Краткое содержание: Ядро Linux поддерживает различные схемы виртуализации, и что, вероятнее всего, будет поддерживать еще больше схем по мере того, как будут появляться новые подходы и схемы виртуализация (например, lguest). Но поскольку все эти схемы работают поверх Linux, как сделать так, чтобы для виртуализации ввода/вывода использовались возможности ядра? Ответ — использовать фреймворк virtio
, в котором предложена работоспособная абстракция гипервизоров и предоставлен обычный набор драйверов, предназначенный для виртуализации ввода/вывода. Давайте изучим virtio
и узнаем, почему скоро Linux будет представлять собой один из гипервизоров.
Если кратко, то фреймворк virtio
является абстрактным слоем над устройствами в гипервизоре, реализованном на принципах паравиртуализации. Фреймворк virtio
был разработан Расти Расселом (Rusty Russell) для поддержки его собственного варианта виртуализации, назваемого lguest
. В настоящей статье сначала вводится понятие паравиртаулизации и эмуляции устройств, а затем исследуются конкретные особенности фреймворка virtio
. Мы сосредоточим внимание на варианте virtio
, реализованного для ядра 2.6.30.
Linux является экспериментальной площадкой для гипервизоров. Как уже было описано во многих статьях, посвященных гипервизорам в Linux, в Linux предлагается большое количество вариантов реализации гипервизоров с различными свойствами и преимуществами. К их числу относятся виртуальная машина, базирующаяся на ядре Linux ( Kernel-based Virtual Machine - KVM), lguest
и пользовательский режим в Linux. Реализация в Linux различных вариантов гипервизоров, может, в свою очередь, требовать от операционной системы дополнительных накладных расходов и возможностей. К числу таких возможностей относится виртуализация устройств. Во фреймворке virtio
вместо того, чтобы применять различные способы эмуляции устройств, используется обычный внешний (front end) интерфейс для эмуляции этих устройств, что позволяет стандартизировать интерфейс и увеличивает повторное использование кода в каждой из платформ.
Сравнение полной виртуализации и паравиртуализации
Давайте начнем с краткого обсуждения двух различныхвидов схем виртуализации: полной виртуализации и паравиртуализации. В случае полной виртуализации
, гостевая операционная система работает поверх гипервизора, который установлен на голом аппаратном обеспечении. Гостевая система не знает, что она в данный момент виртуализирована, и в этой конфигурации не требуется никаких изменений в ее работе. Напротив, при паравиртуализации
, гостевая операционная система не только знает, что она запущена на гипервизоре, но и содержит код, который повышает эффективность взаимодействия гостевой системы и гипервизора (см. рис. 1)
При полной виртуализации гипервизор должен эмулировать аппаратное обеспечение устройства, что происходит на самом низком уровне обмена данными (например, для сетевого драйвера). Хотя благодаря абстракции понятно, как выполнять эмуляцию, она в большинстве случаев неэффективна и очень сложна. В случае паравиртуализации гостевая система и гипервизор могут работать совместно с целью сделать эту эмуляцию эффективной. Недостатком подхода с использованием паравиртуализации является то, что операционная система знает, что она виртуализирована и в ее работу требуется вносить изменения.
Рис.1: Эмуляция устройства в случае полной виртуализации и в случае паравиртуализации
Для того, чтобы поддерживать виртуализацию, продолжает совершенствоваться аппаратное обеспечение. В новые процессоры добавляются современные инструкции, которые повышают эффективность переключения между гостевыми операционными системами и гипервизором. Аппаратное обеспечение также продолжает совершенствоваться и для поддержки виртуализации ввода/вывода (I/O) (смотрите раздел Ресурсы в оригинале статьи, где изучается сквозной доступ к шине PCI и виртуализация ввода/вывода с одной или несколькими корневыми системами).
В традиционной среде полной виртуализации гипервизор должен отлавливать запросы ввода/вывода, а затем эмулировать поведение реального аппаратного обеспечения. Хотя в результате и обеспечивается максимальная гибкость (в частности, работа с немодифицированной операционной системой), такой подход приводит к неэффективности (см. левую часть рис.1). В правой части рис.1 показан вариант для случая паравиртуализации. Здесь гостевой операционной системы известно, что она работает на гипервизоре и в ней есть драйвера, которые работают как внешний интерфейс гипервизора (front-end драйвера) В гипервизоре реализованы внутренние драйвера (back-end драйвера), которые собственно и выполняют эмуляцию конкретного устройства. Эти front-end и back-end драйвера являются именно тем местом, куда встраивается фреймворк virtio
, обеспечивающий стандартизованный интерфейс для разработки доступа к эмулируемым устройствам, что ведет к повторному использованию кода и увеличивает эффективность.
Абстрагирование гостевых систем Linux
Как было описано в предыдущем разделе, фреймворк virtio
является абстрактным набором обычных устройств, эмулируемых в паравиртуализированном гипервизоре. Такая схема позволяет гипервизору экспортировать обычный набор эмулируемых устройств и делает их доступными через общий интерфейс программирования приложений (API). На рис. 2 показано, почему это важно. В гипервизорах с паравиртуализацией гостевые системы реализуют обычный набор интерфейсов, причем конкретная эмуляция устройств будет происходить ниже набора back-end драйверов. Back-end драйвера используются для реализации функциональности внешнего (front end) интерфейса.
Рис.2: Абстрактное представление драйверов в virtio
Обратите внимание, что в действительности (хотя и не обязательно), эмуляция устройств выполняется в пользовательском пространстве с помощью QEMU, так что back-end драйверы работают в пользовательском пространстве гипервизора и помогают реализовывать ввод/вывод через QEMU. QEMU является эмулятором системы, который, кроме предоставления виртуальной платформы для гостевых операционных систем, обеспечивает эмуляцию всех элементов системы (хостовый контроллер PCI, диск, сеть, видео оборудование, USB контроллер, а также другие элементы аппаратной части компьютера).
В API фреймворка virtio
используется абстракция простого буфера, в которая инкапсулирует команды и данные, необходимые для гостевой системы. Давайте рассмотрим внутреннюю структуру API фреймворка virtio
и его компоненты.
Архитектура фреймворка virtio
В добавок к front-end драйверам (реализованным в гостевой операционной системе) и back-end драйверам (реализованным в гипервизоре), в фреймворке virtio
определены два слоя, предназначенные для поддержки взаимодействия гостевых систем и гипервизора. На верхнем уровне (так называемом уровне virtio
) имеется виртуальный интерфейс работы с очередями, с помощью которого происходит взаимодействие между front-end и back-end драйверами. Драйверы, в зависимости от их собственных нужд, могут использовать ноль или большее количество очередей. Например, сетевой драйвер использует две виртуальные очереди (одна - для приема и одна - для передачи), тогда как драйвер работы с блочными устройствами использует только одну очередь. Виртуальные очереди, будучи виртуальными, на самом деле реализованы в виде кольцевых структур, через которые происходит взаимодействие между гостевыми системами и гипервизором. Но их можно реализовывать любым способом, лишь бы в гостевых системах и гипервизоре они были бы реализованы одинаково.
Рис.3. Общая архитектура фреймворка virtio
На рис.3 показаны пять front-end драйверов: для устройств блочного доступа (таких, как диски), сетевых устройств, для эмуляции шины PCI, драйвер управления памятью гостевых систем (balloon драйвер) и консольный драйвер. Для каждого front-end драйвера в гипервизоре есть back-end драйвер.
Иерархия концепций
С точки зрения гостевой операционной системы, иерархия
объектов
определяется так, как показано на рис. 4. Сверху
находится virtio_driver
, который представляет собой front-end драйвер гостевой операционной системы. Устройства, которые соответствуют этому драйверу, инкапсулированы в структуре virtio_config_ops
(представляющее собой устройство в гостевой системе). Дается ссылка на структуру virtio_config_ops
(в которой определены операции конфигурирования устройства virtio
). Ссылка на virtio_device
делается из очереди virtqueue
(в которой находится ссылка на обслуживаемое устройство virtio_device
). Наконец, каждый объект virtqueue
ссылается на объект virtqueue_ops
, в котором определены операции работы с очередями, выполняемые драйвером, находящимся ниже в гипервизоре. Ниже мы рассмотрим как используются операции с очередями, которые являются основными в virtio
API, а затем более подробно рассмотрим операции virtqueue_ops
.
Рис.4. Иерархия объектов уровня front-end
Процесс начинается с создания драйвера virtio_driver
и
последующей его регистрации через register_virtio_driver
. В структуре virtio_driver
определяются драйвер устройства, используемый на более высоком уровне, список идентификаторов устройств, которые поддерживает драйвер, таблица функций (в зависимости от типа устройства) и список функций обратного вызова. Когда гипервизор идентифицирует наличие нового устройства, которое соответствует идентификатору устройств в списке устройств, то вызывается функция probe
(имеющаяся в объекте virtio_driver
), которая возвращает объект virtio_device
. Этот объект кешируется вместе управляющими данными для этого устройства (способ зависит от используемого драйвера). В зависимости от типа драйвера могут вызываться функции virtio_config_ops
, с помощью которых считываются или устанавливаются специфические характеристики устройства (например, получение статуса чтение/запись для устройства virtio_blk
, работающего с диском, или установка размера блока для блочного устройства).
Заметьте, что в virtio_device
нет ссылок на
virtqueue
(но virtqueue
содержит ссылку на virtio_device
). Для идентификации очередей virtqueue
, которые связаны с этим устройством virtio_device
, используется объект virtio_config_ops
и функция find_vq
. В этом объекте будут возвращены виртуальные очереди, связанные с этим экземпляром устройства virtio_device
. В функции find_vq также позволяется указывать функцию обратного вызова для virtqueue
(см. структуру virtqueue
на рис.4), которая используется для уведомления гостевой системы о получении буферов от гипервизора.
Структура virtqueue
является простой структурой, в которой может быть определена, но необязательно, функция обратного вызова (который вызывается, когда гипервизор обрабатывает буферы), ссылка на virtio_device
, ссылка на операции virtqueue
и специальная ссылка priv
, которая используется в нижнем слое реализации . Хотя функция callback
не является обязательной, с ее помощью можно динамически включать и отключать обратные вызовы.
Но основой этой иерархии является структура virtqueue_ops
, в которой определено, как гостевые системы и гипервизор обмениваются между собой командами и данными. Давайте рассмотрим этот объект, которые добавляется к очереди virtqueue
и удаляется из нее.
Буферы virtio
Драйвера гостевых систем (front-end драйвера) взаимодействуют с драйверами гипервизора (back-end драйвера) через буферы. При вводе/выводе гостевая система передает один или большее количество буферов, представляющие собой запрос. Например, вы можете передать три буфера, первый из которых представляет собой запрос на чтение, а последующие два предназначение для возвращаемых данных. С точки зрения внутренней реализации, эта конструкция представляет собой рассредоточенный список (в котором каждый элемент списка задается адресом и длиной).
Ядро API
Связывание гостевого драйвера с драйвером гипервизора осуществляется
через virtio_device
и, в общем случае, через очереди virtqueue
. Для virtqueue
есть свое собственное API, состоящее из пяти функций. Первая функция add_buf
используется для того, чтобы сделать запрос гипервизору. Этот запрос представляет собой рассредоточенный список, который рассматривался ранее. Для выполнения функции add_buf
гостевая система указывает очередь virtqueue
, к которой относится запрос, рассредоточенный список (массив адресов и длин), количество буферов, которые используются в качестве выходных структур (нужно для лежащего ниже гипервизора) и количества входных структур (в которых гипервизор сохранит данные и которые он вернет гостевой системе). Когда запрос гипервизору делается с использованием функции add_buf
, гостевая система может оповестить гипервизор о новом запросе посредством функции kick
. Для достижения наилучшей производительности, гостевая система прежде, чем оповестить гипервизор с помощью команды kick
, должна загрузить в очередь virtqueue
, столько буферов, сколько будет возможно.
Ответ от гипервизора можно получить с помощью функции get_buf
. Гостевая система может делать запрос с помощью этой функции или может ожидать оповещения через функцию virtqueue callback
. Когда гостевая система узнает, что буферы уже доступны, то может вызывать функцию get_buf
, которая вернет заполненные буферы.
Последними двумя функциями в virtqueue
API являются функции enable_cb
и disable_cb
. Эти функции можно использовать для активации и деактивации процесса обратного вызова (через функцию callback
, инициализированную в очереди callback
при помощи функции find_vq
). Заметьте, что функция обратного вызова и гипервизор находятся в различных адресных пространствах, так что вызов происходит через косвенное обращение к гипервизору (например, kvm_hypercall
).
Формат, порядок следования и содержимое буферов важны только для front-end и back-end драйверов. Механизмы внутренней передачи данных (кольцевые структуры в текущей реализации) осуществляют только перемещение буферов и не представляют интереса в данном рассмотрении.
Примеры драйверов virtio
Исходный код различных front-end драйверов вы можете найти в поддиректории ./drivers ядра Linux. Сетевой драйвер virtio
расположен в файле ./drivers/net/virtio_net.c, а драйвер блочного устройства virtio
находится в файле ./drivers/block/virtio_blk.c. В поддиректории ./drivers/virtio есть реализация интерфейсов virtio
(устройство virtio
, драйвер, очередь virtqueue
и кольцевая структура). Фрейворк virtio
также используется в исследованиях высокопроизводительных вычислительных систем для разработки средств взаимодействия виртуальных машин через совместно используемую память. В частности этот фреймворк был использован для реализации виртуализированного интерфейса шины PCI, для чего был использован драйвер virtio PCI
. Более подробную информацию вы можете получить в разделе Ресурсы оригинала статьи.
Примеры использования инфраструктуры паравиртуализации сегодня можно найти в ядре Linux. Все, что вам нужно, это ядро, которое действует как гипервизор, гостевое ядро и QEMU для эмуляции устройств. Вы можете использовать либо KVM (модуль, который существует в хостовом ядра), либо lguest
, разработанный Расти Расселлом (модифицированное гостевое ядро Linux). Оба эти решения виртуализации поддерживают фреймворк virtio
(вместе с QEMU, используемом для эмуляции, и libvirt
, используемом для управления виртуализацией).
Результатом работы Расти Расселла является более простой код драйверов паравиртуализации и более быстрая эмуляция виртуальных устройств. Но даже более важно то, что, как было обнаружено, фреймворк virtio
обеспечивает большую производительность (в 2-3 раза выше для сетевого ввода/вывода), чем имеющиеся в настоящий момент коммерческие решения. Это повышение производительности требует определенных затрат, но они окупаются, если в качестве гипервизора и гостевых систем используется Linux.
Двигаемся дальше
Хотя, возможно, вы никогда не будете разрабатывать front-end или back-end драйвера для фреймворка virtio
, в нем реализована интересная архитектура и в ней стоит разобраться более подробно. В сравнении с предыдущими вариантами, реализованными в Xen, в virtio
предоставлены новые возможности эффективных решений в средах паравиртуализированного ввода/вывода. Linux продолжает самоутверждаться в качестве промышленного гипервизора и в качестве научно-исследовательской платформы для новых технологий виртуализации. А virtio
является еще одним примером преимуществ и пригодности Linux для использования в качестве гипервизора.
Ссылки на другие статьи по теме виртуализации вы найдете в разделе "Технологии и средства виртуализации" нашей Библиотеки.