Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

kvm_watcher项目:修改README.md并添加注释 #652

Merged
merged 2 commits into from
Jan 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 10 additions & 2 deletions eBPF_Supermarket/kvm_watcher/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,11 @@ BPF program used for monitoring KVM event
## 五、测试

可以按照如下流程测试程序输出:

- **查看本地是否支持虚拟化**
```
grep -Eoc '(vmx|svm)' /proc/cpuinfo
若大于0,则支持
```
- **安装依赖**

```
Expand All @@ -134,7 +138,11 @@ BPF program used for monitoring KVM event
```
sudo qemu-system-x86_64 -enable-kvm -cpu host -m 2048 -drive file=cirros-0.5.1-x86_64-disk.img,format=qcow2 -boot c -nographic
```

- **也可以使用virt-manager图形化工具来创建并启动虚拟机**
```
sudo apt install qemu qemu-kvm libvirt-daemon-system libvirt-clients virt-manager virtinst bridge-utils
接下来就可以使用virt-manager图形化工具来设置虚拟机了
```
- **编译&&运行程序**

```
Expand Down
8 changes: 4 additions & 4 deletions eBPF_Supermarket/kvm_watcher/include/kvm_exits.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
#include <bpf/bpf_helpers.h>
#include <bpf/bpf_core_read.h>
#include <bpf/bpf_tracing.h>

//定义哈希结构,存储时间信息
struct {
__uint(type, BPF_MAP_TYPE_HASH);
__uint(max_entries, 8192);
Expand All @@ -38,7 +38,7 @@ struct {
__type(key, u32);
__type(value, u32);
} counts SEC(".maps");

//记录退出的信息
struct exit {
u64 pad;
unsigned int exit_reason;
Expand All @@ -52,7 +52,7 @@ struct exit {
};

int total = 0;

//记录vm_exit的原因以及时间
static int trace_kvm_exit(struct exit *ctx, pid_t vm_pid) {
u64 id, ts;
id = bpf_get_current_pid_tgid();
Expand All @@ -79,7 +79,7 @@ static int trace_kvm_exit(struct exit *ctx, pid_t vm_pid) {
}
return 0;
}

//通过kvm_exit所记录的信息,来计算出整个处理的时间
static int trace_kvm_entry(void *rb, struct common_event *e) {
struct reason_info *reas;
pid_t pid, tid;
Expand Down
4 changes: 2 additions & 2 deletions eBPF_Supermarket/kvm_watcher/include/kvm_vcpu.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ struct {
__type(key, u32);
__type(value, u32);
} vcpu_tid SEC(".maps");

//记录vcpu_halt的id信息
static int trace_kvm_vcpu_halt(struct kvm_vcpu *vcpu, pid_t vm_pid) {
CHECK_PID(vm_pid) {
u32 tid = bpf_get_current_pid_tgid();
Expand All @@ -63,7 +63,7 @@ static int trace_kvm_vcpu_halt(struct kvm_vcpu *vcpu, pid_t vm_pid) {
}
return 0;
}

//使用kvm_vcpu_halt记录的数据,来获取vcpu的启动信息
static int trace_kvm_vcpu_wakeup(struct vcpu_wakeup *ctx, void *rb,
struct common_event *e, pid_t vm_pid) {
CHECK_PID(vm_pid) {
Expand Down
10 changes: 6 additions & 4 deletions eBPF_Supermarket/kvm_watcher/src/kvm_watcher.bpf.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,31 +31,33 @@ char LICENSE[] SEC("license") = "Dual BSD/GPL";
const volatile pid_t vm_pid = -1;
static struct common_event *e;

//定义环形缓冲区maps
struct {
__uint(type, BPF_MAP_TYPE_RINGBUF);
__uint(max_entries, 256 * 1024);
} rb SEC(".maps");

//获取vcpu的id
SEC("fentry/kvm_vcpu_halt")
int BPF_PROG(fentry_kvm_vcpu_halt, struct kvm_vcpu *vcpu) {
return trace_kvm_vcpu_halt(vcpu, vm_pid);
}

//追踪vcpu运行信息
SEC("tp/kvm/kvm_vcpu_wakeup")
int tp_vcpu_wakeup(struct vcpu_wakeup *ctx) {
return trace_kvm_vcpu_wakeup(ctx, &rb, e, vm_pid);
}

//记录vcpu的halt_poll(暂停轮询)时间变化
SEC("tp/kvm/kvm_halt_poll_ns")
int tp_kvm_halt_poll_ns(struct halt_poll_ns *ctx) {
return trace_kvm_halt_poll_ns(ctx, &rb, e, vm_pid);
}

//记录vm_exit的时间
SEC("tp/kvm/kvm_exit")
int tp_exit(struct exit *ctx) {
return trace_kvm_exit(ctx, vm_pid);
}

//记录vm_entry和vm_exit的时间差
SEC("tp/kvm/kvm_entry")
int tp_entry(struct exit *ctx) {
return trace_kvm_entry(&rb, e);
Expand Down
34 changes: 21 additions & 13 deletions eBPF_Supermarket/kvm_watcher/src/kvm_watcher.c
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
#include <unistd.h>
#include "../include/kvm_watcher.h"
#include "kvm_watcher.skel.h"

//定义具体的退出原因
struct ExitReason exitReasons[] = {{0, "EXCEPTION_NMI"},
{1, "EXTERNAL_INTERRUPT"},
{2, "TRIPLE_FAULT"},
Expand Down Expand Up @@ -169,7 +169,7 @@ void freeExitInfoList(Node *head) {
free(temp);
}
}

//打印退出的信息
void printExitInfo(Node *head) {
Node *current = head;
CLEAR_SCREEN();
Expand All @@ -185,7 +185,7 @@ void printExitInfo(Node *head) {
current = current->next;
}
}

//检查具有给定 PID 的进程是否存在
int doesVmProcessExist(pid_t pid) {
char proc_name[256];
snprintf(proc_name, sizeof(proc_name), "/proc/%d/cmdline", pid);
Expand All @@ -197,6 +197,7 @@ int doesVmProcessExist(pid_t pid) {
if (proc_name[size - 1] == '\n') {
proc_name[size - 1] = '\0'; // Remove newline character
}
//查看是否进程文件中是否出现"qemu-system"字符串
if (strstr(proc_name, "qemu-system") != NULL) {
fclose(file);
return 1; // VmProcess name contains the target string
Expand All @@ -223,7 +224,7 @@ struct KeyValPair {
int compare(const void *a, const void *b) {
return ((struct KeyValPair *)b)->value - ((struct KeyValPair *)a)->value;
}

//保存脏页信息到./temp/dirty_temp文件中
int save_count_dirtypagemap_to_file(struct bpf_map *map) {
const char *directory = "./temp";
const char *filename = "./temp/dirty_temp";
Expand Down Expand Up @@ -289,7 +290,7 @@ int save_count_dirtypagemap_to_file(struct bpf_map *map) {
free(pairs);
return 0;
}

//定义env结构体,用来存储程序中的事件信息
static struct env {
bool execute_vcpu_wakeup;
bool execute_exit;
Expand Down Expand Up @@ -320,7 +321,7 @@ const char *argp_program_version = "kvm_watcher 1.0";
const char *argp_program_bug_address = "<[email protected]>";
const char argp_program_doc[] = "BPF program used for monitoring KVM event\n";
int option_selected = 0; // 功能标志变量,确保激活子功能

//具体解释命令行参数
static const struct argp_option opts[] = {
{"vcpu_wakeup", 'w', NULL, 0, "Monitoring the wakeup of vcpu."},
{"vm_exit", 'e', NULL, 0, "Monitoring the event of vm exit."},
Expand All @@ -340,7 +341,7 @@ static const struct argp_option opts[] = {
{"monitoring_time", 't', "SEC", 0, "Time for monitoring."},
{},
};

//解析命令行参数
static error_t parse_arg(int key, char *arg, struct argp_state *state) {
switch (key) {
case 'w':
Expand Down Expand Up @@ -407,7 +408,7 @@ static error_t parse_arg(int key, char *arg, struct argp_state *state) {
}
return 0;
}

//定义解析参数的处理函数
static const struct argp argp = {
.options = opts,
.parser = parse_arg,
Expand All @@ -420,7 +421,7 @@ static int libbpf_print_fn(enum libbpf_print_level level, const char *format,
}

static volatile bool exiting = false;

//设置信号来控制是否打印信息
static void sig_handler(int sig) {
exiting = true;
}
Expand All @@ -447,7 +448,7 @@ static int determineEventType(struct env *env) {
}
return 0;
}

//获取中断控制器的类型
const char *get_irqchip(unsigned char chip) {
if (chip >= KVM_NR_IRQCHIPS) {
return "Invalid";
Expand All @@ -461,7 +462,7 @@ const char *get_irqchip(unsigned char chip) {
return "Unknown";
}
}

/*环形缓冲区的处理函数,用来打印ringbuff中的数据(最后展示的数据行)*/
static int handle_event(void *ctx, void *data, size_t data_sz) {
struct common_event *e = data;
switch (env.event_type) {
Expand Down Expand Up @@ -569,7 +570,7 @@ static int handle_event(void *ctx, void *data, size_t data_sz) {

return 0;
}

/*通过env->event_type属性来选择需要打印的信息表头*/
static int print_event_head(struct env *env) {
if (!env->event_type) {
// 处理无效参数,可以选择抛出错误或返回
Expand Down Expand Up @@ -610,7 +611,7 @@ static int print_event_head(struct env *env) {
}
return 0;
}

/*通过env结构体的属性真值来判断是否加载某个挂载函数*/
static void set_disable_load(struct kvm_watcher_bpf *skel) {
bpf_program__set_autoload(skel->progs.tp_vcpu_wakeup,
env.execute_vcpu_wakeup ? true : false);
Expand Down Expand Up @@ -639,16 +640,19 @@ static void set_disable_load(struct kvm_watcher_bpf *skel) {
}

int main(int argc, char **argv) {
//定义一个环形缓冲区
struct ring_buffer *rb = NULL;
struct kvm_watcher_bpf *skel;
int err;

/* Parse command line arguments */
/*解析命令行参数*/
err = argp_parse(&argp, argc, argv, 0, NULL, NULL);
if (err)
return err;

/* Set up libbpf errors and debug info callback */
/*设置libbpf的错误和调试信息回调*/
libbpf_set_print(libbpf_print_fn);

/* Cleaner handling of Ctrl-C */
Expand All @@ -666,23 +670,27 @@ int main(int argc, char **argv) {
skel->rodata->vm_pid = env.vm_pid;

/* Disable or load kernel hook functions */
/* 禁用或加载内核挂钩函数 */
set_disable_load(skel);

/* Load & verify BPF programs */
/* 加载并验证BPF程序 */
err = kvm_watcher_bpf__load(skel);
if (err) {
fprintf(stderr, "Failed to load and verify BPF skeleton\n");
goto cleanup;
}

/* Attach tracepoint handler */
/* 附加跟踪点处理程序 */
err = kvm_watcher_bpf__attach(skel);
if (err) {
fprintf(stderr, "Failed to attach BPF skeleton\n");
goto cleanup;
}

/* Set up ring buffer polling */
/* 设置环形缓冲区轮询 */
rb = ring_buffer__new(bpf_map__fd(skel->maps.rb), handle_event, NULL, NULL);
if (!rb) {
err = -1;
Expand Down