diff options
Diffstat (limited to 'src/sys_fs_cgroup.c')
-rw-r--r-- | src/sys_fs_cgroup.c | 136 |
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; |