@cryptotaxi247 / netdata-1 / commits / abd8e61b6

Network viewer charts (#9591)

Bring next steps to build the Network Viewer charts.

thiagoftsm committed Aug 14, 2020 at 15:16 UTC abd8e61b649136698307b5509d3d735735b291dd
5 files changed +661 -97
collectors/ebpf.plugin/ebpf.c
+93 -14
@@ -104,11 +104,14 @@ netdata_ebpf_events_t socket_probes[] = {
104
105 ebpf_module_t ebpf_modules[] = {
106 { .thread_name = "process", .config_name = "process", .enabled = 0, .start_routine = ebpf_process_thread,
107 - .update_time = 1, .global_charts = 1, .apps_charts = 1, .mode = MODE_ENTRY, .probes = process_probes },
107 + .update_time = 1, .global_charts = 1, .apps_charts = 1, .mode = MODE_ENTRY, .probes = process_probes,
108 + .optional = 0 },
109 { .thread_name = "socket", .config_name = "network viewer", .enabled = 0, .start_routine = ebpf_socket_thread,
109 - .update_time = 1, .global_charts = 1, .apps_charts = 1, .mode = MODE_ENTRY, .probes = socket_probes },
110 + .update_time = 1, .global_charts = 1, .apps_charts = 1, .mode = MODE_ENTRY, .probes = socket_probes,
111 + .optional = 0 },
112 { .thread_name = NULL, .enabled = 0, .start_routine = NULL, .update_time = 1,
111 - .global_charts = 0, .apps_charts = 1, .mode = MODE_ENTRY, .probes = NULL },
113 + .global_charts = 0, .apps_charts = 1, .mode = MODE_ENTRY, .probes = NULL,
114 + .optional = 0 },
115 };
116
117 // Link with apps.plugin
@@ -116,9 +119,10 @@ pid_t *pid_index;
119 ebpf_process_stat_t *global_process_stat = NULL;
120
121 //Network viewer
119 -ebpf_network_viewer_options_t network_viewer_opt = { .max_dim = 500, .name_resolution_enabled = 0,
120 - .excluded_port = NULL, .included_port = NULL,
121 - .names = NULL, .ipv4_local_ip = NULL, .ipv6_local_ip = NULL };
122 +ebpf_network_viewer_options_t network_viewer_opt = { .max_dim = NETDATA_NV_CAP_VALUE, .hostname_resolution_enabled = 0,
123 + .service_resolution_enabled = 0, .excluded_port = NULL,
124 + .included_port = NULL, .names = NULL, .ipv4_local_ip = NULL,
125 + .ipv6_local_ip = NULL };
126
127 /*****************************************************************
128 *
@@ -699,6 +703,43 @@ static inline void fill_ip_list(ebpf_network_viewer_ip_list_t **out, ebpf_networ
703 #endif
704 }
705
706 +/**
707 + * Read Local Ports
708 + *
709 + * Parse /proc/net/{tcp,udp} and get the ports Linux is listening.
710 + *
711 + * @param filename the proc file to parse.
712 + * @param proto is the magic number associated to the protocol file we are reading.
713 + */
714 +static void read_local_ports(char *filename, uint8_t proto)
715 +{
716 + procfile *ff = procfile_open(filename, " \t:", PROCFILE_FLAG_DEFAULT);
717 + if (!ff)
718 + return;
719 +
720 + ff = procfile_readall(ff);
721 + if (!ff)
722 + return;
723 +
724 + size_t lines = procfile_lines(ff), l;
725 + for(l = 0; l < lines ;l++) {
726 + size_t words = procfile_linewords(ff, l);
727 + // This is header or end of file
728 + if (unlikely(words < 14))
729 + continue;
730 +
731 + // https://elixir.bootlin.com/linux/v5.7.8/source/include/net/tcp_states.h
732 + // 0A = TCP_LISTEN
733 + if (strcmp("0A", procfile_lineword(ff, l, 5)))
734 + continue;
735 +
736 + // Read local port
737 + uint16_t port = (uint16_t)strtol(procfile_lineword(ff, l, 2), NULL, 16);
738 + update_listen_table(htons(port), proto);
739 + }
740 +
741 + procfile_close(ff);
742 +}
743
744 /**
745 * Read Local addresseses
@@ -1479,26 +1520,55 @@ static void link_hostnames(char *parse)
1520 }
1521 }
1522
1523 +/**
1524 + * Read max dimension.
1525 + *
1526 + * Netdata plot two dimensions per connection, so it is necessary to adjust the values.
1527 + */
1528 +static void read_max_dimension()
1529 +{
1530 + int maxdim ;
1531 + maxdim = (int) appconfig_get_number(&collector_config,
1532 + EBPF_NETWORK_VIEWER_SECTION,
1533 + "maximum dimensions",
1534 + NETDATA_NV_CAP_VALUE);
1535 + if (maxdim < 0) {
1536 + error("'maximum dimensions = %d' must be a positive number, Netdata will change for default value %ld.",
1537 + maxdim, NETDATA_NV_CAP_VALUE);
1538 + maxdim = NETDATA_NV_CAP_VALUE;
1539 + }
1540 +
1541 + maxdim /= 2;
1542 + if (!maxdim) {
1543 + info("The number of dimensions is too small (%u), we are setting it to minimum 2", network_viewer_opt.max_dim);
1544 + network_viewer_opt.max_dim = 1;
1545 + }
1546 +
1547 + network_viewer_opt.max_dim = (uint32_t)maxdim;
1548 +}
1549 +
1550 /**
1551 * Parse network viewer section
1552 */
1553 static void parse_network_viewer_section()
1554 {
1487 - network_viewer_opt.max_dim = appconfig_get_number(&collector_config,
1488 - EBPF_NETWORK_VIEWER_SECTION,
1489 - "maximum dimensions",
1490 - 50);
1555 + read_max_dimension();
1556
1492 - network_viewer_opt.name_resolution_enabled = appconfig_get_boolean(&collector_config,
1557 + network_viewer_opt.hostname_resolution_enabled = appconfig_get_boolean(&collector_config,
1558 EBPF_NETWORK_VIEWER_SECTION,
1494 - "resolve hostname ips",
1559 + "resolve hostnames",
1560 0);
1561
1562 + network_viewer_opt.service_resolution_enabled = appconfig_get_boolean(&collector_config,
1563 + EBPF_NETWORK_VIEWER_SECTION,
1564 + "resolve service names",
1565 + 0);
1566 +
1567 char *value = appconfig_get(&collector_config, EBPF_NETWORK_VIEWER_SECTION,
1568 "ports", NULL);
1569 parse_ports(value);
1570
1501 - if (network_viewer_opt.name_resolution_enabled) {
1571 + if (network_viewer_opt.hostname_resolution_enabled) {
1572 value = appconfig_get(&collector_config, EBPF_NETWORK_VIEWER_SECTION, "hostnames", NULL);
1573 link_hostnames(value);
1574 } else {
@@ -1609,7 +1679,8 @@ static void read_collector_values(int *disable_apps)
1679 *disable_apps = parse_disable_apps(value);
1680
1681 // Read ebpf programs section
1612 - uint32_t enabled = appconfig_get_boolean(&collector_config, EBPF_PROGRAMS_SECTION, ebpf_modules[0].config_name, 1);
1682 + uint32_t enabled = appconfig_get_boolean(&collector_config, EBPF_PROGRAMS_SECTION, ebpf_modules[0].config_name,
1683 + 1);
1684 int started = 0;
1685 if (enabled) {
1686 ebpf_enable_chart(EBPF_MODULE_PROCESS_IDX, *disable_apps);
@@ -1625,6 +1696,10 @@ static void read_collector_values(int *disable_apps)
1696 started++;
1697 }
1698
1699 + enabled = appconfig_get_boolean(&collector_config, EBPF_PROGRAMS_SECTION, "network connection monitoring",
1700 + 0);
1701 + ebpf_modules[1].optional = enabled;
1702 +
1703 if (!started){
1704 ebpf_enable_all_charts(*disable_apps);
1705 // Read network viewer section
@@ -1882,6 +1957,10 @@ int main(int argc, char **argv)
1957 ebpf_allocate_common_vectors();
1958
1959 read_local_addresses();
1960 + read_local_ports("/proc/net/tcp", IPPROTO_TCP);
1961 + read_local_ports("/proc/net/tcp6", IPPROTO_TCP);
1962 + read_local_ports("/proc/net/udp", IPPROTO_UDP);
1963 + read_local_ports("/proc/net/udp6", IPPROTO_UDP);
1964
1965 struct netdata_static_thread ebpf_threads[] = {
1966 {"EBPF PROCESS", NULL, NULL, 1, NULL, NULL, ebpf_modules[0].start_routine},
collectors/ebpf.plugin/ebpf.conf
+4 -2
@@ -5,10 +5,12 @@
5 [ebpf programs]
6 process = yes
7 network viewer = yes
8 + network connection monitoring = no
9
10 [network viewer]
10 - maximum dimensions = 500
11 - resolve hostname ips = no
11 + maximum dimensions = 50
12 + resolve hostnames = no
13 + resolve service names = no
14 ports = *
15 ips = !127.0.0.1/8 10.0.0.0/8 172.16.0.0/12 192.168.0.0/16 fc00::/7
16 hostnames = *
collectors/ebpf.plugin/ebpf.h
+4 -2
@@ -85,6 +85,7 @@ typedef struct ebpf_module {
85 netdata_run_mode_t mode;
86 netdata_ebpf_events_t *probes;
87 uint32_t thread_id;
88 + int optional;
89 } ebpf_module_t;
90
91 extern ebpf_module_t ebpf_modules[];
@@ -189,9 +190,10 @@ extern void write_end_chart();
190 #define EBPF_NETWORK_VIEWER_SECTION "network viewer"
191 #define EBPF_SERVICE_NAME_SECTION "service name"
192
192 -#define EBPF_COMMON_DIMENSION_CALL "Calls"
193 +#define EBPF_COMMON_DIMENSION_CALL "calls"
194 #define EBPF_COMMON_DIMENSION_BYTESS "bytes/s"
194 -#define EBPF_COMMON_DIMENSION_DIFFERENCE "Difference"
195 +#define EBPF_COMMON_DIMENSION_DIFFERENCE "difference"
196 +#define EBPF_COMMON_DIMENSION_PACKETS "packets"
197
198 // Common variables
199 extern char *ebpf_user_config_dir;
collectors/ebpf.plugin/ebpf_socket.c
+506 -71
@@ -27,6 +27,8 @@ static ebpf_socket_publish_apps_t **socket_bandwidth_prev = NULL;
27 static ebpf_bandwidth_t *bandwidth_vector = NULL;
28
29 static int socket_apps_created = 0;
30 +pthread_mutex_t nv_mutex;
31 +int wait_to_plot = 0;
32
33 netdata_vector_plot_t inbound_vectors = { .plot = NULL, .next = 0, .last = 0 };
34 netdata_vector_plot_t outbound_vectors = { .plot = NULL, .next = 0, .last = 0 };
@@ -88,6 +90,171 @@ static void ebpf_update_global_publish(
90 udp->read = (long)publish[4].nbyte;
91 }
92
93 +/**
94 + * Update Network Viewer plot data
95 + *
96 + * @param plot the structure where the data will be stored
97 + * @param sock the last update from the socket
98 + */
99 +static inline void update_nv_plot_data(netdata_plot_values_t *plot, netdata_socket_t *sock)
100 +{
101 + if (sock->ct > plot->last_time) {
102 + plot->last_time = sock->ct;
103 + plot->plot_recv_packets = sock->recv_packets;
104 + plot->plot_sent_packets = sock->sent_packets;
105 + plot->plot_recv_bytes = sock->recv_bytes;
106 + plot->plot_sent_bytes = sock->sent_bytes;
107 + plot->plot_retransmit = sock->retransmit;
108 + }
109 +
110 + sock->recv_packets = 0;
111 + sock->sent_packets = 0;
112 + sock->recv_bytes = 0;
113 + sock->sent_bytes = 0;
114 + sock->retransmit = 0;
115 +}
116 +
117 +/**
118 + * Calculate Network Viewer Plot
119 + *
120 + * Do math with collected values before to plot data.
121 + */
122 +static inline void calculate_nv_plot()
123 +{
124 + uint32_t i;
125 + uint32_t end = inbound_vectors.next;
126 + for (i = 0; i < end; i++) {
127 + update_nv_plot_data(&inbound_vectors.plot[i].plot, &inbound_vectors.plot[i].sock);
128 + }
129 + inbound_vectors.max_plot = end;
130 +
131 + // The 'Other' dimension is always calculated for the chart to have at least one dimension
132 + update_nv_plot_data(&inbound_vectors.plot[inbound_vectors.last].plot,
133 + &inbound_vectors.plot[inbound_vectors.last].sock);
134 +
135 + end = outbound_vectors.next;
136 + for (i = 0; i < end; i++) {
137 + update_nv_plot_data(&outbound_vectors.plot[i].plot, &outbound_vectors.plot[i].sock);
138 + }
139 + outbound_vectors.max_plot = end;
140 +
141 + // The 'Other' dimension is always calculated for the chart to have at least one dimension
142 + update_nv_plot_data(&outbound_vectors.plot[outbound_vectors.last].plot,
143 + &outbound_vectors.plot[outbound_vectors.last].sock);
144 +}
145 +
146 +/**
147 + * Network viewer send bytes
148 + *
149 + * @param ptr the structure with values to plot
150 + * @param chart the chart name.
151 + */
152 +static inline void ebpf_socket_nv_send_bytes(netdata_vector_plot_t *ptr, char *chart)
153 +{
154 + uint32_t i;
155 + uint32_t end = ptr->last_plot;
156 + netdata_socket_plot_t *w = ptr->plot;
157 + collected_number value;
158 +
159 + write_begin_chart(NETDATA_EBPF_FAMILY, chart);
160 + for (i = 0; i < end; i++) {
161 + value = ((collected_number) w[i].plot.plot_sent_bytes);
162 + write_chart_dimension(w[i].dimension_sent, value);
163 + value = (collected_number) w[i].plot.plot_recv_bytes;
164 + write_chart_dimension(w[i].dimension_recv, value);
165 + }
166 +
167 + i = ptr->last;
168 + value = ((collected_number) w[i].plot.plot_sent_bytes);
169 + write_chart_dimension(w[i].dimension_sent, value);
170 + value = (collected_number) w[i].plot.plot_recv_bytes;
171 + write_chart_dimension(w[i].dimension_recv, value);
172 + write_end_chart();
173 +}
174 +
175 +/**
176 + * Network Viewer Send packets
177 + *
178 + * @param ptr the structure with values to plot
179 + * @param chart the chart name.
180 + */
181 +static inline void ebpf_socket_nv_send_packets(netdata_vector_plot_t *ptr, char *chart)
182 +{
183 + uint32_t i;
184 + uint32_t end = ptr->last_plot;
185 + netdata_socket_plot_t *w = ptr->plot;
186 + collected_number value;
187 +
188 + write_begin_chart(NETDATA_EBPF_FAMILY, chart);
189 + for (i = 0; i < end; i++) {
190 + value = ((collected_number)w[i].plot.plot_sent_packets);
191 + write_chart_dimension(w[i].dimension_sent, value);
192 + value = (collected_number) w[i].plot.plot_recv_packets;
193 + write_chart_dimension(w[i].dimension_recv, value);
194 + }
195 +
196 + i = ptr->last;
197 + value = ((collected_number)w[i].plot.plot_sent_packets);
198 + write_chart_dimension(w[i].dimension_sent, value);
199 + value = (collected_number)w[i].plot.plot_recv_packets;
200 + write_chart_dimension(w[i].dimension_recv, value);
201 + write_end_chart();
202 +}
203 +
204 +/**
205 + * Network Viewer Send Retransmit
206 + *
207 + * @param ptr the structure with values to plot
208 + * @param chart the chart name.
209 + */
210 +static inline void ebpf_socket_nv_send_retransmit(netdata_vector_plot_t *ptr, char *chart)
211 +{
212 + uint32_t i;
213 + uint32_t end = ptr->last_plot;
214 + netdata_socket_plot_t *w = ptr->plot;
215 + collected_number value;
216 +
217 + write_begin_chart(NETDATA_EBPF_FAMILY, chart);
218 + for (i = 0; i < end; i++) {
219 + value = (collected_number) w[i].plot.plot_retransmit;
220 + write_chart_dimension(w[i].dimension_retransmit, value);
221 + }
222 +
223 + i = ptr->last;
224 + value = (collected_number)w[i].plot.plot_retransmit;
225 + write_chart_dimension(w[i].dimension_retransmit, value);
226 + write_end_chart();
227 +}
228 +
229 +/**
230 + * Send network viewer data
231 + *
232 + * @param ptr the pointer to plot data
233 + */
234 +static void ebpf_socket_send_nv_data(netdata_vector_plot_t *ptr)
235 +{
236 + if (!ptr->flags)
237 + return;
238 +
239 + if (ptr == (netdata_vector_plot_t *)&outbound_vectors) {
240 + ebpf_socket_nv_send_bytes(ptr, NETDATA_NV_OUTBOUND_BYTES);
241 + fflush(stdout);
242 +
243 + ebpf_socket_nv_send_packets(ptr, NETDATA_NV_OUTBOUND_PACKETS);
244 + fflush(stdout);
245 +
246 + ebpf_socket_nv_send_retransmit(ptr, NETDATA_NV_OUTBOUND_RETRANSMIT);
247 + fflush(stdout);
248 + } else {
249 + ebpf_socket_nv_send_bytes(ptr, NETDATA_NV_INBOUND_BYTES);
250 + fflush(stdout);
251 +
252 + ebpf_socket_nv_send_packets(ptr, NETDATA_NV_INBOUND_PACKETS);
253 + fflush(stdout);
254 + }
255 +}
256 +
257 +
258 /**
259 * Update the publish strctures to create the dimenssions
260 *
@@ -308,6 +475,131 @@ void ebpf_socket_create_apps_charts(ebpf_module_t *em, struct target *root)
475 socket_apps_created = 1;
476 }
477
478 +/**
479 + * Create network viewer chart
480 + *
481 + * Create common charts.
482 + *
483 + * @param id the chart id
484 + * @param title the chart title
485 + * @param units the units label
486 + * @param family the group name used to attach the chart on dashaboard
487 + * @param order the chart order
488 + * @param ptr the plot structure with values.
489 + */
490 +static void ebpf_socket_create_nv_chart(char *id, char *title, char *units,
491 + char *family, int order, netdata_vector_plot_t *ptr)
492 +{
493 + ebpf_write_chart_cmd(NETDATA_EBPF_FAMILY,
494 + id,
495 + title,
496 + units,
497 + family,
498 + "stacked",
499 + order);
500 +
501 + uint32_t i;
502 + uint32_t end = ptr->last_plot;
503 + netdata_socket_plot_t *w = ptr->plot;
504 + for (i = 0; i < end; i++) {
505 + fprintf(stdout, "DIMENSION %s '' incremental -1 1\n", w[i].dimension_sent);
506 + fprintf(stdout, "DIMENSION %s '' incremental 1 1\n", w[i].dimension_recv);
507 + }
508 +
509 + end = ptr->last;
510 + fprintf(stdout, "DIMENSION %s '' incremental -1 1\n", w[end].dimension_sent);
511 + fprintf(stdout, "DIMENSION %s '' incremental 1 1\n", w[end].dimension_recv);
512 +}
513 +
514 +/**
515 + * Create network viewer retransmit
516 + *
517 + * Create a specific chart.
518 + *
519 + * @param id the chart id
520 + * @param title the chart title
521 + * @param units the units label
522 + * @param family the group name used to attach the chart on dashaboard
523 + * @param order the chart order
524 + * @param ptr the plot structure with values.
525 + */
526 +static void ebpf_socket_create_nv_retransmit(char *id, char *title, char *units,
527 + char *family, int order, netdata_vector_plot_t *ptr)
528 +{
529 + ebpf_write_chart_cmd(NETDATA_EBPF_FAMILY,
530 + id,
531 + title,
532 + units,
533 + family,
534 + "stacked",
535 + order);
536 +
537 + uint32_t i;
538 + uint32_t end = ptr->last_plot;
539 + netdata_socket_plot_t *w = ptr->plot;
540 + for (i = 0; i < end; i++) {
541 + fprintf(stdout, "DIMENSION %s '' incremental 1 1\n", w[i].dimension_retransmit);
542 + }
543 +
544 + end = ptr->last;
545 + fprintf(stdout, "DIMENSION %s '' incremental 1 1\n", w[end].dimension_retransmit);
546 +}
547 +
548 +/**
549 + * Create Network Viewer charts
550 + *
551 + * Recreate the charts when new sockets are created.
552 + *
553 + * @param ptr a pointer for inbound or outbound vectors.
554 + */
555 +static void ebpf_socket_create_nv_charts(netdata_vector_plot_t *ptr)
556 +{
557 + // We do not have new sockets, so we do not need move forward
558 + if (ptr->max_plot == ptr->last_plot)
559 + return;
560 +
561 + ptr->last_plot = ptr->max_plot;
562 +
563 + if (ptr == (netdata_vector_plot_t *)&outbound_vectors) {
564 + ebpf_socket_create_nv_chart(NETDATA_NV_OUTBOUND_BYTES,
565 + "Outbound connections (bytes).",
566 + EBPF_COMMON_DIMENSION_BYTESS,
567 + NETDATA_NETWORK_CONNECTIONS_GROUP,
568 + 21080,
569 + ptr);
570 +
571 + ebpf_socket_create_nv_chart(NETDATA_NV_OUTBOUND_PACKETS,
572 + "Outbound connections (packets)",
573 + EBPF_COMMON_DIMENSION_PACKETS,
574 + NETDATA_NETWORK_CONNECTIONS_GROUP,
575 + 21082,
576 + ptr);
577 +
578 + ebpf_socket_create_nv_retransmit(NETDATA_NV_OUTBOUND_RETRANSMIT,
579 + "Retransmitted packets",
580 + EBPF_COMMON_DIMENSION_CALL,
581 + NETDATA_NETWORK_CONNECTIONS_GROUP,
582 + 21083,
583 + ptr);
584 + } else {
585 + ebpf_socket_create_nv_chart(NETDATA_NV_INBOUND_BYTES,
586 + "Inbound connections (bytes)",
587 + EBPF_COMMON_DIMENSION_BYTESS,
588 + NETDATA_NETWORK_CONNECTIONS_GROUP,
589 + 21084,
590 + ptr);
591 +
592 + ebpf_socket_create_nv_chart(NETDATA_NV_INBOUND_PACKETS,
593 + "Inbound connections (packets)",
594 + EBPF_COMMON_DIMENSION_PACKETS,
595 + NETDATA_NETWORK_CONNECTIONS_GROUP,
596 + 21085,
597 + ptr);
598 + }
599 +
600 + ptr->flags |= NETWORK_VIEWER_CHARTS_CREATED;
601 +}
602 +
603 /*****************************************************************
604 *
605 * READ INFORMATION FROM KERNEL RING
@@ -471,14 +763,30 @@ static int compare_sockets(void *a, void *b)
763
764 // We do not need to compare val2 family, because data inside hash table is always from the same family
765 if (val1->family == AF_INET) { //IPV4
474 - cmp = memcmp(&val1->index.daddr.addr32[0], &val2->index.daddr.addr32[0], sizeof(uint32_t));
475 - if (!cmp) {
766 + if (val1->flags & NETDATA_INBOUND_DIRECTION) {
767 + if (val1->index.sport == val2->index.sport)
768 + cmp = 0;
769 + else {
770 + cmp = (val1->index.sport > val2->index.sport)?1:-1;
771 + }
772 + } else {
773 cmp = memcmp(&val1->index.dport, &val2->index.dport, sizeof(uint16_t));
774 + if (!cmp) {
775 + cmp = memcmp(&val1->index.daddr.addr32[0], &val2->index.daddr.addr32[0], sizeof(uint32_t));
776 + }
777 }
778 } else {
479 - cmp = memcmp(&val1->index.daddr.addr32, &val2->index.daddr.addr32, 4*sizeof(uint32_t));
480 - if (!cmp) {
779 + if (val1->flags & NETDATA_INBOUND_DIRECTION) {
780 + if (val1->index.sport == val2->index.sport)
781 + cmp = 0;
782 + else {
783 + cmp = (val1->index.sport > val2->index.sport)?1:-1;
784 + }
785 + } else {
786 cmp = memcmp(&val1->index.dport, &val2->index.dport, sizeof(uint16_t));
787 + if (!cmp) {
788 + cmp = memcmp(&val1->index.daddr.addr32, &val2->index.daddr.addr32, 4*sizeof(uint32_t));
789 + }
790 }
791 }
792
@@ -549,7 +857,15 @@ static inline void fill_resolved_name(netdata_socket_plot_t *ptr, char *hostname
857
858 char dimname[CONFIG_MAX_NAME];
859 int size;
552 - char *protocol = (ptr->sock.protocol == IPPROTO_UDP) ? "UDP" : "TCP";
860 + char *protocol;
861 + if (ptr->sock.protocol == IPPROTO_UDP) {
862 + protocol = "UDP";
863 + } else if (ptr->sock.protocol == IPPROTO_TCP) {
864 + protocol = "TCP";
865 + } else {
866 + protocol = "ALL";
867 + }
868 +
869 if (is_outbound)
870 size = build_outbound_dimension_name(dimname, hostname, service_name, protocol, ptr->family);
871 else
@@ -562,6 +878,9 @@ static inline void fill_resolved_name(netdata_socket_plot_t *ptr, char *hostname
878
879 strcpy(&dimname[size], "recv");
880 ptr->dimension_recv = strdupz(dimname);
881 +
882 + dimname[size - 1] = '\0';
883 + ptr->dimension_retransmit = strdupz(dimname);
884 }
885 }
886
@@ -572,11 +891,10 @@ static inline void fill_resolved_name(netdata_socket_plot_t *ptr, char *hostname
891 *
892 * @param ptr a pointer to the structure where the values are stored.
893 * @param is_outbound is a outbound ptr value?
575 - * @param is_last is this the last value possible?
894 *
895 * @return It returns 1 if the name is valid and 0 otherwise.
896 */
579 -int fill_names(netdata_socket_plot_t *ptr, int is_outbound, uint32_t is_last)
897 +int fill_names(netdata_socket_plot_t *ptr, int is_outbound)
898 {
899 char hostname[NI_MAXHOST], service_name[NI_MAXSERV];
900 if (ptr->resolved)
@@ -584,21 +902,12 @@ int fill_names(netdata_socket_plot_t *ptr, int is_outbound, uint32_t is_last)
902
903 int ret;
904 static int resolve_name = -1;
905 + static int resolve_service = -1;
906 if (resolve_name == -1)
588 - resolve_name = network_viewer_opt.name_resolution_enabled;
589 -
590 - if (is_last) {
591 - char *other = { "Other" };
592 - // We are also copying the NULL bytes to avoid warnings in new compilers
593 - strncpy(hostname, other, 6);
594 - strncpy(service_name, other, 6);
595 -
596 - ptr->family = AF_INET;
907 + resolve_name = network_viewer_opt.hostname_resolution_enabled;
908
598 - fill_resolved_name(ptr, hostname, 10 + NETDATA_DOTS_PROTOCOL_COMBINED_LENGTH, service_name, is_outbound);
599 - ret = 1;
600 - goto laststep;
601 - }
909 + if (resolve_service == -1)
910 + resolve_service = network_viewer_opt.service_resolution_enabled;
911
912 netdata_socket_idx_t *idx = &ptr->index;
913
@@ -619,6 +928,11 @@ int fill_names(netdata_socket_plot_t *ptr, int is_outbound, uint32_t is_last)
928
929 ret = (!resolve_name)?-1:getnameinfo((struct sockaddr *)&myaddr, sizeof(myaddr), hostname,
930 sizeof(hostname), service_name, sizeof(service_name), NI_NAMEREQD);
931 +
932 + if (!ret && !resolve_service) {
933 + snprintf(service_name, sizeof(service_name), "%u", ntohs(myaddr.sin_port));
934 + }
935 +
936 if (ret) {
937 // I cannot resolve the name, I will use the IP
938 if (!inet_ntop(AF_INET, &myaddr.sin_addr.s_addr, hostname, NI_MAXHOST)) {
@@ -643,12 +957,19 @@ int fill_names(netdata_socket_plot_t *ptr, int is_outbound, uint32_t is_last)
957
958 ret = (!resolve_name)?-1:getnameinfo((struct sockaddr *)&myaddr6, sizeof(myaddr6), hostname,
959 sizeof(hostname), service_name, sizeof(service_name), NI_NAMEREQD);
960 +
961 + if (!ret && !resolve_service) {
962 + snprintf(service_name, sizeof(service_name), "%u", ntohs(myaddr6.sin6_port));
963 + }
964 +
965 if (ret) {
966 // I cannot resolve the name, I will use the IP
967 if (!inet_ntop(AF_INET6, myaddr6.sin6_addr.s6_addr, hostname, NI_MAXHOST)) {
968 strncpy(hostname, errname, 13);
969 }
970 +
971 snprintf(service_name, sizeof(service_name), "%u", ntohs(myaddr6.sin6_port));
972 +
973 ret = 1;
974 }
975 }
@@ -657,8 +978,6 @@ int fill_names(netdata_socket_plot_t *ptr, int is_outbound, uint32_t is_last)
978 strlen(hostname) + strlen(service_name)+ NETDATA_DOTS_PROTOCOL_COMBINED_LENGTH,
979 service_name, is_outbound);
980
660 -laststep:
661 -
981 if (resolve_name && !ret)
982 ret = hostname_matches_pattern(hostname);
983
@@ -667,6 +986,35 @@ laststep:
986 return ret;
987 }
988
989 +/**
990 + * Fill last Network Viewer Dimension
991 + *
992 + * Fill the unique dimension that is always plotted.
993 + *
994 + * @param ptr the pointer for the last dimension
995 + * @param is_outbound is this an inbound structure?
996 + */
997 +static void fill_last_nv_dimension(netdata_socket_plot_t *ptr, int is_outbound)
998 +{
999 + char hostname[NI_MAXHOST], service_name[NI_MAXSERV];
1000 + char *other = { "other" };
1001 + // We are also copying the NULL bytes to avoid warnings in new compilers
1002 + strncpy(hostname, other, 6);
1003 + strncpy(service_name, other, 6);
1004 +
1005 + ptr->family = AF_INET;
1006 + ptr->sock.protocol = 255;
1007 + ptr->flags = (!is_outbound)?NETDATA_INBOUND_DIRECTION:NETDATA_OUTBOUND_DIRECTION;
1008 +
1009 + fill_resolved_name(ptr, hostname, 10 + NETDATA_DOTS_PROTOCOL_COMBINED_LENGTH, service_name, is_outbound);
1010 +
1011 +#ifdef NETDATA_INTERNAL_CHECKS
1012 + info("Last %s dimension added: ID = %u, IP = OTHER, NAME = %s, DIM1 = %s, DIM2 = %s, DIM3 = %s",
1013 + (is_outbound)?"outbound":"inbound", network_viewer_opt.max_dim - 1, ptr->resolved_name,
1014 + ptr->dimension_recv, ptr->dimension_sent, ptr->dimension_retransmit);
1015 +#endif
1016 +}
1017 +
1018 /**
1019 * Update Socket Data
1020 *
@@ -677,10 +1025,14 @@ laststep:
1025 */
1026 static inline void update_socket_data(netdata_socket_t *sock, netdata_socket_t *lvalues)
1027 {
680 - sock->recv_packets = lvalues->recv_packets;
681 - sock->sent_packets = lvalues->sent_packets;
682 - sock->recv_bytes = lvalues->recv_bytes;
683 - sock->sent_bytes = lvalues->sent_bytes;
1028 + sock->recv_packets += lvalues->recv_packets;
1029 + sock->sent_packets += lvalues->sent_packets;
1030 + sock->recv_bytes += lvalues->recv_bytes;
1031 + sock->sent_bytes += lvalues->sent_bytes;
1032 + sock->retransmit += lvalues->retransmit;
1033 +
1034 + if (lvalues->ct > sock->ct)
1035 + sock->ct = lvalues->ct;
1036 }
1037
1038 /**
@@ -692,17 +1044,21 @@ static inline void update_socket_data(netdata_socket_t *sock, netdata_socket_t *
1044 * @param lvalues Values read from socket ring.
1045 * @param lindex the index information, the real socket.
1046 * @param family the family associated to the socket
1047 + * @param flags the connection flags
1048 */
1049 static void store_socket_inside_avl(netdata_vector_plot_t *out, netdata_socket_t *lvalues,
697 - netdata_socket_idx_t *lindex, int family)
1050 + netdata_socket_idx_t *lindex, int family, uint32_t flags)
1051 {
1052 netdata_socket_plot_t test, *ret ;
1053
701 - memcpy(&test.index, lindex, sizeof(*lindex));
1054 + memcpy(&test.index, lindex, sizeof(netdata_socket_idx_t));
1055 + test.flags = flags;
1056
1057 ret = (netdata_socket_plot_t *) avl_search_lock(&out->tree, (avl *)&test);
1058 if (ret) {
705 - update_socket_data(&ret->sock, lvalues);
1059 + if (lvalues->ct > ret->plot.last_time) {
1060 + update_socket_data(&ret->sock, lvalues);
1061 + }
1062 } else {
1063 uint32_t curr = out->next;
1064 uint32_t last = out->last;
@@ -711,36 +1067,30 @@ static void store_socket_inside_avl(netdata_vector_plot_t *out, netdata_socket_t
1067
1068 int resolved;
1069 if (curr == last) {
714 - if (!w->resolved) {
715 - resolved = fill_names(w, out != (netdata_vector_plot_t *)&inbound_vectors, 1);
716 - UNUSED(resolved);
717 -#ifdef NETDATA_INTERNAL_CHECKS
718 - info("Last %s dimension added: ID = %u, IP = OTHER, NAME = %s, DIM1 = %s, DIM2 = %s",
719 - (out == &inbound_vectors)?"inbound":"outbound", curr, w->resolved_name,
720 - w->dimension_recv, w->dimension_sent);
721 -#endif
1070 + if (lvalues->ct > w->plot.last_time) {
1071 + update_socket_data(&w->sock, lvalues);
1072 }
723 -
724 - update_socket_data(&w->sock, lvalues);
1073 return;
1074 } else {
727 - memcpy(&w->sock, lvalues, sizeof(*lvalues));
728 - memcpy(&w->index, lindex, sizeof(*lindex));
1075 + memcpy(&w->sock, lvalues, sizeof(netdata_socket_t));
1076 + memcpy(&w->index, lindex, sizeof(netdata_socket_idx_t));
1077 w->family = family;
1078
731 - resolved = fill_names(w, out != (netdata_vector_plot_t *)&inbound_vectors, 0);
1079 + resolved = fill_names(w, out != (netdata_vector_plot_t *)&inbound_vectors);
1080 }
1081
1082 if (!resolved) {
1083 freez(w->resolved_name);
1084 freez(w->dimension_sent);
1085 freez(w->dimension_recv);
1086 + freez(w->dimension_retransmit);
1087
1088 memset(w, 0, sizeof(netdata_socket_plot_t));
1089
1090 return;
1091 }
1092
1093 + w->flags = flags;
1094 netdata_socket_plot_t *check ;
1095 check = (netdata_socket_plot_t *) avl_insert_lock(&out->tree, (avl *)w);
1096 if (check != w)
@@ -749,10 +1099,9 @@ static void store_socket_inside_avl(netdata_vector_plot_t *out, netdata_socket_t
1099 #ifdef NETDATA_INTERNAL_CHECKS
1100 char iptext[INET6_ADDRSTRLEN];
1101 if (inet_ntop(family, &w->index.daddr.addr8, iptext, sizeof(iptext)))
752 - info("New %s dimension added: ID = %u, IP = %s, NAME = %s, DIM1 = %s, DIM2 = %s, SENT = %lu(%lu), RECV = %lu(%lu)",
1102 + info("New %s dimension added: ID = %u, IP = %s, NAME = %s, DIM1 = %s, DIM2 = %s, DIM3 = %s",
1103 (out == &inbound_vectors)?"inbound":"outbound", curr, iptext, w->resolved_name,
754 - w->dimension_recv, w->dimension_sent, w->sock.sent_bytes, w->sock.sent_packets,
755 - w->sock.recv_bytes, w->sock.recv_packets);
1104 + w->dimension_recv, w->dimension_sent, w->dimension_retransmit);
1105 #endif
1106 curr++;
1107 if (curr > last)
@@ -766,32 +1115,50 @@ static void store_socket_inside_avl(netdata_vector_plot_t *out, netdata_socket_t
1115 *
1116 * Compare input values with local address to select table to store.
1117 *
769 - * @param cmp index read from hash table.
1118 + * @param direction store inbound and outbound direction.
1119 + * @param cmp index read from hash table.
1120 + * @param proto the protocol read.
1121 *
1122 * @return It returns the structure with address to compare.
1123 */
773 -netdata_vector_plot_t * select_vector_to_store(netdata_socket_idx_t *cmp)
1124 +netdata_vector_plot_t * select_vector_to_store(uint32_t *direction, netdata_socket_idx_t *cmp, uint8_t proto)
1125 {
775 - if (!listen_ports)
1126 + if (!listen_ports) {
1127 + *direction = NETDATA_OUTBOUND_DIRECTION;
1128 return &outbound_vectors;
1129 + }
1130
1131 ebpf_network_viewer_port_list_t *move_ports = listen_ports;
1132 while (move_ports) {
780 - if (move_ports->first == cmp->sport) {
1133 + if (move_ports->protocol == proto && move_ports->first == cmp->sport) {
1134 + *direction = NETDATA_INBOUND_DIRECTION;
1135 return &inbound_vectors;
1136 }
1137
1138 move_ports = move_ports->next;
1139 }
1140
1141 + *direction = NETDATA_OUTBOUND_DIRECTION;
1142 return &outbound_vectors;
1143 }
1144
1145 +/**
1146 + * Hash accumulator
1147 + *
1148 + * @param values the values used to calculate the data.
1149 + * @param key the key to store data.
1150 + * @param removesock check if this socket must be removed .
1151 + * @param family the connection family
1152 + * @param end the values size.
1153 + */
1154 static void hash_accumulator(netdata_socket_t *values, netdata_socket_idx_t *key, int *removesock, int family, int end)
1155 {
1156 uint64_t bsent = 0, brecv = 0, psent = 0, precv = 0;
1157 + uint16_t retransmit = 0;
1158 int i;
1159 uint8_t protocol = values[0].protocol;
1160 + uint64_t ct = values[0].ct;
1161 + error("KILLME_FIRST %u (%u)", protocol, ntohs(key->sport));
1162 for (i = 1; i < end; i++) {
1163 netdata_socket_t *w = &values[i];
1164
@@ -799,23 +1166,31 @@ static void hash_accumulator(netdata_socket_t *values, netdata_socket_idx_t *key
1166 psent += w->sent_packets;
1167 brecv += w->recv_bytes;
1168 bsent += w->sent_bytes;
1169 + retransmit += w->retransmit;
1170
1171 if (!protocol)
1172 protocol = w->protocol;
1173
1174 + if (w->ct > ct)
1175 + ct = w->ct;
1176 +
1177 *removesock += (int)w->removeme;
1178 }
1179
1180 + error("KILLME_LAST %u (%u)", protocol, ntohs(key->sport));
1181 values[0].recv_packets += precv;
1182 values[0].sent_packets += psent;
1183 values[0].recv_bytes += brecv;
1184 values[0].sent_bytes += bsent;
813 - values[0].removeme += *removesock;
814 - values[0].protocol = protocol;
1185 + values[0].retransmit += retransmit;
1186 + values[0].removeme += (uint8_t)*removesock;
1187 + values[0].protocol = (!protocol)?IPPROTO_TCP:protocol;
1188 + values[0].ct = ct;
1189
1190 if (is_socket_allowed(key, family)) {
817 - netdata_vector_plot_t *table = select_vector_to_store(key);
818 - store_socket_inside_avl(table, values, key, family);
1191 + uint32_t dir;
1192 + netdata_vector_plot_t *table = select_vector_to_store(&dir, key, protocol);
1193 + store_socket_inside_avl(table, &values[0], key, family, dir);
1194 }
1195 }
1196
@@ -829,17 +1204,26 @@ static void hash_accumulator(netdata_socket_t *values, netdata_socket_idx_t *key
1204 *
1205 * @return it returns 0 on success and -1 otherwise.
1206 */
832 -static void read_socket_hash_table(int fd, int family)
1207 +static void read_socket_hash_table(int fd, int family, int network_connection)
1208 {
1209 + if (wait_to_plot)
1210 + return;
1211 +
1212 netdata_socket_idx_t key = {};
1213 netdata_socket_idx_t next_key;
1214 netdata_socket_idx_t removeme;
1215 int removesock = 0;
1216
1217 netdata_socket_t *values = socket_values;
1218 + size_t length = ebpf_nprocs*sizeof(netdata_socket_t);
1219 int test, end = (running_on_kernel < NETDATA_KERNEL_V4_15) ? 1 : ebpf_nprocs;
1220
1221 while (bpf_map_get_next_key(fd, &key, &next_key) == 0) {
1222 + // We need to reset the values when we are working on kernel 4.15 or newer, because kernel does not create
1223 + // values for specific processor unless it is used to store data. As result of this behavior one the next socket
1224 + // can have values from the previous one.
1225 + memset(values, 0, length);
1226 + error("KILLME_READ %u %u %u %u (%u)", values[0].protocol, values[1].protocol, values[2].protocol, values[3].protocol, ntohs(key.sport));
1227 test = bpf_map_lookup_elem(fd, &key, values);
1228 if (test < 0) {
1229 key = next_key;
@@ -849,8 +1233,10 @@ static void read_socket_hash_table(int fd, int family)
1233 if (removesock)
1234 bpf_map_delete_elem(fd, &removeme);
1235
852 - removesock = 0;
853 - hash_accumulator(values, &key, &removesock, family, end);
1236 + if (network_connection) {
1237 + removesock = 0;
1238 + hash_accumulator(values, &key, &removesock, family, end);
1239 + }
1240
1241 if (removesock)
1242 removeme = key;
@@ -866,8 +1252,10 @@ static void read_socket_hash_table(int fd, int family)
1252 return;
1253 }
1254
869 - removesock = 0;
870 - hash_accumulator(values, &next_key, &removesock, family, end);
1255 + if (network_connection) {
1256 + removesock = 0;
1257 + hash_accumulator(values, &next_key, &removesock, family, end);
1258 + }
1259
1260 if (removesock)
1261 bpf_map_delete_elem(fd, &next_key);
@@ -879,14 +1267,15 @@ static void read_socket_hash_table(int fd, int family)
1267 * Update link list when it is necessary.
1268 *
1269 * @param value the ports we are listen to.
1270 + * @param proto the protocol used with port connection.
1271 */
883 -void update_listen_table(uint16_t value)
1272 +void update_listen_table(uint16_t value, uint8_t proto)
1273 {
1274 ebpf_network_viewer_port_list_t *w;
1275 if (likely(listen_ports)) {
1276 ebpf_network_viewer_port_list_t *move = listen_ports, *store = listen_ports;
1277 while (move) {
889 - if (move->first == value)
1278 + if (move->protocol == proto && move->first == value)
1279 return;
1280
1281 store = move;
@@ -895,10 +1284,12 @@ void update_listen_table(uint16_t value)
1284
1285 w = callocz(1, sizeof(ebpf_network_viewer_port_list_t));
1286 w->first = value;
1287 + w->protocol = proto;
1288 store->next = w;
1289 } else {
1290 w = callocz(1, sizeof(ebpf_network_viewer_port_list_t));
1291 w->first = value;
1292 + w->protocol = proto;
1293
1294 listen_ports = w;
1295 }
@@ -927,13 +1318,16 @@ static void read_listen_table()
1318 continue;
1319 }
1320
930 - update_listen_table(htons(key));
1321 + // The correct protocol must come from kernel
1322 + update_listen_table(htons(key), (key == 53)?IPPROTO_UDP:IPPROTO_TCP);
1323
1324 key = next_key;
1325 }
1326
935 - if (next_key)
936 - update_listen_table(htons(next_key));
1327 + if (next_key) {
1328 + // The correct protocol must come from kernel
1329 + update_listen_table(htons(next_key), (key == 53)?IPPROTO_UDP:IPPROTO_TCP);
1330 + }
1331 }
1332
1333 /**
@@ -948,20 +1342,24 @@ static void read_listen_table()
1342 */
1343 void *ebpf_socket_read_hash(void *ptr)
1344 {
951 - UNUSED(ptr);
1345 + ebpf_module_t *em = (ebpf_module_t *)ptr;
1346
1347 heartbeat_t hb;
1348 heartbeat_init(&hb);
1349 usec_t step = NETDATA_SOCKET_READ_SLEEP_MS;
1350 int fd_ipv4 = map_fd[NETDATA_SOCKET_IPV4_HASH_TABLE];
1351 int fd_ipv6 = map_fd[NETDATA_SOCKET_IPV6_HASH_TABLE];
1352 + int network_connection = em->optional;
1353 while (!close_ebpf_plugin) {
1354 usec_t dt = heartbeat_next(&hb, step);
1355 (void)dt;
1356
1357 + pthread_mutex_lock(&nv_mutex);
1358 read_listen_table();
963 - read_socket_hash_table(fd_ipv4, AF_INET);
964 - read_socket_hash_table(fd_ipv6, AF_INET6);
1359 + read_socket_hash_table(fd_ipv4, AF_INET, network_connection);
1360 + read_socket_hash_table(fd_ipv6, AF_INET6, network_connection);
1361 + wait_to_plot = 1;
1362 + pthread_mutex_unlock(&nv_mutex);
1363 }
1364
1365 return NULL;
@@ -1108,6 +1506,7 @@ static void socket_collector(usec_t step, ebpf_module_t *em)
1506
1507 int socket_apps_enabled = ebpf_modules[EBPF_MODULE_SOCKET_IDX].apps_charts;
1508 int socket_global_enabled = ebpf_modules[EBPF_MODULE_SOCKET_IDX].global_charts;
1509 + int network_connection = em->optional;
1510 while (!close_ebpf_plugin) {
1511 pthread_mutex_lock(&collect_data_mutex);
1512 pthread_cond_wait(&collect_data_cond_var, &collect_data_mutex);
@@ -1118,6 +1517,8 @@ static void socket_collector(usec_t step, ebpf_module_t *em)
1517 if (socket_apps_enabled)
1518 ebpf_socket_update_apps_data();
1519
1520 + calculate_nv_plot();
1521 +
1522 pthread_mutex_lock(&lock);
1523 if (socket_global_enabled)
1524 ebpf_socket_send_data(em);
@@ -1125,11 +1526,27 @@ static void socket_collector(usec_t step, ebpf_module_t *em)
1526 if (socket_apps_enabled)
1527 ebpf_socket_send_apps_data(em, apps_groups_root_target);
1528
1128 - pthread_mutex_unlock(&collect_data_mutex);
1529 + fflush(stdout);
1530 +
1531 + if (network_connection) {
1532 + // We are calling fflush many times, because when we have a lot of dimensions
1533 + // we began to have not expected outputs and Netdata closed the plugin.
1534 + pthread_mutex_lock(&nv_mutex);
1535 + ebpf_socket_create_nv_charts(&inbound_vectors);
1536 + fflush(stdout);
1537 + ebpf_socket_send_nv_data(&inbound_vectors);
1538 +
1539 + ebpf_socket_create_nv_charts(&outbound_vectors);
1540 + fflush(stdout);
1541 + ebpf_socket_send_nv_data(&outbound_vectors);
1542 + wait_to_plot = 0;
1543 + pthread_mutex_unlock(&nv_mutex);
1544
1545 + }
1546 +
1547 + pthread_mutex_unlock(&collect_data_mutex);
1548 pthread_mutex_unlock(&lock);
1549
1132 - fflush(stdout);
1550 }
1551 }
1552
@@ -1152,6 +1569,7 @@ static inline void clean_internal_socket_plot(netdata_socket_plot_t *ptr)
1569 freez(ptr->dimension_recv);
1570 freez(ptr->dimension_sent);
1571 freez(ptr->resolved_name);
1572 + freez(ptr->dimension_retransmit);
1573 }
1574
1575 /**
@@ -1266,6 +1684,8 @@ static void ebpf_socket_cleanup(void *ptr)
1684 clean_service_names(network_viewer_opt.names);
1685 clean_hostnames(network_viewer_opt.included_hostnames);
1686 clean_hostnames(network_viewer_opt.excluded_hostnames);
1687 +
1688 + pthread_mutex_destroy(&nv_mutex);
1689 }
1690
1691 /*****************************************************************
@@ -1316,6 +1736,19 @@ static void set_local_pointers(ebpf_module_t *em)
1736 }
1737 }
1738
1739 +/**
1740 + * Initialize Inbound and Outbound
1741 + *
1742 + * Initialize the common outbound and inbound sockets.
1743 + */
1744 +static void initialize_inbound_outbound()
1745 +{
1746 + inbound_vectors.last = network_viewer_opt.max_dim - 1;
1747 + outbound_vectors.last = inbound_vectors.last;
1748 + fill_last_nv_dimension(&inbound_vectors.plot[inbound_vectors.last], 0);
1749 + fill_last_nv_dimension(&outbound_vectors.plot[outbound_vectors.last], 1);
1750 +}
1751 +
1752 /*****************************************************************
1753 *
1754 * EBPF SOCKET THREAD
@@ -1338,18 +1771,20 @@ void *ebpf_socket_thread(void *ptr)
1771 avl_init_lock(&inbound_vectors.tree, compare_sockets);
1772 avl_init_lock(&outbound_vectors.tree, compare_sockets);
1773
1341 - inbound_vectors.last = network_viewer_opt.max_dim - 1;
1342 - outbound_vectors.last = inbound_vectors.last;
1343 -
1774 ebpf_module_t *em = (ebpf_module_t *)ptr;
1775 fill_ebpf_data(&socket_data);
1776
1777 if (!em->enabled)
1778 goto endsocket;
1779
1780 + if (pthread_mutex_init(&nv_mutex, NULL)) {
1781 + error("Cannot initialize local mutex");
1782 + goto endsocket;
1783 + }
1784 pthread_mutex_lock(&lock);
1785
1786 ebpf_socket_allocate_global_vectors(NETDATA_MAX_SOCKET_VECTOR);
1787 + initialize_inbound_outbound();
1788
1789 if (ebpf_update_kernel(&socket_data)) {
1790 pthread_mutex_unlock(&lock);
collectors/ebpf.plugin/ebpf_socket.h
+54 -8
@@ -15,7 +15,7 @@
15 #define NETDATA_SOCKET_GLOBAL_HASH_TABLE 4
16 #define NETDATA_SOCKET_LISTEN_TABLE 5
17
18 -#define NETDATA_SOCKET_READ_SLEEP_MS 400000
18 +#define NETDATA_SOCKET_READ_SLEEP_MS 800000ULL
19
20 typedef enum ebpf_socket_idx {
21 NETDATA_KEY_CALLS_TCP_SENDMSG,
@@ -42,6 +42,7 @@ typedef enum ebpf_socket_idx {
42 } ebpf_socket_index_t;
43
44 #define NETDATA_SOCKET_GROUP "Socket"
45 +#define NETDATA_NETWORK_CONNECTIONS_GROUP "Network connections"
46
47 // Global chart name
48 #define NETDATA_TCP_FUNCTION_COUNT "tcp_functions"
@@ -56,6 +57,13 @@ typedef enum ebpf_socket_idx {
57 #define NETDATA_NET_APPS_BANDWIDTH_SENT "bandwidth_sent"
58 #define NETDATA_NET_APPS_BANDWIDTH_RECV "bandwidth_recv"
59
60 +// Network viewer charts
61 +#define NETDATA_NV_OUTBOUND_BYTES "outbound_bytes"
62 +#define NETDATA_NV_OUTBOUND_PACKETS "outbound_packets"
63 +#define NETDATA_NV_OUTBOUND_RETRANSMIT "outbound_retransmit"
64 +#define NETDATA_NV_INBOUND_BYTES "inbound_bytes"
65 +#define NETDATA_NV_INBOUND_PACKETS "inbound_packets"
66 +
67 // Port range
68 #define NETDATA_MINIMUM_PORT_VALUE 1
69 #define NETDATA_MAXIMUM_PORT_VALUE 65535
@@ -91,6 +99,8 @@ typedef struct ebpf_network_viewer_port_list {
99
100 uint16_t cmp_first;
101 uint16_t cmp_last;
102 +
103 + uint8_t protocol;
104 struct ebpf_network_viewer_port_list *next;
105 } ebpf_network_viewer_port_list_t;
106
@@ -125,10 +135,12 @@ typedef struct ebpf_network_viewer_hostname_list {
135 struct ebpf_network_viewer_hostname_list *next;
136 } ebpf_network_viewer_hostname_list_t;
137
138 +#define NETDATA_NV_CAP_VALUE 50L
139 typedef struct ebpf_network_viewer_options {
140 uint32_t max_dim; // Store value read from 'maximum dimensions'
141
131 - uint32_t name_resolution_enabled;
142 + uint32_t hostname_resolution_enabled;
143 + uint32_t service_resolution_enabled;
144
145 ebpf_network_viewer_port_list_t *excluded_port;
146 ebpf_network_viewer_port_list_t *included_port;
@@ -158,11 +170,30 @@ typedef struct netdata_socket {
170 uint64_t first; // First timestamp
171 uint64_t ct; // Current timestamp
172 uint16_t retransmit; // It is never used with UDP
161 - uint8_t protocol; // Should this to be in the index?
173 + uint8_t protocol;
174 uint8_t removeme;
175 uint32_t reserved;
176 } netdata_socket_t __attribute__((__aligned__(8)));
177
178 +
179 +typedef struct netdata_plot_values {
180 + // Values used in the previous iteration
181 + uint64_t recv_packets;
182 + uint64_t sent_packets;
183 + uint64_t recv_bytes;
184 + uint64_t sent_bytes;
185 + uint16_t retransmit;
186 +
187 + uint64_t last_time;
188 +
189 + // Values used to plot
190 + uint64_t plot_recv_packets;
191 + uint64_t plot_sent_packets;
192 + uint64_t plot_recv_bytes;
193 + uint64_t plot_sent_bytes;
194 + uint16_t plot_retransmit;
195 +} netdata_plot_values_t;
196 +
197 /**
198 * Index used together previous structure
199 */
@@ -178,6 +209,8 @@ typedef struct netdata_socket_idx {
209 #define NETDATA_DOTS_PROTOCOL_COMBINED_LENGTH 5 // :TCP:
210 #define NETDATA_DIM_LENGTH_WITHOUT_SERVICE_PROTOCOL 979
211
212 +#define NETDATA_INBOUND_DIRECTION (uint32_t)1
213 +#define NETDATA_OUTBOUND_DIRECTION (uint32_t)2
214 /**
215 * Allocate the maximum number of structures in the beginning, this can force the collector to use more memory
216 * in the long term, on the other had it is faster.
@@ -187,26 +220,39 @@ typedef struct netdata_socket_plot {
220 avl avl;
221 netdata_socket_idx_t index;
222
190 - // Updated data
223 + // Current data
224 netdata_socket_t sock;
225
226 + // Previous values and values used to write on chart.
227 + netdata_plot_values_t plot;
228 +
229 int family; // AF_INET or AF_INET6
230 char *resolved_name; // Resolve only in the first call
231 unsigned char resolved;
232
233 char *dimension_sent;
234 char *dimension_recv;
235 + char *dimension_retransmit;
236 +
237 + uint32_t flags;
238 } netdata_socket_plot_t;
239
240 +#define NETWORK_VIEWER_CHARTS_CREATED (uint32_t)1
241 typedef struct netdata_vector_plot {
202 - netdata_socket_plot_t *plot;
242 + netdata_socket_plot_t *plot; // Vector used to plot charts
243 +
244 + avl_tree_lock tree; // AVL tree to speed up search
245 + uint32_t last; // The 'other' dimension, the last chart accepted.
246 + uint32_t next; // The next position to store in the vector.
247 + uint32_t max_plot; // Max number of elements to plot.
248 + uint32_t last_plot; // Last element plot
249
204 - avl_tree_lock tree;
205 - uint32_t last;
206 - uint32_t next;
250 + uint32_t flags; // Flags
251
252 } netdata_vector_plot_t;
253
254 extern void clean_port_structure(ebpf_network_viewer_port_list_t **clean);
255 +extern ebpf_network_viewer_port_list_t *listen_ports;
256 +extern void update_listen_table(uint16_t value, uint8_t proto);
257
258 #endif