Skip to content

Commit

Permalink
Add -kvm and -vcpu options to show information about all the VMs and …
Browse files Browse the repository at this point in the history
…VCPUs of each VM.

Signed-off-by: Siddhi Katage <[email protected]>
  • Loading branch information
SiddhiK29 committed Nov 22, 2024
1 parent 61704f2 commit c820215
Show file tree
Hide file tree
Showing 2 changed files with 222 additions and 1 deletion.
221 changes: 220 additions & 1 deletion drgn_tools/virtutil.py
100755 → 100644
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,206 @@
Utilities for virtualization
"""
import argparse
from typing import Iterable

from drgn import cast
from drgn import Object
from drgn import Program
from drgn.helpers.linux.cpumask import for_each_possible_cpu
from drgn.helpers.linux.list import list_for_each_entry
from drgn.helpers.linux.percpu import per_cpu
from drgn.helpers.linux.pid import find_task
from drgn.helpers.linux.sched import task_state_to_char
from drgn.helpers.linux.xarray import xa_for_each

from drgn_tools.corelens import CorelensModule
from drgn_tools.table import print_table
from drgn_tools.util import has_member


KVM_VCPU_STATE = {
0: "RUNNABLE",
1: "UNINITIALIZED",
2: "INIT_RECEIVED",
3: "HALTED",
4: "SIPI_RECEIVED",
5: "STOPPED",
6: "CHECK_STOP",
7: "OPERATING",
8: "LOAD",
}


def get_vm_list(prog: Program) -> Iterable[Object]:
"""
Returns list of Object of type ``struct kvm *
"""
vm_list = []
try:
vm_list = list(
list_for_each_entry(
"struct kvm", prog["vm_list"].address_of_(), "vm_list"
)
)
except KeyError:
print("No VMs running")

return vm_list


def print_vm_list(prog: Program) -> None:
"""
Print information for all the VMs
"""
vm_list = get_vm_list(prog)

print(" =============<< VM LIST >>=================")
print("\n")
rows = [
[
"KVM",
"ONL",
"CRT",
"MEMSLOT_0",
"MEMSLOT_1",
"VCPUS",
"KVM_ARCH",
"KVM_STAT",
"PID",
"TASK",
"CPU",
"ST",
]
]

for vm in vm_list:
kvm_addr = hex(vm.value_())
pid = vm.userspace_pid.value_()
task = find_task(prog, pid)
if has_member(task, "cpu"):
cpu = task.cpu.value_()
else:
cpu = task.recent_used_cpu.value_()

if has_member(vm, "vcpus"):
vcpu = hex(vm.vcpus.address_of_())
else:
vcpu = hex(vm.vcpu_array.address_of_())

rows.append(
[
kvm_addr,
vm.online_vcpus.counter.value_(),
vm.created_vcpus.value_(),
hex(vm.memslots[0].value_()),
hex(vm.memslots[1].value_()),
vcpu,
hex(vm.arch.address_of_()),
hex(vm.stat.address_of_()),
pid,
hex(task.value_()),
cpu,
task_state_to_char(task),
]
)
print_table(rows)


def print_vcpu_list(prog: Program) -> None:
"""
Print information for all the vcpus of each VM
"""
vm_list = get_vm_list(prog)
print(" =============<< VCPU LIST >>=================")
print("\n")
rows = [
[
"KVM",
"VCPU",
"ID",
"IDX",
"ARCH",
"STAT",
"STAT_ID",
"STATE",
"CPU",
"TASK",
]
]

# for UEK5 to UEK7:
for vm in vm_list:
if has_member(vm, "vcpus"):
struct_vcpu = vm.vcpus
for i in range(len(struct_vcpu)):
if hex(struct_vcpu[i].value_()) == "0x0":
break
vcpu = hex(struct_vcpu[i].value_())
id = struct_vcpu[i].vcpu_id.value_()
if has_member(struct_vcpu[i], "vcpu_idx"):
idx = struct_vcpu[i].vcpu_idx.value_()
else:
idx = i
arch = hex(struct_vcpu[i].arch.address_of_())
stat = hex(struct_vcpu[i].stat.address_of_())
if has_member(struct_vcpu[i], "stats_id"):
stat_id = struct_vcpu[i].stats_id.string_().decode("utf-8")
else:
# The UEK5 does not have kvm_vcpu.stats_id structure member. Print None instead.
stat_id = None
state = struct_vcpu[i].arch.mp_state.value_()
cpu = struct_vcpu[i].cpu.value_()
if has_member(struct_vcpu[i], "wait"):
task = hex(struct_vcpu[i].wait.task.value_())
else:
# The UEK5 does not have kvm_vcpu.wait structure member. Print None instead.
task = None
rows.append(
[
hex(vm.value_()),
vcpu,
id,
idx,
arch,
stat,
stat_id,
KVM_VCPU_STATE[state],
cpu,
str(task),
]
)
# For UEK-NEXT:
else:
for _, entry in xa_for_each(vm.vcpu_array.address_of_()):
struct_vcpu = cast("struct kvm_vcpu *", entry)
if hex(struct_vcpu.value_()) == "0x0":
break
vcpu = hex(struct_vcpu.value_())
id = struct_vcpu.vcpu_id.value_()
idx = struct_vcpu.vcpu_idx.value_()
arch = hex(struct_vcpu.arch.address_of_())
stat = hex(struct_vcpu.stat.address_of_())
stat_id = struct_vcpu.stats_id.string_().decode("utf-8")
state = struct_vcpu.arch.mp_state.value_()
cpu = struct_vcpu.cpu.value_()
task = hex(struct_vcpu.wait.task.value_())

rows.append(
[
hex(vm.value_()),
vcpu,
id,
idx,
arch,
stat,
stat_id,
KVM_VCPU_STATE[state],
cpu,
str(task),
]
)

print_table(rows)


def get_platform_arch(prog: Program) -> str:
Expand Down Expand Up @@ -93,6 +286,32 @@ class VirtUtil(CorelensModule):

name = "virt"

def add_args(self, parser: argparse.ArgumentParser) -> None:
parser.add_argument(
"-kvm",
dest="list_vm",
action="store_true",
help="show all VM info",
)
parser.add_argument(
"-vcpu",
dest="vcpu_list",
action="store_true",
help="show all vcpu info",
)
parser.add_argument(
"-p",
dest="show_platform",
action="store_true",
help="show platfrom related information",
)

def run(self, prog: Program, args: argparse.Namespace) -> None:
show_platform(prog)
if args.show_platform:
show_platform(prog)
elif args.list_vm:
print_vm_list(prog)
elif args.vcpu_list:
print_vcpu_list(prog)

return
2 changes: 2 additions & 0 deletions tests/test_virtutil.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,5 @@
def test_virtutil(prog):
virtutil.show_cpuhp_state(prog)
virtutil.show_platform(prog)
virtutil.print_vm_list(prog)
virtutil.print_vcpu_list(prog)

0 comments on commit c820215

Please sign in to comment.