Entrevista com Eduardo Habkost

A comunidade kernelnewbies-br volta a suas atividades e com grande prazer realizando uma série de entrevistas com kernel hackers brasileiros, envolvidos com projetos interessantes e que tem muito a nos ensinar. Nesta primeira entrevista com Eduardo Habkost pudemos falar um pouco sobre virtualização, KVM, detalhes e desafios no desenvolvimento de uma plataforma de virtualização.

Olá Eduardo, primeiramente muito obrigado por doar um pouco do seu tempo a comunidade kernelnewbies-br e gostaria de começar sabendo um pouco sobre a sua jornada de kernel hacking? como você começou e quais foram as suas principais motivações?

Eu ouvi falar do Linux pela primeira vez em torno de 1999, quando fazia curso técnico de nível médio em Processamento de Dados na Escola Técnica da UFPR (ET-UFPR). Comecei a ver como é usar o Linux quando os alunos do curso ganharam contas em um servidor com acesso via telnet. Os desktops da escola ainda rodavam Windows, porém.

Enquanto aprendia a programar, sempre me interessei por programação de baixo nível. No curso, depois de aprender Pascal, a minha diversão era aprender como acessar o hardware diretamente em programas para DOS. Do Pascal, resolvi aprender C e assembly. Quando descobri que podia compilar meus próprios programas em C no servidor da escola, foi diversão garantida por vários meses.

Em algum ponto em 1999 instalei o Linux em casa. Comecei com uma distribuição que usava um diretório de uma partição FAT como filesystem, e "bootava" a partir do DOS. Era uma coisa mágica pra mim, e tudo que eu queria era aprender como tudo aquilo funcionava.

Alguns meses depois instalei uma versão extremamente velha do Slackware (acho que era de 1996). Passei por aqueles problemas que todo mundo passava na época: penei para fazer minha placa de video e meu modem funcionarem direito. Com o adicional que eu nem mesmo sabia que o Slackware que eu estava rodando era extremamente velho, tornando os problemas ainda mais bizarros (e divertidos! :P).

Por outro lado isso foi extremamente útil: aprendi muito sobre como compilar programas; e um dia quando algo que eu estava instalando deu um erro de "você precisa de um kernel novo", fui direto baixar e instalar um kernel novo sem saber onde eu estava me metendo. Eu devo ter levado mais de uma semana pra conseguir bootar um kernel novo. Isso sem contar os 3 dias que devo ter levado para baixar o tarball do kernel pela minha conexão discada.

Paralelo a isso, eu trabalhei por uns 2 anos com programação para Windows (Delphi), mas em casa só usava Linux. Até que em 2001 (eu já estava cursando Ciência da Computação na UFPR), vi um anúncio sobre vaga de estágio na Conectiva. Eu sonhava há muito tempo em trabalhar com Linux.

Depois de uns 3 meses trabalhando em sistemas internos da Conectiva, fui convidado para a área de desenvolvimento do Conectiva Linux. Lá é que comecei a realmente trabalhar com kernel (antes, fuçar no kernel era apenas um hobby). Quando comecei a trabalhar na área, o Conectiva Linux 7 tinha acabado de sair. O que fazia principalmente era cuidar do pacote do kernel do CL, durante os CL 8, 9, e 10. Eu até tentava desenvolver alguma coisa e cheguei a enviar alguns patches, mas ainda tinha muito o que aprender. :)

Além de trabalhar diretamente com kernel, trabalhei em desenvolvimento em projetos variados na Conectiva, mas a maioria envolvendo programação de mais baixo nível em C. Apesar da faculdade de Ciência da Computação, foi no trabalho na Conectiva que mais aprendi sobre o kernel Linux e sobre desenvolvimento para Linux.

A Conectiva virou Mandriva, e trabalhei lá até março de 2007. Em 2007 fui para a Red Hat, trabalhar na equipe de virtualização, onde estou até hoje, tendo trabalhado principalmente no Projeto Fedora, com Xen até o ano passado e hoje principalmente com o KVM.

Quais áreas do KVM estão tomando sua atenção para o release do fedora 11?

Basicamente, o trabalho que tem sido feito para o Fedora 11 envolvendo KVM é o trabalho que está sendo feito upstream. O Fedora tem uma política de evitar incluir código que não tenha sido enviado e aceito para os projetos de software.

O que de interessante tem sido feito para melhorar KVM?

Coisas que têm sido feitas na área são muitas, mas posso mencionar: melhorias na área de 'live migration', trabalho bem grande para melhorar a performance de disco e rede nas máquinas virtuais (em geral para os casos em que se usa 'virtio'), melhor integração com o código do qemu[1], entre várias outras coisas.

- Nested KVM:

Outra coisa legal que foi incluída recentemente é o suporte a virtualização nas máquinas virtuais emuladas pelo KVM. Isso significa que dentro de uma máquina virtual será possível carregar o módulo KVM e ter "máquinas virtuais virtuais".

- KSM:

Uma coisa onde há trabalho recentemente[2], mas ainda não foi incluído, é o KSM. O KSM é um truque interessante para fazer processos (incluindo processos de máquinas virtuais do KVM) que possuem páginas de memória com o mesmo conteúdo (o que muito comum quando as máquinas rodam a mesma versão de um sistema operacional, com os mesmos executáveis carregados), e as junta em uma mesma página física, de maneira transparente para o processo. Claro, com todo o esquema de 'copy-on-write', que o kernel já tem para compartilhar memória física com o mesmo conteúdo, que automaticamente vai utilizar áreas de memória separadas caso um dos processos tente modificar a sua versão da página. O impacto no uso de memória física das máquinas virtuais pode ser bastante reduzido com isso.

[1] O KVM utiliza uma versão modificada do Qemu para emulação de dispositivos, mas o objetivo é integrar o suporte ao KVM no próprio Qemu, e diminuir cada vez mais as diferenças entre o Qemu usado pelo KVM e o Qemu original (para quem sabe o dia, reduzir as diferenças a zero :)

[2] http://www.mail-archive.com/kvm-devel@lists.sourceforge.net/msg11868.htm...

Quando isso vai para o Fedora?

Como o trabalho que tenho acompanhado mais é no repositório do KVM, não sei o quanto disso tudo vai acabar entrando na árvore do Linus para o release que vai ser utilizado no Fedora 11. Mas provavelmente boa parte do trabalho que foi feito até o momento vai acabar indo para o 2.6.29.

Você poderia nos detalhar um pouco mais sobre as particularidades de utilização de disco e rede por um sistema operacional em um ambiente virtualizado? e quais os principais obstáculos no processo de otimização da utilização desses recursos?

- Virtualização total vs. paravirtualização:

O problema que primeiro se vê em sistemas virtualizados que rodam sistemas operacionais não modificados como o KVM[1], é que o sistema precisa simular uma máquina de verdade, com detalhes presentes no hardware real.

Sistemas de virtualização que não precisam de moficações no sistema operacional da máquina virtual (como o KVM, Qemu, VMWare, e Xen quando configurado para tal) são chamados de sistemas de /virtualização total/, ou /full virtualization/.

O grande probleme é que aquilo que é muito fácil e eficiente de se implementar em hardware, pode ser extremamente complicado e ineficiente de se simular em software. O que pode ser enviado para o hardware na velocidade de um sinal elétrico pode precisar de trocas de contexto para rodar código do sistema hospedeiro, tratar o evento, e voltar para o sistema virtual (chamado de /guest/).

Por isso sistemas de /paravirtualização/ foram criados. Um dos mais conhecidos hoje é o Xen. Um sistema paravirtualizado precisa que o sistema operacional da máquina virtual seja modificado para pode rodar na máquina virtual.

- Drivers paravirtualizados:

O KVM está indo por um caminho misto entre essas duas abordagens, hoje. O KVM ainda simula boa parte do hardware virtual como se fosse uma máquina real, e pode rodar sistemas operacionais sem modificação. Porém, existem determinados dispositivos "virtuais", que utilizam uma interface específica para o /guest/ conversar com o hardware virtual, de maneira otimizada. Todos os detalhes da comunicação entre o SO e esse /hardware virtual/ foram pensados considerando as características de sistemas de virtualização. Muitas das técnicas utilizadas são semelhantes às usadas em sistemas totalmente paravirtualizados.

A diferença é que a paravirtualização é introduzida apenas onde a performance é algo crucial. Por exemplo, toda a sua máquina virtual pode ser semelhante a uma máquina real, exceto para a controladora de disco e placa de rede, que utilizam uma interface /paravirtual/.

O legal desse esquema éque o SO /guest/ não precisa nem saber que o hardware é virtual: o hardware virtual aparece como um dispositivo PCI como qualquer outro, por exemplo, e o driver para esse dispositivo é um driver que sabe conversar com o /host/ através da inteface paravirtualizada. Para o sistema operacional, o hardware é hardware de verdade, e o driver que conversa com ele é um driver como qualquer outro.

Existem vários padrões utilizados para implementação dessa interface. O XenBus, utilizado pelo Xen é uma dela. A que o KVM usa (e que tem mais futuro, na minha opinião) chama-se 'virtio'. O kernel oficial hoje já possui drivers para esses dispositivos virtuais. Tendo configuado sua máquina virtual para usar disco ou rede através de virtio, você pode simplesmente carregar os módulos 'virtio-net' e 'virtio-blk' no guest.

- I/O "passthrough":

Outra maneira de tentar otimizar o acesso a hardware em sistemas virtualizados é dar acesso a pedaços da máquina real diretamente aos guests. O chamado "I/O passthrough".

O problema dessa técnica é que se o hardware não tiver proteções adicionais, o guest pode instruir o dispositivo que ele está controlando a sobrescrever qualquer área de memória física do sistema real. Isso pode ser um problema de segurança sério.

Esse problema pode ser resolvido utilizando suporte no hardware para que a comunicação entre o guest e os dispositivos de I/O possa ser feita diretamente mas de maneira segura. A parte do hardware capaz de fazer essa intermediação é chamada de "IOMMU".

O kernel incluiu recentemente suporte à IOMMU da AMD, e também à tecnologia VT-d da Intel, também capaz de fazer essa intermediação.

- Otimização do código:

Outro ponto onde há espaço para otimização nos sistemas virtualizados é melhorar a implementação da emulação de dispositivos utilizada pelo KVM. O KVM utiliza o código de emulação de hardware incluindo no emulador Qemu. O código tem melhorado muito ultimamente, em qualidade e eficiência, mas ainda há bastante a fazer para que o KVM possa aproveitar ao máximo o potencial das tecnologias que descrevi acima.

A respeito de "Nested KVM" o que foi modificado para possibilitar o uso de máquinas virtuais em máquinas virtuais? se o sistema guest é um sistema operacional normal - uma vez que ele roda sem modificações com full virtualization - porque é preciso desenvolver modificações pra isso?

Como o KVM simula uma máquina real e tem que cuidar dos detalhes que uma máquina real cuidaria, o KVM também precisa saber simular as instruções SVM e VMX que uma máquina real provê.

As mudanças necessárias aqui são no lado do host, para que ele saiba como fazer de conta que é uma máquina real com suporte a virtualização. No lado do guest é necessário apenas ter um sistema de virtualização que funcione numa máquina real com suporte a SVM (pode ser KVM, Xen, ou outro). O guest nem mesmo precisa ser Linux.

Qual a visão que um sistema hypervisor tem do sistema guest? como é dado o início da virtualização e da emulação da máquina real?

Existem muitos componentes envolvidos, a resposta poderia virar um artigo completo. :)

Pra uma introdução, podemos dividir primeiro as tarefas que o sistema de virtualização tem que fazer, e depois quais componentes fazem cada uma delas no caso do KVM.

As várias tarefas são:

1) Virtualizar a CPU e a memória. Permitir que o sistema guest utilize a CPU e a memória, e expôr esses recursos de maneira segura e do jeito que o guest espera que funcione.

1.1) Gerenciamento do uso da CPU. Dividir o uso da CPU entre os guests

1.2) Gerenciamento do uso da memória.

2) Oferecer interface para acesso aos dispositivos de I/O virtuais. Oferecer uma maneira do guest acessar os dispositivos de I/O. Seja simulando dispositivos reais, seja oferecendo uma interface paravirtualizada para os dispositivos.

3) Oferecer interfaces da BIOS, para o caso de sistemas de virtualização total. Os sistemas operacionais esperam que uma máquina real tenha uma BIOS com todos os serviços que uma BIOS de uma máquina normal oferece.

4) Traduzir as operações realizadas com os dispositivos de I/O virtuais e os dispositivos de I/O reais.

5) Iniciar esse processo e juntar tudo isso.

5.1) Gerenciar o hardware real.

No caso do KVM, isso é feito:

1) A virtualização da CPU e da memória, em baixo nível, é feita pelos módulos kvm-intel e kvm-amd. O módulo kvm oferece uma interface para controlar esse processo a partir de userspace, com o dispositivo /dev/kvm. Boa parte das características do hardware real (manutenção de tabelas de páginas, emulação de algumas instruções privilegiadas) precisam ser tratadas pelo módulo kvm.

1.1) O gerenciamento do uso da CPU é feito pelo próprio scheduler do Linux. A CPU virtual é apenas uma thread, do ponto de vista do kernel.

1.2) O gerenciamento do uso da memória também é feito pelo próprio kernel. O módulo KVM trata de disponibilizar para o guest a memória alocada para o processo que é a CPU virtual. Mas a alocação de memória é feita do mesmo jeito que para um processo comum.

2) As interfaces da BIOS são implementadas por uma BIOS mesmo, que é carregada na memória da máquina virtual nos endereços onde o SO espera encontrá-la. Essa BIOS enxerga o hardware da mesma maneira que o sistema operacional guest enxerga.

3) A interface para o acesso aos dispositivos de I/O é feita em maior parte em userspace, utilizando a emulação de hardware do Qemu. Algumas coisas mais críticas, como timers e controlador de interrupções, podem ser emuladas em kernelspace, sem precisar entrar e sair de kernelspace para essas operações.

4) Quem traduz as operações realizadas com o hardware virtual para o hardware é o próprio Qemu.

4.1) Porém, quem gerencia o acesso ao hardware é o próprio kernel Linux, do mesmo jeito que acontece com processos comuns. Do ponto de vistado kernel host, o Qemu é apenas um processo comum.

5) Quem junta tudo isso e inicia esse processo é o Qemu modificado, com suporte ao kvm. O Qemu cria as "vcpus" (CPUs virtuais) usando o /dev/kvm, aloca a memória (do mesmo jeito que um processo comum), e trata os casos especiais de acesso a hardware cada vez que o /dev/kvm retorna porque o guest realizou uma operação que nem a CPU, nem o módulo do KVM sabem tratar.

Porém, nada impede que outro programa em userspace use o /dev/kvm para criar CPUs virtuais e tratá-las de modo diferente do que o Qemu faz. O Xenner[1], por exemplo, faz exatamente isso.

[1] http://kraxel.fedorapeople.org/xenner/

Quando o sistema está sendo emulado, há operações que são tratadas em diferentes níveis:

- Instruções simples da CPU são simplesmentes executadas pela CPU. Isso é possibilitado pelas extensões de virtualização SVM ou VMX. - Há instruções especiais que a CPU não virtualiza, como operaçõe de I/O e de tabelas de página. Nesse caso a CPU retorna e o módulo do KVM é responsável por virtualizar essa operação. O módulo do KVM trata as operações que pode tratar sem ajuda de userspace sozinho, e retorna o controle para a CPU virtualizada. - Quando é uma operação que o módulo do KVM não sabe tratar (como acesso a dispositivo de I/O que é emulado pelo Qemu), ele retorna o controle para userspace, que vai tratar a operação.

A idéia é que a maior parte das operações sejam feitas no nível mais baixo, até o limite do possível. Sair do modo de virtualização de hardware e retornar para o KVM tem um certo custo. Sair de kernelspace e retornar para userspace tem um custo ainda maior.

Para aqueles que estejam interessados em estudar virtualização - mais especificamente o KVM - quais os softwares/projetos a se atentarem(em user e kernel space)?

Pra qualquer um deles, o principal é: preste atenção no que ocorre nas listas de e-mail kvm-devel e qemu-devel. Tudo o que há de novo no KVM passa por lá.