network-viewer: stabilize topology around self listeners (#22253)
network-viewer: fix self/listener topology projection
Costa Tsaousis committed
Apr 23, 2026 at 07:57 UTC
e065eda50bfe2e545e8ade975f5f8de808c89ae2
1 file changed
+29
-3
src/collectors/network-viewer.plugin/network-viewer.c
+29
-3
@@ -1176,6 +1176,7 @@ static void local_sockets_cb_to_topology(LS_STATE *ls, const LOCAL_SOCKET *n, vo
1176
return;
1177
1178
NV_TOPOLOGY_CONTEXT *ctx = data;
1179
+ bool hidden_listen_socket = (n->direction == SOCKET_DIRECTION_LISTEN && !ctx->options.sockets_listening);
1180
ctx->sockets_total++;
1181
1182
char local_ip[INET6_ADDRSTRLEN] = "";
@@ -1225,6 +1226,19 @@ static void local_sockets_cb_to_topology(LS_STATE *ls, const LOCAL_SOCKET *n, vo
1226
local_actor->sockets++;
1227
}
1228
1229
+ if(hidden_listen_socket) {
1230
+ NV_PROCESS_ACTOR hidden_owner = {
1231
+ .pid = n->pid,
1232
+ .ppid = n->ppid,
1233
+ .uid = n->uid,
1234
+ .net_ns_inode = n->net_ns_inode,
1235
+ };
1236
+ snprintf(hidden_owner.process, sizeof(hidden_owner.process), "%s", process_name);
1237
+ topology_register_endpoint_owner(ctx, n->net_ns_inode, n->local.protocol, local_ip, n->local.port, &hidden_owner, true);
1238
+ ctx->skipped_sockets++;
1239
+ return;
1240
+ }
1241
+
1242
char process_key[NV_TOPOLOGY_KEY_MAX];
1243
if(ctx->options.processes_by_pid) {
1244
snprintf(process_key, sizeof(process_key), "pid=%d|uid=%u|ns=%llu",
@@ -1290,7 +1304,8 @@ static void local_sockets_cb_to_topology(LS_STATE *ls, const LOCAL_SOCKET *n, vo
1304
}
1305
1306
bool remote_is_self = topology_ip_belongs_to_self(ctx, remote_ip, remote_address_space);
1293
- bool create_endpoint_actor = (!remote_is_self || n->direction == SOCKET_DIRECTION_LISTEN);
1307
+ bool self_owned_listen_socket = (n->direction == SOCKET_DIRECTION_LISTEN && remote_is_self);
1308
+ bool create_endpoint_actor = !remote_is_self;
1309
if(create_endpoint_actor) {
1310
char endpoint_actor_key[NV_TOPOLOGY_KEY_MAX];
1311
topology_actor_id_for_remote_endpoint(ctx, remote_ip, remote_address_space, endpoint_actor_key, sizeof(endpoint_actor_key));
@@ -1304,14 +1319,23 @@ static void local_sockets_cb_to_topology(LS_STATE *ls, const LOCAL_SOCKET *n, vo
1319
ra->sockets++;
1320
}
1321
1322
+ if(self_owned_listen_socket) {
1323
+ ctx->skipped_sockets++;
1324
+ return;
1325
+ }
1326
+
1327
const struct socket_endpoint *server_endpoint = NULL;
1328
uint16_t endpoint_port = n->remote.port;
1329
switch(n->direction) {
1330
case SOCKET_DIRECTION_LISTEN:
1331
+ server_endpoint = &n->local;
1332
+ endpoint_port = n->local.port;
1333
+ break;
1334
+
1335
case SOCKET_DIRECTION_INBOUND:
1336
case SOCKET_DIRECTION_LOCAL_INBOUND:
1337
server_endpoint = &n->local;
1314
- endpoint_port = n->local.port;
1338
+ endpoint_port = n->remote.port;
1339
break;
1340
1341
case SOCKET_DIRECTION_OUTBOUND:
@@ -1499,7 +1523,9 @@ static bool topology_prepare_context(NV_TOPOLOGY_CONTEXT *ctx, usec_t now_ut, co
1523
1524
LS_STATE ls = {
1525
.config = {
1502
- .listening = ctx->options.sockets_listening,
1526
+ // Always collect listeners so inbound/outbound socket classification
1527
+ // remains stable across topology socket filters.
1528
+ .listening = true,
1529
.local = ctx->options.sockets_local,
1530
.inbound = ctx->options.sockets_inbound,
1531
.outbound = ctx->options.sockets_outbound,