summaryrefslogtreecommitdiffstats
path: root/src/sys_fs_cgroup.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/sys_fs_cgroup.c')
-rw-r--r--src/sys_fs_cgroup.c136
1 files changed, 112 insertions, 24 deletions
diff --git a/src/sys_fs_cgroup.c b/src/sys_fs_cgroup.c
index 0f9c8854..c047547e 100644
--- a/src/sys_fs_cgroup.c
+++ b/src/sys_fs_cgroup.c
@@ -41,7 +41,7 @@ static char *cgroup_memory_base = NULL;
static char *cgroup_devices_base = NULL;
static int cgroup_root_count = 0;
-static int cgroup_root_max = 500;
+static int cgroup_root_max = 1000;
static int cgroup_max_depth = 0;
static SIMPLE_PATTERN *enabled_cgroup_patterns = NULL;
@@ -50,6 +50,7 @@ static SIMPLE_PATTERN *enabled_cgroup_renames = NULL;
static SIMPLE_PATTERN *systemd_services_cgroups = NULL;
static char *cgroups_rename_script = NULL;
+static char *cgroups_network_interface_script = NULL;
static int cgroups_check = 0;
@@ -103,7 +104,7 @@ void read_cgroup_plugin_configuration() {
mi = mountinfo_find_by_filesystem_super_option(root, "cgroup", "cpuacct");
if(!mi) mi = mountinfo_find_by_filesystem_mount_source(root, "cgroup", "cpuacct");
if(!mi) {
- error("Cannot find cgroup cpuacct mountinfo. Assuming default: /sys/fs/cgroup/cpuacct");
+ error("CGROUP: cannot find cpuacct mountinfo. Assuming default: /sys/fs/cgroup/cpuacct");
s = "/sys/fs/cgroup/cpuacct";
}
else s = mi->mount_point;
@@ -113,7 +114,7 @@ void read_cgroup_plugin_configuration() {
mi = mountinfo_find_by_filesystem_super_option(root, "cgroup", "blkio");
if(!mi) mi = mountinfo_find_by_filesystem_mount_source(root, "cgroup", "blkio");
if(!mi) {
- error("Cannot find cgroup blkio mountinfo. Assuming default: /sys/fs/cgroup/blkio");
+ error("CGROUP: cannot find blkio mountinfo. Assuming default: /sys/fs/cgroup/blkio");
s = "/sys/fs/cgroup/blkio";
}
else s = mi->mount_point;
@@ -123,7 +124,7 @@ void read_cgroup_plugin_configuration() {
mi = mountinfo_find_by_filesystem_super_option(root, "cgroup", "memory");
if(!mi) mi = mountinfo_find_by_filesystem_mount_source(root, "cgroup", "memory");
if(!mi) {
- error("Cannot find cgroup memory mountinfo. Assuming default: /sys/fs/cgroup/memory");
+ error("CGROUP: cannot find memory mountinfo. Assuming default: /sys/fs/cgroup/memory");
s = "/sys/fs/cgroup/memory";
}
else s = mi->mount_point;
@@ -133,7 +134,7 @@ void read_cgroup_plugin_configuration() {
mi = mountinfo_find_by_filesystem_super_option(root, "cgroup", "devices");
if(!mi) mi = mountinfo_find_by_filesystem_mount_source(root, "cgroup", "devices");
if(!mi) {
- error("Cannot find cgroup devices mountinfo. Assuming default: /sys/fs/cgroup/devices");
+ error("CGROUP: cannot find devices mountinfo. Assuming default: /sys/fs/cgroup/devices");
s = "/sys/fs/cgroup/devices";
}
else s = mi->mount_point;
@@ -166,7 +167,7 @@ void read_cgroup_plugin_configuration() {
" !/docker "
" !/libvirt "
" !/lxc "
- " !/lxc/*/ns " // #1397
+ " !/lxc/*/* " // #1397 #2649
" !/machine "
" !/qemu "
" !/system "
@@ -184,13 +185,16 @@ void read_cgroup_plugin_configuration() {
" !/systemd "
" !/user "
" !/user.slice "
- " !/lxc/*/ns/* " // #2161
+ " !/lxc/*/* " // #2161 #2649
" * "
), SIMPLE_PATTERN_EXACT);
snprintfz(filename, FILENAME_MAX, "%s/cgroup-name.sh", netdata_configured_plugins_dir);
cgroups_rename_script = config_get("plugin:cgroups", "script to get cgroup names", filename);
+ snprintfz(filename, FILENAME_MAX, "%s/cgroup-network", netdata_configured_plugins_dir);
+ cgroups_network_interface_script = config_get("plugin:cgroups", "script to get cgroup network interfaces", filename);
+
enabled_cgroup_renames = simple_pattern_create(
config_get("plugin:cgroups", "run script to rename cgroups matching",
" *.scope "
@@ -329,6 +333,12 @@ struct cpuacct_usage {
unsigned long long *cpu_percpu;
};
+struct cgroup_network_interface {
+ const char *host_device;
+ const char *container_device;
+ struct cgroup_network_interface *next;
+};
+
#define CGROUP_OPTIONS_DISABLED_DUPLICATE 0x00000001
#define CGROUP_OPTIONS_SYSTEM_SLICE_SERVICE 0x00000002
@@ -360,6 +370,8 @@ struct cgroup {
struct blkio io_merged; // operations
struct blkio io_queued; // operations
+ struct cgroup_network_interface *interfaces;
+
// per cgroup charts
RRDSET *st_cpu;
RRDSET *st_cpu_per_core;
@@ -433,7 +445,7 @@ static inline void cgroup_read_cpuacct_stat(struct cpuacct_stat *cp) {
unsigned long i, lines = procfile_lines(ff);
if(unlikely(lines < 1)) {
- error("File '%s' should have 1+ lines.", cp->filename);
+ error("CGROUP: file '%s' should have 1+ lines.", cp->filename);
cp->updated = 0;
return;
}
@@ -475,7 +487,7 @@ static inline void cgroup_read_cpuacct_usage(struct cpuacct_usage *ca) {
}
if(unlikely(procfile_lines(ff) < 1)) {
- error("File '%s' should have 1+ lines but has %zu.", ca->filename, procfile_lines(ff));
+ error("CGROUP: file '%s' should have 1+ lines but has %zu.", ca->filename, procfile_lines(ff));
ca->updated = 0;
return;
}
@@ -539,7 +551,7 @@ static inline void cgroup_read_blkio(struct blkio *io) {
unsigned long i, lines = procfile_lines(ff);
if(unlikely(lines < 1)) {
- error("File '%s' should have 1+ lines.", io->filename);
+ error("CGROUP: file '%s' should have 1+ lines.", io->filename);
io->updated = 0;
return;
}
@@ -612,7 +624,7 @@ static inline void cgroup_read_memory(struct memory *mem) {
unsigned long i, lines = procfile_lines(ff);
if(unlikely(lines < 1)) {
- error("File '%s' should have 1+ lines.", mem->filename_detailed);
+ error("CGROUP: file '%s' should have 1+ lines.", mem->filename_detailed);
mem->updated_detailed = 0;
goto memory_next;
}
@@ -718,6 +730,77 @@ static inline void read_all_cgroups(struct cgroup *root) {
}
// ----------------------------------------------------------------------------
+// cgroup network interfaces
+
+#define CGROUP_NETWORK_INTERFACE_MAX_LINE 2048
+static inline void read_cgroup_network_interfaces(struct cgroup *cg) {
+ debug(D_CGROUP, "looking for the network interfaces of cgroup '%s' with chart id '%s' and title '%s'", cg->id, cg->chart_id, cg->chart_title);
+
+ pid_t cgroup_pid;
+ char buffer[CGROUP_NETWORK_INTERFACE_MAX_LINE + 1];
+
+ snprintfz(buffer, CGROUP_NETWORK_INTERFACE_MAX_LINE, "exec %s --cgroup '%s%s'", cgroups_network_interface_script, cgroup_cpuacct_base, cg->id);
+
+ debug(D_CGROUP, "executing command '%s' for cgroup '%s'", buffer, cg->id);
+ FILE *fp = mypopen(buffer, &cgroup_pid);
+ if(fp) {
+ char *s;
+ while((s = fgets(buffer, CGROUP_NETWORK_INTERFACE_MAX_LINE, fp))) {
+ trim(s);
+
+ if(*s && *s != '\n') {
+ char *t = s;
+ while(*t && *t != ' ') t++;
+ if(*t == ' ') {
+ *t = '\0';
+ t++;
+ }
+
+ if(!*s) {
+ error("CGROUP: empty host interface returned by script");
+ continue;
+ }
+
+ if(!*t) {
+ error("CGROUP: empty container interface returned by script");
+ continue;
+ }
+
+ struct cgroup_network_interface *i = callocz(1, sizeof(struct cgroup_network_interface));
+ i->host_device = strdupz(s);
+ i->container_device = strdupz(t);
+ i->next = cg->interfaces;
+ cg->interfaces = i;
+
+ info("CGROUP: cgroup '%s' has network interface '%s' as '%s'", cg->id, i->host_device, i->container_device);
+
+ // register a device rename to proc_net_dev.c
+ netdev_rename_device_add(i->host_device, i->container_device, cg->chart_id);
+ }
+ }
+
+ mypclose(fp, cgroup_pid);
+ // debug(D_CGROUP, "closed command for cgroup '%s'", cg->id);
+ }
+ else
+ error("CGROUP: cannot popen(\"%s\", \"r\").", buffer);
+}
+
+static inline void free_cgroup_network_interfaces(struct cgroup *cg) {
+ while(cg->interfaces) {
+ struct cgroup_network_interface *i = cg->interfaces;
+ cg->interfaces = i->next;
+
+ // delete the registration of proc_net_dev rename
+ netdev_rename_device_del(i->host_device);
+
+ freez((void *)i->host_device);
+ freez((void *)i->container_device);
+ freez((void *)i);
+ }
+}
+
+// ----------------------------------------------------------------------------
// add/remove/find cgroup objects
#define CGROUP_CHARTID_LINE_MAX 1024
@@ -775,7 +858,7 @@ static inline void cgroup_get_chart_name(struct cgroup *cg) {
}
}
else
- error("CGROUP: Cannot popen(\"%s\", \"r\").", buffer);
+ error("CGROUP: cannot popen(\"%s\", \"r\").", buffer);
}
static inline struct cgroup *cgroup_add(const char *id) {
@@ -783,7 +866,7 @@ static inline struct cgroup *cgroup_add(const char *id) {
debug(D_CGROUP, "adding to list, cgroup with id '%s'", id);
if(cgroup_root_count >= cgroup_root_max) {
- info("Maximum number of cgroups reached (%d). Not adding cgroup '%s'", cgroup_root_count, id);
+ info("CGROUP: maximum number of cgroups reached (%d). Not adding cgroup '%s'", cgroup_root_count, id);
return NULL;
}
@@ -872,7 +955,7 @@ static inline struct cgroup *cgroup_add(const char *id) {
for (t = cgroup_root; t; t = t->next) {
if (t != cg && t->enabled && t->hash_chart == cg->hash_chart && !strcmp(t->chart_id, cg->chart_id)) {
if (!strncmp(t->chart_id, "/system.slice/", 14) && !strncmp(cg->chart_id, "/init.scope/system.slice/", 25)) {
- error("Control group with chart id '%s' already exists with id '%s' and is enabled. Swapping them by enabling cgroup with id '%s' and disabling cgroup with id '%s'.",
+ error("CGROUP: chart id '%s' already exists with id '%s' and is enabled. Swapping them by enabling cgroup with id '%s' and disabling cgroup with id '%s'.",
cg->chart_id, t->id, cg->id, t->id);
debug(D_CGROUP, "Control group with chart id '%s' already exists with id '%s' and is enabled. Swapping them by enabling cgroup with id '%s' and disabling cgroup with id '%s'.",
cg->chart_id, t->id, cg->id, t->id);
@@ -880,7 +963,7 @@ static inline struct cgroup *cgroup_add(const char *id) {
t->options |= CGROUP_OPTIONS_DISABLED_DUPLICATE;
}
else {
- error("Control group with chart id '%s' already exists with id '%s' and is enabled and available. Disabling cgroup with id '%s'.",
+ error("CGROUP: chart id '%s' already exists with id '%s' and is enabled and available. Disabling cgroup with id '%s'.",
cg->chart_id, t->id, cg->id);
debug(D_CGROUP, "Control group with chart id '%s' already exists with id '%s' and is enabled and available. Disabling cgroup with id '%s'.",
cg->chart_id, t->id, cg->id);
@@ -893,6 +976,9 @@ static inline struct cgroup *cgroup_add(const char *id) {
}
}
+ if(cg->enabled && !(cg->options & CGROUP_OPTIONS_SYSTEM_SLICE_SERVICE))
+ read_cgroup_network_interfaces(cg);
+
debug(D_CGROUP, "ADDED CGROUP: '%s' with chart id '%s' and title '%s' as %s (default was %s)", cg->id, cg->chart_id, cg->chart_title, (cg->enabled)?"enabled":"disabled", (def)?"enabled":"disabled");
return cg;
@@ -916,6 +1002,8 @@ static inline void cgroup_free(struct cgroup *cg) {
if(cg->st_queued_ops) rrdset_is_obsolete(cg->st_queued_ops);
if(cg->st_merged_ops) rrdset_is_obsolete(cg->st_merged_ops);
+ free_cgroup_network_interfaces(cg);
+
freez(cg->cpuacct_usage.cpu_percpu);
freez(cg->cpuacct_stat.filename);
@@ -979,7 +1067,7 @@ static inline void found_subdir_in_dir(const char *dir) {
depth++;
if(depth > cgroup_max_depth) {
- info("cgroup '%s' is too deep (%d, while max is %d)", dir, depth, cgroup_max_depth);
+ info("CGROUP: '%s' is too deep (%d, while max is %d)", dir, depth, cgroup_max_depth);
return;
}
}
@@ -1004,7 +1092,7 @@ static inline int find_dir_in_subdirs(const char *base, const char *this, void (
DIR *dir = opendir(this);
if(!dir) {
- error("Cannot read cgroups directory '%s'", base);
+ error("CGROUP: cannot read directory '%s'", base);
return ret;
}
ret = 1;
@@ -1110,7 +1198,7 @@ static inline void find_all_cgroups() {
if(find_dir_in_subdirs(cgroup_cpuacct_base, NULL, found_subdir_in_dir) == -1) {
cgroup_enable_cpuacct_stat =
cgroup_enable_cpuacct_usage = CONFIG_BOOLEAN_NO;
- error("disabled CGROUP cpu statistics.");
+ error("CGROUP: disabled cpu statistics.");
}
}
@@ -1122,7 +1210,7 @@ static inline void find_all_cgroups() {
cgroup_enable_blkio_throttle_ops =
cgroup_enable_blkio_merged_ops =
cgroup_enable_blkio_queued_ops = CONFIG_BOOLEAN_NO;
- error("disabled CGROUP blkio statistics.");
+ error("CGROUP: disabled blkio statistics.");
}
}
@@ -1132,14 +1220,14 @@ static inline void find_all_cgroups() {
cgroup_enable_detailed_memory =
cgroup_enable_swap =
cgroup_enable_memory_failcnt = CONFIG_BOOLEAN_NO;
- error("disabled CGROUP memory statistics.");
+ error("CGROUP: disabled memory statistics.");
}
}
if(cgroup_search_in_devices) {
if(find_dir_in_subdirs(cgroup_devices_base, NULL, found_subdir_in_dir) == -1) {
cgroup_search_in_devices = 0;
- error("disabled CGROUP devices statistics.");
+ error("CGROUP: disabled devices statistics.");
}
}
@@ -2508,13 +2596,13 @@ void update_cgroup_charts(int update_every) {
void *cgroups_main(void *ptr) {
struct netdata_static_thread *static_thread = (struct netdata_static_thread *)ptr;
- info("CGROUP Plugin thread created with task id %d", gettid());
+ info("CGROUP plugin thread created with task id %d", gettid());
if(pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL) != 0)
- error("Cannot set pthread cancel type to DEFERRED.");
+ error("CGROUP: cannot set pthread cancel type to DEFERRED.");
if(pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL) != 0)
- error("Cannot set pthread cancel state to ENABLE.");
+ error("CGROUP: cannot set pthread cancel state to ENABLE.");
struct rusage thread;