From 3b5a69c2a29817f4fe114c09107f7e57e5a4d26d Mon Sep 17 00:00:00 2001 From: thiagoftsm Date: Thu, 18 Mar 2021 13:39:30 +0000 Subject: eBPF plugin Change eBPF plugin internal organization. --- collectors/ebpf.plugin/Makefile.am | 18 +- collectors/ebpf.plugin/README.md | 32 +- collectors/ebpf.plugin/ebpf.c | 975 +------------------ collectors/ebpf.plugin/ebpf.conf | 49 - collectors/ebpf.plugin/ebpf.d.conf | 36 + collectors/ebpf.plugin/ebpf.d/cachestat.conf | 14 + .../ebpf.plugin/ebpf.d/ebpf_kernel_reject_list.txt | 1 + collectors/ebpf.plugin/ebpf.d/network.conf | 30 + collectors/ebpf.plugin/ebpf.d/process.conf | 14 + collectors/ebpf.plugin/ebpf.d/sync.conf | 14 + collectors/ebpf.plugin/ebpf.h | 23 +- collectors/ebpf.plugin/ebpf_apps.h | 10 +- collectors/ebpf.plugin/ebpf_cachestat.c | 28 +- collectors/ebpf.plugin/ebpf_cachestat.h | 5 +- collectors/ebpf.plugin/ebpf_kernel_reject_list.txt | 1 - collectors/ebpf.plugin/ebpf_process.c | 46 +- collectors/ebpf.plugin/ebpf_process.h | 4 +- collectors/ebpf.plugin/ebpf_socket.c | 1010 +++++++++++++++++++- collectors/ebpf.plugin/ebpf_socket.h | 27 +- collectors/ebpf.plugin/ebpf_sync.c | 15 +- collectors/ebpf.plugin/ebpf_sync.h | 5 +- libnetdata/ebpf/ebpf.c | 78 +- libnetdata/ebpf/ebpf.h | 25 + netdata-installer.sh | 25 +- 24 files changed, 1420 insertions(+), 1065 deletions(-) delete mode 100644 collectors/ebpf.plugin/ebpf.conf create mode 100644 collectors/ebpf.plugin/ebpf.d.conf create mode 100644 collectors/ebpf.plugin/ebpf.d/cachestat.conf create mode 100644 collectors/ebpf.plugin/ebpf.d/ebpf_kernel_reject_list.txt create mode 100644 collectors/ebpf.plugin/ebpf.d/network.conf create mode 100644 collectors/ebpf.plugin/ebpf.d/process.conf create mode 100644 collectors/ebpf.plugin/ebpf.d/sync.conf delete mode 100644 collectors/ebpf.plugin/ebpf_kernel_reject_list.txt diff --git a/collectors/ebpf.plugin/Makefile.am b/collectors/ebpf.plugin/Makefile.am index 1327d47a69..4fb2056fd8 100644 --- a/collectors/ebpf.plugin/Makefile.am +++ b/collectors/ebpf.plugin/Makefile.am @@ -10,6 +10,12 @@ CLEANFILES = \ include $(top_srcdir)/build/subst.inc SUFFIXES = .in +userebpfconfigdir=$(configdir)/ebpf.d + +# Explicitly install directories to avoid permission issues due to umask +install-exec-local: + $(INSTALL) -d $(DESTDIR)$(userebpfconfigdir) + dist_plugins_SCRIPTS = \ reset_netdata_trace.sh \ $(NULL) @@ -19,7 +25,15 @@ dist_noinst_DATA = \ README.md \ $(NULL) +ebpfconfigdir=$(libconfigdir)/ebpf.d dist_libconfig_DATA = \ - ebpf.conf \ - ebpf_kernel_reject_list.txt \ + ebpf.d.conf \ + $(NULL) + +dist_ebpfconfig_DATA = \ + ebpf.d/ebpf_kernel_reject_list.txt \ + ebpf.d/cachestat.conf \ + ebpf.d/network.conf \ + ebpf.d/process.conf \ + ebpf.d/sync.conf \ $(NULL) diff --git a/collectors/ebpf.plugin/README.md b/collectors/ebpf.plugin/README.md index bfe3f07442..06a76473a6 100644 --- a/collectors/ebpf.plugin/README.md +++ b/collectors/ebpf.plugin/README.md @@ -148,6 +148,7 @@ accepts the following values: ​ - `return`: In the `return` mode, the eBPF collector monitors the same kernel functions as `entry`, but also creates new charts for the return of these functions, such as errors. Monitoring function returns can help in debugging software, such as failing to close file descriptors or creating zombie processes. +- `update every`: Number of seconds used for eBPF to send data for Netdata. #### Integration with `apps.plugin` @@ -186,17 +187,44 @@ If you want to _disable_ the integration with `apps.plugin` along with the above apps = yes ``` -### `[ebpf programs]` +#### `[ebpf programs]` The eBPF collector enables and runs the following eBPF programs by default: +- `cachestat`: Netdata's eBPF data collector creates charts about the memory page cache. When the integration with + [`apps.plugin`](/collectors/apps.plugin/README.md) is enabled, this collector creates charts for the whole host _and_ + for each application. - `process`: This eBPF program creates charts that show information about process creation, VFS IO, and files removed. When in `return` mode, it also creates charts showing errors when these operations are executed. - `network viewer`: This eBPF program creates charts with information about `TCP` and `UDP` functions, including the bandwidth consumed by each. - `sync`: Montitor calls for syscall sync(2). -### `[network connections]` +## Thread configuration + +You can configure each thread of the eBPF data collector by editing either the `cachestat.conf`, `process.conf`, +or `network.conf` files. Use [`edit-config`](/docs/configure/nodes.md) from your Netdata config directory: + +```bash +cd /etc/netdata/ # Replace with your Netdata configuration directory, if not /etc/netdata/ +./edit-config ebpf.d/process.conf +``` + +### Configuration files + +The following configuration files are available: + +- `cachestat.conf`: Configuration for the `cachestat` thread. +- `process.conf`: Configuration for the `process` thread. +- `network.conf`: Configuration for the `network viewer` thread. This config file overwrites the global options and + also lets you specify which network the eBPF collector monitors. + +### Network configuration + +The network configuration has specific options to configure which network(s) the eBPF collector monitors. These options +are divided in the following sections: + +#### `[network connections]` You can configure the information shown on `outbound` and `inbound` charts with the settings in this section. diff --git a/collectors/ebpf.plugin/ebpf.c b/collectors/ebpf.plugin/ebpf.c index 99a426786b..26dacfd3e7 100644 --- a/collectors/ebpf.plugin/ebpf.c +++ b/collectors/ebpf.plugin/ebpf.c @@ -52,8 +52,6 @@ void netdata_cleanup_and_exit(int ret) *****************************************************************/ char *ebpf_plugin_dir = PLUGINS_DIR; -char *ebpf_user_config_dir = CONFIG_DIR; -char *ebpf_stock_config_dir = LIBCONFIG_DIR; static char *ebpf_configured_log_dir = LOG_DIR; char *ebpf_algorithms[] = {"absolute", "incremental"}; @@ -106,58 +104,6 @@ ebpf_network_viewer_options_t network_viewer_opt; * *****************************************************************/ -/** - * Cleanup publish syscall - * - * @param nps list of structures to clean - */ -void ebpf_cleanup_publish_syscall(netdata_publish_syscall_t *nps) -{ - while (nps) { - freez(nps->algorithm); - nps = nps->next; - } -} - -/** - * Clean port Structure - * - * Clean the allocated list. - * - * @param clean the list that will be cleaned - */ -void clean_port_structure(ebpf_network_viewer_port_list_t **clean) -{ - ebpf_network_viewer_port_list_t *move = *clean; - while (move) { - ebpf_network_viewer_port_list_t *next = move->next; - freez(move->value); - freez(move); - - move = next; - } - *clean = NULL; -} - -/** - * Clean IP structure - * - * Clean the allocated list. - * - * @param clean the list that will be cleaned - */ -static void clean_ip_structure(ebpf_network_viewer_ip_list_t **clean) -{ - ebpf_network_viewer_ip_list_t *move = *clean; - while (move) { - ebpf_network_viewer_ip_list_t *next = move->next; - freez(move); - - move = next; - } - *clean = NULL; -} - /** * Clean Loaded Events * @@ -426,15 +372,17 @@ void ebpf_create_global_dimension(void *ptr, int end) /** * Call write_chart_cmd to create the charts * - * @param type chart type - * @param id chart id - * @param units axis label - * @param family group name used to attach the chart on dashaboard - * @param order order number of the specified chart - * @param context chart context - * @param ncd a pointer to a function called to create dimensions - * @param move a pointer for a structure that has the dimensions - * @param end number of dimensions for the chart created + * @param type chart type + * @param id chart id + * @param title chart title + * @param units axis label + * @param family group name used to attach the chart on dashaboard + * @param context chart context + * @param charttype chart type + * @param order order number of the specified chart + * @param ncd a pointer to a function called to create dimensions + * @param move a pointer for a structure that has the dimensions + * @param end number of dimensions for the chart created */ void ebpf_create_chart(char *type, char *id, @@ -442,12 +390,13 @@ void ebpf_create_chart(char *type, char *units, char *family, char *context, + char *charttype, int order, void (*ncd)(void *, int), void *move, int end) { - ebpf_write_chart_cmd(type, id, title, units, family, "line", context, order); + ebpf_write_chart_cmd(type, id, title, units, family, charttype, context, order); ncd(move, end); } @@ -459,15 +408,16 @@ void ebpf_create_chart(char *type, * @param title the value displayed on vertical axis. * @param units the value displayed on vertical axis. * @param family Submenu that the chart will be attached on dashboard. + * @param charttype chart type * @param order the chart order * @param algorithm the algorithm used by dimension * @param root structure used to create the dimensions. */ -void ebpf_create_charts_on_apps(char *id, char *title, char *units, char *family, int order, +void ebpf_create_charts_on_apps(char *id, char *title, char *units, char *family, char *charttype, int order, char *algorithm, struct target *root) { struct target *w; - ebpf_write_chart_cmd(NETDATA_APPS_FAMILY, id, title, units, family, "stacked", NULL, order); + ebpf_write_chart_cmd(NETDATA_APPS_FAMILY, id, title, units, family, charttype, NULL, order); for (w = root; w; w = w->next) { if (unlikely(w->exposed)) @@ -640,87 +590,6 @@ void ebpf_print_help() * *****************************************************************/ -/** - * Is ip inside the range - * - * Check if the ip is inside a IP range - * - * @param rfirst the first ip address of the range - * @param rlast the last ip address of the range - * @param cmpfirst the first ip to compare - * @param cmplast the last ip to compare - * @param family the IP family - * - * @return It returns 1 if the IP is inside the range and 0 otherwise - */ -static int is_ip_inside_range(union netdata_ip_t *rfirst, union netdata_ip_t *rlast, - union netdata_ip_t *cmpfirst, union netdata_ip_t *cmplast, int family) -{ - if (family == AF_INET) { - if (ntohl(rfirst->addr32[0]) <= ntohl(cmpfirst->addr32[0]) && - ntohl(rlast->addr32[0]) >= ntohl(cmplast->addr32[0])) - return 1; - } else { - if (memcmp(rfirst->addr8, cmpfirst->addr8, sizeof(union netdata_ip_t)) <= 0 && - memcmp(rlast->addr8, cmplast->addr8, sizeof(union netdata_ip_t)) >= 0) { - return 1; - } - - } - return 0; -} - - -/** - * Fill IP list - * - * @param out a pointer to the link list. - * @param in the structure that will be linked. - */ -static inline void fill_ip_list(ebpf_network_viewer_ip_list_t **out, ebpf_network_viewer_ip_list_t *in, char *table) -{ -#ifndef NETDATA_INTERNAL_CHECKS - UNUSED(table); -#endif - if (likely(*out)) { - ebpf_network_viewer_ip_list_t *move = *out, *store = *out; - while (move) { - if (in->ver == move->ver && is_ip_inside_range(&move->first, &move->last, &in->first, &in->last, in->ver)) { - info("The range/value (%s) is inside the range/value (%s) already inserted, it will be ignored.", - in->value, move->value); - freez(in->value); - freez(in); - return; - } - store = move; - move = move->next; - } - - store->next = in; - } else { - *out = in; - } - -#ifdef NETDATA_INTERNAL_CHECKS - char first[512], last[512]; - if (in->ver == AF_INET) { - if (inet_ntop(AF_INET, in->first.addr8, first, INET_ADDRSTRLEN) && - inet_ntop(AF_INET, in->last.addr8, last, INET_ADDRSTRLEN)) - info("Adding values %s - %s to %s IP list \"%s\" used on network viewer", - first, last, - (*out == network_viewer_opt.included_ips)?"included":"excluded", - table); - } else { - if (inet_ntop(AF_INET6, in->first.addr8, first, INET6_ADDRSTRLEN) && - inet_ntop(AF_INET6, in->last.addr8, last, INET6_ADDRSTRLEN)) - info("Adding values %s - %s to %s IP list \"%s\" used on network viewer", - first, last, - (*out == network_viewer_opt.included_ips)?"included":"excluded", - table); - } -#endif -} - /** * Read Local Ports * @@ -872,789 +741,26 @@ void fill_ebpf_data(ebpf_data_t *ef) */ static inline void how_to_load(char *ptr) { - if (!strcasecmp(ptr, "return")) + if (!strcasecmp(ptr, EBPF_CFG_LOAD_MODE_RETURN)) ebpf_set_thread_mode(MODE_RETURN); - else if (!strcasecmp(ptr, "entry")) + else if (!strcasecmp(ptr, EBPF_CFG_LOAD_MODE_DEFAULT)) ebpf_set_thread_mode(MODE_ENTRY); else error("the option %s for \"ebpf load mode\" is not a valid option.", ptr); } /** - * Fill Port list - * - * @param out a pointer to the link list. - * @param in the structure that will be linked. - */ -static inline void fill_port_list(ebpf_network_viewer_port_list_t **out, ebpf_network_viewer_port_list_t *in) -{ - if (likely(*out)) { - ebpf_network_viewer_port_list_t *move = *out, *store = *out; - uint16_t first = ntohs(in->first); - uint16_t last = ntohs(in->last); - while (move) { - uint16_t cmp_first = ntohs(move->first); - uint16_t cmp_last = ntohs(move->last); - if (cmp_first <= first && first <= cmp_last && - cmp_first <= last && last <= cmp_last ) { - info("The range/value (%u, %u) is inside the range/value (%u, %u) already inserted, it will be ignored.", - first, last, cmp_first, cmp_last); - freez(in->value); - freez(in); - return; - } else if (first <= cmp_first && cmp_first <= last && - first <= cmp_last && cmp_last <= last) { - info("The range (%u, %u) is bigger than previous range (%u, %u) already inserted, the previous will be ignored.", - first, last, cmp_first, cmp_last); - freez(move->value); - move->value = in->value; - move->first = in->first; - move->last = in->last; - freez(in); - return; - } - - store = move; - move = move->next; - } - - store->next = in; - } else { - *out = in; - } - -#ifdef NETDATA_INTERNAL_CHECKS - info("Adding values %s( %u, %u) to %s port list used on network viewer", - in->value, ntohs(in->first), ntohs(in->last), - (*out == network_viewer_opt.included_port)?"included":"excluded"); -#endif -} - -/** - * Fill port list - * - * Fill an allocated port list with the range given - * - * @param out a pointer to store the link list - * @param range the informed range for the user. - */ -static void parse_port_list(void **out, char *range) -{ - int first, last; - ebpf_network_viewer_port_list_t **list = (ebpf_network_viewer_port_list_t **)out; - - char *copied = strdupz(range); - if (*range == '*' && *(range+1) == '\0') { - first = 1; - last = 65535; - - clean_port_structure(list); - goto fillenvpl; - } - - char *end = range; - //Move while I cannot find a separator - while (*end && *end != ':' && *end != '-') end++; - - //It has a range - if (likely(*end)) { - *end++ = '\0'; - if (*end == '!') { - info("The exclusion cannot be in the second part of the range, the range %s will be ignored.", copied); - freez(copied); - return; - } - last = str2i((const char *)end); - } else { - last = 0; - } - - first = str2i((const char *)range); - if (first < NETDATA_MINIMUM_PORT_VALUE || first > NETDATA_MAXIMUM_PORT_VALUE) { - info("The first port %d of the range \"%s\" is invalid and it will be ignored!", first, copied); - freez(copied); - return; - } - - if (!last) - last = first; - - if (last < NETDATA_MINIMUM_PORT_VALUE || last > NETDATA_MAXIMUM_PORT_VALUE) { - info("The second port %d of the range \"%s\" is invalid and the whole range will be ignored!", last, copied); - freez(copied); - return; - } - - if (first > last) { - info("The specified order %s is wrong, the smallest value is always the first, it will be ignored!", copied); - freez(copied); - return; - } - - ebpf_network_viewer_port_list_t *w; -fillenvpl: - w = callocz(1, sizeof(ebpf_network_viewer_port_list_t)); - w->value = copied; - w->hash = simple_hash(copied); - w->first = (uint16_t)htons((uint16_t)first); - w->last = (uint16_t)htons((uint16_t)last); - w->cmp_first = (uint16_t)first; - w->cmp_last = (uint16_t)last; - - fill_port_list(list, w); -} - -/** - * Parse Service List - * - * @param out a pointer to store the link list - * @param service the service used to create the structure that will be linked. - */ -static void parse_service_list(void **out, char *service) -{ - ebpf_network_viewer_port_list_t **list = (ebpf_network_viewer_port_list_t **)out; - struct servent *serv = getservbyname((const char *)service, "tcp"); - if (!serv) - serv = getservbyname((const char *)service, "udp"); - - if (!serv) { - info("Cannot resolv the service '%s' with protocols TCP and UDP, it will be ignored", service); - return; - } - - ebpf_network_viewer_port_list_t *w = callocz(1, sizeof(ebpf_network_viewer_port_list_t)); - w->value = strdupz(service); - w->hash = simple_hash(service); - - w->first = w->last = (uint16_t)serv->s_port; - - fill_port_list(list, w); -} - -/** - * Netmask - * - * Copied from iprange (https://github.com/firehol/iprange/blob/master/iprange.h) - * - * @param prefix create the netmask based in the CIDR value. - * - * @return - */ -static inline in_addr_t netmask(int prefix) { - - if (prefix == 0) - return (~((in_addr_t) - 1)); - else - return (in_addr_t)(~((1 << (32 - prefix)) - 1)); - -} - -/** - * Broadcast + * Update interval * - * Copied from iprange (https://github.com/firehol/iprange/blob/master/iprange.h) - * - * @param addr is the ip address - * @param prefix is the CIDR value. - * - * @return It returns the last address of the range + * Update default interval with value from user */ -static inline in_addr_t broadcast(in_addr_t addr, int prefix) +static void ebpf_update_interval() { - return (addr | ~netmask(prefix)); -} - -/** - * Network - * - * Copied from iprange (https://github.com/firehol/iprange/blob/master/iprange.h) - * - * @param addr is the ip address - * @param prefix is the CIDR value. - * - * @return It returns the first address of the range. - */ -static inline in_addr_t ipv4_network(in_addr_t addr, int prefix) -{ - return (addr & netmask(prefix)); -} - -/** - * IP to network long - * - * @param dst the vector to store the result - * @param ip the source ip given by our users. - * @param domain the ip domain (IPV4 or IPV6) - * @param source the original string - * - * @return it returns 0 on success and -1 otherwise. - */ -static inline int ip2nl(uint8_t *dst, char *ip, int domain, char *source) -{ - if (inet_pton(domain, ip, dst) <= 0) { - error("The address specified (%s) is invalid ", source); - return -1; - } - - return 0; -} - -/** - * Get IPV6 Last Address - * - * @param out the address to store the last address. - * @param in the address used to do the math. - * @param prefix number of bits used to calculate the address - */ -static void get_ipv6_last_addr(union netdata_ip_t *out, union netdata_ip_t *in, uint64_t prefix) -{ - uint64_t mask,tmp; - uint64_t ret[2]; - memcpy(ret, in->addr32, sizeof(union netdata_ip_t)); - - if (prefix == 128) { - memcpy(out->addr32, in->addr32, sizeof(union netdata_ip_t)); - return; - } else if (!prefix) { - ret[0] = ret[1] = 0xFFFFFFFFFFFFFFFF; - memcpy(out->addr32, ret, sizeof(union netdata_ip_t)); - return; - } else if (prefix <= 64) { - ret[1] = 0xFFFFFFFFFFFFFFFFULL; - - tmp = be64toh(ret[0]); - if (prefix > 0) { - mask = 0xFFFFFFFFFFFFFFFFULL << (64 - prefix); - tmp |= ~mask; - } - ret[0] = htobe64(tmp); - } else { - mask = 0xFFFFFFFFFFFFFFFFULL << (128 - prefix); - tmp = be64toh(ret[1]); - tmp |= ~mask; - ret[1] = htobe64(tmp); - } - - memcpy(out->addr32, ret, sizeof(union netdata_ip_t)); -} - -/** - * Calculate ipv6 first address - * - * @param out the address to store the first address. - * @param in the address used to do the math. - * @param prefix number of bits used to calculate the address - */ -static void get_ipv6_first_addr(union netdata_ip_t *out, union netdata_ip_t *in, uint64_t prefix) -{ - uint64_t mask,tmp; - uint64_t ret[2]; - - memcpy(ret, in->addr32, sizeof(union netdata_ip_t)); - - if (prefix == 128) { - memcpy(out->addr32, in->addr32, sizeof(union netdata_ip_t)); - return; - } else if (!prefix) { - ret[0] = ret[1] = 0; - memcpy(out->addr32, ret, sizeof(union netdata_ip_t)); - return; - } else if (prefix <= 64) { - ret[1] = 0ULL; - - tmp = be64toh(ret[0]); - if (prefix > 0) { - mask = 0xFFFFFFFFFFFFFFFFULL << (64 - prefix); - tmp &= mask; - } - ret[0] = htobe64(tmp); - } else { - mask = 0xFFFFFFFFFFFFFFFFULL << (128 - prefix); - tmp = be64toh(ret[1]); - tmp &= mask; - ret[1] = htobe64(tmp); - } - - memcpy(out->addr32, ret, sizeof(union netdata_ip_t)); -} - -/** - * Parse IP List - * - * Parse IP list and link it. - * - * @param out a pointer to store the link list - * @param ip the value given as parameter - */ -static void parse_ip_list(void **out, char *ip) -{ - ebpf_network_viewer_ip_list_t **list = (ebpf_network_viewer_ip_list_t **)out; - - char *ipdup = strdupz(ip); - union netdata_ip_t first = { }; - union netdata_ip_t last = { }; - char *is_ipv6; - if (*ip == '*' && *(ip+1) == '\0') { - memset(first.addr8, 0, sizeof(first.addr8)); - memset(last.addr8, 0xFF, sizeof(last.addr8)); - - is_ipv6 = ip; - - clean_ip_structure(list); - goto storethisip; - } - - char *end = ip; - // Move while I cannot find a separator - while (*end && *end != '/' && *end != '-') end++; - - // We will use only the classic IPV6 for while, but we could consider the base 85 in a near future - // https://tools.ietf.org/html/rfc1924 - is_ipv6 = strchr(ip, ':'); - - int select; - if (*end && !is_ipv6) { // IPV4 range - select = (*end == '/') ? 0 : 1; - *end++ = '\0'; - if (*end == '!') { - info("The exclusion cannot be in the second part of the range %s, it will be ignored.", ipdup); - goto cleanipdup; - } - - if (!select) { // CIDR - select = ip2nl(first.addr8, ip, AF_INET, ipdup); - if (select) - goto cleanipdup; - - select = (int) str2i(end); - if (select < NETDATA_MINIMUM_IPV4_CIDR || select > NETDATA_MAXIMUM_IPV4_CIDR) { - info("The specified CIDR %s is not valid, the IP %s will be ignored.", end, ip); - goto cleanipdup; - } - - last.addr32[0] = htonl(broadcast(ntohl(first.addr32[0]), select)); - // This was added to remove - // https://app.codacy.com/manual/netdata/netdata/pullRequest?prid=5810941&bid=19021977 - UNUSED(last.addr32[0]); - - uint32_t ipv4_test = htonl(ipv4_network(ntohl(first.addr32[0]), select)); - if (first.addr32[0] != ipv4_test) { - first.addr32[0] = ipv4_test; - struct in_addr ipv4_convert; - ipv4_convert.s_addr = ipv4_test; - char ipv4_msg[INET_ADDRSTRLEN]; - if(inet_ntop(AF_INET, &ipv4_convert, ipv4_msg, INET_ADDRSTRLEN)) - info("The network value of CIDR %s was updated for %s .", ipdup, ipv4_msg); - } - } else { // Range - select = ip2nl(first.addr8, ip, AF_INET, ipdup); - if (select) - goto cleanipdup; - - select = ip2nl(last.addr8, end, AF_INET, ipdup); - if (select) - goto cleanipdup; - } - - if (htonl(first.addr32[0]) > htonl(last.addr32[0])) { - info("The specified range %s is invalid, the second address is smallest than the first, it will be ignored.", - ipdup); - goto cleanipdup; - } - } else if (is_ipv6) { // IPV6 - if (!*end) { // Unique - select = ip2nl(first.addr8, ip, AF_INET6, ipdup); - if (select) - goto cleanipdup; - - memcpy(last.addr8, first.addr8, sizeof(first.addr8)); - } else if (*end == '-') { - *end++ = 0x00; - if (*end == '!') { - info("The exclusion cannot be in the second part of the range %s, it will be ignored.", ipdup); - goto cleanipdup; - } - - select = ip2nl(first.addr8, ip, AF_INET6, ipdup); - if (select) - goto cleanipdup; - - select = ip2nl(last.addr8, end, AF_INET6, ipdup); - if (select) - goto cleanipdup; - } else { // CIDR - *end++ = 0x00; - if (*end == '!') { - info("The exclusion cannot be in the second part of the range %s, it will be ignored.", ipdup); - goto cleanipdup; - } - - select = str2i(end); - if (select < 0 || select > 128) { - info("The CIDR %s is not valid, the address %s will be ignored.", end, ip); - goto cleanipdup; - } - - uint64_t prefix = (uint64_t)select; - select = ip2nl(first.addr8, ip, AF_INET6, ipdup); - if (select) - goto cleanipdup; - - get_ipv6_last_addr(&last, &first, prefix); - - union netdata_ip_t ipv6_test; - get_ipv6_first_addr(&ipv6_test, &first, prefix); - - if (memcmp(first.addr8, ipv6_test.addr8, sizeof(union netdata_ip_t)) != 0) { - memcpy(first.addr8, ipv6_test.addr8, sizeof(union netdata_ip_t)); - - struct in6_addr ipv6_convert; - memcpy(ipv6_convert.s6_addr, ipv6_test.addr8, sizeof(union netdata_ip_t)); - - char ipv6_msg[INET6_ADDRSTRLEN]; - if(inet_ntop(AF_INET6, &ipv6_convert, ipv6_msg, INET6_ADDRSTRLEN)) - info("The network value of CIDR %s was updated for %s .", ipdup, ipv6_msg); - } - } - - if ((be64toh(*(uint64_t *)&first.addr32[2]) > be64toh(*(uint64_t *)&last.addr32[2]) && - !memcmp(first.addr32, last.addr32, 2*sizeof(uint32_t))) || - (be64toh(*(uint64_t *)&first.addr32) > be64toh(*(uint64_t *)&last.addr32)) ) { - info("The specified range %s is invalid, the second address is smallest than the first, it will be ignored.", - ipdup); - goto cleanipdup; - } - } else { // Unique ip - select = ip2nl(first.addr8, ip, AF_INET, ipdup); - if (select) - goto cleanipdup; - - memcpy(last.addr8, first.addr8, sizeof(first.addr8)); - } - - ebpf_network_viewer_ip_list_t *store; - -storethisip: - store = callocz(1, sizeof(ebpf_network_viewer_ip_list_t)); - store->value = ipdup; - store->hash = simple_hash(ipdup); - store->ver = (uint8_t)(!is_ipv6)?AF_INET:AF_INET6; - memcpy(store->first.addr8, first.addr8, sizeof(first.addr8)); - memcpy(store->last.addr8, last.addr8, sizeof(last.addr8)); - - fill_ip_list(list, store, "socket"); - return; - -cleanipdup: - freez(ipdup); -} - -/** - * Parse IP Range - * - * Parse the IP ranges given and create Network Viewer IP Structure - * - * @param ptr is a pointer with the text to parse. - */ -static void parse_ips(char *ptr) -{ - // No value - if (unlikely(!ptr)) - return; - - while (likely(ptr)) { - // Move forward until next valid character - while (isspace(*ptr)) ptr++; - - // No valid value found - if (unlikely(!*ptr)) - return; - - // Find space that ends the list - char *end = strchr(ptr, ' '); - if (end) { - *end++ = '\0'; - } - - int neg = 0; - if (*ptr == '!') { - neg++; - ptr++; - } - - if (isascii(*ptr)) { // Parse port - parse_ip_list((!neg)?(void **)&network_viewer_opt.included_ips:(void **)&network_viewer_opt.excluded_ips, - ptr); - } - - ptr = end; - } -} - - -/** - * Parse Port Range - * - * Parse the port ranges given and create Network Viewer Port Structure - * - * @param ptr is a pointer with the text to parse. - */ -static void parse_ports(char *ptr) -{ - // No value - if (unlikely(!ptr)) - return; - - while (likely(ptr)) { - // Move forward until next valid character - while (isspace(*ptr)) ptr++; - - // No valid value found - if (unlikely(!*ptr)) - return; - - // Find space that ends the list - char *end = strchr(ptr, ' '); - if (end) { - *end++ = '\0'; - } - - int neg = 0; - if (*ptr == '!') { - neg++; - ptr++; - } - - if (isdigit(*ptr)) { // Parse port - parse_port_list((!neg)?(void **)&network_viewer_opt.included_port:(void **)&network_viewer_opt.excluded_port, - ptr); - } else if (isalpha(*ptr)) { // Parse service - parse_service_list((!neg)?(void **)&network_viewer_opt.included_port:(void **)&network_viewer_opt.excluded_port, - ptr); - } else if (*ptr == '*') { // All - parse_port_list((!neg)?(void **)&network_viewer_opt.included_port:(void **)&network_viewer_opt.excluded_port, - ptr); - } - - ptr = end; - } -} - -/** - * Link hostname - * - * @param out is the output link list - * @param in the hostname to add to list. - */ -static void link_hostname(ebpf_network_viewer_hostname_list_t **out, ebpf_network_viewer_hostname_list_t *in) -{ - if (likely(*out)) { - ebpf_network_viewer_hostname_list_t *move = *out; - for (; move->next ; move = move->next ) { - if (move->hash == in->hash && !strcmp(move->value, in->value)) { - info("The hostname %s was already inserted, it will be ignored.", in->value); - freez(in->value); - simple_pattern_free(in->value_pattern); - freez(in); - return; - } - } - - move->next = in; - } else { - *out = in; - } -#ifdef NETDATA_INTERNAL_CHECKS - info("Adding value %s to %s hostname list used on network viewer", - in->value, - (*out == network_viewer_opt.included_hostnames)?"included":"excluded"); -#endif -} - -/** - * Link Hostnames - * - * Parse the list of hostnames to create the link list. - * This is not associated with the IP, because simple patterns like *example* cannot be resolved to IP. - * - * @param out is the output link list - * @param parse is a pointer with the text to parser. - */ -static void link_hostnames(char *parse) -{ - // No value - if (unlikely(!parse)) - return; - - while (likely(parse)) { - // Find the first valid value - while (isspace(*parse)) parse++; - - // No valid value found - if (unlikely(!*parse)) - return; - - // Find space that ends the list - char *end = strchr(parse, ' '); - if (end) { - *end++ = '\0'; - } - - int neg = 0; - if (*parse == '!') { - neg++; - parse++; - } - - ebpf_network_viewer_hostname_list_t *hostname = callocz(1 , sizeof(ebpf_network_viewer_hostname_list_t)); - hostname->value = strdupz(parse); - hostname->hash = simple_hash(parse); - hostname->value_pattern = simple_pattern_create(parse, NULL, SIMPLE_PATTERN_EXACT); - - link_hostname((!neg)?&network_viewer_opt.included_hostnames:&network_viewer_opt.excluded_hostnames, - hostname); - - parse = end; - } -} - -/** - * Read max dimension. - * - * Netdata plot two dimensions per connection, so it is necessary to adjust the values. - */ -static void read_max_dimension() -{ - int maxdim ; - maxdim = (int) appconfig_get_number(&collector_config, - EBPF_NETWORK_VIEWER_SECTION, - "maximum dimensions", - NETDATA_NV_CAP_VALUE); - if (maxdim < 0) { - error("'maximum dimensions = %d' must be a positive number, Netdata will change for default value %ld.", - maxdim, NETDATA_NV_CAP_VALUE); - maxdim = NETDATA_NV_CAP_VALUE; - } - - maxdim /= 2; - if (!maxdim) { - info("The number of dimensions is too small (%u), we are setting it to minimum 2", network_viewer_opt.max_dim); - network_viewer_opt.max_dim = 1; - } - - network_viewer_opt.max_dim = (uint32_t)maxdim; -} - -/** - * Parse network viewer section - */ -static void parse_network_viewer_section() -{ - read_max_dimension(); - - network_viewer_opt.hostname_resolution_enabled = appconfig_get_boolean(&collector_config, - EBPF_NETWORK_VIEWER_SECTION, - "resolve hostnames", - CONFIG_BOOLEAN_NO); - - network_viewer_opt.service_resolution_enabled = appconfig_get_boolean(&collector_config, - EBPF_NETWORK_VIEWER_SECTION, - "resolve service names", - CONFIG_BOOLEAN_NO); - - char *value = appconfig_get(&collector_config, EBPF_NETWORK_VIEWER_SECTION, - "ports", NULL); - parse_ports(value); - - if (network_viewer_opt.hostname_resolution_enabled) { - value = appconfig_get(&collector_config, EBPF_NETWORK_VIEWER_SECTION, "hostnames", NULL); - link_hostnames(value); - } else { - info("Name resolution is disabled, collector will not parser \"hostnames\" list."); - } - - value = appconfig_get(&collector_config, EBPF_NETWORK_VIEWER_SECTION, - "ips", "!127.0.0.1/8 10.0.0.0/8 172.16.0.0/12 192.168.0.0/16 fc00::/7 !::1/128"); - parse_ips(value); -} - -/** - * Link dimension name - * - * Link user specified names inside a link list. - * - * @param port the port number associated to the dimension name. - * @param hash the calculated hash for the dimension name. - * @param name the dimension name. - */ -static void link_dimension_name(char *port, uint32_t hash, char *value) -{ - int test = str2i(port); - if (test < NETDATA_MINIMUM_PORT_VALUE || test > NETDATA_MAXIMUM_PORT_VALUE){ - error("The dimension given (%s = %s) has an invalid value and it will be ignored.", port, value); - return; - } - - ebpf_network_viewer_dim_name_t *w; - w = callocz(1, sizeof(ebpf_network_viewer_dim_name_t)); - - w->name = strdupz(value); - w->hash = hash; - - w->port = (uint16_t) htons(test); - - ebpf_network_viewer_dim_name_t *names = network_viewer_opt.names; - if (unlikely(!names)) { - network_viewer_opt.names = w; - } else { - for (; names->next; names = names->next) { - if (names->port == w->port) { - info("Dupplicated definition for a service, the name %s will be ignored. ", names->name); - freez(names->name); - names->name = w->name; - names->hash = w->hash; - freez(w); - return; - } - } - names->next = w; - } - -#ifdef NETDATA_INTERNAL_CHECKS - info("Adding values %s( %u) to dimension name list used on network viewer", w->name, htons(w->port)); -#endif -} - -/** - * Parse service Name section. - * - * This function gets the values that will be used to overwrite dimensions. - */ -static void parse_service_name_section() -{ - struct section *co = appconfig_get_section(&collector_config, EBPF_SERVICE_NAME_SECTION); - if (co) { - struct config_option *cv; - for (cv = co->values; cv ; cv = cv->next) { - link_dimension_name(cv->name, cv->hash, cv->value); - } - } - - // Always associated the default port to Netdata - ebpf_network_viewer_dim_name_t *names = network_viewer_opt.names; - if (names) { - uint16_t default_port = htons(19999); - while (names) { - if (names->port == default_port) - return; - - names = names->next; - } + int i; + int value = (int) appconfig_get_number(&collector_config, EBPF_GLOBAL_SECTION, EBPF_CFG_UPDATE_EVERY, 1); + for (i = 0; ebpf_modules[i].thread_name; i++) { + ebpf_modules[i].update_time = value; } - - char *port_string = getenv("NETDATA_LISTEN_PORT"); - if (port_string) - link_dimension_name(port_string, simple_hash(port_string), "Netdata"); } /** @@ -1667,18 +773,22 @@ static void read_collector_values(int *disable_apps) // Read global section char *value; if (appconfig_exists(&collector_config, EBPF_GLOBAL_SECTION, "load")) // Backward compatibility - value = appconfig_get(&collector_config, EBPF_GLOBAL_SECTION, "load", "entry"); + value = appconfig_get(&collector_config, EBPF_GLOBAL_SECTION, "load", + EBPF_CFG_LOAD_MODE_DEFAULT); else - value = appconfig_get(&collector_config, EBPF_GLOBAL_SECTION, "ebpf load mode", "entry"); + value = appconfig_get(&collector_config, EBPF_GLOBAL_SECTION, EBPF_CFG_LOAD_MODE, + EBPF_CFG_LOAD_MODE_DEFAULT); how_to_load(value); + ebpf_update_interval(); + // This is kept to keep compatibility uint32_t enabled = appconfig_get_boolean(&collector_config, EBPF_GLOBAL_SECTION, "disable apps", CONFIG_BOOLEAN_NO); if (!enabled) { // Apps is a positive sentence, so we need to invert the values to disable apps. - enabled = appconfig_get_boolean(&collector_config, EBPF_GLOBAL_SECTION, "apps", + enabled = appconfig_get_boolean(&collector_config, EBPF_GLOBAL_SECTION, EBPF_CFG_APPLICATION, CONFIG_BOOLEAN_YES); enabled = (enabled == CONFIG_BOOLEAN_NO)?CONFIG_BOOLEAN_YES:CONFIG_BOOLEAN_NO; } @@ -1704,8 +814,9 @@ static void read_collector_values(int *disable_apps) if (enabled) { ebpf_enable_chart(EBPF_MODULE_SOCKET_IDX, *disable_apps); // Read network viewer section if network viewer is enabled - parse_network_viewer_section(); - parse_service_name_section(); + // This is kept here to keep backward compatibility + parse_network_viewer_section(&collector_config); + parse_service_name_section(&collector_config); started++; } @@ -1736,8 +847,9 @@ static void read_collector_values(int *disable_apps) if (!started){ ebpf_enable_all_charts(*disable_apps); // Read network viewer section - parse_network_viewer_section(); - parse_service_name_section(); + // This is kept here to keep backward compatibility + parse_network_viewer_section(&collector_config); + parse_service_name_section(&collector_config); } } @@ -1753,10 +865,13 @@ static int load_collector_config(char *path, int *disable_apps) { char lpath[4096]; - snprintf(lpath, 4095, "%s/%s", path, "ebpf.conf"); - - if (!appconfig_load(&collector_config, lpath, 0, NULL)) - return -1; + snprintf(lpath, 4095, "%s/%s", path, NETDATA_EBPF_CONFIG_FILE); + if (!appconfig_load(&collector_config, lpath, 0, NULL)) { + snprintf(lpath, 4095, "%s/%s", path, NETDATA_EBPF_OLD_CONFIG_FILE); + if (!appconfig_load(&collector_config, lpath, 0, NULL)) { + return -1; + } + } read_collector_values(disable_apps); diff --git a/collectors/ebpf.plugin/ebpf.conf b/collectors/ebpf.plugin/ebpf.conf deleted file mode 100644 index a61ba2d2be..0000000000 --- a/collectors/ebpf.plugin/ebpf.conf +++ /dev/null @@ -1,49 +0,0 @@ -# -# Global options -# -# The `ebpf load mode` option accepts the following values : -# `entry` : The eBPF collector only monitors calls for the functions, and does not show charts related to errors. -# `return : In the `return` mode, the eBPF collector monitors the same kernel functions as `entry`, but also creates -# new charts for the return of these functions, such as errors. -# -# The eBPF collector also creates charts for each running application through an integration with the `apps plugin`. -# If you want to disable the integration with `apps.plugin` along with the above charts, change the setting `apps` to -# 'no'. -# -[global] - ebpf load mode = entry - apps = yes - -# -# eBPF Programs -# -# The eBPF collector enables and runs the following eBPF programs by default: -# -# `cachestat`: Make charts for kernel functions related to page cache. -# `process` : This eBPF program creates charts that show information about process creation, VFS IO, and -# files removed. -# `socket` : This eBPF program creates charts with information about `TCP` and `UDP` functions, including the -# bandwidth consumed by each. -# `sync` : Montitor calls for syscall sync(2). -[ebpf programs] - cachestat = no - process = yes - socket = yes - sync = yes - network connections = no - -# -# Network Connection -# -# This is a feature with status WIP(Work in Progress) -# -[network connections] - maximum dimensions = 50 - resolve hostnames = no - resolve service names = no - ports = * - ips = !127.0.0.1/8 10.0.0.0/8 172.16.0.0/12 192.168.0.0/16 fc00::/7 !::1/128 - hostnames = * - -[service name] - 19999 = Netdata diff --git a/collectors/ebpf.plugin/ebpf.d.conf b/collectors/ebpf.plugin/ebpf.d.conf new file mode 100644 index 0000000000..7191d7416c --- /dev/null +++ b/collectors/ebpf.plugin/ebpf.d.conf @@ -0,0 +1,36 @@ +# +# Global options +# +# The `ebpf load mode` option accepts the following values : +# `entry` : The eBPF collector only monitors calls for the functions, and does not show charts related to errors. +# `return : In the `return` mode, the eBPF collector monitors the same kernel functions as `entry`, but also creates +# new charts for the return of these functions, such as errors. +# +# The eBPF collector also creates charts for each running application through an integration with the `apps plugin`. +# If you want to disable the integration with `apps.plugin` along with the above charts, change the setting `apps` to +# 'no'. +# +# The `update every` option defines the number of seconds used to read data from kernel and send to netdata +[global] + ebpf load mode = entry + apps = yes + update every = 1 + +# +# eBPF Programs +# +# The eBPF collector enables and runs the following eBPF programs by default: +# +# `cachestat`: Make charts for kernel functions related to page cache. +# `process` : This eBPF program creates charts that show information about process creation, VFS IO, and +# files removed. +# `socket` : This eBPF program creates charts with information about `TCP` and `UDP` functions, including the +# bandwidth consumed by each. +# `sync` : Montitor calls for syscall sync(2). +[ebpf programs] + cachestat = no + process = yes + socket = yes + sync = yes + network connections = no + diff --git a/collectors/ebpf.plugin/ebpf.d/cachestat.conf b/collectors/ebpf.plugin/ebpf.d/cachestat.conf new file mode 100644 index 0000000000..78277cf560 --- /dev/null +++ b/collectors/ebpf.plugin/ebpf.d/cachestat.conf @@ -0,0 +1,14 @@ +# The `ebpf load mode` option accepts the following values : +# `entry` : The eBPF collector only monitors calls for the functions, and does not show charts related to errors. +# `return : In the `return` mode, the eBPF collector monitors the same kernel functions as `entry`, but also creates +# new charts for the return of these functions, such as errors. +# +# The eBPF collector also creates charts for each running application through an integration with the `apps plugin`. +# If you want to disable the integration with `apps.plugin` along with the above charts, change the setting `apps` to +# 'no'. +# +# +[global] + ebpf load mode = entry + apps = yes + update every = 2 diff --git a/collectors/ebpf.plugin/ebpf.d/ebpf_kernel_reject_list.txt b/collectors/ebpf.plugin/ebpf.d/ebpf_kernel_reject_list.txt new file mode 100644 index 0000000000..539bf357f6 --- /dev/null +++ b/collectors/ebpf.plugin/ebpf.d/ebpf_kernel_reject_list.txt @@ -0,0 +1 @@ +Ubuntu 4.18.0 diff --git a/collectors/ebpf.plugin/ebpf.d/network.conf b/collectors/ebpf.plugin/ebpf.d/network.conf new file mode 100644 index 0000000000..b033bc39c0 --- /dev/null +++ b/collectors/ebpf.plugin/ebpf.d/network.conf @@ -0,0 +1,30 @@ +# The `ebpf load mode` option accepts the following values : +# `entry` : The eBPF collector only monitors calls for the functions, and does not show charts related to errors. +# `return : In the `return` mode, the eBPF collector monitors the same kernel functions as `entry`, but also creates +# new charts for the return of these functions, such as errors. +# +# The eBPF collector also creates charts for each running application through an integration with the `apps plugin`. +# If you want to disable the integration with `apps.plugin` along with the above charts, change the setting `apps` to +# 'no'. +# +# +[global] + ebpf load mode = entry + apps = yes + update every = 1 + +# +# Network Connection +# +# This is a feature with status WIP(Work in Progress) +# +[network connections] + maximum dimensions = 50 + resolve hostnames = no + resolve service names = no + ports = * + ips = !127.0.0.1/8 10.0.0.0/8 172.16.0.0/12 192.168.0.0/16 fc00::/7 !::1/128 + hostnames = * + +[service name] + 19999 = Netdata diff --git a/collectors/ebpf.plugin/ebpf.d/process.conf b/collectors/ebpf.plugin/ebpf.d/process.conf new file mode 100644 index 0000000000..7806dc8443 --- /dev/null +++ b/collectors/ebpf.plugin/ebpf.d/process.conf @@ -0,0 +1,14 @@ +# The `ebpf load mode` option accepts the following values : +# `entry` : The eBPF collector only monitors calls for the functions, and does not show charts related to errors. +# `return : In the `return` mode, the eBPF collector monitors the same kernel functions as `entry`, but also creates +# new charts for the return of these functions, such as errors. +# +# The eBPF collector also creates charts for each running application through an integration with the `apps plugin`. +# If you want to disable the integration with `apps.plugin` along with the above charts, change the setting `apps` to +# 'no'. +# +# +[global] + ebpf load mode = entry + apps = yes + update every = 1 diff --git a/collectors/ebpf.plugin/ebpf.d/sync.conf b/collectors/ebpf.plugin/ebpf.d/sync.conf new file mode 100644 index 0000000000..78277cf560 --- /dev/null +++ b/collectors/ebpf.plugin/ebpf.d/sync.conf @@ -0,0 +1,14 @@ +# The `ebpf load mode` option accepts the following values : +# `entry` : The eBPF collector only monitors calls for the functions, and does not show charts related to errors. +# `return : In the `return` mode, the eBPF collector monitors the same kernel functions as `entry`, but also creates +# new charts for the return of these functions, such as errors. +# +# The eBPF collector also creates charts for each running application through an integration with the `apps plugin`. +# If you want to disable the integration with `apps.plugin` along with the above charts, change the setting `apps` to +# 'no'. +# +# +[global] + ebpf load mode = entry + apps = yes + update every = 2 diff --git a/collectors/ebpf.plugin/ebpf.h b/collectors/ebpf.plugin/ebpf.h index 4f7c371c4c..6796dcdad2 100644 --- a/collectors/ebpf.plugin/ebpf.h +++ b/collectors/ebpf.plugin/ebpf.h @@ -31,6 +31,9 @@ #include "ebpf_apps.h" +#define NETDATA_EBPF_OLD_CONFIG_FILE "ebpf.conf" +#define NETDATA_EBPF_CONFIG_FILE "ebpf.d.conf" + typedef struct netdata_syscall_stat { unsigned long bytes; // total number of bytes uint64_t call; // total number of calls @@ -88,6 +91,8 @@ enum ebpf_module_indexes { // Chart defintions #define NETDATA_EBPF_FAMILY "ebpf" +#define NETDATA_EBPF_CHART_TYPE_LINE "line" +#define NETDATA_EBPF_CHART_TYPE_STACKED "stacked" #define NETDATA_EBPF_MEMORY_GROUP "mem" // Log file @@ -151,6 +156,7 @@ extern void ebpf_create_chart(char *type, char *units, char *family, char *context, + char *charttype, int order, void (*ncd)(void *, int), void *move, @@ -173,6 +179,7 @@ extern void ebpf_create_charts_on_apps(char *name, char *title, char *units, char *family, + char *charttype, int order, char *algorithm, struct target *root); @@ -181,10 +188,7 @@ extern void write_end_chart(); extern void ebpf_cleanup_publish_syscall(netdata_publish_syscall_t *nps); -#define EBPF_GLOBAL_SECTION "global" #define EBPF_PROGRAMS_SECTION "ebpf programs" -#define EBPF_NETWORK_VIEWER_SECTION "network connections" -#define EBPF_SERVICE_NAME_SECTION "service name" #define EBPF_COMMON_DIMENSION_PERCENTAGE "%" #define EBPF_COMMON_DIMENSION_CALL "calls/s" @@ -194,11 +198,15 @@ extern void ebpf_cleanup_publish_syscall(netdata_publish_syscall_t *nps); #define EBPF_COMMON_DIMENSION_PACKETS "packets" // Common variables -extern char *ebpf_user_config_dir; -extern char *ebpf_stock_config_dir; extern int debug_enabled; extern struct pid_stat *root_of_pids; extern char *ebpf_algorithms[]; +extern struct config collector_config; +extern struct pid_stat *root_of_pids; +extern ebpf_process_stat_t *global_process_stat; +extern size_t all_pids_count; +extern int update_every; +extern uint32_t finalized_threads; // Socket functions and variables // Common functions @@ -207,11 +215,6 @@ extern void ebpf_socket_create_apps_charts(struct ebpf_module *em, void *ptr); extern void ebpf_cachestat_create_apps_charts(struct ebpf_module *em, void *root); extern void ebpf_one_dimension_write_charts(char *family, char *chart, char *dim, long long v1); extern collected_number get_value_from_structure(char *basis, size_t offset); -extern struct pid_stat *root_of_pids; -extern ebpf_process_stat_t *global_process_stat; -extern size_t all_pids_count; -extern int update_every; -extern uint32_t finalized_threads; #define EBPF_MAX_SYNCHRONIZATION_TIME 300 diff --git a/collectors/ebpf.plugin/ebpf_apps.h b/collectors/ebpf.plugin/ebpf_apps.h index b03d0f0c74..eb54754c65 100644 --- a/collectors/ebpf.plugin/ebpf_apps.h +++ b/collectors/ebpf.plugin/ebpf_apps.h @@ -11,11 +11,11 @@ #include "libnetdata/ebpf/ebpf.h" #define NETDATA_APPS_FAMILY "apps" -#define NETDATA_APPS_FILE_GROUP "ebpf file" -#define NETDATA_APPS_VFS_GROUP "ebpf vfs" -#define NETDATA_APPS_PROCESS_GROUP "ebpf process" -#define NETDATA_APPS_NET_GROUP "ebpf net" -#define NETDATA_APPS_CACHESTAT_GROUP "ebpf cachestat" +#define NETDATA_APPS_FILE_GROUP "file (eBPF)" +#define NETDATA_APPS_VFS_GROUP "vfs (eBPF)" +#define NETDATA_APPS_PROCESS_GROUP "process (eBPF)" +#define NETDATA_APPS_NET_GROUP "net (eBPF)" +#define NETDATA_APPS_CACHESTAT_GROUP "page cache (eBPF)" #include "ebpf_process.h" #include "ebpf_cachestat.h" diff --git a/collectors/ebpf.plugin/ebpf_cachestat.c b/collectors/ebpf.plugin/ebpf_cachestat.c index 25254032d7..6516d4da21 100644 --- a/collectors/ebpf.plugin/ebpf_cachestat.c +++ b/collectors/ebpf.plugin/ebpf_cachestat.c @@ -11,8 +11,8 @@ static struct bpf_object *objects = NULL; static char *cachestat_counter_dimension_name[NETDATA_CACHESTAT_END] = { "ratio", "dirty", "hit", "miss" }; -static netdata_syscall_stat_t *cachestat_counter_aggregated_data = NULL; -static netdata_publish_syscall_t *cachestat_counter_publish_aggregated = NULL; +static netdata_syscall_stat_t cachestat_counter_aggregated_data[NETDATA_CACHESTAT_END]; +static netdata_publish_syscall_t cachestat_counter_publish_aggregated[NETDATA_CACHESTAT_END]; netdata_cachestat_pid_t *cachestat_vector = NULL; @@ -26,6 +26,12 @@ struct netdata_static_thread cachestat_threads = {"CACHESTAT KERNEL", static int *map_fd = NULL; +struct config cachestat_config = { .first_section = NULL, + .last_section = NULL, + .mutex = NETDATA_MUTEX_INITIALIZER, + .index = { .avl_tree = { .root = NULL, .compar = appconfig_section_compare }, + .rwlock = AVL_LOCK_INITIALIZER } }; + /***************************************************************** * * FUNCTIONS TO CLOSE THE THREAD @@ -68,9 +74,7 @@ static void ebpf_cachestat_cleanup(void *ptr) clean_pid_structures(); freez(cachestat_pid); - freez(cachestat_counter_aggregated_data); ebpf_cleanup_publish_syscall(cachestat_counter_publish_aggregated); - freez(cachestat_counter_publish_aggregated); freez(cachestat_vector); freez(cachestat_hash_values); @@ -278,6 +282,7 @@ void ebpf_cachestat_create_apps_charts(struct ebpf_module *em, void *ptr) "The ratio is calculated dividing the Hit pages per total cache accesses without counting dirties.", EBPF_COMMON_DIMENSION_PERCENTAGE, NETDATA_APPS_CACHESTAT_GROUP, + NETDATA_EBPF_CHART_TYPE_STACKED, 20090, ebpf_algorithms[NETDATA_EBPF_ABSOLUTE_IDX], root); @@ -286,6 +291,7 @@ void ebpf_cachestat_create_apps_charts(struct ebpf_module *em, void *ptr) "Number of pages marked as dirty. When a page is called dirty, this means that the data stored inside the page needs to be written to devices.", EBPF_CACHESTAT_DIMENSION_PAGE, NETDATA_APPS_CACHESTAT_GROUP, + NETDATA_EBPF_CHART_TYPE_STACKED, 20091, ebpf_algorithms[NETDATA_EBPF_INCREMENTAL_IDX], root); @@ -294,6 +300,7 @@ void ebpf_cachestat_create_apps_charts(struct ebpf_module *em, void *ptr) "Number of cache access without counting dirty pages and page additions.", EBPF_CACHESTAT_DIMENSION_HITS, NETDATA_APPS_CACHESTAT_GROUP, + NETDATA_EBPF_CHART_TYPE_STACKED, 20092, ebpf_algorithms[NETDATA_EBPF_ABSOLUTE_IDX], root); @@ -302,6 +309,7 @@ void ebpf_cachestat_create_apps_charts(struct ebpf_module *em, void *ptr) "Page caches added without counting dirty pages", EBPF_CACHESTAT_DIMENSION_MISSES, NETDATA_APPS_CACHESTAT_GROUP, + NETDATA_EBPF_CHART_TYPE_STACKED, 20093, ebpf_algorithms[NETDATA_EBPF_ABSOLUTE_IDX], root); @@ -348,10 +356,10 @@ void *ebpf_cachestat_read_hash(void *ptr) heartbeat_t hb; heartbeat_init(&hb); - usec_t step = NETDATA_LATENCY_CACHESTAT_SLEEP_MS; ebpf_module_t *em = (ebpf_module_t *)ptr; + usec_t step = NETDATA_LATENCY_CACHESTAT_SLEEP_MS * em->update_time; int apps = em->apps_charts; while (!close_ebpf_plugin) { usec_t dt = heartbeat_next(&hb, step); @@ -533,6 +541,7 @@ static void ebpf_create_memory_charts() "Hit is calculating using total cache added without dirties per total added because of red misses.", EBPF_CACHESTAT_DIMENSION_HITS, NETDATA_CACHESTAT_SUBMENU, NULL, + NETDATA_EBPF_CHART_TYPE_LINE, 21100, ebpf_create_global_dimension, cachestat_counter_publish_aggregated, 1); @@ -541,6 +550,7 @@ static void ebpf_create_memory_charts() "Number of dirty pages added to the page cache.", EBPF_CACHESTAT_DIMENSION_PAGE, NETDATA_CACHESTAT_SUBMENU, NULL, + NETDATA_EBPF_CHART_TYPE_LINE, 21101, ebpf_create_global_dimension, &cachestat_counter_publish_aggregated[NETDATA_CACHESTAT_IDX_DIRTY], 1); @@ -549,6 +559,7 @@ static void ebpf_create_memory_charts() "Hits are function calls that Netdata counts.", EBPF_CACHESTAT_DIMENSION_HITS, NETDATA_CACHESTAT_SUBMENU, NULL, + NETDATA_EBPF_CHART_TYPE_LINE, 21102, ebpf_create_global_dimension, &cachestat_counter_publish_aggregated[NETDATA_CACHESTAT_IDX_HIT], 1); @@ -557,6 +568,7 @@ static void ebpf_create_memory_charts() "Misses are function calls that Netdata counts.", EBPF_CACHESTAT_DIMENSION_MISSES, NETDATA_CACHESTAT_SUBMENU, NULL, + NETDATA_EBPF_CHART_TYPE_LINE, 21103, ebpf_create_global_dimension, &cachestat_counter_publish_aggregated[NETDATA_CACHESTAT_IDX_MISS], 1); @@ -579,8 +591,8 @@ static void ebpf_cachestat_allocate_global_vectors(size_t length) cachestat_hash_values = callocz(length, sizeof(netdata_idx_t)); - cachestat_counter_aggregated_data = callocz(length, sizeof(netdata_syscall_stat_t)); - cachestat_counter_publish_aggregated = callocz(length, sizeof(netdata_publish_syscall_t)); + memset(cachestat_counter_aggregated_data, 0, length * sizeof(netdata_syscall_stat_t)); + memset(cachestat_counter_publish_aggregated, 0, length * sizeof(netdata_publish_syscall_t)); } /***************************************************************** @@ -605,6 +617,8 @@ void *ebpf_cachestat_thread(void *ptr) ebpf_module_t *em = (ebpf_module_t *)ptr; fill_ebpf_data(&cachestat_data); + ebpf_update_module(em, &cachestat_config, NETDATA_CACHESTAT_CONFIG_FILE); + if (!em->enabled) goto endcachestat; diff --git a/collectors/ebpf.plugin/ebpf_cachestat.h b/collectors/ebpf.plugin/ebpf_cachestat.h index c6fdb79a4b..daf678975a 100644 --- a/collectors/ebpf.plugin/ebpf_cachestat.h +++ b/collectors/ebpf.plugin/ebpf_cachestat.h @@ -9,7 +9,7 @@ #define NETDATA_CACHESTAT_HIT_CHART "cachestat_hits" #define NETDATA_CACHESTAT_MISSES_CHART "cachestat_misses" -#define NETDATA_CACHESTAT_SUBMENU "page cache" +#define NETDATA_CACHESTAT_SUBMENU "page cache (eBPF)" #define EBPF_CACHESTAT_DIMENSION_PAGE "pages/s" #define EBPF_CACHESTAT_DIMENSION_HITS "hits/s" @@ -17,6 +17,9 @@ #define NETDATA_LATENCY_CACHESTAT_SLEEP_MS 600000ULL +// configuration file +#define NETDATA_CACHESTAT_CONFIG_FILE "cachestat.conf" + // variables enum cachestat_counters { NETDATA_KEY_CALLS_ADD_TO_PAGE_CACHE_LRU, diff --git a/collectors/ebpf.plugin/ebpf_kernel_reject_list.txt b/collectors/ebpf.plugin/ebpf_kernel_reject_list.txt deleted file mode 100644 index 539bf357f6..0000000000 --- a/collectors/ebpf.plugin/ebpf_kernel_reject_list.txt +++ /dev/null @@ -1 +0,0 @@ -Ubuntu 4.18.0 diff --git a/collectors/ebpf.plugin/ebpf_process.c b/collectors/ebpf.plugin/ebpf_process.c index 677b7db635..5fa930b2dd 100644 --- a/collectors/ebpf.plugin/ebpf_process.c +++ b/collectors/ebpf.plugin/ebpf_process.c @@ -19,8 +19,8 @@ static char *process_id_names[NETDATA_KEY_PUBLISH_PROCESS_END] = { "do_sys_open" static char *status[] = { "process", "zombie" }; static netdata_idx_t *process_hash_values = NULL; -static netdata_syscall_stat_t *process_aggregated_data = NULL; -static netdata_publish_syscall_t *process_publish_aggregated = NULL; +static netdata_syscall_stat_t process_aggregated_data[NETDATA_KEY_PUBLISH_PROCESS_END]; +static netdata_publish_syscall_t process_publish_aggregated[NETDATA_KEY_PUBLISH_PROCESS_END]; static ebpf_data_t process_data; @@ -33,6 +33,12 @@ static int *map_fd = NULL; static struct bpf_object *objects = NULL; static struct bpf_link **probe_links = NULL; +struct config process_config = { .first_section = NULL, + .last_section = NULL, + .mutex = NETDATA_MUTEX_INITIALIZER, + .index = { .avl_tree = { .root = NULL, .compar = appconfig_section_compare }, + .rwlock = AVL_LOCK_INITIALIZER } }; + /***************************************************************** * * PROCESS DATA AND SEND TO NETDATA @@ -521,6 +527,7 @@ static void ebpf_create_global_charts(ebpf_module_t *em) EBPF_COMMON_DIMENSION_CALL, NETDATA_FILE_GROUP, NULL, + NETDATA_EBPF_CHART_TYPE_LINE, 21000, ebpf_create_global_dimension, process_publish_aggregated, @@ -533,6 +540,7 @@ static void ebpf_create_global_charts(ebpf_module_t *em) EBPF_COMMON_DIMENSION_CALL, NETDATA_FILE_GROUP, NULL, + NETDATA_EBPF_CHART_TYPE_LINE, 21001, ebpf_create_global_dimension, process_publish_aggregated, @@ -545,6 +553,7 @@ static void ebpf_create_global_charts(ebpf_module_t *em) EBPF_COMMON_DIMENSION_CALL, NETDATA_VFS_GROUP, NULL, + NETDATA_EBPF_CHART_TYPE_LINE, 21002, ebpf_create_global_dimension, &process_publish_aggregated[NETDATA_DEL_START], @@ -556,6 +565,7 @@ static void ebpf_create_global_charts(ebpf_module_t *em) EBPF_COMMON_DIMENSION_CALL,