583 lines
18 KiB
Diff
583 lines
18 KiB
Diff
|
|
From 0eac597a6f853c4eb41d7ebe58398c117798542c Mon Sep 17 00:00:00 2001
|
||
|
|
From: WangFengTu <wangfengtu@huawei.com>
|
||
|
|
Date: Fri, 29 Jan 2021 16:55:13 +0800
|
||
|
|
Subject: [PATCH] support cgroup v2
|
||
|
|
|
||
|
|
Signed-off-by: WangFengTu <wangfengtu@huawei.com>
|
||
|
|
---
|
||
|
|
src/lxc/cgroups/cgroup2_devices.c | 126 +++++++++++++++++++----------
|
||
|
|
src/lxc/cgroups/isulad_cgfsng.c | 56 ++++++++++++-
|
||
|
|
src/lxc/lxccontainer.c | 129 ++++++++++++++++++++++++++++++
|
||
|
|
3 files changed, 269 insertions(+), 42 deletions(-)
|
||
|
|
|
||
|
|
diff --git a/src/lxc/cgroups/cgroup2_devices.c b/src/lxc/cgroups/cgroup2_devices.c
|
||
|
|
index 4efb28fb..05613c51 100644
|
||
|
|
--- a/src/lxc/cgroups/cgroup2_devices.c
|
||
|
|
+++ b/src/lxc/cgroups/cgroup2_devices.c
|
||
|
|
@@ -25,6 +25,19 @@
|
||
|
|
#include <linux/bpf.h>
|
||
|
|
#include <linux/filter.h>
|
||
|
|
|
||
|
|
+#define BPF_LOG_BUF_SIZE (1 << 23) /* 8MB */
|
||
|
|
+#ifndef BPF_LOG_LEVEL1
|
||
|
|
+#define BPF_LOG_LEVEL1 1
|
||
|
|
+#endif
|
||
|
|
+
|
||
|
|
+#ifndef BPF_LOG_LEVEL2
|
||
|
|
+#define BPF_LOG_LEVEL2 2
|
||
|
|
+#endif
|
||
|
|
+
|
||
|
|
+#ifndef BPF_LOG_LEVEL
|
||
|
|
+#define BPF_LOG_LEVEL (BPF_LOG_LEVEL1 | BPF_LOG_LEVEL2)
|
||
|
|
+#endif
|
||
|
|
+
|
||
|
|
lxc_log_define(cgroup2_devices, cgroup);
|
||
|
|
|
||
|
|
static int bpf_program_add_instructions(struct bpf_program *prog,
|
||
|
|
@@ -42,6 +55,8 @@ static int bpf_program_add_instructions(struct bpf_program *prog,
|
||
|
|
return log_error_errno(-1, ENOMEM, "Failed to reallocate bpf cgroup program");
|
||
|
|
|
||
|
|
prog->instructions = new_insn;
|
||
|
|
+ memset(prog->instructions + prog->n_instructions, 0,
|
||
|
|
+ sizeof(struct bpf_insn) * count);
|
||
|
|
memcpy(prog->instructions + prog->n_instructions, instructions,
|
||
|
|
sizeof(struct bpf_insn) * count);
|
||
|
|
prog->n_instructions += count;
|
||
|
|
@@ -118,29 +133,27 @@ void bpf_program_free(struct bpf_program *prog)
|
||
|
|
.off = 0, \
|
||
|
|
.imm = 0})
|
||
|
|
|
||
|
|
-static int bpf_access_mask(const char *acc)
|
||
|
|
+static int bpf_access_mask(const char *acc, __u32 *mask)
|
||
|
|
{
|
||
|
|
- int mask = 0;
|
||
|
|
-
|
||
|
|
if (!acc)
|
||
|
|
- return mask;
|
||
|
|
+ return 0;
|
||
|
|
|
||
|
|
for (; *acc; acc++)
|
||
|
|
switch (*acc) {
|
||
|
|
case 'r':
|
||
|
|
- mask |= BPF_DEVCG_ACC_READ;
|
||
|
|
+ *mask |= BPF_DEVCG_ACC_READ;
|
||
|
|
break;
|
||
|
|
case 'w':
|
||
|
|
- mask |= BPF_DEVCG_ACC_WRITE;
|
||
|
|
+ *mask |= BPF_DEVCG_ACC_WRITE;
|
||
|
|
break;
|
||
|
|
case 'm':
|
||
|
|
- mask |= BPF_DEVCG_ACC_MKNOD;
|
||
|
|
+ *mask |= BPF_DEVCG_ACC_MKNOD;
|
||
|
|
break;
|
||
|
|
default:
|
||
|
|
return -EINVAL;
|
||
|
|
}
|
||
|
|
|
||
|
|
- return mask;
|
||
|
|
+ return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
static int bpf_device_type(char type)
|
||
|
|
@@ -157,19 +170,18 @@ static int bpf_device_type(char type)
|
||
|
|
return -1;
|
||
|
|
}
|
||
|
|
|
||
|
|
-static inline bool bpf_device_all_access(int access_mask)
|
||
|
|
+static inline bool bpf_device_all_access(__u32 access_mask)
|
||
|
|
{
|
||
|
|
- return (access_mask == (BPF_DEVCG_ACC_READ | BPF_DEVCG_ACC_WRITE |
|
||
|
|
- BPF_DEVCG_ACC_MKNOD));
|
||
|
|
+ return access_mask == (BPF_DEVCG_ACC_READ | BPF_DEVCG_ACC_WRITE | BPF_DEVCG_ACC_MKNOD);
|
||
|
|
}
|
||
|
|
|
||
|
|
struct bpf_program *bpf_program_new(uint32_t prog_type)
|
||
|
|
{
|
||
|
|
__do_free struct bpf_program *prog = NULL;
|
||
|
|
|
||
|
|
- prog = calloc(1, sizeof(struct bpf_program));
|
||
|
|
+ prog = zalloc(sizeof(struct bpf_program));
|
||
|
|
if (!prog)
|
||
|
|
- return NULL;
|
||
|
|
+ return ret_set_errno(NULL, ENOMEM);
|
||
|
|
|
||
|
|
prog->prog_type = prog_type;
|
||
|
|
prog->kernel_fd = -EBADF;
|
||
|
|
@@ -209,12 +221,10 @@ int bpf_program_append_device(struct bpf_program *prog, struct device_item *devi
|
||
|
|
{
|
||
|
|
int ret;
|
||
|
|
int jump_nr = 1;
|
||
|
|
- struct bpf_insn bpf_access_decision[] = {
|
||
|
|
- BPF_MOV64_IMM(BPF_REG_0, device->allow),
|
||
|
|
- BPF_EXIT_INSN(),
|
||
|
|
- };
|
||
|
|
- int access_mask;
|
||
|
|
+ __u32 access_mask = 0;
|
||
|
|
int device_type;
|
||
|
|
+ struct bpf_insn bpf_access_decision[2];
|
||
|
|
+ bool add_exist = false;
|
||
|
|
|
||
|
|
if (!prog || !device)
|
||
|
|
return ret_set_errno(-1, EINVAL);
|
||
|
|
@@ -225,6 +235,13 @@ int bpf_program_append_device(struct bpf_program *prog, struct device_item *devi
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
+ ret = bpf_access_mask(device->access, &access_mask);
|
||
|
|
+ if (ret < 0)
|
||
|
|
+ return log_error_errno(ret, -ret, "Invalid access mask specified %s", device->access);
|
||
|
|
+
|
||
|
|
+ if (!bpf_device_all_access(access_mask))
|
||
|
|
+ jump_nr += 3;
|
||
|
|
+
|
||
|
|
device_type = bpf_device_type(device->type);
|
||
|
|
if (device_type < 0)
|
||
|
|
return log_error_errno(-1, EINVAL, "Invalid bpf cgroup device type %c", device->type);
|
||
|
|
@@ -232,63 +249,67 @@ int bpf_program_append_device(struct bpf_program *prog, struct device_item *devi
|
||
|
|
if (device_type > 0)
|
||
|
|
jump_nr++;
|
||
|
|
|
||
|
|
- access_mask = bpf_access_mask(device->access);
|
||
|
|
- if (!bpf_device_all_access(access_mask))
|
||
|
|
- jump_nr += 3;
|
||
|
|
-
|
||
|
|
- if (device->major != -1)
|
||
|
|
+ if (device->major >= 0)
|
||
|
|
jump_nr++;
|
||
|
|
|
||
|
|
- if (device->minor != -1)
|
||
|
|
+ if (device->minor >= 0)
|
||
|
|
jump_nr++;
|
||
|
|
|
||
|
|
if (device_type > 0) {
|
||
|
|
struct bpf_insn ins[] = {
|
||
|
|
- BPF_JMP_IMM(BPF_JNE, BPF_REG_2, device_type, jump_nr--),
|
||
|
|
+ BPF_JMP_IMM(BPF_JNE, BPF_REG_2, device_type, jump_nr--),
|
||
|
|
};
|
||
|
|
|
||
|
|
ret = bpf_program_add_instructions(prog, ins, ARRAY_SIZE(ins));
|
||
|
|
if (ret)
|
||
|
|
return log_error_errno(-1, errno, "Failed to add instructions to bpf cgroup program");
|
||
|
|
+ add_exist = true;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (!bpf_device_all_access(access_mask)) {
|
||
|
|
struct bpf_insn ins[] = {
|
||
|
|
- BPF_MOV32_REG(BPF_REG_1, BPF_REG_3),
|
||
|
|
- BPF_ALU32_IMM(BPF_AND, BPF_REG_1, access_mask),
|
||
|
|
- BPF_JMP_REG(BPF_JNE, BPF_REG_1, BPF_REG_3, jump_nr),
|
||
|
|
+ BPF_MOV32_REG(BPF_REG_1, BPF_REG_3),
|
||
|
|
+ BPF_ALU32_IMM(BPF_AND, BPF_REG_1, access_mask),
|
||
|
|
+ BPF_JMP_REG(BPF_JNE, BPF_REG_1, BPF_REG_3, jump_nr-2),
|
||
|
|
};
|
||
|
|
|
||
|
|
jump_nr -= 3;
|
||
|
|
ret = bpf_program_add_instructions(prog, ins, ARRAY_SIZE(ins));
|
||
|
|
if (ret)
|
||
|
|
return log_error_errno(-1, errno, "Failed to add instructions to bpf cgroup program");
|
||
|
|
+ add_exist = true;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (device->major >= 0) {
|
||
|
|
struct bpf_insn ins[] = {
|
||
|
|
- BPF_JMP_IMM(BPF_JNE, BPF_REG_4, device->major, jump_nr--),
|
||
|
|
+ BPF_JMP_IMM(BPF_JNE, BPF_REG_4, device->major, jump_nr--),
|
||
|
|
};
|
||
|
|
|
||
|
|
ret = bpf_program_add_instructions(prog, ins, ARRAY_SIZE(ins));
|
||
|
|
if (ret)
|
||
|
|
return log_error_errno(-1, errno, "Failed to add instructions to bpf cgroup program");
|
||
|
|
+ add_exist = true;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (device->minor >= 0) {
|
||
|
|
struct bpf_insn ins[] = {
|
||
|
|
- BPF_JMP_IMM(BPF_JNE, BPF_REG_5, device->minor, jump_nr--),
|
||
|
|
+ BPF_JMP_IMM(BPF_JNE, BPF_REG_5, device->minor, jump_nr--),
|
||
|
|
};
|
||
|
|
|
||
|
|
ret = bpf_program_add_instructions(prog, ins, ARRAY_SIZE(ins));
|
||
|
|
if (ret)
|
||
|
|
return log_error_errno(-1, errno, "Failed to add instructions to bpf cgroup program");
|
||
|
|
+ add_exist = true;
|
||
|
|
}
|
||
|
|
|
||
|
|
- ret = bpf_program_add_instructions(prog, bpf_access_decision,
|
||
|
|
- ARRAY_SIZE(bpf_access_decision));
|
||
|
|
- if (ret)
|
||
|
|
- return log_error_errno(-1, errno, "Failed to add instructions to bpf cgroup program");
|
||
|
|
+ if (add_exist) {
|
||
|
|
+ bpf_access_decision[0] = BPF_MOV64_IMM(BPF_REG_0, device->allow);
|
||
|
|
+ bpf_access_decision[1] = BPF_EXIT_INSN();
|
||
|
|
+ ret = bpf_program_add_instructions(prog, bpf_access_decision,
|
||
|
|
+ ARRAY_SIZE(bpf_access_decision));
|
||
|
|
+ if (ret)
|
||
|
|
+ return log_error_errno(-1, errno, "Failed to add instructions to bpf cgroup program");
|
||
|
|
+ }
|
||
|
|
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
@@ -310,30 +331,49 @@ int bpf_program_finalize(struct bpf_program *prog)
|
||
|
|
return bpf_program_add_instructions(prog, ins, ARRAY_SIZE(ins));
|
||
|
|
}
|
||
|
|
|
||
|
|
-static int bpf_program_load_kernel(struct bpf_program *prog, char *log_buf,
|
||
|
|
- size_t log_size)
|
||
|
|
+static int bpf_program_load_kernel(struct bpf_program *prog)
|
||
|
|
{
|
||
|
|
+ __do_free char *log_buf = NULL;
|
||
|
|
+ __u32 log_level = 0;
|
||
|
|
+ __u32 log_size = 0;
|
||
|
|
union bpf_attr attr;
|
||
|
|
+ struct rlimit limit = {
|
||
|
|
+ .rlim_cur = RLIM_INFINITY,
|
||
|
|
+ .rlim_max = RLIM_INFINITY,
|
||
|
|
+ };
|
||
|
|
|
||
|
|
if (prog->kernel_fd >= 0) {
|
||
|
|
- memset(log_buf, 0, log_size);
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
+ if (lxc_log_get_level() <= LXC_LOG_LEVEL_DEBUG) {
|
||
|
|
+ log_buf = zalloc(BPF_LOG_BUF_SIZE);
|
||
|
|
+ if (!log_buf) {
|
||
|
|
+ WARN("Failed to allocate bpf log buffer");
|
||
|
|
+ } else {
|
||
|
|
+ log_level = BPF_LOG_LEVEL;
|
||
|
|
+ log_size = BPF_LOG_BUF_SIZE;
|
||
|
|
+ }
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ if (setrlimit(RLIMIT_MEMLOCK, &limit) < 0)
|
||
|
|
+ return log_error_errno(-1, errno, "Failed to set rlimit memlock to unlimited");
|
||
|
|
+
|
||
|
|
attr = (union bpf_attr){
|
||
|
|
.prog_type = prog->prog_type,
|
||
|
|
.insns = PTR_TO_UINT64(prog->instructions),
|
||
|
|
.insn_cnt = prog->n_instructions,
|
||
|
|
.license = PTR_TO_UINT64("GPL"),
|
||
|
|
.log_buf = PTR_TO_UINT64(log_buf),
|
||
|
|
- .log_level = !!log_buf,
|
||
|
|
+ .log_level = log_level,
|
||
|
|
.log_size = log_size,
|
||
|
|
};
|
||
|
|
|
||
|
|
prog->kernel_fd = bpf(BPF_PROG_LOAD, &attr, sizeof(attr));
|
||
|
|
if (prog->kernel_fd < 0)
|
||
|
|
- return log_error_errno(-1, errno, "Failed to load bpf program");
|
||
|
|
+ return log_error_errno(-1, errno, "Failed to load bpf program: %s", log_buf);
|
||
|
|
|
||
|
|
+ TRACE("Loaded bpf program: %s", log_buf ?: "(null)");
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
@@ -362,7 +402,7 @@ int bpf_program_cgroup_attach(struct bpf_program *prog, int type,
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
|
||
|
|
- ret = bpf_program_load_kernel(prog, NULL, 0);
|
||
|
|
+ ret = bpf_program_load_kernel(prog);
|
||
|
|
if (ret < 0)
|
||
|
|
return log_error_errno(-1, ret, "Failed to load bpf program");
|
||
|
|
|
||
|
|
@@ -518,11 +558,15 @@ bool bpf_devices_cgroup_supported(void)
|
||
|
|
if (prog < 0)
|
||
|
|
return log_trace(false, "Failed to allocate new bpf device cgroup program");
|
||
|
|
|
||
|
|
+ ret = bpf_program_init(prog);
|
||
|
|
+ if (ret)
|
||
|
|
+ return log_error_errno(false, ENOMEM, "Failed to initialize bpf program");
|
||
|
|
+
|
||
|
|
ret = bpf_program_add_instructions(prog, dummy, ARRAY_SIZE(dummy));
|
||
|
|
if (ret < 0)
|
||
|
|
return log_trace(false, "Failed to add new instructions to bpf device cgroup program");
|
||
|
|
|
||
|
|
- ret = bpf_program_load_kernel(prog, NULL, 0);
|
||
|
|
+ ret = bpf_program_load_kernel(prog);
|
||
|
|
if (ret < 0)
|
||
|
|
return log_trace(false, "Failed to load new bpf device cgroup program");
|
||
|
|
|
||
|
|
diff --git a/src/lxc/cgroups/isulad_cgfsng.c b/src/lxc/cgroups/isulad_cgfsng.c
|
||
|
|
index e16f8a19..c80527d5 100644
|
||
|
|
--- a/src/lxc/cgroups/isulad_cgfsng.c
|
||
|
|
+++ b/src/lxc/cgroups/isulad_cgfsng.c
|
||
|
|
@@ -823,6 +823,9 @@ static bool isulad_cg_legacy_handle_cpuset_hierarchy(struct hierarchy *h, char *
|
||
|
|
char *cgpath, *slash;
|
||
|
|
bool sub_mk_success = false;
|
||
|
|
|
||
|
|
+ if (is_unified_hierarchy(h))
|
||
|
|
+ return true;
|
||
|
|
+
|
||
|
|
if (!string_in_list(h->controllers, "cpuset"))
|
||
|
|
return true;
|
||
|
|
|
||
|
|
@@ -1288,6 +1291,20 @@ __cgfsng_ops static bool isulad_cgfsng_mount(struct cgroup_ops *ops,
|
||
|
|
ERROR("Failed to create directory: %s", tmpfspath);
|
||
|
|
goto on_error;
|
||
|
|
}
|
||
|
|
+
|
||
|
|
+ if (ops->cgroup_layout == CGROUP_LAYOUT_UNIFIED) {
|
||
|
|
+ if (has_cgns && wants_force_mount) {
|
||
|
|
+ /*
|
||
|
|
+ * If cgroup namespaces are supported but the container
|
||
|
|
+ * will not have CAP_SYS_ADMIN after it has started we
|
||
|
|
+ * need to mount the cgroups manually.
|
||
|
|
+ */
|
||
|
|
+ return cg_mount_in_cgroup_namespace(type, ops->unified, tmpfspath) == 0;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ return cg_mount_cgroup_full(type, ops->unified, tmpfspath) == 0;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
ret = safe_mount(NULL, tmpfspath, "tmpfs",
|
||
|
|
MS_NOSUID | MS_NODEV | MS_NOEXEC | MS_RELATIME,
|
||
|
|
"size=10240k,mode=755", root, handler->conf->lsm_se_mount_context);
|
||
|
|
@@ -2196,8 +2213,16 @@ __cgfsng_ops static int isulad_cgfsng_set(struct cgroup_ops *ops,
|
||
|
|
h = get_hierarchy(ops, controller);
|
||
|
|
if (h) {
|
||
|
|
char *fullpath;
|
||
|
|
-
|
||
|
|
fullpath = build_full_cgpath_from_monitorpath(h, path, filename);
|
||
|
|
+
|
||
|
|
+ if (strcmp(filename, "io.weight") == 0 || strcmp(filename, "io.bfq.weight") == 0) {
|
||
|
|
+ if (!file_exists(fullpath)) {
|
||
|
|
+ free(path);
|
||
|
|
+ free(fullpath);
|
||
|
|
+ return 0;
|
||
|
|
+ }
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
ret = lxc_write_to_file(fullpath, value, strlen(value), false, 0666);
|
||
|
|
free(fullpath);
|
||
|
|
}
|
||
|
|
@@ -2428,6 +2453,9 @@ __cgfsng_ops static bool isulad_cgfsng_setup_limits_legacy(struct cgroup_ops *op
|
||
|
|
if (!ops->hierarchies)
|
||
|
|
return ret_set_errno(false, EINVAL);
|
||
|
|
|
||
|
|
+ if (pure_unified_layout(ops))
|
||
|
|
+ return true;
|
||
|
|
+
|
||
|
|
sorted_cgroup_settings = sort_cgroup_settings(cgroup_settings);
|
||
|
|
if (!sorted_cgroup_settings)
|
||
|
|
return false;
|
||
|
|
@@ -2528,6 +2556,7 @@ static int bpf_device_cgroup_prepare(struct cgroup_ops *ops,
|
||
|
|
__cgfsng_ops static bool isulad_cgfsng_setup_limits(struct cgroup_ops *ops,
|
||
|
|
struct lxc_handler *handler)
|
||
|
|
{
|
||
|
|
+ __do_free char *path = NULL;
|
||
|
|
struct lxc_list *cgroup_settings, *iterator;
|
||
|
|
struct hierarchy *h;
|
||
|
|
struct lxc_conf *conf;
|
||
|
|
@@ -2549,6 +2578,9 @@ __cgfsng_ops static bool isulad_cgfsng_setup_limits(struct cgroup_ops *ops,
|
||
|
|
return true;
|
||
|
|
cgroup_settings = &conf->cgroup2;
|
||
|
|
|
||
|
|
+ if (!pure_unified_layout(ops))
|
||
|
|
+ return true;
|
||
|
|
+
|
||
|
|
if (!ops->unified)
|
||
|
|
return false;
|
||
|
|
h = ops->unified;
|
||
|
|
@@ -2560,7 +2592,29 @@ __cgfsng_ops static bool isulad_cgfsng_setup_limits(struct cgroup_ops *ops,
|
||
|
|
if (strncmp("devices", cg->subsystem, 7) == 0) {
|
||
|
|
ret = bpf_device_cgroup_prepare(ops, conf, cg->subsystem,
|
||
|
|
cg->value);
|
||
|
|
+ } else if (strcmp(cg->subsystem, "files.limit") == 0) {
|
||
|
|
+ long long int setvalue = 0;
|
||
|
|
+ const char *cgvalue = cg->value;
|
||
|
|
+
|
||
|
|
+ if (lxc_safe_long_long(cgvalue, &setvalue) != 0)
|
||
|
|
+ return log_error(false, "Invalid integer value %s", cgvalue);
|
||
|
|
+
|
||
|
|
+ if (setvalue <= 0)
|
||
|
|
+ cgvalue = "max";
|
||
|
|
+
|
||
|
|
+ ret = lxc_write_openat(h->container_full_path,
|
||
|
|
+ cg->subsystem, cgvalue,
|
||
|
|
+ strlen(cgvalue));
|
||
|
|
+ if (ret < 0)
|
||
|
|
+ return log_error_errno(false, errno, "Failed to set \"%s\" to \"%s\"",
|
||
|
|
+ cg->subsystem, cgvalue);
|
||
|
|
} else {
|
||
|
|
+ if (strcmp(cg->subsystem, "io.weight") == 0 || strcmp(cg->subsystem, "io.bfq.weight") == 0) {
|
||
|
|
+ path = must_make_path(h->container_full_path, cg->subsystem, NULL);
|
||
|
|
+ if (!file_exists(path)) {
|
||
|
|
+ continue;
|
||
|
|
+ }
|
||
|
|
+ }
|
||
|
|
ret = lxc_write_openat(h->container_full_path,
|
||
|
|
cg->subsystem, cg->value,
|
||
|
|
strlen(cg->value));
|
||
|
|
diff --git a/src/lxc/lxccontainer.c b/src/lxc/lxccontainer.c
|
||
|
|
index 06552ce5..5769b251 100644
|
||
|
|
--- a/src/lxc/lxccontainer.c
|
||
|
|
+++ b/src/lxc/lxccontainer.c
|
||
|
|
@@ -87,6 +87,9 @@
|
||
|
|
|
||
|
|
lxc_log_define(lxccontainer, lxc);
|
||
|
|
|
||
|
|
+typedef bool (*func_is_io_stat_read)(const char *value);
|
||
|
|
+typedef bool (*func_is_io_stat_write)(const char *value);
|
||
|
|
+
|
||
|
|
static bool do_lxcapi_destroy(struct lxc_container *c);
|
||
|
|
static const char *lxcapi_get_config_path(struct lxc_container *c);
|
||
|
|
#define do_lxcapi_get_config_path(c) lxcapi_get_config_path(c)
|
||
|
|
@@ -5768,6 +5771,26 @@ static uint64_t metrics_get_ull(struct lxc_container *c, struct cgroup_ops *cgro
|
||
|
|
return val;
|
||
|
|
}
|
||
|
|
|
||
|
|
+static uint64_t metrics_get_ull_with_max(struct lxc_container *c, struct cgroup_ops *cgroup_ops, const char *item)
|
||
|
|
+{
|
||
|
|
+ char buf[80] = {0};
|
||
|
|
+ int len = 0;
|
||
|
|
+ uint64_t val = 0;
|
||
|
|
+
|
||
|
|
+ len = cgroup_ops->get(cgroup_ops, item, buf, sizeof(buf), c->name, c->config_path);
|
||
|
|
+ if (len <= 0) {
|
||
|
|
+ DEBUG("unable to read cgroup item %s", item);
|
||
|
|
+ return 0;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ if (strcmp(buf, "max") == 0) {
|
||
|
|
+ return ULONG_MAX;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ val = strtoull(buf, NULL, 0);
|
||
|
|
+ return val;
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
static inline bool is_blk_metrics_read(const char *value)
|
||
|
|
{
|
||
|
|
return strcmp(value, "Read") == 0;
|
||
|
|
@@ -5826,6 +5849,60 @@ err_out:
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
+static void metrics_get_io_stats_v2(struct lxc_container *c, struct cgroup_ops *cgroup_ops, const char *item, struct lxc_blkio_metrics *stats, func_is_io_stat_read is_io_stat_read, func_is_io_stat_write is_io_stat_write)
|
||
|
|
+{
|
||
|
|
+#define BUFSIZE 4096
|
||
|
|
+ char buf[BUFSIZE] = {0};
|
||
|
|
+ int i = 0;
|
||
|
|
+ int j = 0;
|
||
|
|
+ int len = 0;
|
||
|
|
+ char **lines = NULL;
|
||
|
|
+ char **cols = NULL;
|
||
|
|
+ char **kv = NULL;
|
||
|
|
+
|
||
|
|
+ len = cgroup_ops->get(cgroup_ops, item, buf, sizeof(buf), c->name, c->config_path);
|
||
|
|
+ if (len <= 0) {
|
||
|
|
+ DEBUG("unable to read cgroup item %s", item);
|
||
|
|
+ return;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ lines = lxc_string_split_and_trim(buf, '\n');
|
||
|
|
+ if (lines == NULL) {
|
||
|
|
+ return;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ (void)memset(stats, 0, sizeof(struct lxc_blkio_metrics));
|
||
|
|
+ // line example:
|
||
|
|
+ // 259:0 rbytes=0 wbytes=12288 rios=0 wios=4 dbytes=0 dios=0
|
||
|
|
+ for (i = 0; lines[i]; i++) {
|
||
|
|
+ cols = lxc_string_split_and_trim(lines[i], ' ');
|
||
|
|
+ if (cols == NULL || lxc_array_len((void **)cols) < 2) {
|
||
|
|
+ goto err_out;
|
||
|
|
+ }
|
||
|
|
+ len = lxc_array_len((void **)cols);
|
||
|
|
+ for (j = 1; j < len; j++) {
|
||
|
|
+ kv = lxc_string_split(cols[j], '=');
|
||
|
|
+ if (kv == NULL || lxc_array_len((void **)kv) != 2) {
|
||
|
|
+ lxc_free_array((void **)kv, free);
|
||
|
|
+ continue;
|
||
|
|
+ }
|
||
|
|
+ if (is_io_stat_read(kv[0])) {
|
||
|
|
+ stats->read += strtoull(kv[1], NULL, 0);
|
||
|
|
+ } else if (is_io_stat_write(kv[0])) {
|
||
|
|
+ stats->write += strtoull(kv[1], NULL, 0);
|
||
|
|
+ }
|
||
|
|
+ lxc_free_array((void **)kv, free);
|
||
|
|
+ }
|
||
|
|
+ lxc_free_array((void **)cols, free);
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ stats->total = stats->read + stats->write;
|
||
|
|
+
|
||
|
|
+err_out:
|
||
|
|
+ lxc_free_array((void **)lines, free);
|
||
|
|
+ return;
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
static uint64_t metrics_match_get_ull(struct lxc_container *c, struct cgroup_ops *cgroup_ops, const char *item, const char *match, int column)
|
||
|
|
{
|
||
|
|
#define BUFSIZE 4096
|
||
|
|
@@ -5874,6 +5951,54 @@ err_out:
|
||
|
|
return val;
|
||
|
|
}
|
||
|
|
|
||
|
|
+static bool is_io_stat_rbytes(const char *value)
|
||
|
|
+{
|
||
|
|
+ return strcmp(value, "rbytes") == 0;
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+static bool is_io_stat_wbytes(const char *value)
|
||
|
|
+{
|
||
|
|
+ return strcmp(value, "wbytes") == 0;
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+static bool is_io_stat_rios(const char *value)
|
||
|
|
+{
|
||
|
|
+ return strcmp(value, "rios") == 0;
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+static bool is_io_stat_wios(const char *value)
|
||
|
|
+{
|
||
|
|
+ return strcmp(value, "wios") == 0;
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+static bool unified_metrics_get(struct lxc_container *c, struct cgroup_ops *cgroup_ops, struct lxc_container_metrics *metrics)
|
||
|
|
+{
|
||
|
|
+ // cpu
|
||
|
|
+ metrics->cpu_use_nanos = metrics_match_get_ull(c, cgroup_ops, "cpu.stat", "usage_usec", 1) * 1000;
|
||
|
|
+ metrics->cpu_use_user = metrics_match_get_ull(c, cgroup_ops, "cpu.stat", "user_usec", 1) * 1000;
|
||
|
|
+ metrics->cpu_use_sys = metrics_match_get_ull(c, cgroup_ops, "cpu.stat", "system_usec", 1) * 1000;
|
||
|
|
+
|
||
|
|
+ // io
|
||
|
|
+ metrics_get_io_stats_v2(c, cgroup_ops, "io.stat", &metrics->io_service_bytes, is_io_stat_rbytes, is_io_stat_wbytes);
|
||
|
|
+ metrics_get_io_stats_v2(c, cgroup_ops, "io.stat", &metrics->io_serviced, is_io_stat_rios, is_io_stat_wios);
|
||
|
|
+
|
||
|
|
+ // memory
|
||
|
|
+ metrics->mem_used = metrics_get_ull(c, cgroup_ops, "memory.current");
|
||
|
|
+ metrics->mem_limit = metrics_get_ull_with_max(c, cgroup_ops, "memory.max");
|
||
|
|
+ metrics->inactive_file_total = metrics_match_get_ull(c, cgroup_ops, "memory.stat", "inactive_file", 1);
|
||
|
|
+ metrics->cache = metrics_match_get_ull(c, cgroup_ops, "memory.stat", "file", 1);
|
||
|
|
+ metrics->cache_total = metrics->cache;
|
||
|
|
+
|
||
|
|
+ // cgroup v2 does not support kernel memory
|
||
|
|
+ metrics->kmem_used = 0;
|
||
|
|
+ metrics->kmem_limit = 0;
|
||
|
|
+
|
||
|
|
+ // pids
|
||
|
|
+ metrics->pids_current = metrics_get_ull(c, cgroup_ops, "pids.current");
|
||
|
|
+
|
||
|
|
+ return true;
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
/* isulad add get container metrics */
|
||
|
|
static bool do_lxcapi_get_container_metrics(struct lxc_container *c, struct lxc_container_metrics *metrics)
|
||
|
|
{
|
||
|
|
@@ -5897,6 +6022,10 @@ static bool do_lxcapi_get_container_metrics(struct lxc_container *c, struct lxc
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
+ if (cgroup_ops->cgroup_layout == CGROUP_LAYOUT_UNIFIED) {
|
||
|
|
+ return unified_metrics_get(c, cgroup_ops, metrics);
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
metrics->cpu_use_nanos = metrics_get_ull(c, cgroup_ops, "cpuacct.usage");
|
||
|
|
metrics->pids_current = metrics_get_ull(c, cgroup_ops, "pids.current");
|
||
|
|
|
||
|
|
--
|
||
|
|
2.20.1
|
||
|
|
|