add port service names to network viewer (#18107)
* add port service names to network viewer * use unique function names
Costa Tsaousis committed
Jul 10, 2024 at 22:33 UTC
c77e3d5b1262c76065a6326b71ca6b92ee10c14d
3 files changed
+130
-14
CMakeLists.txt
+1
@@ -1182,6 +1182,7 @@ set(SYSTEMD_JOURNAL_PLUGIN_FILES
1182
src/collectors/systemd-journal.plugin/systemd-journal-dyncfg.c
1183
src/libnetdata/maps/system-users.h
1184
src/libnetdata/maps/system-groups.h
1185
+ src/libnetdata/maps/system-services.h
1186
)
1187
1188
set(STREAMING_PLUGIN_FILES
src/collectors/network-viewer.plugin/network-viewer.c
+37
-14
@@ -2,6 +2,7 @@
2
3
#include "collectors/all.h"
4
#include "libnetdata/libnetdata.h"
5
+
6
#include "libnetdata/required_dummies.h"
7
8
static SPAWN_SERVER *spawn_srv = NULL;
@@ -24,6 +25,7 @@ static SPAWN_SERVER *spawn_srv = NULL;
25
26
#include "libnetdata/maps/local-sockets.h"
27
#include "libnetdata/maps/system-users.h"
28
+#include "libnetdata/maps/system-services.h"
29
30
#define NETWORK_CONNECTIONS_VIEWER_FUNCTION "network-connections"
31
#define NETWORK_CONNECTIONS_VIEWER_HELP "Network connections explorer"
@@ -35,6 +37,7 @@ static SPAWN_SERVER *spawn_srv = NULL;
37
netdata_mutex_t stdout_mutex = NETDATA_MUTEX_INITIALIZER;
38
static bool plugin_should_exit = false;
39
static USERNAMES_CACHE *uc;
40
+static SERVICENAMES_CACHE *sc;
41
42
ENUM_STR_MAP_DEFINE(SOCKET_DIRECTION) = {
43
{ .id = SOCKET_DIRECTION_LISTEN, .name = "listen" },
@@ -153,18 +156,7 @@ static void local_socket_to_json_array(struct sockets_stats *st, LOCAL_SOCKET *n
156
string_freez(u);
157
}
158
156
- if(!aggregated) {
157
- buffer_json_add_array_item_string(wb, local_address);
158
- buffer_json_add_array_item_uint64(wb, n->local.port);
159
- }
160
- buffer_json_add_array_item_string(wb, n->network_viewer.aggregated_key.local_address_space);
161
-
162
- if(!aggregated) {
163
- buffer_json_add_array_item_string(wb, remote_address);
164
- buffer_json_add_array_item_uint64(wb, n->remote.port);
165
- }
166
- buffer_json_add_array_item_string(wb, n->network_viewer.aggregated_key.remote_address_space);
167
-
159
+ struct socket_endpoint *server_endpoint;
160
const char *server_address;
161
const char *client_address_space;
162
const char *server_address_space;
@@ -175,6 +167,7 @@ static void local_socket_to_json_array(struct sockets_stats *st, LOCAL_SOCKET *n
167
server_address = local_address;
168
server_address_space = n->network_viewer.aggregated_key.local_address_space;
169
client_address_space = n->network_viewer.aggregated_key.remote_address_space;
170
+ server_endpoint = &n->local;
171
break;
172
173
case SOCKET_DIRECTION_OUTBOUND:
@@ -182,15 +175,36 @@ static void local_socket_to_json_array(struct sockets_stats *st, LOCAL_SOCKET *n
175
server_address = remote_address;
176
server_address_space = n->network_viewer.aggregated_key.remote_address_space;
177
client_address_space = n->network_viewer.aggregated_key.local_address_space;
178
+ server_endpoint = &n->remote;
179
break;
180
181
case SOCKET_DIRECTION_NONE:
182
server_address = NULL;
183
client_address_space = NULL;
184
server_address_space = NULL;
185
+ server_endpoint = NULL;
186
break;
187
}
188
189
+ if(server_endpoint) {
190
+ STRING *serv = system_servicenames_cache_lookup(sc, server_endpoint->port, server_endpoint->protocol);
191
+ buffer_json_add_array_item_string(wb, string2str(serv));
192
+ }
193
+ else
194
+ buffer_json_add_array_item_string(wb, "[unknown]");
195
+
196
+ if(!aggregated) {
197
+ buffer_json_add_array_item_string(wb, local_address);
198
+ buffer_json_add_array_item_uint64(wb, n->local.port);
199
+ }
200
+ buffer_json_add_array_item_string(wb, n->network_viewer.aggregated_key.local_address_space);
201
+
202
+ if(!aggregated) {
203
+ buffer_json_add_array_item_string(wb, remote_address);
204
+ buffer_json_add_array_item_uint64(wb, n->remote.port);
205
+ }
206
+ buffer_json_add_array_item_string(wb, n->network_viewer.aggregated_key.remote_address_space);
207
+
208
if(aggregated) {
209
buffer_json_add_array_item_string(wb, server_address);
210
}
@@ -618,6 +632,14 @@ void network_viewer_function(const char *transaction, char *function __maybe_unu
632
RRDF_FIELD_OPTS_VISIBLE,
633
NULL);
634
635
+ // Portname
636
+ buffer_rrdf_table_add_field(wb, field_id++, "Portname", "Server Port Name",
637
+ RRDF_FIELD_TYPE_STRING, RRDF_FIELD_VISUAL_VALUE, RRDF_FIELD_TRANSFORM_NONE,
638
+ 0, NULL, NAN, RRDF_FIELD_SORT_ASCENDING, NULL,
639
+ RRDF_FIELD_SUMMARY_COUNT, RRDF_FIELD_FILTER_MULTISELECT,
640
+ RRDF_FIELD_OPTS_VISIBLE,
641
+ NULL);
642
+
643
if(!aggregated) {
644
// Local Address
645
buffer_rrdf_table_add_field(wb, field_id++, "LocalIP", "Local IP Address",
@@ -938,14 +960,15 @@ int main(int argc __maybe_unused, char **argv __maybe_unused) {
960
netdata_configured_host_prefix = getenv("NETDATA_HOST_PREFIX");
961
if(verify_netdata_host_prefix(true) == -1) exit(1);
962
941
- uc = system_usernames_cache_init();
942
-
963
spawn_srv = spawn_server_create(SPAWN_SERVER_OPTION_CALLBACK, "setns", local_sockets_spawn_server_callback, argc, (const char **)argv);
964
if(spawn_srv == NULL) {
965
fprintf(stderr, "Cannot create spawn server.\n");
966
exit(1);
967
}
968
969
+ uc = system_usernames_cache_init();
970
+ sc = system_servicenames_cache_init();
971
+
972
// ----------------------------------------------------------------------------------------------------------------
973
974
if(argc == 2 && strcmp(argv[1], "debug") == 0) {
src/libnetdata/maps/system-services.h
new
+92
@@ -0,0 +1,92 @@
1
+// SPDX-License-Identifier: GPL-3.0-or-later
2
+
3
+#ifndef NETDATA_SYSTEM_SERVICES_H
4
+#define NETDATA_SYSTEM_SERVICES_H
5
+
6
+#include "libnetdata/libnetdata.h"
7
+#include <netdb.h>
8
+
9
+// --------------------------------------------------------------------------------------------------------------------
10
+// hashtable for caching port and protocol to service name mappings
11
+// key is the combination of protocol and port packed into a uint64_t, value is service name (STRING)
12
+
13
+#define SIMPLE_HASHTABLE_VALUE_TYPE STRING
14
+#define SIMPLE_HASHTABLE_NAME _SERVICENAMES_CACHE
15
+#include "libnetdata/simple_hashtable.h"
16
+
17
+typedef struct servicenames_cache {
18
+ SPINLOCK spinlock;
19
+ SIMPLE_HASHTABLE_SERVICENAMES_CACHE ht;
20
+} SERVICENAMES_CACHE;
21
+
22
+static inline uint64_t system_servicenames_key(uint16_t port, uint16_t ipproto) {
23
+ return ((uint64_t)ipproto << 16) | (uint64_t)port;
24
+}
25
+
26
+static inline const char *system_servicenames_ipproto2str(uint16_t ipproto) {
27
+ return (ipproto == IPPROTO_TCP) ? "tcp" : "udp";
28
+}
29
+
30
+static inline const char *static_portnames(uint16_t port, uint16_t ipproto) {
31
+ if(port == 19999 && ipproto == IPPROTO_TCP)
32
+ return "netdata";
33
+
34
+ if(port == 8125)
35
+ return "statsd";
36
+
37
+ return NULL;
38
+}
39
+
40
+static inline STRING *system_servicenames_cache_lookup(SERVICENAMES_CACHE *sc, uint16_t port, uint16_t ipproto) {
41
+ uint64_t key = system_servicenames_key(port, ipproto);
42
+ spinlock_lock(&sc->spinlock);
43
+
44
+ SIMPLE_HASHTABLE_SLOT_SERVICENAMES_CACHE *sl = simple_hashtable_get_slot_SERVICENAMES_CACHE(&sc->ht, key, &key, true);
45
+ STRING *s = SIMPLE_HASHTABLE_SLOT_DATA(sl);
46
+ if (!s) {
47
+ const char *st = static_portnames(port, ipproto);
48
+ if(st) {
49
+ s = string_strdupz(st);
50
+ }
51
+ else {
52
+ struct servent *se = getservbyport(htons(port), system_servicenames_ipproto2str(ipproto));
53
+
54
+ if (!se || !se->s_name) {
55
+ char name[50];
56
+ snprintfz(name, sizeof(name), "%u/%s", port, system_servicenames_ipproto2str(ipproto));
57
+ s = string_strdupz(name);
58
+ }
59
+ else
60
+ s = string_strdupz(se->s_name);
61
+ }
62
+
63
+ simple_hashtable_set_slot_SERVICENAMES_CACHE(&sc->ht, sl, key, s);
64
+ }
65
+
66
+ s = string_dup(s);
67
+ spinlock_unlock(&sc->spinlock);
68
+ return s;
69
+}
70
+
71
+static inline SERVICENAMES_CACHE *system_servicenames_cache_init(void) {
72
+ SERVICENAMES_CACHE *sc = callocz(1, sizeof(*sc));
73
+ spinlock_init(&sc->spinlock);
74
+ simple_hashtable_init_SERVICENAMES_CACHE(&sc->ht, 100);
75
+ return sc;
76
+}
77
+
78
+static inline void system_servicenames_cache_destroy(SERVICENAMES_CACHE *sc) {
79
+ spinlock_lock(&sc->spinlock);
80
+
81
+ for (SIMPLE_HASHTABLE_SLOT_SERVICENAMES_CACHE *sl = simple_hashtable_first_read_only_SERVICENAMES_CACHE(&sc->ht);
82
+ sl;
83
+ sl = simple_hashtable_next_read_only_SERVICENAMES_CACHE(&sc->ht, sl)) {
84
+ STRING *s = SIMPLE_HASHTABLE_SLOT_DATA(sl);
85
+ string_freez(s);
86
+ }
87
+
88
+ simple_hashtable_destroy_SERVICENAMES_CACHE(&sc->ht);
89
+ freez(sc);
90
+}
91
+
92
+#endif //NETDATA_SYSTEM_SERVICES_H