summaryrefslogtreecommitdiffstats
path: root/src/collectors/windows.plugin/perflib-network.c
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-07-24 09:54:23 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-07-24 09:54:44 +0000
commit836b47cb7e99a977c5a23b059ca1d0b5065d310e (patch)
tree1604da8f482d02effa033c94a84be42bc0c848c3 /src/collectors/windows.plugin/perflib-network.c
parentReleasing debian version 1.44.3-2. (diff)
downloadnetdata-836b47cb7e99a977c5a23b059ca1d0b5065d310e.tar.xz
netdata-836b47cb7e99a977c5a23b059ca1d0b5065d310e.zip
Merging upstream version 1.46.3.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/collectors/windows.plugin/perflib-network.c')
-rw-r--r--src/collectors/windows.plugin/perflib-network.c453
1 files changed, 453 insertions, 0 deletions
diff --git a/src/collectors/windows.plugin/perflib-network.c b/src/collectors/windows.plugin/perflib-network.c
new file mode 100644
index 000000000..2f1bc3c53
--- /dev/null
+++ b/src/collectors/windows.plugin/perflib-network.c
@@ -0,0 +1,453 @@
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#include "windows_plugin.h"
+#include "windows-internals.h"
+
+// --------------------------------------------------------------------------------------------------------------------
+// network protocols
+
+struct network_protocol {
+ const char *protocol;
+
+ struct {
+ COUNTER_DATA received;
+ COUNTER_DATA sent;
+ COUNTER_DATA delivered;
+ COUNTER_DATA forwarded;
+ RRDSET *st;
+ RRDDIM *rd_received;
+ RRDDIM *rd_sent;
+ RRDDIM *rd_forwarded;
+ RRDDIM *rd_delivered;
+ const char *type;
+ const char *id;
+ const char *family;
+ const char *context;
+ const char *title;
+ long priority;
+ } packets;
+
+} networks[] = {
+ {
+ .protocol = "IPv4",
+ .packets = {
+ .received = { .key = "Datagrams Received/sec" },
+ .sent = { .key = "Datagrams Sent/sec" },
+ .delivered = { .key = "Datagrams Received Delivered/sec" },
+ .forwarded = { .key = "Datagrams Forwarded/sec" },
+ .type = "ipv4",
+ .id = "packets",
+ .family = "packets",
+ .context = "ipv4.packets",
+ .title = "IPv4 Packets",
+ .priority = NETDATA_CHART_PRIO_IPV4_PACKETS,
+ },
+ },
+ {
+ .protocol = "IPv6",
+ .packets = {
+ .received = { .key = "Datagrams Received/sec" },
+ .sent = { .key = "Datagrams Sent/sec" },
+ .delivered = { .key = "Datagrams Received Delivered/sec" },
+ .forwarded = { .key = "Datagrams Forwarded/sec" },
+ .type = "ipv6",
+ .id = "packets",
+ .family = "packets",
+ .context = "ip6.packets",
+ .title = "IPv6 Packets",
+ .priority = NETDATA_CHART_PRIO_IPV6_PACKETS,
+ },
+ },
+ {
+ .protocol = "TCPv4",
+ .packets = {
+ .received = { .key = "Segments Received/sec" },
+ .sent = { .key = "Segments Sent/sec" },
+ .type = "ipv4",
+ .id = "tcppackets",
+ .family = "tcp",
+ .context = "ipv4.tcppackets",
+ .title = "IPv4 TCP Packets",
+ .priority = NETDATA_CHART_PRIO_IPV4_TCP_PACKETS,
+ },
+ },
+ {
+ .protocol = "TCPv6",
+ .packets = {
+ .received = { .key = "Segments Received/sec" },
+ .sent = { .key = "Segments Sent/sec" },
+ .type = "ipv6",
+ .id = "tcppackets",
+ .family = "tcp6",
+ .context = "ipv6.tcppackets",
+ .title = "IPv6 TCP Packets",
+ .priority = NETDATA_CHART_PRIO_IPV6_TCP_PACKETS,
+ },
+ },
+ {
+ .protocol = "UDPv4",
+ .packets = {
+ .received = { .key = "Datagrams Received/sec" },
+ .sent = { .key = "Datagrams Sent/sec" },
+ .type = "ipv4",
+ .id = "udppackets",
+ .family = "udp",
+ .context = "ipv4.udppackets",
+ .title = "IPv4 UDP Packets",
+ .priority = NETDATA_CHART_PRIO_IPV4_UDP_PACKETS,
+ },
+ },
+ {
+ .protocol = "UDPv6",
+ .packets = {
+ .received = { .key = "Datagrams Received/sec" },
+ .sent = { .key = "Datagrams Sent/sec" },
+ .type = "ipv6",
+ .id = "udppackets",
+ .family = "udp6",
+ .context = "ipv6.udppackets",
+ .title = "IPv6 UDP Packets",
+ .priority = NETDATA_CHART_PRIO_IPV6_UDP_PACKETS,
+ },
+ },
+ {
+ .protocol = "ICMP",
+ .packets = {
+ .received = { .key = "Messages Received/sec" },
+ .sent = { .key = "Messages Sent/sec" },
+ .type = "ipv4",
+ .id = "icmp",
+ .family = "icmp",
+ .context = "ipv4.icmp",
+ .title = "IPv4 ICMP Packets",
+ .priority = NETDATA_CHART_PRIO_IPV4_ICMP_PACKETS,
+ },
+ },
+ {
+ .protocol = "ICMPv6",
+ .packets = {
+ .received = { .key = "Messages Received/sec" },
+ .sent = { .key = "Messages Sent/sec" },
+ .type = "ipv6",
+ .id = "icmp",
+ .family = "icmp6",
+ .context = "ipv6.icmp",
+ .title = "IPv6 ICMP Packets",
+ .priority = NETDATA_CHART_PRIO_IPV6_ICMP_PACKETS,
+ },
+ },
+
+ // terminator
+ {
+ .protocol = NULL,
+ }
+};
+
+struct network_protocol tcp46 = {
+ .packets = {
+ .type = "ip",
+ .id = "tcppackets",
+ .family = "tcp",
+ .context = "ip.tcppackets",
+ .title = "TCP Packets",
+ .priority = NETDATA_CHART_PRIO_IP_TCP_PACKETS,
+ }
+};
+
+static void protocol_packets_chart_update(struct network_protocol *p, int update_every) {
+ if(!p->packets.st) {
+ p->packets.st = rrdset_create_localhost(
+ p->packets.type
+ , p->packets.id
+ , NULL
+ , p->packets.family
+ , NULL
+ , p->packets.title
+ , "packets/s"
+ , PLUGIN_WINDOWS_NAME
+ , "PerflibNetwork"
+ , p->packets.priority
+ , update_every
+ , RRDSET_TYPE_AREA
+ );
+
+ p->packets.rd_received = rrddim_add(p->packets.st, "received", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ p->packets.rd_sent = rrddim_add(p->packets.st, "sent", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+
+ if(p->packets.forwarded.key)
+ p->packets.rd_forwarded = rrddim_add(p->packets.st, "forwarded", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+
+ if(p->packets.delivered.key)
+ p->packets.rd_delivered = rrddim_add(p->packets.st, "delivered", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ }
+
+ if(p->packets.received.updated)
+ rrddim_set_by_pointer(p->packets.st, p->packets.rd_received, (collected_number)p->packets.received.current.Data);
+
+ if(p->packets.sent.updated)
+ rrddim_set_by_pointer(p->packets.st, p->packets.rd_sent, (collected_number)p->packets.sent.current.Data);
+
+ if(p->packets.forwarded.key && p->packets.forwarded.updated)
+ rrddim_set_by_pointer(p->packets.st, p->packets.rd_forwarded, (collected_number)p->packets.forwarded.current.Data);
+
+ if(p->packets.delivered.key && p->packets.delivered.updated)
+ rrddim_set_by_pointer(p->packets.st, p->packets.rd_delivered, (collected_number)p->packets.delivered.current.Data);
+
+ rrdset_done(p->packets.st);
+}
+
+static bool do_network_protocol(PERF_DATA_BLOCK *pDataBlock, int update_every, struct network_protocol *p) {
+ if(!p || !p->protocol) return false;
+
+ PERF_OBJECT_TYPE *pObjectType = perflibFindObjectTypeByName(pDataBlock, p->protocol);
+ if(!pObjectType) return false;
+
+ size_t packets = 0;
+ if(p->packets.received.key)
+ packets += perflibGetObjectCounter(pDataBlock, pObjectType, &p->packets.received) ? 1 : 0;
+
+ if(p->packets.sent.key)
+ packets += perflibGetObjectCounter(pDataBlock, pObjectType, &p->packets.sent) ? 1 : 0;
+
+ if(p->packets.delivered.key)
+ packets += perflibGetObjectCounter(pDataBlock, pObjectType, &p->packets.delivered) ? 1 :0;
+
+ if(p->packets.forwarded.key)
+ packets += perflibGetObjectCounter(pDataBlock, pObjectType, &p->packets.forwarded) ? 1 : 0;
+
+ if(packets)
+ protocol_packets_chart_update(p, update_every);
+
+ return true;
+}
+
+// --------------------------------------------------------------------------------------------------------------------
+// network interfaces
+
+struct network_interface {
+ bool collected_metadata;
+
+ struct {
+ COUNTER_DATA received;
+ COUNTER_DATA sent;
+
+ RRDSET *st;
+ RRDDIM *rd_received;
+ RRDDIM *rd_sent;
+ } packets;
+
+ struct {
+ COUNTER_DATA received;
+ COUNTER_DATA sent;
+
+ RRDSET *st;
+ RRDDIM *rd_received;
+ RRDDIM *rd_sent;
+ } traffic;
+};
+
+static DICTIONARY *physical_interfaces = NULL, *virtual_interfaces = NULL;
+
+static void network_interface_init(struct network_interface *ni) {
+ ni->packets.received.key = "Packets Received/sec";
+ ni->packets.sent.key = "Packets Sent/sec";
+
+ ni->traffic.received.key = "Bytes Received/sec";
+ ni->traffic.sent.key = "Bytes Sent/sec";
+}
+
+void dict_interface_insert_cb(const DICTIONARY_ITEM *item __maybe_unused, void *value, void *data __maybe_unused) {
+ struct network_interface *ni = value;
+ network_interface_init(ni);
+}
+
+static void initialize(void) {
+ physical_interfaces = dictionary_create_advanced(DICT_OPTION_DONT_OVERWRITE_VALUE |
+ DICT_OPTION_FIXED_SIZE, NULL, sizeof(struct network_interface));
+
+ virtual_interfaces = dictionary_create_advanced(DICT_OPTION_DONT_OVERWRITE_VALUE |
+ DICT_OPTION_FIXED_SIZE, NULL, sizeof(struct network_interface));
+
+ dictionary_register_insert_callback(physical_interfaces, dict_interface_insert_cb, NULL);
+ dictionary_register_insert_callback(virtual_interfaces, dict_interface_insert_cb, NULL);
+}
+
+static void add_interface_labels(RRDSET *st, const char *name, bool physical) {
+ rrdlabels_add(st->rrdlabels, "device", name, RRDLABEL_SRC_AUTO);
+ rrdlabels_add(st->rrdlabels, "interface_type", physical ? "real" : "virtual", RRDLABEL_SRC_AUTO);
+}
+
+static bool is_physical_interface(const char *name) {
+ void *d = dictionary_get(physical_interfaces, name);
+ return d ? true : false;
+}
+
+static bool do_network_interface(PERF_DATA_BLOCK *pDataBlock, int update_every, bool physical) {
+ DICTIONARY *dict = physical_interfaces;
+
+ PERF_OBJECT_TYPE *pObjectType = perflibFindObjectTypeByName(pDataBlock, physical ? "Network Interface" : "Network Adapter");
+ if(!pObjectType) return false;
+
+ uint64_t total_received = 0, total_sent = 0;
+
+ PERF_INSTANCE_DEFINITION *pi = NULL;
+ for(LONG i = 0; i < pObjectType->NumInstances ; i++) {
+ pi = perflibForEachInstance(pDataBlock, pObjectType, pi);
+ if(!pi) break;
+
+ if(!getInstanceName(pDataBlock, pObjectType, pi, windows_shared_buffer, sizeof(windows_shared_buffer)))
+ strncpyz(windows_shared_buffer, "[unknown]", sizeof(windows_shared_buffer) - 1);
+
+ if(strcasecmp(windows_shared_buffer, "_Total") == 0)
+ continue;
+
+ if(!physical && is_physical_interface(windows_shared_buffer))
+ // this virtual interface is already reported as physical interface
+ continue;
+
+ struct network_interface *d = dictionary_set(dict, windows_shared_buffer, NULL, sizeof(*d));
+
+ if(!d->collected_metadata) {
+ // TODO - get metadata about the network interface
+ d->collected_metadata = true;
+ }
+
+ if(perflibGetInstanceCounter(pDataBlock, pObjectType, pi, &d->traffic.received) ||
+ perflibGetInstanceCounter(pDataBlock, pObjectType, pi, &d->traffic.sent)) {
+
+ if(d->traffic.received.current.Data == 0 && d->traffic.sent.current.Data == 0)
+ // this interface has not received or sent any traffic
+ continue;
+
+ if (unlikely(!d->traffic.st)) {
+ d->traffic.st = rrdset_create_localhost(
+ "net",
+ windows_shared_buffer,
+ NULL,
+ windows_shared_buffer,
+ "net.net",
+ "Bandwidth",
+ "kilobits/s",
+ PLUGIN_WINDOWS_NAME,
+ "PerflibNetwork",
+ NETDATA_CHART_PRIO_FIRST_NET_IFACE,
+ update_every,
+ RRDSET_TYPE_AREA);
+
+ rrdset_flag_set(d->traffic.st, RRDSET_FLAG_DETAIL);
+
+ add_interface_labels(d->traffic.st, windows_shared_buffer, physical);
+
+ d->traffic.rd_received = rrddim_add(d->traffic.st, "received", NULL, 8, BITS_IN_A_KILOBIT, RRD_ALGORITHM_INCREMENTAL);
+ d->traffic.rd_sent = rrddim_add(d->traffic.st, "sent", NULL, -8, BITS_IN_A_KILOBIT, RRD_ALGORITHM_INCREMENTAL);
+ }
+
+ total_received += d->traffic.received.current.Data;
+ total_sent += d->traffic.sent.current.Data;
+
+ rrddim_set_by_pointer(d->traffic.st, d->traffic.rd_received, (collected_number)d->traffic.received.current.Data);
+ rrddim_set_by_pointer(d->traffic.st, d->traffic.rd_sent, (collected_number)d->traffic.sent.current.Data);
+ rrdset_done(d->traffic.st);
+ }
+
+ if(perflibGetInstanceCounter(pDataBlock, pObjectType, pi, &d->packets.received) ||
+ perflibGetInstanceCounter(pDataBlock, pObjectType, pi, &d->packets.sent)) {
+
+ if (unlikely(!d->packets.st)) {
+ d->packets.st = rrdset_create_localhost(
+ "net_packets",
+ windows_shared_buffer,
+ NULL,
+ windows_shared_buffer,
+ "net.packets",
+ "Packets",
+ "packets/s",
+ PLUGIN_WINDOWS_NAME,
+ "PerflibNetwork",
+ NETDATA_CHART_PRIO_FIRST_NET_IFACE + 1,
+ update_every,
+ RRDSET_TYPE_LINE);
+
+ rrdset_flag_set(d->packets.st, RRDSET_FLAG_DETAIL);
+
+ add_interface_labels(d->traffic.st, windows_shared_buffer, physical);
+
+ d->packets.rd_received = rrddim_add(d->packets.st, "received", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ d->packets.rd_sent = rrddim_add(d->packets.st, "sent", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ }
+
+ rrddim_set_by_pointer(d->packets.st, d->packets.rd_received, (collected_number)d->packets.received.current.Data);
+ rrddim_set_by_pointer(d->packets.st, d->packets.rd_sent, (collected_number)d->packets.sent.current.Data);
+ rrdset_done(d->packets.st);
+ }
+ }
+
+ if(physical) {
+ static RRDSET *st = NULL;
+ static RRDDIM *rd_received = NULL, *rd_sent = NULL;
+
+ if (unlikely(!st)) {
+ st = rrdset_create_localhost(
+ "system",
+ "net",
+ NULL,
+ "network",
+ "system.net",
+ "Physical Network Interfaces Aggregated Bandwidth",
+ "kilobits/s",
+ PLUGIN_WINDOWS_NAME,
+ "PerflibNetwork",
+ NETDATA_CHART_PRIO_SYSTEM_NET,
+ update_every,
+ RRDSET_TYPE_AREA);
+
+ rd_received = rrddim_add(st, "received", NULL, 8, BITS_IN_A_KILOBIT, RRD_ALGORITHM_INCREMENTAL);
+ rd_sent = rrddim_add(st, "sent", NULL, -8, BITS_IN_A_KILOBIT, RRD_ALGORITHM_INCREMENTAL);
+ }
+
+ rrddim_set_by_pointer(st, rd_received, (collected_number)total_received);
+ rrddim_set_by_pointer(st, rd_sent, (collected_number)total_sent);
+ rrdset_done(st);
+ }
+
+ return true;
+}
+
+int do_PerflibNetwork(int update_every, usec_t dt __maybe_unused) {
+ static bool initialized = false;
+
+ if(unlikely(!initialized)) {
+ initialize();
+ initialized = true;
+ }
+
+ DWORD id = RegistryFindIDByName("Network Interface");
+ if(id == PERFLIB_REGISTRY_NAME_NOT_FOUND)
+ return -1;
+
+ PERF_DATA_BLOCK *pDataBlock = perflibGetPerformanceData(id);
+ if(!pDataBlock) return -1;
+
+ do_network_interface(pDataBlock, update_every, true);
+ do_network_interface(pDataBlock, update_every, false);
+
+ struct network_protocol *tcp4 = NULL, *tcp6 = NULL;
+ for(size_t i = 0; networks[i].protocol ;i++) {
+ do_network_protocol(pDataBlock, update_every, &networks[i]);
+
+ if(!tcp4 && strcmp(networks[i].protocol, "TCPv4") == 0)
+ tcp4 = &networks[i];
+ if(!tcp6 && strcmp(networks[i].protocol, "TCPv6") == 0)
+ tcp6 = &networks[i];
+ }
+
+ if(tcp4 && tcp6) {
+ tcp46.packets.received = tcp4->packets.received;
+ tcp46.packets.sent = tcp4->packets.sent;
+ tcp46.packets.received.current.Data += tcp6->packets.received.current.Data;
+ tcp46.packets.sent.current.Data += tcp6->packets.sent.current.Data;
+ protocol_packets_chart_update(&tcp46, update_every);
+ }
+
+ return 0;
+}