Bạn đang quản lý một VM đang chạy và cần debug vấn đề gì đó mà không muốn SSH vào guest? Hoặc muốn test xem ứng dụng phản ứng thế nào khi disk bị lỗi đột ngột? QEMU Monitor Console và QMP Protocol cho phép làm đúng những thứ đó — trực tiếp từ tầng hypervisor, guest OS không hề hay biết.
Quick Start — Kết nối QEMU Monitor trong 5 phút
Nếu bạn đang khởi động VM với QEMU/KVM thủ công, thêm hai option này vào lệnh khởi động:
qemu-system-x86_64 \
-monitor unix:/tmp/qemu-monitor.sock,server,nowait \
-qmp unix:/tmp/qemu-qmp.sock,server,nowait \
-drive file=/path/to/disk.qcow2,if=virtio \
-m 2048 -smp 2
Kết nối vào monitor bằng socat — nc thường buffer lệnh không đúng trên Ubuntu, socat xử lý readline tốt hơn nhiều:
socat readline UNIX-CONNECT:/tmp/qemu-monitor.sock
Prompt (qemu) xuất hiện — bạn đang ở trong QEMU Monitor. Thử ngay vài lệnh:
(qemu) info status
(qemu) info cpus
(qemu) info block
(qemu) stop
(qemu) cont
Nếu VM chạy qua libvirt, dùng virsh để ra lệnh mà không cần mở interactive session:
virsh qemu-monitor-command --hmp myvm "info status"
virsh qemu-monitor-command --hmp myvm "info block"
QEMU Monitor Console là gì và khi nào cần dùng?
Nghĩ nó như một backdoor vào chính tiến trình QEMU — không phải vào guest OS. Guest không nhận được bất kỳ tín hiệu nào khi bạn tương tác qua monitor, dù bạn đang stop CPU hay dump toàn bộ RAM của nó.
Có hai protocol để nói chuyện với monitor:
- HMP (Human Monitor Protocol) — text command, gõ tay được, dùng để debug nhanh
- QMP (QEMU Machine Protocol) — JSON-based, dành cho scripting và automation
Mình chạy homelab với Proxmox VE quản lý 12 VM và container — đây là playground để test mọi thứ trước khi đưa lên production. Và có những tình huống SSH vào guest đơn giản là không khả thi:
- VM bị treo hoàn toàn, không nhận SSH nhưng process QEMU vẫn còn sống
- Cần snapshot memory để phân tích trạng thái RAM mà không làm gián đoạn guest
- Muốn inject disk error để kiểm tra disaster recovery script có chạy thật không
- Debug network packet ở tầng virtual NIC trước khi vào kernel của guest
QMP Protocol — Tự động hóa bằng JSON và Python
QMP trả JSON cho mọi response. Parse xong là có dict sạch ngay — không cần regex, không cần tự split chuỗi như với HMP.
Kết nối QMP thủ công
socat - UNIX-CONNECT:/tmp/qemu-qmp.sock
Server gửi greeting ngay lập tức. Bắt buộc phải gửi qmp_capabilities trước khi ra bất kỳ lệnh nào:
{ "execute": "qmp_capabilities" }
{ "execute": "query-status" }
Script Python để giao tiếp với QMP
Thay vì gõ tay từng JSON, viết một wrapper nhỏ tiện hơn nhiều:
import socket
import json
class QMPClient:
def __init__(self, sock_path):
self.sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
self.sock.settimeout(10)
self.sock.connect(sock_path)
self._recv() # greeting
self.execute("qmp_capabilities")
def _recv(self):
data = b""
while True:
chunk = self.sock.recv(4096)
data += chunk
try:
return json.loads(data.decode())
except json.JSONDecodeError:
continue
def execute(self, cmd, **kwargs):
payload = {"execute": cmd}
if kwargs:
payload["arguments"] = kwargs
self.sock.sendall(json.dumps(payload).encode() + b"\n")
return self._recv()
# Sử dụng
qmp = QMPClient("/tmp/qemu-qmp.sock")
status = qmp.execute("query-status")
print(status) # {"return": {"status": "running", "running": true}}
qmp.execute("stop")
qmp.execute("cont")
Inject lỗi và Debug từ tầng Hypervisor
Pause VM như breakpoint trong debugger
Stop VM tại một thời điểm cụ thể để quan sát toàn bộ trạng thái — mọi thứ đứng lại nguyên vẹn, từ CPU registers đến memory mapping:
(qemu) stop
(qemu) info registers # CPU registers tại thời điểm dừng
(qemu) info mem # memory mapping
(qemu) x /10i $rip # disassemble 10 instructions từ instruction pointer
(qemu) cont # tiếp tục chạy
Dump memory để phân tích forensic
# Qua HMP
(qemu) dump-guest-memory -z /tmp/vm-memory.dump
# Qua QMP
qmp.execute("dump-guest-memory",
paging=False,
protocol="file:/tmp/vm-memory.dump",
format="elf"
)
File dump mở được bằng Volatility để tìm process đang chạy, open file handles, hay artifact bất kỳ trong RAM. Mình đã dùng cách này để phân tích một VM nghi bị cài rootkit — dump xong chạy volatility3 -f vm-memory.dump linux.pslist, tìm ra một process ẩn dưới tên kworker/1:2H với parent PID bất thường. Điều tra xong mà volatile data còn nguyên, máy không bị tắt lần nào.
Inject disk error để test disaster recovery
Đây là use case mình dùng thường xuyên nhất — kiểm tra backup script có thực sự recover được không khi disk fail:
# Liệt kê block devices
(qemu) info block
# Output: drive-scsi0-0-0-0: /var/lib/vz/images/100/vm-100-disk-0.qcow2
# Throttle I/O xuống gần 0 để simulate disk chậm/lỗi
(qemu) block_set_io_throttle drive-scsi0-0-0-0 1 0 1 0 0 0
Sáu con số lần lượt giới hạn: tổng bandwidth (bytes/s), read bandwidth, write bandwidth, tổng iops, read iops, write iops — giá trị 0 nghĩa là không áp giới hạn riêng chiều đó. Đặt bandwidth về 1 byte/s là disk hoạt động nhưng cực chậm, đủ để trigger timeout và kiểm tra retry logic của ứng dụng.
Để inject lỗi I/O ở tầng thấp hơn, dùng blkdebug driver khi khởi động VM:
qemu-system-x86_64 \
-drive file=blkdebug::/path/to/disk.qcow2,if=virtio,format=qcow2 \
-m 2048
Live snapshot mà không tắt VM
# Lưu toàn bộ trạng thái (CPU + RAM + disk)
(qemu) savevm checkpoint-before-test
# Liệt kê snapshots
(qemu) info snapshots
# Revert về trạng thái cũ
(qemu) loadvm checkpoint-before-test
Lưu ý: savevm tạo internal QEMU snapshot, khác với snapshot của libvirt. File snapshot lưu trực tiếp vào qcow2 image.
Capture network packet tại virtual NIC
# Bật packet capture trên interface ảo (netdev id lấy từ config khởi động)
(qemu) object_add filter-dump,id=f1,netdev=net0,file=/tmp/vm-traffic.pcap
# Tắt khi xong
(qemu) object_del f1
File pcap này mở bằng Wireshark bình thường. Điểm hay là bạn thấy đúng những gì đi vào virtual NIC — trước khi iptables hay bất kỳ firewall rule nào bên trong guest can thiệp. Dùng để tách biệt hai câu hỏi khác nhau hoàn toàn: “traffic có tới VM không” và “VM có xử lý traffic đó không”.
Tips thực tế khi làm việc với QEMU Monitor
Tìm socket path khi không biết ở đâu:
ps aux | grep qemu | grep -o 'qmp [^ ]*'
# Hoặc với libvirt
virsh dumpxml myvm | grep -i monitor
QMP over TCP cho remote control:
qemu-system-x86_64 \
-qmp tcp:127.0.0.1:4444,server,nowait \
...
# Kết nối (chỉ mở port ra ngoài khi có firewall hoặc tunnel, QMP không có auth)
socat - TCP:127.0.0.1:4444
One-liner với virsh cho scripting:
# HMP command
virsh qemu-monitor-command --hmp myvm "info block"
# QMP command (JSON)
virsh qemu-monitor-command myvm '{"execute": "query-block"}'
Kiểm tra VM còn sống khi bị treo:
# Nếu monitor vẫn respond thì process QEMU còn sống dù guest có hang
virsh qemu-monitor-command --hmp myvm "info status"
Monitor console không thay thế SSH hay các tool monitoring thông thường. Nhưng khi mọi thứ khác không dùng được — VM treo cứng, SSH timeout, agent không respond — monitor vẫn ở đó. Memory dump trong vòng 30 giây. Disk throttle để test recovery mà không cần hardware thật hỏng. Quen với nó rồi sẽ thấy nhiều bài toán VM tưởng khó hóa ra giải quyết được trong vài phút.

