diff options
Diffstat (limited to 'src/cgroup-network.c')
-rw-r--r-- | src/cgroup-network.c | 184 |
1 files changed, 155 insertions, 29 deletions
diff --git a/src/cgroup-network.c b/src/cgroup-network.c index 8894d60e..7b1a0234 100644 --- a/src/cgroup-network.c +++ b/src/cgroup-network.c @@ -1,4 +1,5 @@ #include "common.h" +#include <libgen.h> #ifdef HAVE_SETNS #ifndef _GNU_SOURCE @@ -14,6 +15,10 @@ void netdata_cleanup_and_exit(int ret) { exit(ret); } +void health_reload(void) {}; +void rrdhost_save_all(void) {}; + + struct iface { const char *device; uint32_t hash; @@ -269,38 +274,62 @@ pid_t read_pid_from_cgroup(const char *path) { return pid; } -void usage(void) { - fprintf(stderr, "%s [ -p PID | --pid PID | --cgroup /path/to/cgroup ]\n", program_name); - exit(1); -} -int main(int argc, char **argv) { - pid_t pid = 0; +// ---------------------------------------------------------------------------- +// send the result to netdata - program_name = argv[0]; - program_version = VERSION; - error_log_syslog = 0; +struct found_device { + const char *host_device; + const char *guest_device; - if(argc == 2 && (!strcmp(argv[1], "version") || !strcmp(argv[1], "-version") || !strcmp(argv[1], "--version") || !strcmp(argv[1], "-v") || !strcmp(argv[1], "-V"))) { - fprintf(stderr, "cgroup-network %s\n", VERSION); - exit(0); - } + uint32_t host_device_hash; - if(argc != 3) - usage(); + struct found_device *next; +} *detected_devices = NULL; - if(!strcmp(argv[1], "-p") || !strcmp(argv[1], "--pid")) { - pid = atoi(argv[2]); +void add_device(const char *host, const char *guest) { + uint32_t hash = simple_hash(host); + + if(guest && (!*guest || strcmp(host, guest) == 0)) + guest = NULL; + + struct found_device *f; + for(f = detected_devices; f ; f = f->next) { + if(f->host_device_hash == hash && strcmp(host, f->host_device) == 0) { + + if(guest && !f->guest_device) + f->guest_device = strdup(guest); + + return; + } } - else if(!strcmp(argv[1], "--cgroup")) { - pid = read_pid_from_cgroup(argv[2]); + + f = mallocz(sizeof(struct found_device)); + f->host_device = strdupz(host); + f->host_device_hash = hash; + f->guest_device = (guest)?strdupz(guest):NULL; + f->next = detected_devices; + detected_devices = f; +} + +int send_devices(void) { + int found = 0; + + struct found_device *f; + for(f = detected_devices; f ; f = f->next) { + found++; + printf("%s %s\n", f->host_device, (f->guest_device)?f->guest_device:f->host_device); } - else - usage(); - if(pid <= 0) - fatal("Invalid pid %d", (int)pid); + return found; +} + +// ---------------------------------------------------------------------------- +// this function should be called only **ONCE** +// also it has to be the **LAST** to be called +// since it switches namespaces, so after this call, everything is different! +void detect_veth_interfaces(pid_t pid) { struct iface *host, *cgroup, *h, *c; const char *prefix = getenv("NETDATA_HOST_PREFIX"); @@ -321,20 +350,117 @@ int main(int argc, char **argv) { if(!eligible_ifaces(cgroup)) fatal("there are not double-linked cgroup interfaces available."); - int found = 0; for(h = host; h ; h = h->next) { if(iface_is_eligible(h)) { for (c = cgroup; c; c = c->next) { if(iface_is_eligible(c) && h->ifindex == c->iflink && h->iflink == c->ifindex) { - printf("%s %s\n", h->device, c->device); - found++; + add_device(h->device, c->device); } } } } +} - if(!found) - return 1; +// ---------------------------------------------------------------------------- +// call the external helper - return 0; +#define CGROUP_NETWORK_INTERFACE_MAX_LINE 2048 +void call_the_helper(const char *me, pid_t pid, const char *cgroup) { + const char *pluginsdir = getenv("NETDATA_PLUGINS_DIR"); + char *m = NULL; + + if(!pluginsdir || !*pluginsdir) { + m = strdupz(me); + pluginsdir = dirname(m); + } + + if(setresuid(0, 0, 0) == -1) + error("setresuid(0, 0, 0) failed."); + + char buffer[CGROUP_NETWORK_INTERFACE_MAX_LINE + 1]; + if(cgroup) + snprintfz(buffer, CGROUP_NETWORK_INTERFACE_MAX_LINE, "exec %s/cgroup-network-helper.sh --cgroup '%s'", pluginsdir, cgroup); + else + snprintfz(buffer, CGROUP_NETWORK_INTERFACE_MAX_LINE, "exec %s/cgroup-network-helper.sh --pid %d", pluginsdir, pid); + + info("running: %s", buffer); + + pid_t cgroup_pid; + 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 || !*t) continue; + add_device(s, t); + } + } + + mypclose(fp, cgroup_pid); + } + else + error("cannot execute cgroup-network helper script: %s", buffer); + + freez(m); +} + + +// ---------------------------------------------------------------------------- +// main + +void usage(void) { + fprintf(stderr, "%s [ -p PID | --pid PID | --cgroup /path/to/cgroup ]\n", program_name); + exit(1); +} + +int main(int argc, char **argv) { + pid_t pid = 0; + + program_name = argv[0]; + program_version = VERSION; + error_log_syslog = 0; + + if(argc == 2 && (!strcmp(argv[1], "version") || !strcmp(argv[1], "-version") || !strcmp(argv[1], "--version") || !strcmp(argv[1], "-v") || !strcmp(argv[1], "-V"))) { + fprintf(stderr, "cgroup-network %s\n", VERSION); + exit(0); + } + + if(argc != 3) + usage(); + + if(!strcmp(argv[1], "-p") || !strcmp(argv[1], "--pid")) { + pid = atoi(argv[2]); + + if(pid <= 0) { + errno = 0; + fatal("Invalid pid %d given", (int) pid); + } + + call_the_helper(argv[0], pid, NULL); + } + else if(!strcmp(argv[1], "--cgroup")) { + pid = read_pid_from_cgroup(argv[2]); + call_the_helper(argv[0], pid, argv[2]); + + if(pid <= 0 && !detected_devices) { + errno = 0; + fatal("Invalid pid %d read from cgroup '%s'", (int) pid, argv[2]); + } + } + else + usage(); + + if(pid > 0) + detect_veth_interfaces(pid); + + return send_devices(); } |