28
29
#define NETWORK_CONNECTIONS_VIEWER_FUNCTION "network-connections"
30
#define NETWORK_CONNECTIONS_VIEWER_HELP "Shows active network connections with protocol details, states, addresses, ports, and performance metrics."
31
+#define NETWORK_TOPOLOGY_VIEWER_FUNCTION "topology:network-connections"
32
+#define NETWORK_TOPOLOGY_VIEWER_HELP "Shows live network-connections topology with self/process/endpoint actors and ownership/socket links."
33
+#define NETWORK_VIEWER_RESPONSE_UPDATE_EVERY 5
34
+// Keep in sync with the topology schema contract used across topology producers.
35
+#define NETWORK_TOPOLOGY_SCHEMA_VERSION "2.0"
36
+#define NETWORK_TOPOLOGY_SOURCE "network-connections"
37
+#define NETWORK_TOPOLOGY_LAYER "l7"
38
+#define NV_TOPOLOGY_MAX_PPID_DEPTH 64
39
+
40
+#define NV_TOPOLOGY_USERNAME_MAX 128
41
+#define NV_TOPOLOGY_CMDLINE_MAX 512
42
+#define NV_TOPOLOGY_KEY_MAX 1024
43
+
44
+typedef struct {
45
+ pid_t pid;
46
+ pid_t ppid;
47
+ uid_t uid;
48
+ uint64_t net_ns_inode;
49
+ uint64_t sockets;
50
+ char process[TASK_COMM_LEN + 1];
51
+ char username[NV_TOPOLOGY_USERNAME_MAX];
52
+ char namespace_type[16];
53
+ char local_ip[INET6_ADDRSTRLEN];
54
+ char local_address_space[16];
55
+ char cmdline[NV_TOPOLOGY_CMDLINE_MAX];
56
+} NV_PROCESS_ACTOR;
57
+
58
+typedef struct {
59
+ uint64_t sockets;
60
+ char ip[INET6_ADDRSTRLEN];
61
+ char address_space[16];
62
+} NV_REMOTE_ACTOR;
63
+
64
+typedef struct {
65
+ uint64_t sockets;
66
+ char ip[INET6_ADDRSTRLEN];
67
+ char address_space[16];
68
+} NV_LOCAL_IP;
69
+
70
+typedef struct {
71
+ uint64_t pid;
72
+ uint64_t ppid;
73
+ uint64_t uid;
74
+ uint64_t net_ns_inode;
75
+ char process[TASK_COMM_LEN + 1];
76
+} NV_ENDPOINT_OWNER;
77
+
78
+typedef struct {
79
+ uint64_t pid;
80
+ uint64_t ppid;
81
+ uint64_t uid;
82
+ uint64_t net_ns_inode;
83
+ uint64_t sockets;
84
+ uint64_t retransmissions;
85
+ uint32_t max_rtt_usec;
86
+ uint32_t max_rcv_rtt_usec;
87
+ uint16_t local_port;
88
+ uint16_t remote_port;
89
+ uint16_t peer_port;
90
+ uint16_t protocol_id;
91
+ uint8_t direction_id;
92
+ char process[TASK_COMM_LEN + 1];
93
+ char username[NV_TOPOLOGY_USERNAME_MAX];
94
+ char namespace_type[16];
95
+ char protocol[8];
96
+ char protocol_family[8];
97
+ char direction[16];
98
+ char state[32];
99
+ char local_ip[INET6_ADDRSTRLEN];
100
+ char remote_ip[INET6_ADDRSTRLEN];
101
+ char peer_ip[INET6_ADDRSTRLEN];
102
+ char local_address_space[16];
103
+ char remote_address_space[16];
104
+ char port_name[64];
105
+ char cmdline[NV_TOPOLOGY_CMDLINE_MAX];
106
+} NV_TOPOLOGY_LINK;
107
+
108
+typedef struct {
109
+ bool info_only;
110
+ bool processes_by_pid;
111
+ bool sockets_listening;
112
+ bool sockets_local;
113
+ bool sockets_inbound;
114
+ bool sockets_outbound;
115
+ bool protocols_ipv4_tcp;
116
+ bool protocols_ipv6_tcp;
117
+ bool protocols_ipv4_udp;
118
+ bool protocols_ipv6_udp;
119
+} NV_TOPOLOGY_OPTIONS;
120
+
121
+typedef struct {
122
+ DICTIONARY *process_actors;
123
+ DICTIONARY *remote_actors;
124
+ DICTIONARY *local_ips;
125
+ DICTIONARY *endpoint_owners_exact;
126
+ DICTIONARY *endpoint_owners_exact_any_ns;
127
+ DICTIONARY *endpoint_owners_service;
128
+ DICTIONARY *endpoint_owners_service_any_ns;
129
+ DICTIONARY *links;
130
+ usec_t now_ut;
131
+ uint64_t sockets_total;
132
+ uint64_t skipped_sockets;
133
+ char hostname[256];
134
+ char machine_guid[128];
135
+ NV_TOPOLOGY_OPTIONS options;
136
+} NV_TOPOLOGY_CONTEXT;
137
+
138
+typedef struct {
139
+ uint64_t ppid;
140
+} NV_PPID_CACHE_ENTRY;
141
+
142
+typedef struct {
143
+ size_t process_actor_count;
144
+ size_t socket_link_count;
145
+ size_t local_ip_count;
146
+ size_t endpoint_actor_count;
147
+ size_t ownership_link_count;
148
+ char host_actor_id[NV_TOPOLOGY_KEY_MAX];
149
+} NV_TOPOLOGY_RENDER_STATE;
150
+
151
+typedef struct nv_process_socket_row {
152
+ const NV_TOPOLOGY_LINK *link;
153
+ struct nv_process_socket_row *next;
154
+} NV_PROCESS_SOCKET_ROW;
155
+
156
+typedef struct {
157
+ NV_PROCESS_SOCKET_ROW *head;
158
+ NV_PROCESS_SOCKET_ROW *tail;
159
+} NV_PROCESS_SOCKET_ROWS;
160
161
#define SIMPLE_HASHTABLE_VALUE_TYPE LOCAL_SOCKET *
162
#define SIMPLE_HASHTABLE_NAME _AGGREGATED_SOCKETS
191
{ .id = TCP_ESTABLISHED, .name = "established" },
192
{ .id = TCP_SYN_SENT, .name = "syn-sent" },
193
{ .id = TCP_SYN_RECV, .name = "syn-received" },
65
- { .id = TCP_FIN_WAIT1, .name = "fin1-wait1" },
66
- { .id = TCP_FIN_WAIT2, .name = "fin1-wait2" },
194
+ { .id = TCP_FIN_WAIT1, .name = "fin-wait1" },
195
+ { .id = TCP_FIN_WAIT2, .name = "fin-wait2" },
196
{ .id = TCP_TIME_WAIT, .name = "time-wait" },
197
{ .id = TCP_CLOSE, .name = "close" },
198
{ .id = TCP_CLOSE_WAIT, .name = "close-wait" },
215
} max;
216
};
217
218
+static inline const char *network_viewer_machine_guid(void) {
219
+ const char *guid = getenv("NETDATA_REGISTRY_UNIQUE_ID");
220
+ return (guid && *guid) ? guid : NULL;
221
+}
222
+
223
+static inline void topology_options_defaults(NV_TOPOLOGY_OPTIONS *opts) {
224
+ if(!opts)
225
+ return;
226
+
227
+ memset(opts, 0, sizeof(*opts));
228
+ opts->processes_by_pid = false; // default: by_name
229
+ opts->sockets_listening = false;
230
+ opts->sockets_local = false;
231
+ opts->sockets_inbound = true;
232
+ opts->sockets_outbound = true;
233
+ opts->protocols_ipv4_tcp = true;
234
+ opts->protocols_ipv6_tcp = true;
235
+ opts->protocols_ipv4_udp = true;
236
+ opts->protocols_ipv6_udp = true;
237
+}
238
+
239
+static inline bool topology_sockets_any_enabled(const NV_TOPOLOGY_OPTIONS *opts) {
240
+ if(!opts)
241
+ return false;
242
+
243
+ return (opts->sockets_listening ||
244
+ opts->sockets_local ||
245
+ opts->sockets_inbound ||
246
+ opts->sockets_outbound);
247
+}
248
+
249
+static inline bool topology_protocols_any_enabled(const NV_TOPOLOGY_OPTIONS *opts) {
250
+ if(!opts)
251
+ return false;
252
+
253
+ return (opts->protocols_ipv4_tcp ||
254
+ opts->protocols_ipv6_tcp ||
255
+ opts->protocols_ipv4_udp ||
256
+ opts->protocols_ipv6_udp);
257
+}
258
+
259
+static void topology_parse_options(const char *function, NV_TOPOLOGY_OPTIONS *opts) {
260
+ topology_options_defaults(opts);
261
+ if(!function || !*function || !opts)
262
+ return;
263
+
264
+ bool protocols_selected_explicitly = false;
265
+ bool sockets_selected_explicitly = false;
266
+
267
+ char *function_copy = strdupz(function);
268
+ char *words[1024];
269
+ size_t num_words = quoted_strings_splitter_whitespace(function_copy, words, 1024);
270
+ for(size_t i = 1; i < num_words; i++) {
271
+ char *param = get_word(words, num_words, i);
272
+ if(!param || !*param)
273
+ continue;
274
+
275
+ if(strcmp(param, "info") == 0) {
276
+ opts->info_only = true;
277
+ continue;
278
+ }
279
+
280
+ if(strcmp(param, "processes:by_name") == 0 || strcmp(param, "processes:by-name") == 0) {
281
+ opts->processes_by_pid = false;
282
+ continue;
283
+ }
284
+ if(strcmp(param, "processes:by_pid") == 0 || strcmp(param, "processes:by-pid") == 0) {
285
+ opts->processes_by_pid = true;
286
+ continue;
287
+ }
288
+
289
+ if(strcmp(param, "endpoints:by_ip") == 0 || strcmp(param, "endpoints:by-ip") == 0)
290
+ continue;
291
+
292
+ if(strncmp(param, "sockets:", 8) == 0) {
293
+ if(!sockets_selected_explicitly) {
294
+ opts->sockets_listening = false;
295
+ opts->sockets_local = false;
296
+ opts->sockets_inbound = false;
297
+ opts->sockets_outbound = false;
298
+ sockets_selected_explicitly = true;
299
+ }
300
+
301
+ char *sockets_copy = strdupz(¶m[8]);
302
+ char *sockets_remaining = sockets_copy;
303
+ char *socket_kind;
304
+ while(sockets_remaining && *sockets_remaining &&
305
+ (socket_kind = strsep_skip_consecutive_separators(&sockets_remaining, ","))) {
306
+ socket_kind = trim(socket_kind);
307
+ if(!socket_kind || !*socket_kind)
308
+ continue;
309
+
310
+ if(strcmp(socket_kind, "listening") == 0)
311
+ opts->sockets_listening = true;
312
+ else if(strcmp(socket_kind, "local") == 0)
313
+ opts->sockets_local = true;
314
+ else if(strcmp(socket_kind, "inbound") == 0)
315
+ opts->sockets_inbound = true;
316
+ else if(strcmp(socket_kind, "outbound") == 0)
317
+ opts->sockets_outbound = true;
318
+ }
319
+ freez(sockets_copy);
320
+ continue;
321
+ }
322
+
323
+ if(strncmp(param, "protocols:", 10) == 0) {
324
+ if(!protocols_selected_explicitly) {
325
+ opts->protocols_ipv4_tcp = false;
326
+ opts->protocols_ipv6_tcp = false;
327
+ opts->protocols_ipv4_udp = false;
328
+ opts->protocols_ipv6_udp = false;
329
+ protocols_selected_explicitly = true;
330
+ }
331
+
332
+ char *protocols_copy = strdupz(¶m[10]);
333
+ char *protocols_remaining = protocols_copy;
334
+ char *protocol;
335
+ while(protocols_remaining && *protocols_remaining &&
336
+ (protocol = strsep_skip_consecutive_separators(&protocols_remaining, ","))) {
337
+ protocol = trim(protocol);
338
+ if(!protocol || !*protocol)
339
+ continue;
340
+
341
+ if(strcmp(protocol, "ipv4_tcp") == 0 || strcmp(protocol, "ipv4-tcp") == 0)
342
+ opts->protocols_ipv4_tcp = true;
343
+ else if(strcmp(protocol, "ipv6_tcp") == 0 || strcmp(protocol, "ipv6-tcp") == 0)
344
+ opts->protocols_ipv6_tcp = true;
345
+ else if(strcmp(protocol, "ipv4_udp") == 0 || strcmp(protocol, "ipv4-udp") == 0)
346
+ opts->protocols_ipv4_udp = true;
347
+ else if(strcmp(protocol, "ipv6_udp") == 0 || strcmp(protocol, "ipv6-udp") == 0)
348
+ opts->protocols_ipv6_udp = true;
349
+ }
350
+ freez(protocols_copy);
351
+ }
352
+ }
353
+ freez(function_copy);
354
+
355
+ if(!topology_sockets_any_enabled(opts)) {
356
+ opts->sockets_listening = false;
357
+ opts->sockets_local = false;
358
+ opts->sockets_inbound = true;
359
+ opts->sockets_outbound = true;
360
+ }
361
+
362
+ if(!topology_protocols_any_enabled(opts)) {
363
+ opts->protocols_ipv4_tcp = true;
364
+ opts->protocols_ipv6_tcp = true;
365
+ opts->protocols_ipv4_udp = true;
366
+ opts->protocols_ipv6_udp = true;
367
+ }
368
+}
369
+
370
+static inline const char *socket_protocol_name(uint16_t protocol) {
371
+ return (protocol == IPPROTO_UDP) ? "udp" : "tcp";
372
+}
373
+
374
+static inline const char *socket_protocol_family_name(const LOCAL_SOCKET *n) {
375
+ if(is_local_socket_ipv46(n))
376
+ return "ipv46";
377
+
378
+ if(n->local.family == AF_INET)
379
+ return "ipv4";
380
+
381
+ if(n->local.family == AF_INET6)
382
+ return "ipv6";
383
+
384
+ return "unknown";
385
+}
386
+
387
+static bool socket_endpoint_to_ip_text(const struct socket_endpoint *ep, char *dst) {
388
+ if(ep->family == AF_INET) {
389
+ ipv4_address_to_txt(ep->ip.ipv4, dst);
390
+ return true;
391
+ }
392
+
393
+ if(ep->family == AF_INET6) {
394
+ ipv6_address_to_txt(&ep->ip.ipv6, dst);
395
+ return true;
396
+ }
397
+
398
+ dst[0] = '\0';
399
+ return false;
400
+}
401
+
402
+static inline void topology_format_ip_port(const char *ip, uint16_t port, char *dst, size_t dst_size) {
403
+ if(!dst || !dst_size)
404
+ return;
405
+
406
+ if(!ip)
407
+ ip = "";
408
+
409
+ if(strchr(ip, ':'))
410
+ snprintf(dst, dst_size, "[%s]:%u", ip, port);
411
+ else
412
+ snprintf(dst, dst_size, "%s:%u", ip, port);
413
+}
414
+
415
+static inline bool topology_ip_is_unspecified(const char *ip) {
416
+ if(!ip || !*ip)
417
+ return true;
418
+
419
+ return (strcmp(ip, "*") == 0 || strcmp(ip, "0.0.0.0") == 0 || strcmp(ip, "::") == 0);
420
+}
421
+
422
+static inline bool topology_ip_is_self_range(const char *ip) {
423
+ if(!ip || !*ip)
424
+ return false;
425
+
426
+ if(strncmp(ip, "127.", 4) == 0)
427
+ return true;
428
+ if(strncmp(ip, "0.", 2) == 0)
429
+ return true;
430
+ if(strcmp(ip, "::1") == 0)
431
+ return true;
432
+ if(strncmp(ip, "::ffff:127.", 10) == 0)
433
+ return true;
434
+
435
+ return false;
436
+}
437
+
438
+static inline bool topology_ip_belongs_to_self(const NV_TOPOLOGY_CONTEXT *ctx, const char *ip, const char *address_space) {
439
+ if(topology_ip_is_unspecified(ip))
440
+ return true;
441
+
442
+ if(topology_ip_is_self_range(ip))
443
+ return true;
444
+
445
+ if(address_space && *address_space) {
446
+ if(strcmp(address_space, "loopback") == 0 || strcmp(address_space, "zero") == 0)
447
+ return true;
448
+ }
449
+
450
+ if(ctx && ctx->local_ips && ip && *ip && dictionary_get(ctx->local_ips, ip))
451
+ return true;
452
+
453
+ return false;
454
+}
455
+
456
+static void topology_add_single_item_string_array(BUFFER *wb, const char *key, const char *value) {
457
+ if(!value || !*value)
458
+ return;
459
+
460
+ if(strcmp(key, "ip_addresses") == 0 && strcmp(value, "*") == 0)
461
+ return;
462
+
463
+ buffer_json_member_add_array(wb, key);
464
+ {
465
+ buffer_json_add_array_item_string(wb, value);
466
+ }
467
+ buffer_json_array_close(wb);
468
+}
469
+
470
+static void topology_add_process_match(BUFFER *wb, const NV_TOPOLOGY_CONTEXT *ctx, const NV_PROCESS_ACTOR *pa) {
471
+ buffer_json_member_add_object(wb, "match");
472
+ {
473
+ buffer_json_member_add_string(wb, "process_name", pa->process);
474
+ if(ctx && ctx->options.processes_by_pid) {
475
+ buffer_json_member_add_uint64(wb, "pid", pa->pid);
476
+ buffer_json_member_add_uint64(wb, "uid", pa->uid);
477
+ buffer_json_member_add_uint64(wb, "net_ns_inode", pa->net_ns_inode);
478
+ }
479
+ }
480
+ buffer_json_object_close(wb);
481
+}
482
+
483
+static void topology_add_process_identity_match(BUFFER *wb, const NV_TOPOLOGY_CONTEXT *ctx, uint64_t pid, uint64_t uid, uint64_t net_ns_inode, const char *process_name) {
484
+ buffer_json_member_add_object(wb, "match");
485
+ {
486
+ buffer_json_member_add_string(wb, "process_name", process_name && *process_name ? process_name : "[unknown]");
487
+ if(ctx && ctx->options.processes_by_pid) {
488
+ buffer_json_member_add_uint64(wb, "pid", pid);
489
+ buffer_json_member_add_uint64(wb, "uid", uid);
490
+ buffer_json_member_add_uint64(wb, "net_ns_inode", net_ns_inode);
491
+ }
492
+ }
493
+ buffer_json_object_close(wb);
494
+}
495
+
496
+static inline void topology_process_parent_lookup_key(
497
+ char *dst,
498
+ size_t dst_size,
499
+ uint64_t pid,
500
+ uint64_t net_ns_inode,
501
+ bool include_ns
502
+) {
503
+ if(!dst || !dst_size)
504
+ return;
505
+
506
+ if(include_ns)
507
+ snprintf(dst, dst_size, "ns=%llu|pid=%llu",
508
+ (unsigned long long)net_ns_inode,
509
+ (unsigned long long)pid);
510
+ else
511
+ snprintf(dst, dst_size, "pid=%llu",
512
+ (unsigned long long)pid);
513
+}
514
+
515
+static inline void topology_pid_lookup_key(char *dst, size_t dst_size, uint64_t pid) {
516
+ if(!dst || !dst_size)
517
+ return;
518
+
519
+ snprintf(dst, dst_size, "pid=%llu", (unsigned long long)pid);
520
+}
521
+
522
+static bool topology_read_proc_ppid(uint64_t pid, uint64_t *ppid) {
523
+ if(!pid || !ppid)
524
+ return false;
525
+
526
+ char filename[FILENAME_MAX + 1];
527
+ char status_buf[1024];
528
+ snprintfz(filename, sizeof(filename), "%s/proc/%llu/status",
529
+ netdata_configured_host_prefix,
530
+ (unsigned long long)pid);
531
+
532
+ if(read_txt_file(filename, status_buf, sizeof(status_buf)))
533
+ return false;
534
+
535
+ char *p = strstr(status_buf, "PPid:");
536
+ if(!p)
537
+ return false;
538
+
539
+ p += 5;
540
+ while(isspace((unsigned char)*p))
541
+ p++;
542
+
543
+ if(*p < '0' || *p > '9')
544
+ return false;
545
+
546
+ uint64_t parent = strtoull(p, NULL, 10);
547
+ if(parent == pid)
548
+ parent = 0;
549
+
550
+ *ppid = parent;
551
+ return true;
552
+}
553
+
554
+static uint64_t topology_ppid_cache_get_or_load(DICTIONARY *ppid_cache, uint64_t pid) {
555
+ if(!ppid_cache || !pid)
556
+ return 0;
557
+
558
+ char pid_key[64];
559
+ topology_pid_lookup_key(pid_key, sizeof(pid_key), pid);
560
+
561
+ NV_PPID_CACHE_ENTRY *cached = dictionary_get(ppid_cache, pid_key);
562
+ if(cached)
563
+ return cached->ppid;
564
+
565
+ NV_PPID_CACHE_ENTRY tmp = { .ppid = 0 };
566
+ uint64_t ppid = 0;
567
+ if(topology_read_proc_ppid(pid, &ppid))
568
+ tmp.ppid = ppid;
569
+
570
+ cached = dictionary_set(ppid_cache, pid_key, &tmp, sizeof(tmp));
571
+ return cached ? cached->ppid : tmp.ppid;
572
+}
573
+
574
+static NV_ENDPOINT_OWNER *topology_find_process_parent_actor(
575
+ uint64_t ppid,
576
+ uint64_t net_ns_inode,
577
+ DICTIONARY *process_parent_ns_lookup,
578
+ DICTIONARY *process_parent_any_lookup,
579
+ DICTIONARY *ppid_cache
580
+) {
581
+ if(!ppid || !process_parent_ns_lookup || !process_parent_any_lookup)
582
+ return NULL;
583
+
584
+ uint64_t current_pid = ppid;
585
+ for(size_t depth = 0; depth < NV_TOPOLOGY_MAX_PPID_DEPTH && current_pid; depth++) {
586
+ char parent_key_ns[NV_TOPOLOGY_KEY_MAX];
587
+ char parent_key_any[NV_TOPOLOGY_KEY_MAX];
588
+
589
+ topology_process_parent_lookup_key(parent_key_ns, sizeof(parent_key_ns), current_pid, net_ns_inode, true);
590
+ NV_ENDPOINT_OWNER *parent = dictionary_get(process_parent_ns_lookup, parent_key_ns);
591
+ if(!parent) {
592
+ topology_process_parent_lookup_key(parent_key_any, sizeof(parent_key_any), current_pid, 0, false);
593
+ parent = dictionary_get(process_parent_any_lookup, parent_key_any);
594
+ }
595
+
596
+ if(parent)
597
+ return parent;
598
+
599
+ if(!ppid_cache)
600
+ break;
601
+
602
+ uint64_t next_ppid = topology_ppid_cache_get_or_load(ppid_cache, current_pid);
603
+ if(!next_ppid || next_ppid == current_pid)
604
+ break;
605
+
606
+ current_pid = next_ppid;
607
+ }
608
+
609
+ return NULL;
610
+}
611
+
612
+static void topology_endpoint_owner_exact_key(char *dst, size_t dst_size, uint64_t net_ns_inode, uint16_t protocol, const char *ip, uint16_t port, bool include_ns) {
613
+ if(!dst || !dst_size)
614
+ return;
615
+
616
+ if(include_ns)
617
+ snprintf(dst, dst_size, "ns=%llu|proto=%u|ip=%s|port=%u",
618
+ (unsigned long long)net_ns_inode, (unsigned)protocol, ip, (unsigned)port);
619
+ else
620
+ snprintf(dst, dst_size, "proto=%u|ip=%s|port=%u", (unsigned)protocol, ip, (unsigned)port);
621
+}
622
+
623
+static void topology_endpoint_owner_service_key(char *dst, size_t dst_size, uint64_t net_ns_inode, uint16_t protocol, uint16_t port, bool include_ns) {
624
+ if(!dst || !dst_size)
625
+ return;
626
+
627
+ if(include_ns)
628
+ snprintf(dst, dst_size, "ns=%llu|proto=%u|port=%u",
629
+ (unsigned long long)net_ns_inode, (unsigned)protocol, (unsigned)port);
630
+ else
631
+ snprintf(dst, dst_size, "proto=%u|port=%u", (unsigned)protocol, (unsigned)port);
632
+}
633
+
634
+static void topology_register_endpoint_owner(
635
+ NV_TOPOLOGY_CONTEXT *ctx,
636
+ uint64_t net_ns_inode,
637
+ uint16_t protocol,
638
+ const char *ip,
639
+ uint16_t port,
640
+ const NV_PROCESS_ACTOR *pa,
641
+ bool service_candidate
642
+) {
643
+ if(!ctx || !pa || !port)
644
+ return;
645
+
646
+ NV_ENDPOINT_OWNER owner = {
647
+ .pid = pa->pid,
648
+ .ppid = pa->ppid,
649
+ .uid = pa->uid,
650
+ .net_ns_inode = pa->net_ns_inode,
651
+ };
652
+ snprintf(owner.process, sizeof(owner.process), "%s", pa->process);
653
+
654
+ char key[NV_TOPOLOGY_KEY_MAX];
655
+ if(ip && *ip && strcmp(ip, "*") != 0) {
656
+ if(ctx->endpoint_owners_exact) {
657
+ topology_endpoint_owner_exact_key(key, sizeof(key), net_ns_inode, protocol, ip, port, true);
658
+ dictionary_set(ctx->endpoint_owners_exact, key, &owner, sizeof(owner));
659
+ }
660
+ if(ctx->endpoint_owners_exact_any_ns) {
661
+ topology_endpoint_owner_exact_key(key, sizeof(key), 0, protocol, ip, port, false);
662
+ dictionary_set(ctx->endpoint_owners_exact_any_ns, key, &owner, sizeof(owner));
663
+ }
664
+ }
665
+
666
+ if(service_candidate) {
667
+ if(ctx->endpoint_owners_service) {
668
+ topology_endpoint_owner_service_key(key, sizeof(key), net_ns_inode, protocol, port, true);
669
+ dictionary_set(ctx->endpoint_owners_service, key, &owner, sizeof(owner));
670
+ }
671
+ if(ctx->endpoint_owners_service_any_ns) {
672
+ topology_endpoint_owner_service_key(key, sizeof(key), 0, protocol, port, false);
673
+ dictionary_set(ctx->endpoint_owners_service_any_ns, key, &owner, sizeof(owner));
674
+ }
675
+ }
676
+}
677
+
678
+static NV_ENDPOINT_OWNER *topology_lookup_endpoint_owner(
679
+ const NV_TOPOLOGY_CONTEXT *ctx,
680
+ uint64_t net_ns_inode,
681
+ uint16_t protocol,
682
+ const char *ip,
683
+ uint16_t port,
684
+ bool allow_service_fallback
685
+) {
686
+ if(!ctx || !port)
687
+ return NULL;
688
+
689
+ char key[NV_TOPOLOGY_KEY_MAX];
690
+ NV_ENDPOINT_OWNER *owner = NULL;
691
+
692
+ if(ip && *ip && strcmp(ip, "*") != 0) {
693
+ if(ctx->endpoint_owners_exact) {
694
+ topology_endpoint_owner_exact_key(key, sizeof(key), net_ns_inode, protocol, ip, port, true);
695
+ owner = dictionary_get(ctx->endpoint_owners_exact, key);
696
+ if(owner)
697
+ return owner;
698
+ }
699
+
700
+ if(ctx->endpoint_owners_exact_any_ns) {
701
+ topology_endpoint_owner_exact_key(key, sizeof(key), 0, protocol, ip, port, false);
702
+ owner = dictionary_get(ctx->endpoint_owners_exact_any_ns, key);
703
+ if(owner)
704
+ return owner;
705
+ }
706
+ }
707
+
708
+ if(!allow_service_fallback)
709
+ return NULL;
710
+
711
+ if(ctx->endpoint_owners_service) {
712
+ topology_endpoint_owner_service_key(key, sizeof(key), net_ns_inode, protocol, port, true);
713
+ owner = dictionary_get(ctx->endpoint_owners_service, key);
714
+ if(owner)
715
+ return owner;
716
+ }
717
+
718
+ if(ctx->endpoint_owners_service_any_ns) {
719
+ topology_endpoint_owner_service_key(key, sizeof(key), 0, protocol, port, false);
720
+ owner = dictionary_get(ctx->endpoint_owners_service_any_ns, key);
721
+ if(owner)
722
+ return owner;
723
+ }
724
+
725
+ return NULL;
726
+}
727
+
728
+static void topology_add_host_match(BUFFER *wb, const NV_TOPOLOGY_CONTEXT *ctx) {
729
+ buffer_json_member_add_object(wb, "match");
730
+ {
731
+ if(ctx->machine_guid[0])
732
+ buffer_json_member_add_string(wb, "netdata_machine_guid", ctx->machine_guid);
733
+
734
+ topology_add_single_item_string_array(wb, "hostnames", ctx->hostname);
735
+ buffer_json_member_add_array(wb, "ip_addresses");
736
+ {
737
+ NV_LOCAL_IP *lip;
738
+ dfe_start_read(ctx->local_ips, lip) {
739
+ if(!lip->ip[0]) continue;
740
+ if(topology_ip_is_unspecified(lip->ip)) continue;
741
+ buffer_json_add_array_item_string(wb, lip->ip);
742
+ }
743
+ dfe_done(lip);
744
+ }
745
+ buffer_json_array_close(wb);
746
+ }
747
+ buffer_json_object_close(wb);
748
+}
749
+
750
+static void topology_add_remote_match(BUFFER *wb, const char *ip) {
751
+ buffer_json_member_add_object(wb, "match");
752
+ {
753
+ topology_add_single_item_string_array(wb, "ip_addresses", ip);
754
+ }
755
+ buffer_json_object_close(wb);
756
+}
757
+
758
+static void topology_encode_identifier_component(char *dst, size_t dst_size, const char *src) {
759
+ if(!dst || !dst_size)
760
+ return;
761
+
762
+ const uint8_t *s = (const uint8_t *)((src && *src) ? src : "[unknown]");
763
+ size_t written = 0;
764
+
765
+ while(*s && written + 1 < dst_size) {
766
+ uint8_t ch = *s++;
767
+
768
+ if(isalnum(ch) || ch == '-' || ch == '_' || ch == '.' || ch == '~') {
769
+ dst[written++] = (char)ch;
770
+ continue;
771
+ }
772
+
773
+ if(written + 3 >= dst_size)
774
+ break;
775
+
776
+ dst[written++] = '%';
777
+ dst[written++] = hex_digits_lower[(ch >> 4) & 0x0F];
778
+ dst[written++] = hex_digits_lower[ch & 0x0F];
779
+ }
780
+
781
+ dst[written] = '\0';
782
+}
783
+
784
+static void topology_actor_id_for_host(const NV_TOPOLOGY_CONTEXT *ctx, char *dst, size_t dst_size) {
785
+ if(!dst || !dst_size)
786
+ return;
787
+
788
+ if(ctx && ctx->machine_guid[0])
789
+ snprintf(dst, dst_size, "netdata-machine-guid:%s", ctx->machine_guid);
790
+ else if(ctx && ctx->hostname[0])
791
+ snprintf(dst, dst_size, "hostname:%s", ctx->hostname);
792
+ else
793
+ snprintf(dst, dst_size, "host:unknown");
794
+}
795
+
796
+static void topology_actor_id_for_process(
797
+ const NV_TOPOLOGY_CONTEXT *ctx,
798
+ uint64_t pid,
799
+ uint64_t uid,
800
+ uint64_t net_ns_inode,
801
+ const char *process,
802
+ char *dst,
803
+ size_t dst_size
804
+) {
805
+ if(!dst || !dst_size)
806
+ return;
807
+
808
+ const char *node_identity = (ctx && ctx->machine_guid[0]) ? ctx->machine_guid : (ctx && ctx->hostname[0] ? ctx->hostname : "unknown");
809
+ const char *safe_process = (process && *process) ? process : "[unknown]";
810
+ if(ctx && !ctx->options.processes_by_pid) {
811
+ char encoded_process[((TASK_COMM_LEN + 1) * 3) + 1];
812
+ topology_encode_identifier_component(encoded_process, sizeof(encoded_process), safe_process);
813
+ snprintf(dst, dst_size, "process:%s|comm=%s", node_identity, encoded_process);
814
+ }
815
+ else {
816
+ snprintf(dst, dst_size, "process:%s|pid=%llu|uid=%llu|ns=%llu",
817
+ node_identity,
818
+ (unsigned long long)pid,
819
+ (unsigned long long)uid,
820
+ (unsigned long long)net_ns_inode);
821
+ }
822
+}
823
+
824
+static bool topology_process_name_is_unknown(const char *process_name) {
825
+ return !process_name || !*process_name || strcmp(process_name, "[unknown]") == 0;
826
+}
827
+
828
+static void topology_actor_id_for_remote_endpoint(const NV_TOPOLOGY_CONTEXT *ctx, const char *ip, const char *address_space, char *dst, size_t dst_size) {
829
+ if(!dst || !dst_size)
830
+ return;
831
+
832
+ (void)ctx;
833
+ (void)address_space;
834
+ if(ip && *ip)
835
+ snprintf(dst, dst_size, "ip:%s", ip);
836
+ else
837
+ snprintf(dst, dst_size, "ip:unknown");
838
+}
839
+
840
+static void topology_process_display_name(
841
+ const NV_TOPOLOGY_CONTEXT *ctx,
842
+ const char *process_name,
843
+ uint64_t pid,
844
+ char *dst,
845
+ size_t dst_size
846
+) {
847
+ if(!dst || !dst_size)
848
+ return;
849
+
850
+ const char *safe_process = (process_name && *process_name) ? process_name : "[unknown]";
851
+ if(ctx && !ctx->options.processes_by_pid)
852
+ snprintf(dst, dst_size, "%s", safe_process);
853
+ else
854
+ snprintf(dst, dst_size, "%s[%llu]", safe_process, (unsigned long long)pid);
855
+}
856
+
857
static void local_socket_to_json_array(struct sockets_stats *st, const LOCAL_SOCKET *n, uint64_t proc_self_net_ns_inode, bool aggregated) {
858
if(n->direction == SOCKET_DIRECTION_NONE)
859
return;
1009
if(st->max.tcpi_total_retrans < n->info.tcp.tcpi_total_retrans)
1010
st->max.tcpi_total_retrans = n->info.tcp.tcpi_total_retrans;
1011
244
- // count
245
- buffer_json_add_array_item_uint64(wb, n->network_viewer.count);
1012
+ // count
1013
+ buffer_json_add_array_item_uint64(wb, n->network_viewer.count);
1014
+ }
1015
+ buffer_json_array_close(wb);
1016
+}
1017
+
1018
+static void populate_aggregated_key(const LOCAL_SOCKET *nn) {
1019
+ LOCAL_SOCKET *n = (LOCAL_SOCKET *)nn;
1020
+
1021
+ n->network_viewer.count = 1;
1022
+
1023
+ n->network_viewer.aggregated_key.pid = n->pid;
1024
+ n->network_viewer.aggregated_key.uid = n->uid;
1025
+ n->network_viewer.aggregated_key.direction = n->direction;
1026
+ n->network_viewer.aggregated_key.net_ns_inode = n->net_ns_inode;
1027
+ n->network_viewer.aggregated_key.state = n->state;
1028
+
1029
+ switch(n->direction) {
1030
+ case SOCKET_DIRECTION_INBOUND:
1031
+ case SOCKET_DIRECTION_LOCAL_INBOUND:
1032
+ case SOCKET_DIRECTION_LISTEN:
1033
+ n->network_viewer.aggregated_key.server = n->local;
1034
+ break;
1035
+
1036
+ case SOCKET_DIRECTION_OUTBOUND:
1037
+ case SOCKET_DIRECTION_LOCAL_OUTBOUND:
1038
+ n->network_viewer.aggregated_key.server = n->remote;
1039
+ break;
1040
+
1041
+ case SOCKET_DIRECTION_NONE:
1042
+ break;
1043
+ }
1044
+
1045
+ n->network_viewer.aggregated_key.local_address_space = local_sockets_address_space(&n->local);
1046
+ n->network_viewer.aggregated_key.remote_address_space = local_sockets_address_space(&n->remote);
1047
+}
1048
+
1049
+static void local_sockets_cb_to_json(LS_STATE *ls, const LOCAL_SOCKET *n, void *data) {
1050
+ struct sockets_stats *st = data;
1051
+ populate_aggregated_key(n);
1052
+ local_socket_to_json_array(st, n, ls->proc_self_net_ns_inode, false);
1053
+}
1054
+
1055
+#define KEEP_THE_BIGGER(a, b) (a) = ((a) < (b)) ? (b) : (a)
1056
+#define KEEP_THE_SMALLER(a, b) (a) = ((a) > (b)) ? (b) : (a)
1057
+#define SUM_THEM_ALL(a, b) (a) += (b)
1058
+#define OR_THEM_ALL(a, b) (a) |= (b)
1059
+
1060
+static void local_sockets_cb_to_aggregation(LS_STATE *ls __maybe_unused, const LOCAL_SOCKET *n, void *data) {
1061
+ SIMPLE_HASHTABLE_AGGREGATED_SOCKETS *ht = data;
1062
+
1063
+ populate_aggregated_key(n);
1064
+ XXH64_hash_t hash = XXH3_64bits(&n->network_viewer.aggregated_key, sizeof(n->network_viewer.aggregated_key));
1065
+ SIMPLE_HASHTABLE_SLOT_AGGREGATED_SOCKETS *sl = simple_hashtable_get_slot_AGGREGATED_SOCKETS(ht, hash, (LOCAL_SOCKET *)n, true);
1066
+ LOCAL_SOCKET *t = SIMPLE_HASHTABLE_SLOT_DATA(sl);
1067
+ if(t) {
1068
+ t->network_viewer.count++;
1069
+
1070
+ KEEP_THE_BIGGER(t->timer, n->timer);
1071
+ KEEP_THE_BIGGER(t->retransmits, n->retransmits);
1072
+ KEEP_THE_SMALLER(t->expires, n->expires);
1073
+ KEEP_THE_BIGGER(t->rqueue, n->rqueue);
1074
+ KEEP_THE_BIGGER(t->wqueue, n->wqueue);
1075
+
1076
+ // The current number of consecutive retransmissions that have occurred for the most recently transmitted segment.
1077
+ SUM_THEM_ALL(t->info.tcp.tcpi_retransmits, n->info.tcp.tcpi_retransmits);
1078
+
1079
+ // The total number of retransmissions that have occurred for the entire connection since it was established.
1080
+ SUM_THEM_ALL(t->info.tcp.tcpi_total_retrans, n->info.tcp.tcpi_total_retrans);
1081
+
1082
+ // The total number of segments that have been retransmitted since the connection was established.
1083
+ SUM_THEM_ALL(t->info.tcp.tcpi_retrans, n->info.tcp.tcpi_retrans);
1084
+
1085
+ // The number of keepalive probes sent
1086
+ SUM_THEM_ALL(t->info.tcp.tcpi_probes, n->info.tcp.tcpi_probes);
1087
+
1088
+ // The number of times the retransmission timeout has been backed off.
1089
+ SUM_THEM_ALL(t->info.tcp.tcpi_backoff, n->info.tcp.tcpi_backoff);
1090
+
1091
+ // A bitmask representing the TCP options currently enabled for the connection, such as SACK and Timestamps.
1092
+ OR_THEM_ALL(t->info.tcp.tcpi_options, n->info.tcp.tcpi_options);
1093
+
1094
+ // The send window scale value used for this connection
1095
+ KEEP_THE_SMALLER(t->info.tcp.tcpi_snd_wscale, n->info.tcp.tcpi_snd_wscale);
1096
+
1097
+ // The receive window scale value used for this connection
1098
+ KEEP_THE_SMALLER(t->info.tcp.tcpi_rcv_wscale, n->info.tcp.tcpi_rcv_wscale);
1099
+
1100
+ // Retransmission timeout in milliseconds
1101
+ KEEP_THE_SMALLER(t->info.tcp.tcpi_rto, n->info.tcp.tcpi_rto);
1102
+
1103
+ // The delayed acknowledgement timeout in milliseconds.
1104
+ KEEP_THE_SMALLER(t->info.tcp.tcpi_ato, n->info.tcp.tcpi_ato);
1105
+
1106
+ // The maximum segment size for sending.
1107
+ KEEP_THE_SMALLER(t->info.tcp.tcpi_snd_mss, n->info.tcp.tcpi_snd_mss);
1108
+
1109
+ // The maximum segment size for receiving.
1110
+ KEEP_THE_SMALLER(t->info.tcp.tcpi_rcv_mss, n->info.tcp.tcpi_rcv_mss);
1111
+
1112
+ // The number of unacknowledged segments
1113
+ SUM_THEM_ALL(t->info.tcp.tcpi_unacked, n->info.tcp.tcpi_unacked);
1114
+
1115
+ // The number of segments that have been selectively acknowledged
1116
+ SUM_THEM_ALL(t->info.tcp.tcpi_sacked, n->info.tcp.tcpi_sacked);
1117
+
1118
+ // The number of lost segments.
1119
+ SUM_THEM_ALL(t->info.tcp.tcpi_lost, n->info.tcp.tcpi_lost);
1120
+
1121
+ // The number of forward acknowledgment segments.
1122
+ SUM_THEM_ALL(t->info.tcp.tcpi_fackets, n->info.tcp.tcpi_fackets);
1123
+
1124
+ // The time in milliseconds since the last data was sent.
1125
+ KEEP_THE_SMALLER(t->info.tcp.tcpi_last_data_sent, n->info.tcp.tcpi_last_data_sent);
1126
+
1127
+ // The time in milliseconds since the last acknowledgment was sent (not tracked in Linux, hence often zero).
1128
+ KEEP_THE_SMALLER(t->info.tcp.tcpi_last_ack_sent, n->info.tcp.tcpi_last_ack_sent);
1129
+
1130
+ // The time in milliseconds since the last data was received.
1131
+ KEEP_THE_SMALLER(t->info.tcp.tcpi_last_data_recv, n->info.tcp.tcpi_last_data_recv);
1132
+
1133
+ // The time in milliseconds since the last acknowledgment was received.
1134
+ KEEP_THE_SMALLER(t->info.tcp.tcpi_last_ack_recv, n->info.tcp.tcpi_last_ack_recv);
1135
+
1136
+ // The path MTU for this connection
1137
+ KEEP_THE_SMALLER(t->info.tcp.tcpi_pmtu, n->info.tcp.tcpi_pmtu);
1138
+
1139
+ // The slow start threshold for receiving
1140
+ KEEP_THE_SMALLER(t->info.tcp.tcpi_rcv_ssthresh, n->info.tcp.tcpi_rcv_ssthresh);
1141
+
1142
+ // The slow start threshold for sending
1143
+ KEEP_THE_SMALLER(t->info.tcp.tcpi_snd_ssthresh, n->info.tcp.tcpi_snd_ssthresh);
1144
+
1145
+ // The round trip time in milliseconds
1146
+ KEEP_THE_BIGGER(t->info.tcp.tcpi_rtt, n->info.tcp.tcpi_rtt);
1147
+
1148
+ // The round trip time variance in milliseconds.
1149
+ KEEP_THE_BIGGER(t->info.tcp.tcpi_rttvar, n->info.tcp.tcpi_rttvar);
1150
+
1151
+ // The size of the sending congestion window.
1152
+ KEEP_THE_SMALLER(t->info.tcp.tcpi_snd_cwnd, n->info.tcp.tcpi_snd_cwnd);
1153
+
1154
+ // The maximum segment size that could be advertised.
1155
+ KEEP_THE_BIGGER(t->info.tcp.tcpi_advmss, n->info.tcp.tcpi_advmss);
1156
+
1157
+ // The reordering metric
1158
+ KEEP_THE_SMALLER(t->info.tcp.tcpi_reordering, n->info.tcp.tcpi_reordering);
1159
+
1160
+ // The receive round trip time in milliseconds.
1161
+ KEEP_THE_BIGGER(t->info.tcp.tcpi_rcv_rtt, n->info.tcp.tcpi_rcv_rtt);
1162
+
1163
+ // The available space in the receive buffer.
1164
+ KEEP_THE_SMALLER(t->info.tcp.tcpi_rcv_space, n->info.tcp.tcpi_rcv_space);
1165
+ }
1166
+ else {
1167
+ t = mallocz(sizeof(*t));
1168
+ memcpy(t, n, sizeof(*t));
1169
+ t->cmdline = string_dup(t->cmdline);
1170
+ simple_hashtable_set_slot_AGGREGATED_SOCKETS(ht, sl, hash, t);
1171
+ }
1172
+}
1173
+
1174
+static void local_sockets_cb_to_topology(LS_STATE *ls, const LOCAL_SOCKET *n, void *data) {
1175
+ if(n->direction == SOCKET_DIRECTION_NONE)
1176
+ return;
1177
+
1178
+ NV_TOPOLOGY_CONTEXT *ctx = data;
1179
+ ctx->sockets_total++;
1180
+
1181
+ char local_ip[INET6_ADDRSTRLEN] = "";
1182
+ char remote_ip[INET6_ADDRSTRLEN] = "";
1183
+ char remote_peer_ip[INET6_ADDRSTRLEN] = "";
1184
+
1185
+ if(is_local_socket_ipv46(n))
1186
+ strncpyz(local_ip, "*", sizeof(local_ip) - 1);
1187
+ else if(!socket_endpoint_to_ip_text(&n->local, local_ip))
1188
+ return;
1189
+
1190
+ if(!local_sockets_is_zero_address(&n->remote)) {
1191
+ socket_endpoint_to_ip_text(&n->remote, remote_ip);
1192
+ snprintf(remote_peer_ip, sizeof(remote_peer_ip), "%s", remote_ip);
1193
+ }
1194
+
1195
+ const char *namespace_type;
1196
+ if(n->net_ns_inode == ls->proc_self_net_ns_inode)
1197
+ namespace_type = "system";
1198
+ else if(n->net_ns_inode == 0)
1199
+ namespace_type = "unknown";
1200
+ else
1201
+ namespace_type = "container";
1202
+
1203
+ const char *local_address_space = local_sockets_address_space(&n->local);
1204
+ const char *remote_address_space = local_sockets_address_space(&n->remote);
1205
+ const char *process_name = n->comm[0] ? n->comm : "[unknown]";
1206
+ const char *cmdline = string2str(n->cmdline);
1207
+
1208
+ char username[NV_TOPOLOGY_USERNAME_MAX] = "[unknown]";
1209
+ if(n->uid != UID_UNSET) {
1210
+ CACHED_USERNAME cu = cached_username_get_by_uid(n->uid);
1211
+ const char *cached_username = string2str(cu.username);
1212
+ if(cached_username && *cached_username)
1213
+ snprintf(username, sizeof(username), "%s", cached_username);
1214
+ cached_username_release(cu);
1215
+ }
1216
+
1217
+ if(local_ip[0] && !topology_ip_is_unspecified(local_ip)) {
1218
+ NV_LOCAL_IP *local_actor = dictionary_get(ctx->local_ips, local_ip);
1219
+ if(!local_actor) {
1220
+ NV_LOCAL_IP tmp = { 0 };
1221
+ snprintf(tmp.ip, sizeof(tmp.ip), "%s", local_ip);
1222
+ snprintf(tmp.address_space, sizeof(tmp.address_space), "%s", local_address_space);
1223
+ local_actor = dictionary_set(ctx->local_ips, local_ip, &tmp, sizeof(tmp));
1224
+ }
1225
+ local_actor->sockets++;
1226
+ }
1227
+
1228
+ char process_key[NV_TOPOLOGY_KEY_MAX];
1229
+ if(ctx->options.processes_by_pid) {
1230
+ snprintf(process_key, sizeof(process_key), "pid=%d|uid=%u|ns=%llu",
1231
+ n->pid,
1232
+ (unsigned)n->uid,
1233
+ (unsigned long long)n->net_ns_inode);
1234
+ }
1235
+ else {
1236
+ char encoded_process[((TASK_COMM_LEN + 1) * 3) + 1];
1237
+ topology_encode_identifier_component(encoded_process, sizeof(encoded_process), process_name);
1238
+ snprintf(process_key, sizeof(process_key), "comm=%s", encoded_process);
1239
+ }
1240
+
1241
+ NV_PROCESS_ACTOR *pa = dictionary_get(ctx->process_actors, process_key);
1242
+ if(!pa) {
1243
+ NV_PROCESS_ACTOR tmp = { 0 };
1244
+ tmp.pid = n->pid;
1245
+ tmp.ppid = n->ppid;
1246
+ tmp.uid = n->uid;
1247
+ tmp.net_ns_inode = n->net_ns_inode;
1248
+ snprintf(tmp.process, sizeof(tmp.process), "%s", process_name);
1249
+ snprintf(tmp.username, sizeof(tmp.username), "%s", username);
1250
+ snprintf(tmp.namespace_type, sizeof(tmp.namespace_type), "%s", namespace_type);
1251
+ snprintf(tmp.local_ip, sizeof(tmp.local_ip), "%s", local_ip);
1252
+ snprintf(tmp.local_address_space, sizeof(tmp.local_address_space), "%s", local_address_space);
1253
+ if(cmdline && *cmdline)
1254
+ snprintf(tmp.cmdline, sizeof(tmp.cmdline), "%s", cmdline);
1255
+ pa = dictionary_set(ctx->process_actors, process_key, &tmp, sizeof(tmp));
1256
+ }
1257
+ pa->sockets++;
1258
+ if(!pa->ppid && n->ppid)
1259
+ pa->ppid = n->ppid;
1260
+ if(topology_process_name_is_unknown(pa->process) && !topology_process_name_is_unknown(process_name))
1261
+ snprintf(pa->process, sizeof(pa->process), "%s", process_name);
1262
+ if(!pa->cmdline[0] && cmdline && *cmdline)
1263
+ snprintf(pa->cmdline, sizeof(pa->cmdline), "%s", cmdline);
1264
+ if((!pa->local_ip[0] || topology_ip_is_unspecified(pa->local_ip)) && local_ip[0] && !topology_ip_is_unspecified(local_ip))
1265
+ snprintf(pa->local_ip, sizeof(pa->local_ip), "%s", local_ip);
1266
+
1267
+ bool service_candidate = (n->direction == SOCKET_DIRECTION_LISTEN ||
1268
+ n->direction == SOCKET_DIRECTION_INBOUND ||
1269
+ n->direction == SOCKET_DIRECTION_LOCAL_INBOUND);
1270
+ topology_register_endpoint_owner(ctx, n->net_ns_inode, n->local.protocol, local_ip, n->local.port, pa, service_candidate);
1271
+
1272
+ if(!remote_ip[0]) {
1273
+ if(n->direction == SOCKET_DIRECTION_LISTEN || n->direction == SOCKET_DIRECTION_LOCAL_INBOUND) {
1274
+ if(strcmp(local_ip, "*") == 0 || local_sockets_is_zero_address(&n->local)) {
1275
+ ctx->skipped_sockets++;
1276
+ return;
1277
+ }
1278
+ snprintf(remote_ip, sizeof(remote_ip), "%s", local_ip);
1279
+ remote_address_space = local_address_space;
1280
+ }
1281
+ else {
1282
+ ctx->skipped_sockets++;
1283
+ return;
1284
+ }
1285
+ }
1286
+
1287
+ if(topology_ip_is_unspecified(remote_ip)) {
1288
+ ctx->skipped_sockets++;
1289
+ return;
1290
+ }
1291
+
1292
+ 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);
1294
+ if(create_endpoint_actor) {
1295
+ char endpoint_actor_key[NV_TOPOLOGY_KEY_MAX];
1296
+ topology_actor_id_for_remote_endpoint(ctx, remote_ip, remote_address_space, endpoint_actor_key, sizeof(endpoint_actor_key));
1297
+ NV_REMOTE_ACTOR *ra = dictionary_get(ctx->remote_actors, endpoint_actor_key);
1298
+ if(!ra) {
1299
+ NV_REMOTE_ACTOR tmp = { 0 };
1300
+ snprintf(tmp.ip, sizeof(tmp.ip), "%s", remote_ip);
1301
+ snprintf(tmp.address_space, sizeof(tmp.address_space), "%s", remote_address_space);
1302
+ ra = dictionary_set(ctx->remote_actors, endpoint_actor_key, &tmp, sizeof(tmp));
1303
+ }
1304
+ ra->sockets++;
1305
+ }
1306
+
1307
+ const struct socket_endpoint *server_endpoint = NULL;
1308
+ uint16_t endpoint_port = n->remote.port;
1309
+ switch(n->direction) {
1310
+ case SOCKET_DIRECTION_LISTEN:
1311
+ case SOCKET_DIRECTION_INBOUND:
1312
+ case SOCKET_DIRECTION_LOCAL_INBOUND:
1313
+ server_endpoint = &n->local;
1314
+ endpoint_port = n->local.port;
1315
+ break;
1316
+
1317
+ case SOCKET_DIRECTION_OUTBOUND:
1318
+ case SOCKET_DIRECTION_LOCAL_OUTBOUND:
1319
+ server_endpoint = &n->remote;
1320
+ endpoint_port = n->remote.port;
1321
+ break;
1322
+
1323
+ default:
1324
+ break;
1325
+ }
1326
+
1327
+ char port_name[64] = "[unknown]";
1328
+ if(server_endpoint) {
1329
+ STRING *serv = system_servicenames_cache_lookup(sc, server_endpoint->port, server_endpoint->protocol);
1330
+ const char *tmp_name = string2str(serv);
1331
+ if(tmp_name && *tmp_name)
1332
+ snprintf(port_name, sizeof(port_name), "%s", tmp_name);
1333
+ }
1334
+
1335
+ char link_key[NV_TOPOLOGY_KEY_MAX];
1336
+ snprintf(link_key, sizeof(link_key), "pid=%d|uid=%u|ns=%llu|local=%s|remote=%s|proto=%u|dir=%u|state=%u|lport=%u|rport=%u",
1337
+ n->pid,
1338
+ (unsigned)n->uid,
1339
+ (unsigned long long)n->net_ns_inode,
1340
+ local_ip,
1341
+ remote_ip,
1342
+ (unsigned)n->local.protocol,
1343
+ (unsigned)n->direction,
1344
+ (unsigned)n->state,
1345
+ n->local.port,
1346
+ endpoint_port);
1347
+
1348
+ NV_TOPOLOGY_LINK *link = dictionary_get(ctx->links, link_key);
1349
+ if(!link) {
1350
+ NV_TOPOLOGY_LINK tmp = { 0 };
1351
+ tmp.pid = n->pid;
1352
+ tmp.ppid = n->ppid;
1353
+ tmp.uid = n->uid;
1354
+ tmp.net_ns_inode = n->net_ns_inode;
1355
+ tmp.local_port = n->local.port;
1356
+ tmp.remote_port = endpoint_port;
1357
+ tmp.peer_port = n->remote.port;
1358
+ tmp.protocol_id = n->local.protocol;
1359
+ tmp.direction_id = (uint8_t)n->direction;
1360
+ snprintf(tmp.process, sizeof(tmp.process), "%s", process_name);
1361
+ snprintf(tmp.username, sizeof(tmp.username), "%s", username);
1362
+ snprintf(tmp.namespace_type, sizeof(tmp.namespace_type), "%s", namespace_type);
1363
+ snprintf(tmp.protocol, sizeof(tmp.protocol), "%s", socket_protocol_name(n->local.protocol));
1364
+ snprintf(tmp.protocol_family, sizeof(tmp.protocol_family), "%s", socket_protocol_family_name(n));
1365
+ snprintf(tmp.direction, sizeof(tmp.direction), "%s", SOCKET_DIRECTION_2str(n->direction));
1366
+ snprintf(tmp.state, sizeof(tmp.state), "%s",
1367
+ n->local.protocol == IPPROTO_TCP ? TCP_STATE_2str(n->state) : "stateless");
1368
+ snprintf(tmp.local_ip, sizeof(tmp.local_ip), "%s", local_ip);
1369
+ snprintf(tmp.remote_ip, sizeof(tmp.remote_ip), "%s", remote_ip);
1370
+ snprintf(tmp.peer_ip, sizeof(tmp.peer_ip), "%s", remote_peer_ip);
1371
+ snprintf(tmp.local_address_space, sizeof(tmp.local_address_space), "%s", local_address_space);
1372
+ snprintf(tmp.remote_address_space, sizeof(tmp.remote_address_space), "%s", remote_address_space);
1373
+ snprintf(tmp.port_name, sizeof(tmp.port_name), "%s", port_name);
1374
+ if(cmdline && *cmdline)
1375
+ snprintf(tmp.cmdline, sizeof(tmp.cmdline), "%s", cmdline);
1376
+ link = dictionary_set(ctx->links, link_key, &tmp, sizeof(tmp));
1377
+ }
1378
+
1379
+ link->sockets++;
1380
+ link->retransmissions += n->info.tcp.tcpi_total_retrans;
1381
+ if(link->max_rtt_usec < n->info.tcp.tcpi_rtt)
1382
+ link->max_rtt_usec = n->info.tcp.tcpi_rtt;
1383
+ if(link->max_rcv_rtt_usec < n->info.tcp.tcpi_rcv_rtt)
1384
+ link->max_rcv_rtt_usec = n->info.tcp.tcpi_rcv_rtt;
1385
+}
1386
+
1387
+static void topology_context_destroy(NV_TOPOLOGY_CONTEXT *ctx) {
1388
+ if(!ctx)
1389
+ return;
1390
+
1391
+ if(ctx->links)
1392
+ dictionary_destroy(ctx->links);
1393
+ if(ctx->endpoint_owners_service_any_ns)
1394
+ dictionary_destroy(ctx->endpoint_owners_service_any_ns);
1395
+ if(ctx->endpoint_owners_service)
1396
+ dictionary_destroy(ctx->endpoint_owners_service);
1397
+ if(ctx->endpoint_owners_exact_any_ns)
1398
+ dictionary_destroy(ctx->endpoint_owners_exact_any_ns);
1399
+ if(ctx->endpoint_owners_exact)
1400
+ dictionary_destroy(ctx->endpoint_owners_exact);
1401
+ if(ctx->local_ips)
1402
+ dictionary_destroy(ctx->local_ips);
1403
+ if(ctx->remote_actors)
1404
+ dictionary_destroy(ctx->remote_actors);
1405
+ if(ctx->process_actors)
1406
+ dictionary_destroy(ctx->process_actors);
1407
+}
1408
+
1409
+static DICTIONARY *topology_build_process_socket_index(const NV_TOPOLOGY_CONTEXT *ctx) {
1410
+ if(!ctx || !ctx->links)
1411
+ return NULL;
1412
+
1413
+ DICTIONARY *index = dictionary_create_advanced(
1414
+ DICT_OPTION_SINGLE_THREADED | DICT_OPTION_DONT_OVERWRITE_VALUE | DICT_OPTION_FIXED_SIZE,
1415
+ NULL,
1416
+ sizeof(NV_PROCESS_SOCKET_ROWS));
1417
+ if(!index)
1418
+ return NULL;
1419
+
1420
+ NV_TOPOLOGY_LINK *link;
1421
+ dfe_start_read(ctx->links, link) {
1422
+ char process_actor_id[NV_TOPOLOGY_KEY_MAX];
1423
+ topology_actor_id_for_process(ctx, link->pid, link->uid, link->net_ns_inode, link->process, process_actor_id, sizeof(process_actor_id));
1424
+
1425
+ NV_PROCESS_SOCKET_ROWS *rows = dictionary_get(index, process_actor_id);
1426
+ if(!rows) {
1427
+ NV_PROCESS_SOCKET_ROWS tmp = { 0 };
1428
+ rows = dictionary_set(index, process_actor_id, &tmp, sizeof(tmp));
1429
+ }
1430
+
1431
+ if(!rows)
1432
+ continue;
1433
+
1434
+ NV_PROCESS_SOCKET_ROW *row = callocz(1, sizeof(*row));
1435
+ row->link = link;
1436
+
1437
+ if(rows->tail)
1438
+ rows->tail->next = row;
1439
+ else
1440
+ rows->head = row;
1441
+ rows->tail = row;
1442
+ }
1443
+ dfe_done(link);
1444
+
1445
+ return index;
1446
+}
1447
+
1448
+static void topology_destroy_process_socket_index(DICTIONARY *index) {
1449
+ if(!index)
1450
+ return;
1451
+
1452
+ NV_PROCESS_SOCKET_ROWS *rows;
1453
+ dfe_start_read(index, rows) {
1454
+ NV_PROCESS_SOCKET_ROW *row = rows->head;
1455
+ while(row) {
1456
+ NV_PROCESS_SOCKET_ROW *next = row->next;
1457
+ freez(row);
1458
+ row = next;
1459
+ }
1460
+ }
1461
+ dfe_done(rows);
1462
+
1463
+ dictionary_destroy(index);
1464
+}
1465
+
1466
+static bool topology_prepare_context(NV_TOPOLOGY_CONTEXT *ctx, usec_t now_ut, const NV_TOPOLOGY_OPTIONS *options) {
1467
+ if(!ctx)
1468
+ return false;
1469
+
1470
+ memset(ctx, 0, sizeof(*ctx));
1471
+ ctx->now_ut = now_ut;
1472
+ if(options)
1473
+ ctx->options = *options;
1474
+
1475
+ if(ctx->options.info_only)
1476
+ return true;
1477
+
1478
+ ctx->process_actors = dictionary_create_advanced(DICT_OPTION_SINGLE_THREADED | DICT_OPTION_DONT_OVERWRITE_VALUE | DICT_OPTION_FIXED_SIZE, NULL, sizeof(NV_PROCESS_ACTOR));
1479
+ ctx->remote_actors = dictionary_create_advanced(DICT_OPTION_SINGLE_THREADED | DICT_OPTION_DONT_OVERWRITE_VALUE | DICT_OPTION_FIXED_SIZE, NULL, sizeof(NV_REMOTE_ACTOR));
1480
+ ctx->local_ips = dictionary_create_advanced(DICT_OPTION_SINGLE_THREADED | DICT_OPTION_DONT_OVERWRITE_VALUE | DICT_OPTION_FIXED_SIZE, NULL, sizeof(NV_LOCAL_IP));
1481
+ ctx->endpoint_owners_exact = dictionary_create_advanced(DICT_OPTION_SINGLE_THREADED | DICT_OPTION_DONT_OVERWRITE_VALUE | DICT_OPTION_FIXED_SIZE, NULL, sizeof(NV_ENDPOINT_OWNER));
1482
+ ctx->endpoint_owners_exact_any_ns = dictionary_create_advanced(DICT_OPTION_SINGLE_THREADED | DICT_OPTION_DONT_OVERWRITE_VALUE | DICT_OPTION_FIXED_SIZE, NULL, sizeof(NV_ENDPOINT_OWNER));
1483
+ ctx->endpoint_owners_service = dictionary_create_advanced(DICT_OPTION_SINGLE_THREADED | DICT_OPTION_DONT_OVERWRITE_VALUE | DICT_OPTION_FIXED_SIZE, NULL, sizeof(NV_ENDPOINT_OWNER));
1484
+ ctx->endpoint_owners_service_any_ns = dictionary_create_advanced(DICT_OPTION_SINGLE_THREADED | DICT_OPTION_DONT_OVERWRITE_VALUE | DICT_OPTION_FIXED_SIZE, NULL, sizeof(NV_ENDPOINT_OWNER));
1485
+ ctx->links = dictionary_create_advanced(DICT_OPTION_SINGLE_THREADED | DICT_OPTION_DONT_OVERWRITE_VALUE | DICT_OPTION_FIXED_SIZE, NULL, sizeof(NV_TOPOLOGY_LINK));
1486
+
1487
+ if(!(ctx->process_actors && ctx->remote_actors && ctx->local_ips &&
1488
+ ctx->endpoint_owners_exact && ctx->endpoint_owners_exact_any_ns &&
1489
+ ctx->endpoint_owners_service && ctx->endpoint_owners_service_any_ns &&
1490
+ ctx->links))
1491
+ return false;
1492
+
1493
+ if(!os_hostname(ctx->hostname, sizeof(ctx->hostname), netdata_configured_host_prefix))
1494
+ snprintf(ctx->hostname, sizeof(ctx->hostname), "%s", "localhost");
1495
+
1496
+ const char *machine_guid = network_viewer_machine_guid();
1497
+ if(machine_guid)
1498
+ snprintf(ctx->machine_guid, sizeof(ctx->machine_guid), "%s", machine_guid);
1499
+
1500
+ LS_STATE ls = {
1501
+ .config = {
1502
+ .listening = ctx->options.sockets_listening,
1503
+ .local = ctx->options.sockets_local,
1504
+ .inbound = ctx->options.sockets_inbound,
1505
+ .outbound = ctx->options.sockets_outbound,
1506
+ .tcp4 = ctx->options.protocols_ipv4_tcp,
1507
+ .tcp6 = ctx->options.protocols_ipv6_tcp,
1508
+ .udp4 = ctx->options.protocols_ipv4_udp,
1509
+ .udp6 = ctx->options.protocols_ipv6_udp,
1510
+ .pid = true,
1511
+ .uid = true,
1512
+ .cmdline = true,
1513
+ .comm = true,
1514
+ .namespaces = true,
1515
+ .tcp_info = true,
1516
+ .max_errors = 10,
1517
+ .max_concurrent_namespaces = 5,
1518
+ .cb = local_sockets_cb_to_topology,
1519
+ .data = ctx,
1520
+ },
1521
+#if defined(LOCAL_SOCKETS_USE_SETNS)
1522
+ .spawn_server = spawn_srv,
1523
+#endif
1524
+ .stats = { 0 },
1525
+ .sockets_hashtable = { 0 },
1526
+ .local_ips_hashtable = { 0 },
1527
+ .listening_ports_hashtable = { 0 },
1528
+ };
1529
+
1530
+ local_sockets_process(&ls);
1531
+ return true;
1532
+}
1533
+
1534
+static void topology_render_state_init(NV_TOPOLOGY_RENDER_STATE *state, const NV_TOPOLOGY_CONTEXT *ctx) {
1535
+ if(!state)
1536
+ return;
1537
+
1538
+ memset(state, 0, sizeof(*state));
1539
+ if(!ctx)
1540
+ return;
1541
+
1542
+ state->process_actor_count = ctx->process_actors ? dictionary_entries(ctx->process_actors) : 0;
1543
+ state->socket_link_count = ctx->links ? dictionary_entries(ctx->links) : 0;
1544
+ state->local_ip_count = ctx->local_ips ? dictionary_entries(ctx->local_ips) : 0;
1545
+ topology_actor_id_for_host(ctx, state->host_actor_id, sizeof(state->host_actor_id));
1546
+}
1547
+
1548
+static void topology_finalize_response(const char *transaction, BUFFER *wb, time_t now_s) {
1549
+ buffer_json_member_add_time_t(wb, "expires", now_s + NETWORK_VIEWER_RESPONSE_UPDATE_EVERY);
1550
+ buffer_json_finalize(wb);
1551
+
1552
+ netdata_mutex_lock(&stdout_mutex);
1553
+ wb->response_code = HTTP_RESP_OK;
1554
+ wb->content_type = CT_APPLICATION_JSON;
1555
+ wb->expires = now_s + NETWORK_VIEWER_RESPONSE_UPDATE_EVERY;
1556
+ pluginsd_function_result_to_stdout(transaction, wb);
1557
+ netdata_mutex_unlock(&stdout_mutex);
1558
+}
1559
+
1560
+static void topology_write_response_metadata(BUFFER *wb) {
1561
+ buffer_json_member_add_uint64(wb, "status", HTTP_RESP_OK);
1562
+ buffer_json_member_add_string(wb, "type", "topology");
1563
+ buffer_json_member_add_time_t(wb, "update_every", NETWORK_VIEWER_RESPONSE_UPDATE_EVERY);
1564
+ buffer_json_member_add_boolean(wb, "has_history", false);
1565
+ buffer_json_member_add_string(wb, "help", NETWORK_TOPOLOGY_VIEWER_HELP);
1566
+ buffer_json_member_add_array(wb, "accepted_params");
1567
+ {
1568
+ buffer_json_add_array_item_string(wb, "info");
1569
+ buffer_json_add_array_item_string(wb, "processes");
1570
+ buffer_json_add_array_item_string(wb, "sockets");
1571
+ buffer_json_add_array_item_string(wb, "protocols");
1572
+ buffer_json_add_array_item_string(wb, "endpoints");
1573
+ }
1574
+ buffer_json_array_close(wb);
1575
+ buffer_json_member_add_array(wb, "required_params");
1576
+ {
1577
+ buffer_json_add_array_item_object(wb);
1578
+ {
1579
+ buffer_json_member_add_string(wb, "id", "processes");
1580
+ buffer_json_member_add_string(wb, "name", "Processes");
1581
+ buffer_json_member_add_string(wb, "help", "Group process actors by process name or by PID.");
1582
+ buffer_json_member_add_boolean(wb, "unique_view", true);
1583
+ buffer_json_member_add_string(wb, "type", "select");
1584
+ buffer_json_member_add_array(wb, "options");
1585
+ {
1586
+ buffer_json_add_array_item_object(wb);
1587
+ {
1588
+ buffer_json_member_add_string(wb, "id", "by_name");
1589
+ buffer_json_member_add_string(wb, "name", "Processes by Name");
1590
+ buffer_json_member_add_boolean(wb, "defaultSelected", true);
1591
+ }
1592
+ buffer_json_object_close(wb);
1593
+ buffer_json_add_array_item_object(wb);
1594
+ {
1595
+ buffer_json_member_add_string(wb, "id", "by_pid");
1596
+ buffer_json_member_add_string(wb, "name", "Processes by PID");
1597
+ }
1598
+ buffer_json_object_close(wb);
1599
+ }
1600
+ buffer_json_array_close(wb);
1601
+ }
1602
+ buffer_json_object_close(wb);
1603
+
1604
+ buffer_json_add_array_item_object(wb);
1605
+ {
1606
+ buffer_json_member_add_string(wb, "id", "sockets");
1607
+ buffer_json_member_add_string(wb, "name", "Sockets");
1608
+ buffer_json_member_add_string(wb, "help", "Select one or more socket directions.");
1609
+ buffer_json_member_add_string(wb, "type", "multiselect");
1610
+ buffer_json_member_add_array(wb, "options");
1611
+ {
1612
+ buffer_json_add_array_item_object(wb);
1613
+ {
1614
+ buffer_json_member_add_string(wb, "id", "listening");
1615
+ buffer_json_member_add_string(wb, "name", "Listening");
1616
+ }
1617
+ buffer_json_object_close(wb);
1618
+ buffer_json_add_array_item_object(wb);
1619
+ {
1620
+ buffer_json_member_add_string(wb, "id", "local");
1621
+ buffer_json_member_add_string(wb, "name", "Local");
1622
+ }
1623
+ buffer_json_object_close(wb);
1624
+ buffer_json_add_array_item_object(wb);
1625
+ {
1626
+ buffer_json_member_add_string(wb, "id", "inbound");
1627
+ buffer_json_member_add_string(wb, "name", "Inbound");
1628
+ buffer_json_member_add_boolean(wb, "defaultSelected", true);
1629
+ }
1630
+ buffer_json_object_close(wb);
1631
+ buffer_json_add_array_item_object(wb);
1632
+ {
1633
+ buffer_json_member_add_string(wb, "id", "outbound");
1634
+ buffer_json_member_add_string(wb, "name", "Outbound");
1635
+ buffer_json_member_add_boolean(wb, "defaultSelected", true);
1636
+ }
1637
+ buffer_json_object_close(wb);
1638
+ }
1639
+ buffer_json_array_close(wb);
1640
+ }
1641
+ buffer_json_object_close(wb);
1642
+
1643
+ buffer_json_add_array_item_object(wb);
1644
+ {
1645
+ buffer_json_member_add_string(wb, "id", "protocols");
1646
+ buffer_json_member_add_string(wb, "name", "Protocols");
1647
+ buffer_json_member_add_string(wb, "help", "Select one or more socket protocol families.");
1648
+ buffer_json_member_add_string(wb, "type", "multiselect");
1649
+ buffer_json_member_add_array(wb, "options");
1650
+ {
1651
+ buffer_json_add_array_item_object(wb);
1652
+ {
1653
+ buffer_json_member_add_string(wb, "id", "ipv4_tcp");
1654
+ buffer_json_member_add_string(wb, "name", "IPv4 TCP");
1655
+ buffer_json_member_add_boolean(wb, "defaultSelected", true);
1656
+ }
1657
+ buffer_json_object_close(wb);
1658
+ buffer_json_add_array_item_object(wb);
1659
+ {
1660
+ buffer_json_member_add_string(wb, "id", "ipv6_tcp");
1661
+ buffer_json_member_add_string(wb, "name", "IPv6 TCP");
1662
+ buffer_json_member_add_boolean(wb, "defaultSelected", true);
1663
+ }
1664
+ buffer_json_object_close(wb);
1665
+ buffer_json_add_array_item_object(wb);
1666
+ {
1667
+ buffer_json_member_add_string(wb, "id", "ipv4_udp");
1668
+ buffer_json_member_add_string(wb, "name", "IPv4 UDP");
1669
+ buffer_json_member_add_boolean(wb, "defaultSelected", true);
1670
+ }
1671
+ buffer_json_object_close(wb);
1672
+ buffer_json_add_array_item_object(wb);
1673
+ {
1674
+ buffer_json_member_add_string(wb, "id", "ipv6_udp");
1675
+ buffer_json_member_add_string(wb, "name", "IPv6 UDP");
1676
+ buffer_json_member_add_boolean(wb, "defaultSelected", true);
1677
+ }
1678
+ buffer_json_object_close(wb);
1679
+ }
1680
+ buffer_json_array_close(wb);
1681
+ }
1682
+ buffer_json_object_close(wb);
1683
+
1684
+ buffer_json_add_array_item_object(wb);
1685
+ {
1686
+ buffer_json_member_add_string(wb, "id", "endpoints");
1687
+ buffer_json_member_add_string(wb, "name", "Endpoints");
1688
+ buffer_json_member_add_string(wb, "help", "Keep non-private endpoints by IP until AS grouping is available.");
1689
+ buffer_json_member_add_boolean(wb, "unique_view", true);
1690
+ buffer_json_member_add_string(wb, "type", "select");
1691
+ buffer_json_member_add_array(wb, "options");
1692
+ {
1693
+ buffer_json_add_array_item_object(wb);
1694
+ {
1695
+ buffer_json_member_add_string(wb, "id", "by_ip");
1696
+ buffer_json_member_add_string(wb, "name", "Non-Private Endpoints by IP");
1697
+ buffer_json_member_add_boolean(wb, "defaultSelected", true);
1698
+ }
1699
+ buffer_json_object_close(wb);
1700
+ }
1701
+ buffer_json_array_close(wb);
1702
+ }
1703
+ buffer_json_object_close(wb);
1704
+ }
1705
+ buffer_json_array_close(wb);
1706
+}
1707
+
1708
+static void topology_write_presentation(BUFFER *wb) {
1709
+ buffer_json_member_add_object(wb, "presentation");
1710
+ {
1711
+ buffer_json_member_add_object(wb, "actor_types");
1712
+ {
1713
+ buffer_json_member_add_object(wb, "self");
1714
+ {
1715
+ buffer_json_member_add_string(wb, "label", "This host");
1716
+ buffer_json_member_add_string(wb, "color_slot", "self");
1717
+ buffer_json_member_add_boolean(wb, "border", true);
1718
+ buffer_json_member_add_boolean(wb, "size_by_links", true);
1719
+
1720
+ buffer_json_member_add_array(wb, "summary_fields");
1721
+ {
1722
+ buffer_json_add_array_item_object(wb);
1723
+ buffer_json_member_add_string(wb, "key", "hostname");
1724
+ buffer_json_member_add_string(wb, "label", "Hostname");
1725
+ buffer_json_member_add_array(wb, "sources");
1726
+ buffer_json_add_array_item_string(wb, "attributes.hostname");
1727
+ buffer_json_array_close(wb);
1728
+ buffer_json_object_close(wb);
1729
+
1730
+ buffer_json_add_array_item_object(wb);
1731
+ buffer_json_member_add_string(wb, "key", "local_ip_count");
1732
+ buffer_json_member_add_string(wb, "label", "Local IPs");
1733
+ buffer_json_member_add_array(wb, "sources");
1734
+ buffer_json_add_array_item_string(wb, "attributes.local_ip_count");
1735
+ buffer_json_array_close(wb);
1736
+ buffer_json_object_close(wb);
1737
+
1738
+ buffer_json_add_array_item_object(wb);
1739
+ buffer_json_member_add_string(wb, "key", "observed_sockets");
1740
+ buffer_json_member_add_string(wb, "label", "Sockets");
1741
+ buffer_json_member_add_array(wb, "sources");
1742
+ buffer_json_add_array_item_string(wb, "attributes.observed_sockets");
1743
+ buffer_json_array_close(wb);
1744
+ buffer_json_object_close(wb);
1745
+ }
1746
+ buffer_json_array_close(wb);
1747
+
1748
+ buffer_json_member_add_object(wb, "tables");
1749
+ {
1750
+ buffer_json_member_add_object(wb, "links");
1751
+ {
1752
+ buffer_json_member_add_string(wb, "label", "Connections");
1753
+ buffer_json_member_add_string(wb, "source", "links");
1754
+ buffer_json_member_add_array(wb, "columns");
1755
+ {
1756
+ buffer_json_add_array_item_object(wb);
1757
+ buffer_json_member_add_string(wb, "key", "remoteLabel");
1758
+ buffer_json_member_add_string(wb, "label", "Remote");
1759
+ buffer_json_member_add_string(wb, "type", "actor_link");
1760
+ buffer_json_object_close(wb);
1761
+
1762
+ buffer_json_add_array_item_object(wb);
1763
+ buffer_json_member_add_string(wb, "key", "protocol");
1764
+ buffer_json_member_add_string(wb, "label", "Protocol");
1765
+ buffer_json_object_close(wb);
1766
+
1767
+ buffer_json_add_array_item_object(wb);
1768
+ buffer_json_member_add_string(wb, "key", "direction");
1769
+ buffer_json_member_add_string(wb, "label", "Direction");
1770
+ buffer_json_object_close(wb);
1771
+ }
1772
+ buffer_json_array_close(wb);
1773
+ }
1774
+ buffer_json_object_close(wb);
1775
+ }
1776
+ buffer_json_object_close(wb);
1777
+
1778
+ buffer_json_member_add_array(wb, "modal_tabs");
1779
+ {
1780
+ buffer_json_add_array_item_object(wb);
1781
+ buffer_json_member_add_string(wb, "id", "info");
1782
+ buffer_json_member_add_string(wb, "label", "Info");
1783
+ buffer_json_object_close(wb);
1784
+ }
1785
+ buffer_json_array_close(wb);
1786
+ }
1787
+ buffer_json_object_close(wb);
1788
+
1789
+ buffer_json_member_add_object(wb, "process");
1790
+ {
1791
+ buffer_json_member_add_string(wb, "label", "Process");
1792
+ buffer_json_member_add_string(wb, "color_slot", "primary");
1793
+ buffer_json_member_add_boolean(wb, "border", true);
1794
+ buffer_json_member_add_boolean(wb, "size_by_links", true);
1795
+ buffer_json_member_add_boolean(wb, "show_port_bullets", true);
1796
+
1797
+ buffer_json_member_add_array(wb, "summary_fields");
1798
+ {
1799
+ buffer_json_add_array_item_object(wb);
1800
+ buffer_json_member_add_string(wb, "key", "display_name");
1801
+ buffer_json_member_add_string(wb, "label", "Process");
1802
+ buffer_json_member_add_array(wb, "sources");
1803
+ buffer_json_add_array_item_string(wb, "attributes.display_name");
1804
+ buffer_json_array_close(wb);
1805
+ buffer_json_object_close(wb);
1806
+
1807
+ buffer_json_add_array_item_object(wb);
1808
+ buffer_json_member_add_string(wb, "key", "cmdline");
1809
+ buffer_json_member_add_string(wb, "label", "Command");
1810
+ buffer_json_member_add_array(wb, "sources");
1811
+ buffer_json_add_array_item_string(wb, "attributes.cmdline");
1812
+ buffer_json_array_close(wb);
1813
+ buffer_json_object_close(wb);
1814
+
1815
+ buffer_json_add_array_item_object(wb);
1816
+ buffer_json_member_add_string(wb, "key", "socket_count");
1817
+ buffer_json_member_add_string(wb, "label", "Sockets");
1818
+ buffer_json_member_add_array(wb, "sources");
1819
+ buffer_json_add_array_item_string(wb, "attributes.socket_count");
1820
+ buffer_json_array_close(wb);
1821
+ buffer_json_object_close(wb);
1822
+
1823
+ buffer_json_add_array_item_object(wb);
1824
+ buffer_json_member_add_string(wb, "key", "local_ip");
1825
+ buffer_json_member_add_string(wb, "label", "Local IP");
1826
+ buffer_json_member_add_array(wb, "sources");
1827
+ buffer_json_add_array_item_string(wb, "attributes.local_ip");
1828
+ buffer_json_array_close(wb);
1829
+ buffer_json_object_close(wb);
1830
+
1831
+ buffer_json_add_array_item_object(wb);
1832
+ buffer_json_member_add_string(wb, "key", "user");
1833
+ buffer_json_member_add_string(wb, "label", "User");
1834
+ buffer_json_member_add_array(wb, "sources");
1835
+ buffer_json_add_array_item_string(wb, "labels.user");
1836
+ buffer_json_array_close(wb);
1837
+ buffer_json_object_close(wb);
1838
+ }
1839
+ buffer_json_array_close(wb);
1840
+
1841
+ buffer_json_member_add_object(wb, "tables");
1842
+ {
1843
+ buffer_json_member_add_object(wb, "sockets");
1844
+ {
1845
+ buffer_json_member_add_string(wb, "label", "Sockets");
1846
+ buffer_json_member_add_string(wb, "source", "data");
1847
+ buffer_json_member_add_boolean(wb, "bullet_source", true);
1848
+ buffer_json_member_add_uint64(wb, "order", 0);
1849
+ buffer_json_member_add_array(wb, "columns");
1850
+ {
1851
+ buffer_json_add_array_item_object(wb);
1852
+ buffer_json_member_add_string(wb, "key", "remote");
1853
+ buffer_json_member_add_string(wb, "label", "Remote");
1854
+ buffer_json_object_close(wb);
1855
+
1856
+ buffer_json_add_array_item_object(wb);
1857
+ buffer_json_member_add_string(wb, "key", "protocol");
1858
+ buffer_json_member_add_string(wb, "label", "Protocol");
1859
+ buffer_json_member_add_string(wb, "type", "badge");
1860
+ buffer_json_object_close(wb);
1861
+
1862
+ buffer_json_add_array_item_object(wb);
1863
+ buffer_json_member_add_string(wb, "key", "direction");
1864
+ buffer_json_member_add_string(wb, "label", "Direction");
1865
+ buffer_json_member_add_string(wb, "type", "badge");
1866
+ buffer_json_object_close(wb);
1867
+
1868
+ buffer_json_add_array_item_object(wb);
1869
+ buffer_json_member_add_string(wb, "key", "state");
1870
+ buffer_json_member_add_string(wb, "label", "State");
1871
+ buffer_json_member_add_string(wb, "type", "badge");
1872
+ buffer_json_object_close(wb);
1873
+ }
1874
+ buffer_json_array_close(wb);
1875
+ }
1876
+ buffer_json_object_close(wb);
1877
+
1878
+ buffer_json_member_add_object(wb, "links");
1879
+ {
1880
+ buffer_json_member_add_string(wb, "label", "Connections");
1881
+ buffer_json_member_add_string(wb, "source", "links");
1882
+ buffer_json_member_add_uint64(wb, "order", 1);
1883
+ buffer_json_member_add_array(wb, "columns");
1884
+ {
1885
+ buffer_json_add_array_item_object(wb);
1886
+ buffer_json_member_add_string(wb, "key", "remoteLabel");
1887
+ buffer_json_member_add_string(wb, "label", "Remote");
1888
+ buffer_json_member_add_string(wb, "type", "actor_link");
1889
+ buffer_json_object_close(wb);
1890
+
1891
+ buffer_json_add_array_item_object(wb);
1892
+ buffer_json_member_add_string(wb, "key", "protocol");
1893
+ buffer_json_member_add_string(wb, "label", "Protocol");
1894
+ buffer_json_object_close(wb);
1895
+
1896
+ buffer_json_add_array_item_object(wb);
1897
+ buffer_json_member_add_string(wb, "key", "direction");
1898
+ buffer_json_member_add_string(wb, "label", "Direction");
1899
+ buffer_json_object_close(wb);
1900
+
1901
+ buffer_json_add_array_item_object(wb);
1902
+ buffer_json_member_add_string(wb, "key", "state");
1903
+ buffer_json_member_add_string(wb, "label", "State");
1904
+ buffer_json_object_close(wb);
1905
+ }
1906
+ buffer_json_array_close(wb);
1907
+ }
1908
+ buffer_json_object_close(wb);
1909
+ }
1910
+ buffer_json_object_close(wb);
1911
+
1912
+ buffer_json_member_add_array(wb, "modal_tabs");
1913
+ {
1914
+ buffer_json_add_array_item_object(wb);
1915
+ buffer_json_member_add_string(wb, "id", "info");
1916
+ buffer_json_member_add_string(wb, "label", "Info");
1917
+ buffer_json_object_close(wb);
1918
+ }
1919
+ buffer_json_array_close(wb);
1920
+ }
1921
+ buffer_json_object_close(wb);
1922
+
1923
+ buffer_json_member_add_object(wb, "endpoint");
1924
+ {
1925
+ buffer_json_member_add_string(wb, "label", "Endpoint");
1926
+ buffer_json_member_add_string(wb, "color_slot", "derived");
1927
+ buffer_json_member_add_boolean(wb, "border", true);
1928
+
1929
+ buffer_json_member_add_array(wb, "summary_fields");
1930
+ {
1931
+ buffer_json_add_array_item_object(wb);
1932
+ buffer_json_member_add_string(wb, "key", "display_name");
1933
+ buffer_json_member_add_string(wb, "label", "IP Address");
1934
+ buffer_json_member_add_array(wb, "sources");
1935
+ buffer_json_add_array_item_string(wb, "attributes.display_name");
1936
+ buffer_json_add_array_item_string(wb, "match.ip_addresses.0");
1937
+ buffer_json_array_close(wb);
1938
+ buffer_json_object_close(wb);
1939
+
1940
+ buffer_json_add_array_item_object(wb);
1941
+ buffer_json_member_add_string(wb, "key", "socket_count");
1942
+ buffer_json_member_add_string(wb, "label", "Sockets");
1943
+ buffer_json_member_add_array(wb, "sources");
1944
+ buffer_json_add_array_item_string(wb, "attributes.socket_count");
1945
+ buffer_json_array_close(wb);
1946
+ buffer_json_object_close(wb);
1947
+
1948
+ buffer_json_add_array_item_object(wb);
1949
+ buffer_json_member_add_string(wb, "key", "address_space");
1950
+ buffer_json_member_add_string(wb, "label", "Address Space");
1951
+ buffer_json_member_add_array(wb, "sources");
1952
+ buffer_json_add_array_item_string(wb, "labels.address_space");
1953
+ buffer_json_array_close(wb);
1954
+ buffer_json_object_close(wb);
1955
+ }
1956
+ buffer_json_array_close(wb);
1957
+
1958
+ buffer_json_member_add_object(wb, "tables");
1959
+ {
1960
+ buffer_json_member_add_object(wb, "links");
1961
+ {
1962
+ buffer_json_member_add_string(wb, "label", "Connections");
1963
+ buffer_json_member_add_string(wb, "source", "links");
1964
+ buffer_json_member_add_array(wb, "columns");
1965
+ {
1966
+ buffer_json_add_array_item_object(wb);
1967
+ buffer_json_member_add_string(wb, "key", "remoteLabel");
1968
+ buffer_json_member_add_string(wb, "label", "Remote");
1969
+ buffer_json_member_add_string(wb, "type", "actor_link");
1970
+ buffer_json_object_close(wb);
1971
+
1972
+ buffer_json_add_array_item_object(wb);
1973
+ buffer_json_member_add_string(wb, "key", "protocol");
1974
+ buffer_json_member_add_string(wb, "label", "Protocol");
1975
+ buffer_json_object_close(wb);
1976
+
1977
+ buffer_json_add_array_item_object(wb);
1978
+ buffer_json_member_add_string(wb, "key", "direction");
1979
+ buffer_json_member_add_string(wb, "label", "Direction");
1980
+ buffer_json_object_close(wb);
1981
+ }
1982
+ buffer_json_array_close(wb);
1983
+ }
1984
+ buffer_json_object_close(wb);
1985
+ }
1986
+ buffer_json_object_close(wb);
1987
+
1988
+ buffer_json_member_add_array(wb, "modal_tabs");
1989
+ {
1990
+ buffer_json_add_array_item_object(wb);
1991
+ buffer_json_member_add_string(wb, "id", "info");
1992
+ buffer_json_member_add_string(wb, "label", "Info");
1993
+ buffer_json_object_close(wb);
1994
+ }
1995
+ buffer_json_array_close(wb);
1996
+ }
1997
+ buffer_json_object_close(wb);
1998
+ }
1999
+ buffer_json_object_close(wb);
2000
+
2001
+ buffer_json_member_add_object(wb, "link_types");
2002
+ {
2003
+ buffer_json_member_add_object(wb, "ownership");
2004
+ {
2005
+ buffer_json_member_add_string(wb, "label", "Ownership");
2006
+ buffer_json_member_add_string(wb, "color_slot", "muted");
2007
+ buffer_json_member_add_boolean(wb, "dash", true);
2008
+ }
2009
+ buffer_json_object_close(wb);
2010
+
2011
+ buffer_json_member_add_object(wb, "socket");
2012
+ {
2013
+ buffer_json_member_add_string(wb, "label", "Socket");
2014
+ buffer_json_member_add_string(wb, "color_slot", "primary");
2015
+ buffer_json_member_add_double(wb, "width", 1.5);
2016
+ }
2017
+ buffer_json_object_close(wb);
2018
+ }
2019
+ buffer_json_object_close(wb);
2020
+
2021
+ buffer_json_member_add_array(wb, "port_fields");
2022
+ {
2023
+ buffer_json_add_array_item_object(wb);
2024
+ buffer_json_member_add_string(wb, "key", "type");
2025
+ buffer_json_member_add_string(wb, "label", "Type");
2026
+ buffer_json_object_close(wb);
2027
+ }
2028
+ buffer_json_array_close(wb);
2029
+
2030
+ buffer_json_member_add_object(wb, "port_types");
2031
+ {
2032
+ buffer_json_member_add_object(wb, "topology");
2033
+ {
2034
+ buffer_json_member_add_string(wb, "label", "Socket");
2035
+ buffer_json_member_add_string(wb, "color_slot", "primary");
2036
+ buffer_json_member_add_double(wb, "opacity", 1.0);
2037
+ }
2038
+ buffer_json_object_close(wb);
2039
+ }
2040
+ buffer_json_object_close(wb);
2041
+
2042
+ buffer_json_member_add_object(wb, "legend");
2043
+ {
2044
+ buffer_json_member_add_array(wb, "actors");
2045
+ {
2046
+ buffer_json_add_array_item_object(wb);
2047
+ buffer_json_member_add_string(wb, "type", "self");
2048
+ buffer_json_member_add_string(wb, "label", "This host");
2049
+ buffer_json_object_close(wb);
2050
+
2051
+ buffer_json_add_array_item_object(wb);
2052
+ buffer_json_member_add_string(wb, "type", "process");
2053
+ buffer_json_member_add_string(wb, "label", "Process");
2054
+ buffer_json_object_close(wb);
2055
+
2056
+ buffer_json_add_array_item_object(wb);
2057
+ buffer_json_member_add_string(wb, "type", "endpoint");
2058
+ buffer_json_member_add_string(wb, "label", "Endpoint");
2059
+ buffer_json_object_close(wb);
2060
+ }
2061
+ buffer_json_array_close(wb);
2062
+
2063
+ buffer_json_member_add_array(wb, "links");
2064
+ {
2065
+ buffer_json_add_array_item_object(wb);
2066
+ buffer_json_member_add_string(wb, "type", "ownership");
2067
+ buffer_json_member_add_string(wb, "label", "Ownership");
2068
+ buffer_json_object_close(wb);
2069
+
2070
+ buffer_json_add_array_item_object(wb);
2071
+ buffer_json_member_add_string(wb, "type", "socket");
2072
+ buffer_json_member_add_string(wb, "label", "Socket");
2073
+ buffer_json_object_close(wb);
2074
+ }
2075
+ buffer_json_array_close(wb);
2076
+
2077
+ buffer_json_member_add_array(wb, "ports");
2078
+ {
2079
+ buffer_json_add_array_item_object(wb);
2080
+ buffer_json_member_add_string(wb, "type", "topology");
2081
+ buffer_json_member_add_string(wb, "label", "Socket");
2082
+ buffer_json_object_close(wb);
2083
+ }
2084
+ buffer_json_array_close(wb);
2085
+ }
2086
+ buffer_json_object_close(wb);
2087
+
2088
+ buffer_json_member_add_string(wb, "actor_click_behavior", "highlight_connections");
2089
}
247
- buffer_json_array_close(wb);
2090
+ buffer_json_object_close(wb);
2091
}
2092
250
-static void populate_aggregated_key(const LOCAL_SOCKET *nn) {
251
- LOCAL_SOCKET *n = (LOCAL_SOCKET *)nn;
252
-
253
- n->network_viewer.count = 1;
254
-
255
- n->network_viewer.aggregated_key.pid = n->pid;
256
- n->network_viewer.aggregated_key.uid = n->uid;
257
- n->network_viewer.aggregated_key.direction = n->direction;
258
- n->network_viewer.aggregated_key.net_ns_inode = n->net_ns_inode;
259
- n->network_viewer.aggregated_key.state = n->state;
2093
+static void topology_write_actors(BUFFER *wb, const NV_TOPOLOGY_CONTEXT *ctx, NV_TOPOLOGY_RENDER_STATE *state) {
2094
+ DICTIONARY *process_socket_index = topology_build_process_socket_index(ctx);
2095
261
- switch(n->direction) {
262
- case SOCKET_DIRECTION_INBOUND:
263
- case SOCKET_DIRECTION_LOCAL_INBOUND:
264
- case SOCKET_DIRECTION_LISTEN:
265
- n->network_viewer.aggregated_key.server = n->local;
266
- break;
2096
+ buffer_json_member_add_array(wb, "actors");
2097
+ {
2098
+ buffer_json_add_array_item_object(wb);
2099
+ {
2100
+ buffer_json_member_add_string(wb, "actor_id", state->host_actor_id);
2101
+ buffer_json_member_add_string(wb, "actor_type", "self");
2102
+ buffer_json_member_add_string(wb, "layer", NETWORK_TOPOLOGY_LAYER);
2103
+ buffer_json_member_add_string(wb, "source", NETWORK_TOPOLOGY_SOURCE);
2104
+ topology_add_host_match(wb, ctx);
2105
268
- case SOCKET_DIRECTION_OUTBOUND:
269
- case SOCKET_DIRECTION_LOCAL_OUTBOUND:
270
- n->network_viewer.aggregated_key.server = n->remote;
271
- break;
2106
+ buffer_json_member_add_object(wb, "attributes");
2107
+ {
2108
+ buffer_json_member_add_string(wb, "hostname", ctx->hostname);
2109
+ buffer_json_member_add_uint64(wb, "local_ip_count", state->local_ip_count);
2110
+ buffer_json_member_add_uint64(wb, "observed_sockets", ctx->sockets_total);
2111
+ buffer_json_member_add_string(wb, "display_name", ctx->hostname);
2112
+ buffer_json_member_add_string(wb, "actor_class", "self");
2113
+ }
2114
+ buffer_json_object_close(wb);
2115
273
- case SOCKET_DIRECTION_NONE:
274
- break;
275
- }
2116
+ buffer_json_member_add_object(wb, "labels");
2117
+ {
2118
+ buffer_json_member_add_string(wb, "hostname", ctx->hostname);
2119
+ if(ctx->machine_guid[0])
2120
+ buffer_json_member_add_string(wb, "netdata_machine_guid", ctx->machine_guid);
2121
+ buffer_json_member_add_string(wb, "source", NETWORK_TOPOLOGY_SOURCE);
2122
+ buffer_json_member_add_string(wb, "display_name", ctx->hostname);
2123
+ buffer_json_member_add_string(wb, "actor_class", "self");
2124
+ }
2125
+ buffer_json_object_close(wb);
2126
+ }
2127
+ buffer_json_object_close(wb);
2128
277
- n->network_viewer.aggregated_key.local_address_space = local_sockets_address_space(&n->local);
278
- n->network_viewer.aggregated_key.remote_address_space = local_sockets_address_space(&n->remote);
279
-}
2129
+ NV_PROCESS_ACTOR *pa;
2130
+ dfe_start_read(ctx->process_actors, pa) {
2131
+ char process_actor_id[NV_TOPOLOGY_KEY_MAX];
2132
+ char process_display_name[NV_TOPOLOGY_KEY_MAX];
2133
+ topology_actor_id_for_process(ctx, pa->pid, pa->uid, pa->net_ns_inode, pa->process, process_actor_id, sizeof(process_actor_id));
2134
+ topology_process_display_name(ctx, pa->process, pa->pid, process_display_name, sizeof(process_display_name));
2135
+ buffer_json_add_array_item_object(wb);
2136
+ {
2137
+ buffer_json_member_add_string(wb, "actor_id", process_actor_id);
2138
+ buffer_json_member_add_string(wb, "actor_type", "process");
2139
+ buffer_json_member_add_string(wb, "layer", NETWORK_TOPOLOGY_LAYER);
2140
+ buffer_json_member_add_string(wb, "source", NETWORK_TOPOLOGY_SOURCE);
2141
+ topology_add_process_match(wb, ctx, pa);
2142
281
-static void local_sockets_cb_to_json(LS_STATE *ls, const LOCAL_SOCKET *n, void *data) {
282
- struct sockets_stats *st = data;
283
- populate_aggregated_key(n);
284
- local_socket_to_json_array(st, n, ls->proc_self_net_ns_inode, false);
285
-}
2143
+ buffer_json_member_add_object(wb, "parent_match");
2144
+ {
2145
+ if(ctx->machine_guid[0])
2146
+ buffer_json_member_add_string(wb, "netdata_machine_guid", ctx->machine_guid);
2147
+ topology_add_single_item_string_array(wb, "hostnames", ctx->hostname);
2148
+ }
2149
+ buffer_json_object_close(wb);
2150
287
-#define KEEP_THE_BIGGER(a, b) (a) = ((a) < (b)) ? (b) : (a)
288
-#define KEEP_THE_SMALLER(a, b) (a) = ((a) > (b)) ? (b) : (a)
289
-#define SUM_THEM_ALL(a, b) (a) += (b)
290
-#define OR_THEM_ALL(a, b) (a) |= (b)
2151
+ buffer_json_member_add_object(wb, "attributes");
2152
+ {
2153
+ if(ctx->options.processes_by_pid) {
2154
+ buffer_json_member_add_uint64(wb, "pid", pa->pid);
2155
+ buffer_json_member_add_uint64(wb, "ppid", pa->ppid);
2156
+ buffer_json_member_add_uint64(wb, "uid", pa->uid);
2157
+ buffer_json_member_add_uint64(wb, "net_ns_inode", pa->net_ns_inode);
2158
+ }
2159
+ buffer_json_member_add_uint64(wb, "socket_count", pa->sockets);
2160
+ buffer_json_member_add_string(wb, "local_ip", pa->local_ip);
2161
+ buffer_json_member_add_string(wb, "local_address_space", pa->local_address_space);
2162
+ buffer_json_member_add_string(wb, "display_name", process_display_name);
2163
+ buffer_json_member_add_string(wb, "actor_class", "process");
2164
+ if(pa->cmdline[0])
2165
+ buffer_json_member_add_string(wb, "cmdline", pa->cmdline);
2166
+ }
2167
+ buffer_json_object_close(wb);
2168
292
-static void local_sockets_cb_to_aggregation(LS_STATE *ls __maybe_unused, const LOCAL_SOCKET *n, void *data) {
293
- SIMPLE_HASHTABLE_AGGREGATED_SOCKETS *ht = data;
2169
+ buffer_json_member_add_object(wb, "labels");
2170
+ {
2171
+ buffer_json_member_add_string(wb, "process", pa->process);
2172
+ buffer_json_member_add_string(wb, "user", pa->username);
2173
+ buffer_json_member_add_string(wb, "namespace", pa->namespace_type);
2174
+ buffer_json_member_add_string(wb, "local_address_space", pa->local_address_space);
2175
+ buffer_json_member_add_string(wb, "display_name", process_display_name);
2176
+ buffer_json_member_add_string(wb, "actor_class", "process");
2177
+ }
2178
+ buffer_json_object_close(wb);
2179
295
- populate_aggregated_key(n);
296
- XXH64_hash_t hash = XXH3_64bits(&n->network_viewer.aggregated_key, sizeof(n->network_viewer.aggregated_key));
297
- SIMPLE_HASHTABLE_SLOT_AGGREGATED_SOCKETS *sl = simple_hashtable_get_slot_AGGREGATED_SOCKETS(ht, hash, (LOCAL_SOCKET *)n, true);
298
- LOCAL_SOCKET *t = SIMPLE_HASHTABLE_SLOT_DATA(sl);
299
- if(t) {
300
- t->network_viewer.count++;
2180
+ buffer_json_member_add_object(wb, "tables");
2181
+ {
2182
+ buffer_json_member_add_array(wb, "sockets");
2183
+ {
2184
+ NV_PROCESS_SOCKET_ROWS *rows = process_socket_index ? dictionary_get(process_socket_index, process_actor_id) : NULL;
2185
+ for(NV_PROCESS_SOCKET_ROW *row = rows ? rows->head : NULL; row; row = row->next) {
2186
+ char remote_endpoint[128];
2187
+ topology_format_ip_port(row->link->remote_ip, row->link->remote_port, remote_endpoint, sizeof(remote_endpoint));
2188
+ buffer_json_add_array_item_object(wb);
2189
+ buffer_json_member_add_string(wb, "remote", remote_endpoint);
2190
+ buffer_json_member_add_string(wb, "protocol", row->link->protocol);
2191
+ buffer_json_member_add_string(wb, "direction", row->link->direction);
2192
+ buffer_json_member_add_string(wb, "state", row->link->state);
2193
+ buffer_json_object_close(wb);
2194
+ }
2195
+ }
2196
+ buffer_json_array_close(wb);
2197
+ }
2198
+ buffer_json_object_close(wb);
2199
+ }
2200
+ buffer_json_object_close(wb);
2201
+ }
2202
+ dfe_done(pa);
2203
302
- KEEP_THE_BIGGER(t->timer, n->timer);
303
- KEEP_THE_BIGGER(t->retransmits, n->retransmits);
304
- KEEP_THE_SMALLER(t->expires, n->expires);
305
- KEEP_THE_BIGGER(t->rqueue, n->rqueue);
306
- KEEP_THE_BIGGER(t->wqueue, n->wqueue);
2204
+ NV_REMOTE_ACTOR *ra;
2205
+ dfe_start_read(ctx->remote_actors, ra) {
2206
+ bool endpoint_is_self = topology_ip_belongs_to_self(ctx, ra->ip, ra->address_space);
2207
308
- // The current number of consecutive retransmissions that have occurred for the most recently transmitted segment.
309
- SUM_THEM_ALL(t->info.tcp.tcpi_retransmits, n->info.tcp.tcpi_retransmits);
2208
+ char endpoint_actor_id[NV_TOPOLOGY_KEY_MAX];
2209
+ topology_actor_id_for_remote_endpoint(ctx, ra->ip, ra->address_space, endpoint_actor_id, sizeof(endpoint_actor_id));
2210
+ state->endpoint_actor_count++;
2211
+ buffer_json_add_array_item_object(wb);
2212
+ {
2213
+ buffer_json_member_add_string(wb, "actor_id", endpoint_actor_id);
2214
+ buffer_json_member_add_string(wb, "actor_type", "endpoint");
2215
+ buffer_json_member_add_string(wb, "layer", NETWORK_TOPOLOGY_LAYER);
2216
+ buffer_json_member_add_string(wb, "source", NETWORK_TOPOLOGY_SOURCE);
2217
+ topology_add_remote_match(wb, ra->ip);
2218
+
2219
+ if(endpoint_is_self) {
2220
+ buffer_json_member_add_object(wb, "parent_match");
2221
+ {
2222
+ if(ctx->machine_guid[0])
2223
+ buffer_json_member_add_string(wb, "netdata_machine_guid", ctx->machine_guid);
2224
+ topology_add_single_item_string_array(wb, "hostnames", ctx->hostname);
2225
+ }
2226
+ buffer_json_object_close(wb);
2227
+ }
2228
311
- // The total number of retransmissions that have occurred for the entire connection since it was established.
312
- SUM_THEM_ALL(t->info.tcp.tcpi_total_retrans, n->info.tcp.tcpi_total_retrans);
2229
+ buffer_json_member_add_object(wb, "attributes");
2230
+ {
2231
+ buffer_json_member_add_uint64(wb, "socket_count", ra->sockets);
2232
+ buffer_json_member_add_uint64(wb, "local_socket_count", endpoint_is_self ? ra->sockets : 0);
2233
+ buffer_json_member_add_uint64(wb, "remote_socket_count", endpoint_is_self ? 0 : ra->sockets);
2234
+ buffer_json_member_add_string(wb, "endpoint_scope", endpoint_is_self ? "self" : "remote");
2235
+ buffer_json_member_add_string(wb, "display_name", ra->ip);
2236
+ buffer_json_member_add_string(wb, "actor_class", "endpoint");
2237
+ }
2238
+ buffer_json_object_close(wb);
2239
314
- // The total number of segments that have been retransmitted since the connection was established.
315
- SUM_THEM_ALL(t->info.tcp.tcpi_retrans, n->info.tcp.tcpi_retrans);
2240
+ buffer_json_member_add_object(wb, "labels");
2241
+ {
2242
+ buffer_json_member_add_string(wb, "address_space", ra->address_space);
2243
+ buffer_json_member_add_string(wb, "endpoint_scope", endpoint_is_self ? "self" : "remote");
2244
+ buffer_json_member_add_string(wb, "display_name", ra->ip);
2245
+ buffer_json_member_add_string(wb, "actor_class", "endpoint");
2246
+ }
2247
+ buffer_json_object_close(wb);
2248
+ }
2249
+ buffer_json_object_close(wb);
2250
+ }
2251
+ dfe_done(ra);
2252
+ }
2253
+ buffer_json_array_close(wb);
2254
317
- // The number of keepalive probes sent
318
- SUM_THEM_ALL(t->info.tcp.tcpi_probes, n->info.tcp.tcpi_probes);
2255
+ topology_destroy_process_socket_index(process_socket_index);
2256
+}
2257
320
- // The number of times the retransmission timeout has been backed off.
321
- SUM_THEM_ALL(t->info.tcp.tcpi_backoff, n->info.tcp.tcpi_backoff);
2258
+static void topology_write_links_and_stats(BUFFER *wb, const NV_TOPOLOGY_CONTEXT *ctx, NV_TOPOLOGY_RENDER_STATE *state) {
2259
+ buffer_json_member_add_array(wb, "links");
2260
+ {
2261
+ DICTIONARY *process_parent_ns_lookup = NULL;
2262
+ DICTIONARY *process_parent_any_lookup = NULL;
2263
+ DICTIONARY *ppid_cache = NULL;
2264
+ if(ctx->options.processes_by_pid) {
2265
+ process_parent_ns_lookup = dictionary_create_advanced(
2266
+ DICT_OPTION_SINGLE_THREADED | DICT_OPTION_DONT_OVERWRITE_VALUE | DICT_OPTION_FIXED_SIZE,
2267
+ NULL, sizeof(NV_ENDPOINT_OWNER));
2268
+ process_parent_any_lookup = dictionary_create_advanced(
2269
+ DICT_OPTION_SINGLE_THREADED | DICT_OPTION_DONT_OVERWRITE_VALUE | DICT_OPTION_FIXED_SIZE,
2270
+ NULL, sizeof(NV_ENDPOINT_OWNER));
2271
+ ppid_cache = dictionary_create_advanced(
2272
+ DICT_OPTION_SINGLE_THREADED | DICT_OPTION_DONT_OVERWRITE_VALUE | DICT_OPTION_FIXED_SIZE,
2273
+ NULL, sizeof(NV_PPID_CACHE_ENTRY));
2274
+
2275
+ if(process_parent_ns_lookup && process_parent_any_lookup) {
2276
+ char parent_key_ns[NV_TOPOLOGY_KEY_MAX];
2277
+ char parent_key_any[NV_TOPOLOGY_KEY_MAX];
2278
+ char pid_key[64];
2279
+ NV_PROCESS_ACTOR *pa_index;
2280
+ dfe_start_read(ctx->process_actors, pa_index) {
2281
+ if(!pa_index->pid)
2282
+ continue;
2283
+
2284
+ NV_ENDPOINT_OWNER owner = {
2285
+ .pid = pa_index->pid,
2286
+ .ppid = pa_index->ppid,
2287
+ .uid = pa_index->uid,
2288
+ .net_ns_inode = pa_index->net_ns_inode,
2289
+ };
2290
+ snprintf(owner.process, sizeof(owner.process), "%s", pa_index->process);
2291
+
2292
+ topology_process_parent_lookup_key(parent_key_ns, sizeof(parent_key_ns),
2293
+ (uint64_t)pa_index->pid, pa_index->net_ns_inode, true);
2294
+ dictionary_set(process_parent_ns_lookup, parent_key_ns, &owner, sizeof(owner));
2295
+
2296
+ topology_process_parent_lookup_key(parent_key_any, sizeof(parent_key_any),
2297
+ (uint64_t)pa_index->pid, 0, false);
2298
+ dictionary_set(process_parent_any_lookup, parent_key_any, &owner, sizeof(owner));
2299
+
2300
+ if(ppid_cache) {
2301
+ NV_PPID_CACHE_ENTRY ppid_entry = { .ppid = pa_index->ppid };
2302
+ topology_pid_lookup_key(pid_key, sizeof(pid_key), (uint64_t)pa_index->pid);
2303
+ dictionary_set(ppid_cache, pid_key, &ppid_entry, sizeof(ppid_entry));
2304
+ }
2305
+ }
2306
+ dfe_done(pa_index);
2307
+ }
2308
+ }
2309
323
- // A bitmask representing the TCP options currently enabled for the connection, such as SACK and Timestamps.
324
- OR_THEM_ALL(t->info.tcp.tcpi_options, n->info.tcp.tcpi_options);
2310
+ NV_PROCESS_ACTOR *pa;
2311
+ dfe_start_read(ctx->process_actors, pa) {
2312
+ bool src_is_process = false;
2313
+ NV_ENDPOINT_OWNER *parent_pa = NULL;
2314
+ NV_ENDPOINT_OWNER parent_resolved = { 0 };
2315
+ const char *ownership_kind = "self_root";
2316
+ char src_actor_id[NV_TOPOLOGY_KEY_MAX];
2317
+ char src_display_name[NV_TOPOLOGY_KEY_MAX];
2318
+ char process_actor_id[NV_TOPOLOGY_KEY_MAX];
2319
+ char process_display_name[NV_TOPOLOGY_KEY_MAX];
2320
+ char ownership_display_name[NV_TOPOLOGY_KEY_MAX * 2 + 7];
2321
+ topology_actor_id_for_process(ctx, pa->pid, pa->uid, pa->net_ns_inode, pa->process, process_actor_id, sizeof(process_actor_id));
2322
+ topology_process_display_name(ctx, pa->process, pa->pid, process_display_name, sizeof(process_display_name));
2323
+
2324
+ if(ctx->options.processes_by_pid &&
2325
+ process_parent_ns_lookup && process_parent_any_lookup &&
2326
+ pa->ppid && pa->ppid != pa->pid) {
2327
+ parent_pa = topology_find_process_parent_actor(pa->ppid, pa->net_ns_inode,
2328
+ process_parent_ns_lookup,
2329
+ process_parent_any_lookup,
2330
+ ppid_cache);
2331
+
2332
+ if(parent_pa) {
2333
+ src_is_process = true;
2334
+ ownership_kind = "process_parent";
2335
+ parent_resolved = *parent_pa;
2336
+ parent_pa = &parent_resolved;
2337
+ topology_actor_id_for_process(ctx, parent_pa->pid, parent_pa->uid, parent_pa->net_ns_inode, parent_pa->process, src_actor_id, sizeof(src_actor_id));
2338
+ topology_process_display_name(ctx, parent_pa->process, parent_pa->pid, src_display_name, sizeof(src_display_name));
2339
+ }
2340
+ }
2341
326
- // The send window scale value used for this connection
327
- KEEP_THE_SMALLER(t->info.tcp.tcpi_snd_wscale, n->info.tcp.tcpi_snd_wscale);
2342
+ if(!src_is_process) {
2343
+ snprintf(src_actor_id, sizeof(src_actor_id), "%s", state->host_actor_id);
2344
+ snprintf(src_display_name, sizeof(src_display_name), "%s", ctx->hostname);
2345
+ }
2346
329
- // The receive window scale value used for this connection
330
- KEEP_THE_SMALLER(t->info.tcp.tcpi_rcv_wscale, n->info.tcp.tcpi_rcv_wscale);
2347
+ snprintf(ownership_display_name, sizeof(ownership_display_name), "%s owns %s", src_display_name, process_display_name);
2348
+ state->ownership_link_count++;
2349
332
- // Retransmission timeout in milliseconds
333
- KEEP_THE_SMALLER(t->info.tcp.tcpi_rto, n->info.tcp.tcpi_rto);
2350
+ buffer_json_add_array_item_object(wb);
2351
+ {
2352
+ buffer_json_member_add_string(wb, "layer", NETWORK_TOPOLOGY_LAYER);
2353
+ buffer_json_member_add_string(wb, "protocol", "ownership");
2354
+ buffer_json_member_add_string(wb, "link_type", "ownership");
2355
+ buffer_json_member_add_string(wb, "direction", "contains");
2356
+ buffer_json_member_add_string(wb, "state", "active");
2357
+ buffer_json_member_add_string(wb, "src_actor_id", src_actor_id);
2358
+ buffer_json_member_add_string(wb, "dst_actor_id", process_actor_id);
2359
+ buffer_json_member_add_datetime_rfc3339(wb, "discovered_at", ctx->now_ut, true);
2360
+ buffer_json_member_add_datetime_rfc3339(wb, "last_seen", ctx->now_ut, true);
2361
+
2362
+ buffer_json_member_add_object(wb, "src");
2363
+ {
2364
+ if(src_is_process) {
2365
+ topology_add_process_identity_match(wb, ctx, parent_pa->pid, parent_pa->uid, parent_pa->net_ns_inode, parent_pa->process);
2366
+
2367
+ buffer_json_member_add_object(wb, "attributes");
2368
+ {
2369
+ buffer_json_member_add_string(wb, "actor_type", "process");
2370
+ if(ctx->options.processes_by_pid) {
2371
+ buffer_json_member_add_uint64(wb, "pid", parent_pa->pid);
2372
+ buffer_json_member_add_uint64(wb, "ppid", parent_pa->ppid);
2373
+ buffer_json_member_add_uint64(wb, "uid", parent_pa->uid);
2374
+ buffer_json_member_add_uint64(wb, "net_ns_inode", parent_pa->net_ns_inode);
2375
+ }
2376
+ buffer_json_member_add_string(wb, "process", parent_pa->process);
2377
+ buffer_json_member_add_string(wb, "display_name", src_display_name);
2378
+ }
2379
+ buffer_json_object_close(wb);
2380
+ }
2381
+ else {
2382
+ topology_add_host_match(wb, ctx);
2383
+
2384
+ buffer_json_member_add_object(wb, "attributes");
2385
+ {
2386
+ buffer_json_member_add_string(wb, "actor_type", "self");
2387
+ buffer_json_member_add_string(wb, "display_name", ctx->hostname);
2388
+ }
2389
+ buffer_json_object_close(wb);
2390
+ }
2391
+ }
2392
+ buffer_json_object_close(wb);
2393
335
- // The delayed acknowledgement timeout in milliseconds.
336
- KEEP_THE_SMALLER(t->info.tcp.tcpi_ato, n->info.tcp.tcpi_ato);
2394
+ buffer_json_member_add_object(wb, "dst");
2395
+ {
2396
+ topology_add_process_match(wb, ctx, pa);
2397
338
- // The maximum segment size for sending.
339
- KEEP_THE_SMALLER(t->info.tcp.tcpi_snd_mss, n->info.tcp.tcpi_snd_mss);
2398
+ buffer_json_member_add_object(wb, "attributes");
2399
+ {
2400
+ buffer_json_member_add_string(wb, "actor_type", "process");
2401
+ if(ctx->options.processes_by_pid) {
2402
+ buffer_json_member_add_uint64(wb, "pid", pa->pid);
2403
+ buffer_json_member_add_uint64(wb, "ppid", pa->ppid);
2404
+ buffer_json_member_add_uint64(wb, "uid", pa->uid);
2405
+ buffer_json_member_add_uint64(wb, "net_ns_inode", pa->net_ns_inode);
2406
+ }
2407
+ buffer_json_member_add_string(wb, "process", pa->process);
2408
+ buffer_json_member_add_string(wb, "display_name", process_display_name);
2409
+ }
2410
+ buffer_json_object_close(wb);
2411
+ }
2412
+ buffer_json_object_close(wb);
2413
341
- // The maximum segment size for receiving.
342
- KEEP_THE_SMALLER(t->info.tcp.tcpi_rcv_mss, n->info.tcp.tcpi_rcv_mss);
2414
+ buffer_json_member_add_object(wb, "metrics");
2415
+ {
2416
+ buffer_json_member_add_uint64(wb, "socket_count", pa->sockets);
2417
+ buffer_json_member_add_string(wb, "display_name", ownership_display_name);
2418
+ }
2419
+ buffer_json_object_close(wb);
2420
344
- // The number of unacknowledged segments
345
- SUM_THEM_ALL(t->info.tcp.tcpi_unacked, n->info.tcp.tcpi_unacked);
2421
+ buffer_json_member_add_object(wb, "labels");
2422
+ {
2423
+ buffer_json_member_add_string(wb, "link_class", "ownership");
2424
+ buffer_json_member_add_string(wb, "render_intent", "dark");
2425
+ buffer_json_member_add_string(wb, "ownership_kind", ownership_kind);
2426
+ buffer_json_member_add_string(wb, "display_name", ownership_display_name);
2427
+ }
2428
+ buffer_json_object_close(wb);
2429
+ }
2430
+ buffer_json_object_close(wb);
2431
+ }
2432
+ dfe_done(pa);
2433
+
2434
+ if(process_parent_ns_lookup)
2435
+ dictionary_destroy(process_parent_ns_lookup);
2436
+ if(process_parent_any_lookup)
2437
+ dictionary_destroy(process_parent_any_lookup);
2438
+ if(ppid_cache)
2439
+ dictionary_destroy(ppid_cache);
2440
+
2441
+ NV_TOPOLOGY_LINK *link;
2442
+ dfe_start_read(ctx->links, link) {
2443
+ char process_actor_id[NV_TOPOLOGY_KEY_MAX];
2444
+ char dst_actor_id[NV_TOPOLOGY_KEY_MAX];
2445
+ char endpoint_actor_id[NV_TOPOLOGY_KEY_MAX];
2446
+ char local_bind_port[128];
2447
+ char remote_endpoint_port[128];
2448
+ char process_display_name[NV_TOPOLOGY_KEY_MAX];
2449
+ char dst_process_display_name[NV_TOPOLOGY_KEY_MAX];
2450
+ char dst_process_port_name[64] = "";
2451
+ char link_display_name[NV_TOPOLOGY_KEY_MAX * 2 + 256 + 7];
2452
+ bool remote_is_self = topology_ip_belongs_to_self(ctx, link->remote_ip, link->remote_address_space);
2453
+ bool dst_is_process = false;
2454
+ bool dst_local_peer_unresolved = false;
2455
+ uint64_t dst_pid = link->pid;
2456
+ uint64_t dst_ppid = link->ppid;
2457
+ uint64_t dst_uid = link->uid;
2458
+ uint64_t dst_net_ns_inode = link->net_ns_inode;
2459
+ const char *dst_process_name = link->process;
2460
+ uint16_t dst_process_port = 0;
2461
+
2462
+ topology_actor_id_for_process(ctx, link->pid, link->uid, link->net_ns_inode, link->process, process_actor_id, sizeof(process_actor_id));
2463
+ topology_actor_id_for_remote_endpoint(ctx, link->remote_ip, link->remote_address_space, endpoint_actor_id, sizeof(endpoint_actor_id));
2464
+ snprintf(local_bind_port, sizeof(local_bind_port), "%u", link->local_port);
2465
+ topology_format_ip_port(link->remote_ip, link->remote_port, remote_endpoint_port, sizeof(remote_endpoint_port));
2466
+ topology_process_display_name(ctx, link->process, link->pid, process_display_name, sizeof(process_display_name));
2467
+
2468
+ if(remote_is_self && link->direction_id != SOCKET_DIRECTION_LISTEN) {
2469
+ const char *peer_ip = link->peer_ip[0] ? link->peer_ip : link->remote_ip;
2470
+ bool allow_service_fallback = true;
2471
+ NV_ENDPOINT_OWNER *owner = topology_lookup_endpoint_owner(ctx, link->net_ns_inode, link->protocol_id, peer_ip, link->peer_port, allow_service_fallback);
2472
+
2473
+ if(owner) {
2474
+ dst_pid = owner->pid;
2475
+ dst_ppid = owner->ppid;
2476
+ dst_uid = owner->uid;
2477
+ dst_net_ns_inode = owner->net_ns_inode;
2478
+ dst_process_name = owner->process;
2479
+ dst_process_port = link->peer_port;
2480
+ }
2481
+ else {
2482
+ dst_local_peer_unresolved = (link->direction_id != SOCKET_DIRECTION_LISTEN);
2483
+ dst_process_port = (link->direction_id == SOCKET_DIRECTION_LISTEN) ? link->local_port : (link->peer_port ? link->peer_port : link->remote_port);
2484
+ }
2485
347
- // The number of segments that have been selectively acknowledged
348
- SUM_THEM_ALL(t->info.tcp.tcpi_sacked, n->info.tcp.tcpi_sacked);
2486
+ dst_is_process = true;
2487
+ topology_actor_id_for_process(ctx, dst_pid, dst_uid, dst_net_ns_inode, dst_process_name, dst_actor_id, sizeof(dst_actor_id));
2488
+ topology_process_display_name(ctx, dst_process_name, dst_pid, dst_process_display_name, sizeof(dst_process_display_name));
2489
+ if(dst_process_port)
2490
+ snprintf(dst_process_port_name, sizeof(dst_process_port_name), "%u", dst_process_port);
2491
+ else
2492
+ snprintf(dst_process_port_name, sizeof(dst_process_port_name), "unknown");
2493
350
- // The number of segments that have been selectively acknowledged
351
- SUM_THEM_ALL(t->info.tcp.tcpi_sacked, n->info.tcp.tcpi_sacked);
2494
+ snprintf(link_display_name, sizeof(link_display_name), "%s:%s -> %s:%s",
2495
+ process_display_name, local_bind_port, dst_process_display_name, dst_process_port_name);
2496
+ }
2497
+ else {
2498
+ snprintf(dst_actor_id, sizeof(dst_actor_id), "%s", endpoint_actor_id);
2499
+ snprintf(link_display_name, sizeof(link_display_name), "%s:%s -> %s",
2500
+ process_display_name, local_bind_port, remote_endpoint_port);
2501
+ }
2502
353
- // The number of lost segments.
354
- SUM_THEM_ALL(t->info.tcp.tcpi_lost, n->info.tcp.tcpi_lost);
2503
+ buffer_json_add_array_item_object(wb);
2504
+ {
2505
+ buffer_json_member_add_string(wb, "layer", NETWORK_TOPOLOGY_LAYER);
2506
+ buffer_json_member_add_string(wb, "protocol", link->protocol);
2507
+ buffer_json_member_add_string(wb, "link_type", "socket");
2508
+ buffer_json_member_add_string(wb, "direction", link->direction);
2509
+ buffer_json_member_add_string(wb, "state", link->state);
2510
+ buffer_json_member_add_string(wb, "src_actor_id", process_actor_id);
2511
+ buffer_json_member_add_string(wb, "dst_actor_id", dst_actor_id);
2512
+ buffer_json_member_add_datetime_rfc3339(wb, "discovered_at", ctx->now_ut, true);
2513
+ buffer_json_member_add_datetime_rfc3339(wb, "last_seen", ctx->now_ut, true);
2514
+
2515
+ buffer_json_member_add_object(wb, "src");
2516
+ {
2517
+ buffer_json_member_add_object(wb, "match");
2518
+ {
2519
+ if(ctx->machine_guid[0])
2520
+ buffer_json_member_add_string(wb, "netdata_machine_guid", ctx->machine_guid);
2521
+ topology_add_single_item_string_array(wb, "hostnames", ctx->hostname);
2522
+ topology_add_single_item_string_array(wb, "ip_addresses", link->local_ip);
2523
+ }
2524
+ buffer_json_object_close(wb);
2525
356
- // The number of forward acknowledgment segments.
357
- SUM_THEM_ALL(t->info.tcp.tcpi_fackets, n->info.tcp.tcpi_fackets);
2526
+ buffer_json_member_add_object(wb, "attributes");
2527
+ {
2528
+ buffer_json_member_add_string(wb, "actor_type", "process");
2529
+ if(ctx->options.processes_by_pid) {
2530
+ buffer_json_member_add_uint64(wb, "pid", link->pid);
2531
+ buffer_json_member_add_uint64(wb, "ppid", link->ppid);
2532
+ buffer_json_member_add_uint64(wb, "uid", link->uid);
2533
+ buffer_json_member_add_uint64(wb, "net_ns_inode", link->net_ns_inode);
2534
+ }
2535
+ buffer_json_member_add_string(wb, "process", link->process);
2536
+ buffer_json_member_add_string(wb, "user", link->username);
2537
+ buffer_json_member_add_string(wb, "namespace", link->namespace_type);
2538
+ buffer_json_member_add_string(wb, "address_space", link->local_address_space);
2539
+ buffer_json_member_add_uint64(wb, "port", link->local_port);
2540
+ buffer_json_member_add_string(wb, "port_name", local_bind_port);
2541
+ buffer_json_member_add_string(wb, "bind_ip", link->local_ip);
2542
+ buffer_json_member_add_string(wb, "service_name", link->port_name);
2543
+ buffer_json_member_add_string(wb, "display_name", process_display_name);
2544
+ buffer_json_member_add_string(wb, "protocol_family", link->protocol_family);
2545
+ if(link->cmdline[0])
2546
+ buffer_json_member_add_string(wb, "cmdline", link->cmdline);
2547
+ }
2548
+ buffer_json_object_close(wb);
2549
+ }
2550
+ buffer_json_object_close(wb);
2551
359
- // The time in milliseconds since the last data was sent.
360
- KEEP_THE_SMALLER(t->info.tcp.tcpi_last_data_sent, n->info.tcp.tcpi_last_data_sent);
2552
+ buffer_json_member_add_object(wb, "dst");
2553
+ {
2554
+ if(dst_is_process)
2555
+ topology_add_process_identity_match(wb, ctx, dst_pid, dst_uid, dst_net_ns_inode, dst_process_name);
2556
+ else
2557
+ topology_add_remote_match(wb, link->remote_ip);
2558
362
- // The time in milliseconds since the last acknowledgment was sent (not tracked in Linux, hence often zero).
363
- KEEP_THE_SMALLER(t->info.tcp.tcpi_last_ack_sent, n->info.tcp.tcpi_last_ack_sent);
2559
+ buffer_json_member_add_object(wb, "attributes");
2560
+ {
2561
+ if(dst_is_process) {
2562
+ buffer_json_member_add_string(wb, "actor_type", "process");
2563
+ if(ctx->options.processes_by_pid) {
2564
+ buffer_json_member_add_uint64(wb, "pid", dst_pid);
2565
+ buffer_json_member_add_uint64(wb, "ppid", dst_ppid);
2566
+ buffer_json_member_add_uint64(wb, "uid", dst_uid);
2567
+ buffer_json_member_add_uint64(wb, "net_ns_inode", dst_net_ns_inode);
2568
+ }
2569
+ buffer_json_member_add_string(wb, "process", dst_process_name);
2570
+ buffer_json_member_add_string(wb, "address_space", "self");
2571
+ if(dst_process_port) {
2572
+ buffer_json_member_add_uint64(wb, "port", dst_process_port);
2573
+ buffer_json_member_add_string(wb, "port_name", dst_process_port_name);
2574
+ }
2575
+ buffer_json_member_add_string(wb, "display_name", dst_process_display_name);
2576
+ if(dst_local_peer_unresolved)
2577
+ buffer_json_member_add_boolean(wb, "unresolved_local_peer", true);
2578
+ }
2579
+ else {
2580
+ buffer_json_member_add_string(wb, "actor_type", "endpoint");
2581
+ buffer_json_member_add_string(wb, "address_space", link->remote_address_space);
2582
+ buffer_json_member_add_uint64(wb, "port", link->remote_port);
2583
+ buffer_json_member_add_string(wb, "port_name", remote_endpoint_port);
2584
+ buffer_json_member_add_string(wb, "display_name", link->remote_ip);
2585
+ }
2586
+ }
2587
+ buffer_json_object_close(wb);
2588
+ }
2589
+ buffer_json_object_close(wb);
2590
365
- // The time in milliseconds since the last data was received.
366
- KEEP_THE_SMALLER(t->info.tcp.tcpi_last_data_recv, n->info.tcp.tcpi_last_data_recv);
2591
+ buffer_json_member_add_object(wb, "metrics");
2592
+ {
2593
+ buffer_json_member_add_uint64(wb, "socket_count", link->sockets);
2594
+ buffer_json_member_add_uint64(wb, "retransmissions", link->retransmissions);
2595
+ buffer_json_member_add_double(wb, "rtt_ms_max", (double)link->max_rtt_usec / (double)USEC_PER_MS);
2596
+ buffer_json_member_add_double(wb, "recv_rtt_ms_max", (double)link->max_rcv_rtt_usec / (double)USEC_PER_MS);
2597
+ buffer_json_member_add_string(wb, "display_name", link_display_name);
2598
+ }
2599
+ buffer_json_object_close(wb);
2600
368
- // The time in milliseconds since the last acknowledgment was received.
369
- KEEP_THE_SMALLER(t->info.tcp.tcpi_last_ack_recv, n->info.tcp.tcpi_last_ack_recv);
2601
+ buffer_json_member_add_object(wb, "labels");
2602
+ {
2603
+ buffer_json_member_add_string(wb, "protocol", link->protocol);
2604
+ buffer_json_member_add_string(wb, "direction", link->direction);
2605
+ buffer_json_member_add_string(wb, "state", link->state);
2606
+ buffer_json_member_add_string(wb, "process", link->process);
2607
+ buffer_json_member_add_string(wb, "user", link->username);
2608
+ buffer_json_member_add_string(wb, "namespace", link->namespace_type);
2609
+ buffer_json_member_add_string(wb, "protocol_family", link->protocol_family);
2610
+ buffer_json_member_add_string(wb, "local_address_space", link->local_address_space);
2611
+ buffer_json_member_add_string(wb, "remote_address_space", link->remote_address_space);
2612
+ buffer_json_member_add_string(wb, "port_name", local_bind_port);
2613
+ buffer_json_member_add_string(wb, "bind_ip", link->local_ip);
2614
+ buffer_json_member_add_string(wb, "service_name", link->port_name);
2615
+ buffer_json_member_add_string(wb, "link_class", "socket");
2616
+ buffer_json_member_add_string(wb, "socket_kind", link->direction);
2617
+ buffer_json_member_add_string(wb, "render_intent", "socket");
2618
+ buffer_json_member_add_string(wb, "display_name", link_display_name);
2619
+ }
2620
+ buffer_json_object_close(wb);
2621
+ }
2622
+ buffer_json_object_close(wb);
2623
+ }
2624
+ dfe_done(link);
2625
+ }
2626
+ buffer_json_array_close(wb);
2627
371
- // The path MTU for this connection
372
- KEEP_THE_SMALLER(t->info.tcp.tcpi_pmtu, n->info.tcp.tcpi_pmtu);
2628
+ buffer_json_member_add_object(wb, "stats");
2629
+ {
2630
+ size_t links_total = state->socket_link_count + state->ownership_link_count;
2631
+ buffer_json_member_add_string(wb, "processes_mode", ctx->options.processes_by_pid ? "by_pid" : "by_name");
2632
+ buffer_json_member_add_boolean(wb, "sockets_listening", ctx->options.sockets_listening);
2633
+ buffer_json_member_add_boolean(wb, "sockets_local", ctx->options.sockets_local);
2634
+ buffer_json_member_add_boolean(wb, "sockets_inbound", ctx->options.sockets_inbound);
2635
+ buffer_json_member_add_boolean(wb, "sockets_outbound", ctx->options.sockets_outbound);
2636
+ buffer_json_member_add_string(wb, "endpoints_mode_selected", "by_ip");
2637
+ buffer_json_member_add_string(wb, "endpoints_mode_effective", "by_ip");
2638
+ buffer_json_member_add_boolean(wb, "protocol_ipv4_tcp", ctx->options.protocols_ipv4_tcp);
2639
+ buffer_json_member_add_boolean(wb, "protocol_ipv6_tcp", ctx->options.protocols_ipv6_tcp);
2640
+ buffer_json_member_add_boolean(wb, "protocol_ipv4_udp", ctx->options.protocols_ipv4_udp);
2641
+ buffer_json_member_add_boolean(wb, "protocol_ipv6_udp", ctx->options.protocols_ipv6_udp);
2642
+ buffer_json_member_add_uint64(wb, "sockets_total", ctx->sockets_total);
2643
+ buffer_json_member_add_uint64(wb, "sockets_without_remote_endpoint", ctx->skipped_sockets);
2644
+ buffer_json_member_add_uint64(wb, "local_process_actors", state->process_actor_count);
2645
+ buffer_json_member_add_uint64(wb, "endpoint_actors", state->endpoint_actor_count);
2646
+ buffer_json_member_add_uint64(wb, "socket_links", state->socket_link_count);
2647
+ buffer_json_member_add_uint64(wb, "ownership_links", state->ownership_link_count);
2648
+ buffer_json_member_add_uint64(wb, "links_total", links_total);
2649
+ }
2650
+ buffer_json_object_close(wb);
2651
+}
2652
374
- // The slow start threshold for receiving
375
- KEEP_THE_SMALLER(t->info.tcp.tcpi_rcv_ssthresh, n->info.tcp.tcpi_rcv_ssthresh);
2653
+static void topology_write_data(BUFFER *wb, const NV_TOPOLOGY_CONTEXT *ctx) {
2654
+ if(!ctx || ctx->options.info_only || !ctx->process_actors || !ctx->remote_actors || !ctx->local_ips || !ctx->links)
2655
+ return;
2656
377
- // The slow start threshold for sending
378
- KEEP_THE_SMALLER(t->info.tcp.tcpi_snd_ssthresh, n->info.tcp.tcpi_snd_ssthresh);
2657
+ NV_TOPOLOGY_RENDER_STATE state;
2658
+ topology_render_state_init(&state, ctx);
2659
380
- // The round trip time in milliseconds
381
- KEEP_THE_BIGGER(t->info.tcp.tcpi_rtt, n->info.tcp.tcpi_rtt);
2660
+ buffer_json_member_add_object(wb, "data");
2661
+ {
2662
+ buffer_json_member_add_string(wb, "schema_version", NETWORK_TOPOLOGY_SCHEMA_VERSION);
2663
+ buffer_json_member_add_string(wb, "source", NETWORK_TOPOLOGY_SOURCE);
2664
+ buffer_json_member_add_string(wb, "layer", NETWORK_TOPOLOGY_LAYER);
2665
+ buffer_json_member_add_string(wb, "agent_id", ctx->machine_guid[0] ? ctx->machine_guid : ctx->hostname);
2666
+ buffer_json_member_add_datetime_rfc3339(wb, "collected_at", ctx->now_ut, true);
2667
+
2668
+ topology_write_actors(wb, ctx, &state);
2669
+ topology_write_links_and_stats(wb, ctx, &state);
2670
+ }
2671
+ buffer_json_object_close(wb);
2672
+}
2673
383
- // The round trip time variance in milliseconds.
384
- KEEP_THE_BIGGER(t->info.tcp.tcpi_rttvar, n->info.tcp.tcpi_rttvar);
2674
+static void network_viewer_topology_function(
2675
+ const char *transaction, char *function, usec_t *stop_monotonic_ut __maybe_unused,
2676
+ bool *cancelled __maybe_unused, BUFFER *payload __maybe_unused, HTTP_ACCESS access __maybe_unused,
2677
+ const char *source __maybe_unused, void *data __maybe_unused) {
2678
386
- // The size of the sending congestion window.
387
- KEEP_THE_SMALLER(t->info.tcp.tcpi_snd_cwnd, n->info.tcp.tcpi_snd_cwnd);
2679
+ time_t now_s = now_realtime_sec();
2680
+ usec_t now_ut = now_realtime_usec();
2681
+ NV_TOPOLOGY_OPTIONS options = { 0 };
2682
+ topology_parse_options(function, &options);
2683
389
- // The maximum segment size that could be advertised.
390
- KEEP_THE_BIGGER(t->info.tcp.tcpi_advmss, n->info.tcp.tcpi_advmss);
2684
+ CLEAN_BUFFER *wb = buffer_create(0, NULL);
2685
+ buffer_flush(wb);
2686
+ wb->content_type = CT_APPLICATION_JSON;
2687
+ buffer_json_initialize(wb, "\"", "\"", 0, true, BUFFER_JSON_OPTIONS_MINIFY);
2688
392
- // The reordering metric
393
- KEEP_THE_SMALLER(t->info.tcp.tcpi_reordering, n->info.tcp.tcpi_reordering);
2689
+ topology_write_response_metadata(wb);
2690
+ topology_write_presentation(wb);
2691
395
- // The receive round trip time in milliseconds.
396
- KEEP_THE_BIGGER(t->info.tcp.tcpi_rcv_rtt, n->info.tcp.tcpi_rcv_rtt);
2692
+ NV_TOPOLOGY_CONTEXT ctx;
2693
+ bool ctx_ready = topology_prepare_context(&ctx, now_ut, &options);
2694
+ if(ctx_ready)
2695
+ topology_write_data(wb, &ctx);
2696
398
- // The available space in the receive buffer.
399
- KEEP_THE_SMALLER(t->info.tcp.tcpi_rcv_space, n->info.tcp.tcpi_rcv_space);
400
- }
401
- else {
402
- t = mallocz(sizeof(*t));
403
- memcpy(t, n, sizeof(*t));
404
- t->cmdline = string_dup(t->cmdline);
405
- simple_hashtable_set_slot_AGGREGATED_SOCKETS(ht, sl, hash, t);
406
- }
2697
+ topology_context_destroy(&ctx);
2698
+ topology_finalize_response(transaction, wb, now_s);
2699
}
2700
2701
static int local_sockets_compar(const void *a, const void *b) {
2721
2722
buffer_json_member_add_uint64(wb, "status", HTTP_RESP_OK);
2723
buffer_json_member_add_string(wb, "type", "table");
432
- buffer_json_member_add_time_t(wb, "update_every", 5);
2724
+ buffer_json_member_add_time_t(wb, "update_every", NETWORK_VIEWER_RESPONSE_UPDATE_EVERY);
2725
buffer_json_member_add_boolean(wb, "has_history", false);
2726
buffer_json_member_add_string(wb, "help", NETWORK_CONNECTIONS_VIEWER_HELP);
2727
2767
size_t num_words = quoted_strings_splitter_whitespace(function_copy, words, 1024);
2768
for(size_t i = 1; i < num_words ;i++) {
2769
char *param = get_word(words, num_words, i);
2770
+ if(!param || !*param) continue;
2771
if(strcmp(param, "sockets:aggregated") == 0) {
2772
aggregated = true;
2773
}
2838
local_sockets_process(&ls);
2839
2840
if(aggregated) {
548
- LOCAL_SOCKET *array[ht.used];
2841
size_t added = 0;
2842
uint64_t proc_self_net_ns_inode = ls.proc_self_net_ns_inode;
551
- for(SIMPLE_HASHTABLE_SLOT_AGGREGATED_SOCKETS *sl = simple_hashtable_first_read_only_AGGREGATED_SOCKETS(&ht);
552
- sl;
553
- sl = simple_hashtable_next_read_only_AGGREGATED_SOCKETS(&ht, sl)) {
554
- LOCAL_SOCKET *n = SIMPLE_HASHTABLE_SLOT_DATA(sl);
555
- if(!n || added >= ht.used) continue;
2843
557
- array[added++] = n;
558
- }
2844
+ if(ht.used) {
2845
+ LOCAL_SOCKET **array = mallocz(ht.used * sizeof(LOCAL_SOCKET *));
2846
+ for(SIMPLE_HASHTABLE_SLOT_AGGREGATED_SOCKETS *sl = simple_hashtable_first_read_only_AGGREGATED_SOCKETS(&ht);
2847
+ sl;
2848
+ sl = simple_hashtable_next_read_only_AGGREGATED_SOCKETS(&ht, sl)) {
2849
+ LOCAL_SOCKET *n = SIMPLE_HASHTABLE_SLOT_DATA(sl);
2850
+ if(!n || added >= ht.used) continue;
2851
560
- qsort(array, added, sizeof(LOCAL_SOCKET *), local_sockets_compar);
2852
+ array[added++] = n;
2853
+ }
2854
+
2855
+ qsort(array, added, sizeof(LOCAL_SOCKET *), local_sockets_compar);
2856
+
2857
+ for(size_t i = 0; i < added ;i++) {
2858
+ local_socket_to_json_array(&st, array[i], proc_self_net_ns_inode, true);
2859
+ string_freez(array[i]->cmdline);
2860
+ freez(array[i]);
2861
+ }
2862
562
- for(size_t i = 0; i < added ;i++) {
563
- local_socket_to_json_array(&st, array[i], proc_self_net_ns_inode, true);
564
- string_freez(array[i]->cmdline);
565
- freez(array[i]);
2863
+ freez(array);
2864
}
2865
2866
simple_hashtable_destroy_AGGREGATED_SOCKETS(&ht);
3104
3105
buffer_json_member_add_object(wb, "charts");
3106
{
809
- // Data Collection Age chart
810
- buffer_json_member_add_object(wb, "Count");
3107
+ buffer_json_member_add_object(wb, "Count by Direction");
3108
{
3109
buffer_json_member_add_string(wb, "type", "stacked-bar");
3110
buffer_json_member_add_array(wb, "columns");
3115
}
3116
buffer_json_object_close(wb);
3117
821
- // Streaming Age chart
822
- buffer_json_member_add_object(wb, "Count");
3118
+ buffer_json_member_add_object(wb, "Count by Process");
3119
{
3120
buffer_json_member_add_string(wb, "type", "stacked-bar");
3121
buffer_json_member_add_array(wb, "columns");
3126
}
3127
buffer_json_object_close(wb);
3128
833
- // DB Duration
834
- buffer_json_member_add_object(wb, "Count");
3129
+ buffer_json_member_add_object(wb, "Count by Protocol");
3130
{
3131
buffer_json_member_add_string(wb, "type", "stacked-bar");
3132
buffer_json_member_add_array(wb, "columns");
3249
}
3250
3251
close_and_send:
957
- buffer_json_member_add_time_t(wb, "expires", now_s + 1);
3252
+ buffer_json_member_add_time_t(wb, "expires", now_s + NETWORK_VIEWER_RESPONSE_UPDATE_EVERY);
3253
buffer_json_finalize(wb);
3254
3255
netdata_mutex_lock(&stdout_mutex);
3256
wb->response_code = HTTP_RESP_OK;
3257
wb->content_type = CT_APPLICATION_JSON;
963
- wb->expires = now_s + 1;
3258
+ wb->expires = now_s + NETWORK_VIEWER_RESPONSE_UPDATE_EVERY;
3259
pluginsd_function_result_to_stdout(transaction, wb);
3260
netdata_mutex_unlock(&stdout_mutex);
3261
}
3285
3286
// ----------------------------------------------------------------------------------------------------------------
3287
3288
+ // Manual debug mode only; normal plugins.d execution never takes this path.
3289
if(argc == 2 && strcmp(argv[1], "debug") == 0) {
3290
// for(int i = 0; i < 100; i++) {
3291
bool cancelled = false;
3292
usec_t stop_monotonic_ut = now_monotonic_usec() + 600 * USEC_PER_SEC;
3293
+ char topo_buf[] = "topology:network-connections";
3294
+ network_viewer_topology_function("123", topo_buf, &stop_monotonic_ut, &cancelled,
3295
+ NULL, HTTP_ACCESS_ALL, NULL, NULL);
3296
+
3297
char buf[] = "network-connections sockets:aggregated";
3298
network_viewer_function("123", buf, &stop_monotonic_ut, &cancelled,
3299
NULL, HTTP_ACCESS_ALL, NULL, NULL);
3309
3310
// ----------------------------------------------------------------------------------------------------------------
3311
3312
+ fprintf(stdout, PLUGINSD_KEYWORD_FUNCTION " GLOBAL \"%s\" %d \"%s\" \"top\" "HTTP_ACCESS_FORMAT" %d\n",
3313
+ NETWORK_TOPOLOGY_VIEWER_FUNCTION, 60,
3314
+ NETWORK_TOPOLOGY_VIEWER_HELP,
3315
+ (HTTP_ACCESS_FORMAT_CAST)(HTTP_ACCESS_SIGNED_ID | HTTP_ACCESS_SAME_SPACE | HTTP_ACCESS_SENSITIVE_DATA),
3316
+ RRDFUNCTIONS_PRIORITY_DEFAULT);
3317
+
3318
fprintf(stdout, PLUGINSD_KEYWORD_FUNCTION " GLOBAL \"%s\" %d \"%s\" \"top\" "HTTP_ACCESS_FORMAT" %d\n",
3319
NETWORK_CONNECTIONS_VIEWER_FUNCTION, 60,
3320
NETWORK_CONNECTIONS_VIEWER_HELP,
3331
PLUGINS_FUNCTIONS_TIMEOUT_DEFAULT,
3332
NULL);
3333
3334
+ functions_evloop_add_function(wg, NETWORK_TOPOLOGY_VIEWER_FUNCTION,
3335
+ network_viewer_topology_function,
3336
+ PLUGINS_FUNCTIONS_TIMEOUT_DEFAULT,
3337
+ NULL);
3338
+
3339
// ----------------------------------------------------------------------------------------------------------------
3340
3341
usec_t send_newline_ut = 0;