O KVM é uma API do kernel para virtualização. Não lida com portas seriais . qemu
é um emulador de máquina (PC e outros) que pode usar kvm
para melhorar o desempenho da virtualização. Ele pode emular uma porta serial padrão UART 8250 ( isa-serial
) ou uma porta serial paravirtualizada ( virtio-serial
).
No qemu, você define sua máquina com argumentos de linha de comando que especificam qual dispositivo incluir em sua máquina e o que backend esses dispositivos mapeiam (por exemplo, disco rígido emulado para um arquivo de imagem, rede adaptadores para um tap
device ...).
Para portas seriais, você normalmente mapeia isso para o que o qemu chama chardevs .
Há muitos possíveis diferentes, normalmente qualquer coisa que possa enviar e receber bytes, como pipes, soquetes, descritores de arquivos, pseudo-terminais.
Por exemplo, se você executar o qemu como:
qemu ... -device isa-serial,chardev=c,id=s -chardev pty,id=c
qemu aloca um pseudo-terminal, relata isso no stdout na inicialização:
char device redirected to /dev/pts/18 (label c)
e mapeia isso para uma nova porta serial isa adicionada à VM. Se inicializar uma VM Linux, você verá nos logs do kernel:
[ 3.636092] Serial: 8250/16550 driver, 32 ports, IRQ sharing enabled
[ 3.658666] 00:05: ttyS0 at I/O 0x3f8 (irq = 4, base_baud = 115200) is a 16550A
E se você escrever algo para /dev/ttyS0
no convidado, poderá lê-lo em /dev/pts/18
no host.
Depois que um qemu VM é iniciado, você pode controlá-lo com o que o qemu chama de monitor interfaces. Existem dois tipos de interfaces monitor :
- Monitor humano: um CLI semelhante a shell
- Monitor de máquina: uma interface mais amigável à máquina que implementa um protocolo de texto (json) chamado qemu machine protocol (QMP).
Se você não especificar nada e usar o console SDL padrão, você receberá um monitor humano no console SDL pressionando Ctrl + Alt + 2 . p>
Mas você também pode especificar qualquer backend chardev (pty, socket, stdio ...) para isso. Normalmente, eu uso stdio
lá:
qemu ... -monitor stdio
Para obter o monitor no terminal, inicio o qemu ao executar o qemu para testes.
Na interface monitor , você pode executar o comando info qtree
para obter informações sobre os dispositivos da sua máquina:
(qemu) info qtree
bus: main-system-bus
[...]
dev: i440FX-pcihost, id ""
[...]
bus: pci.0
[...]
dev: PIIX3, id ""
class ISA bridge, addr 00:01.0, pci id 8086:7000 (sub 1af4:1100)
bus: isa.0
type ISA
dev: isa-serial, id "s"
index = 0 (0)
iobase = 1016 (0x3f8)
irq = 4 (0x4)
chardev = "c"
Acima, você vê o dispositivo isa-serial
que criei anteriormente e mapeia para o "c"
chardev .
Você pode obter informações desse chardev usando info chardev
:
(qemu) info chardev
parallel0: filename=vc
c: filename=pty:/dev/pts/18
compat_monitor0: filename=stdio
Você vê c
maps no /dev/pts/18
pty .
Você pode obter as mesmas informações programaticamente com um monitor QMP. Se você iniciar sua VM com -qmp stdio
, poderá passar os comandos para lá:
{"execute":"qmp_capabilities"} # enable commands
{"return": {}} # return value
{"execute":"qom-list","arguments":{"path":"/machine/peripheral/s"}}
{"return": [{"name": "parent_bus", "type": "link<bus>"}, {"name": "wakeup", "type": "uint32"}, {"name": "chardev", "type": "str"}, {"name": "irq", "type": "uint32"}, {"name": "iobase", "type": "uint32"}, {"name": "index", "type": "uint32"}, {"name": "hotpluggable", "type": "bool"}, {"name": "realized", "type": "bool"}, {"name": "type", "type": "string"}]}
# query chardev for "s":
{"execute":"qom-get","arguments":{"path":"/machine/peripheral/s","property":"chardev"}}
{"return": "c"}
# query chardevs:
{"execute":"query-chardev"}
{"return": [{"filename": "vc", "label": "parallel0"}, {"filename": "pty:/dev/pts/18", "label": "c"}, {"filename": "stdio", "label": "compat_monitor0"}]}
(veja como os qom-list
e qom-get
(qom que representam o modelo de objeto do qemu) fazem reminiscência de fazer ls
e cat
in /sys
na máquina Linux).
Agora, sua pergunta sugere que você não está chamando o qemu diretamente à mão, mas usando libvirt
. libvirt
é uma das muitas infraestruturas de gerenciamento de virtualização. Pode gerenciar VMs do qemu (com ou sem kvm), xen ou virtualbox (pelo menos).
Para VMs do qemu, quando você define uma VM em libvirt (com virt-manager ou outro), isso se traduz em argumentos a serem passados para um comando qemu, e o libvirt normalmente usa um monitor qmp para controlar uma VM após foi iniciado.
Para um domínio libvirt
, você pode obter a configuração atual de um domínio com:
virsh dumpxml the-domain
Que despeja a configuração como XML. Você pode extrair informações usando xmllint
ou xmlstarlet
ou qualquer solução de análise XML de sua escolha.
$ virsh dumpxml domain | xmllint --xpath '//serial' -
<serial type="pty">
<source path="/dev/pts/4"/>
<target port="0"/>
<alias name="serial0"/>
</serial><serial type="pty">
<source path="/dev/pts/5"/>
<target port="1"/>
<alias name="serial1"/>
</serial><serial type="pty">
<source path="/dev/pts/6"/>
<target port="2"/>
<alias name="serial2"/>
</serial>
$ virsh dumpxml domain |
xmllint --xpath 'string(//serial[target/@port=0]/source/@path)' -
/dev/pts/4
Os equivalentes com xmlstarlet
:
sudo virsh dumpxml domain | xmlstarlet sel -t -c '//serial'
sudo virsh dumpxml domain |
xmlstarlet sel -t -v '//serial[target/@port=0]/source/@path'
Note que você também pode passar comandos para o monitor QMP com o comando virsh qemu-monitor-command
.
Por exemplo:
$ virsh qemu-monitor-command domain '{"execute":"qom-get","arguments":
{"path":"/machine/peripheral/serial0","property":"chardev"}}'
{"return":"charserial0","id":"libvirt-84"}