summaryrefslogtreecommitdiffstats
path: root/src/collectors/windows.plugin/perflib-network.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/collectors/windows.plugin/perflib-network.c')
-rw-r--r--src/collectors/windows.plugin/perflib-network.c1500
1 files changed, 1047 insertions, 453 deletions
diff --git a/src/collectors/windows.plugin/perflib-network.c b/src/collectors/windows.plugin/perflib-network.c
index ecadd1e87..55d873b6f 100644
--- a/src/collectors/windows.plugin/perflib-network.c
+++ b/src/collectors/windows.plugin/perflib-network.c
@@ -1,453 +1,1047 @@
-// 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;
-}
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#include "windows_plugin.h"
+#include "windows-internals.h"
+
+#define ADD_PACKET_IF_KEY(p, packets, pDataBlock, pObjectType, counter) \
+ do { \
+ if ((p)->packets.counter.key) { \
+ packets += perflibGetObjectCounter((pDataBlock), (pObjectType), &(p)->packets.counter) ? 1 : 0; \
+ } \
+ } while (0)
+
+#define SET_DIM_IF_KEY_AND_UPDATED(p, field) \
+ do { \
+ if ((p)->packets.field.key && (p)->packets.field.updated) { \
+ rrddim_set_by_pointer( \
+ (p)->packets.st, (p)->packets.rd_##field, (collected_number)(p)->packets.field.current.Data); \
+ } \
+ } while (0)
+
+#define ADD_RRD_DIM_IF_KEY(packet_field, id, name, multiplier, algorithm) \
+ do { \
+ if (p->packets.packet_field.key) \
+ p->packets.rd_##packet_field = rrddim_add(st, id, name, multiplier, 1, algorithm); \
+ } while (0)
+
+// --------------------------------------------------------------------------------------------------------------------
+// network protocols
+
+struct network_protocol {
+ const char *protocol;
+
+ struct {
+ COUNTER_DATA received;
+ COUNTER_DATA sent;
+ COUNTER_DATA delivered;
+ COUNTER_DATA forwarded;
+
+ COUNTER_DATA InDiscards;
+ COUNTER_DATA OutDiscards;
+ COUNTER_DATA InHdrErrors;
+ COUNTER_DATA InAddrErrors;
+ COUNTER_DATA InUnknownProtos;
+ COUNTER_DATA InTooBigErrors;
+ COUNTER_DATA InTruncatedPkts;
+ COUNTER_DATA InNoRoutes;
+ COUNTER_DATA OutNoRoutes;
+
+ COUNTER_DATA InEchoReps;
+ COUNTER_DATA OutEchoReps;
+ COUNTER_DATA InDestUnreachs;
+ COUNTER_DATA OutDestUnreachs;
+ COUNTER_DATA InRedirects;
+ COUNTER_DATA OutRedirects;
+ COUNTER_DATA InEchos;
+ COUNTER_DATA OutEchos;
+ COUNTER_DATA InRouterAdvert;
+ COUNTER_DATA OutRouterAdvert;
+ COUNTER_DATA InRouterSelect;
+ COUNTER_DATA OutRouterSelect;
+ COUNTER_DATA InTimeExcds;
+ COUNTER_DATA OutTimeExcds;
+ COUNTER_DATA InParmProbs;
+ COUNTER_DATA OutParmProbs;
+ COUNTER_DATA InTimestamps;
+ COUNTER_DATA OutTimestamps;
+ COUNTER_DATA InTimestampReps;
+ COUNTER_DATA OutTimestampReps;
+
+ RRDSET *st;
+ RRDDIM *rd_received;
+ RRDDIM *rd_sent;
+ RRDDIM *rd_forwarded;
+ RRDDIM *rd_delivered;
+
+ RRDDIM *rd_InDiscards;
+ RRDDIM *rd_OutDiscards;
+ RRDDIM *rd_InHdrErrors;
+ RRDDIM *rd_InAddrErrors;
+ RRDDIM *rd_InUnknownProtos;
+ RRDDIM *rd_InTooBigErrors;
+ RRDDIM *rd_InTruncatedPkts;
+ RRDDIM *rd_InNoRoutes;
+ RRDDIM *rd_OutNoRoutes;
+
+ RRDDIM *rd_InEchoReps;
+ RRDDIM *rd_OutEchoReps;
+ RRDDIM *rd_InDestUnreachs;
+ RRDDIM *rd_OutDestUnreachs;
+ RRDDIM *rd_InRedirects;
+ RRDDIM *rd_OutRedirects;
+ RRDDIM *rd_InEchos;
+ RRDDIM *rd_OutEchos;
+ RRDDIM *rd_InRouterAdvert;
+ RRDDIM *rd_OutRouterAdvert;
+ RRDDIM *rd_InRouterSelect;
+ RRDDIM *rd_OutRouterSelect;
+ RRDDIM *rd_InTimeExcds;
+ RRDDIM *rd_OutTimeExcds;
+ RRDDIM *rd_InParmProbs;
+ RRDDIM *rd_OutParmProbs;
+ RRDDIM *rd_InTimestamps;
+ RRDDIM *rd_OutTimestamps;
+ RRDDIM *rd_InTimestampReps;
+ RRDDIM *rd_OutTimestampReps;
+
+ 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,
+ },
+ },
+
+ {
+ .protocol = "IPv4",
+ .packets = {
+ .InDiscards = { .key = "Datagrams Received Discarded" },
+ .OutDiscards = { .key = "Datagrams Outbound Discarded" },
+ .OutNoRoutes = { .key = "Datagrams Outbound No Route" },
+ .InAddrErrors = { .key = "Datagrams Received Address Errors" },
+ .InHdrErrors = { .key = "Datagrams Received Header Errors" },
+ .InUnknownProtos = { .key = "Datagrams Received Unknown Protocol" },
+ .type = "ipv4",
+ .id = "errors",
+ .family = "errors",
+ .context = "ipv4.errors",
+ .title = "IPv4 errors",
+ .priority = NETDATA_CHART_PRIO_IPV4_ERRORS,
+ },
+ },
+ {
+ .protocol = "IPv6",
+ .packets = {
+ .InDiscards = { .key = "Datagrams Received Discarded" },
+ .OutDiscards = { .key = "Datagrams Outbound Discarded" },
+ .OutNoRoutes = { .key = "Datagrams Outbound No Route" },
+ .InAddrErrors = { .key = "Datagrams Received Address Errors" },
+ .InHdrErrors = { .key = "Datagrams Received Header Errors" },
+ .InUnknownProtos = { .key = "Datagrams Received Unknown Protocol" },
+ .type = "ipv6",
+ .id = "errors",
+ .family = "errors",
+ .context = "ipv6.errors",
+ .title = "IPv6 errors",
+ .priority = NETDATA_CHART_PRIO_IPV6_ERRORS,
+ },
+ },
+ {
+ .protocol = "ICMP",
+ .packets =
+ {
+ .InEchoReps = {.key = "Received Echo Reply/sec"},
+ .OutEchoReps = {.key = "Received Echo Reply/sec"},
+ .InDestUnreachs = {.key = "Received Dest. Unreachable"},
+ .OutDestUnreachs = {.key = "Sent Destination Unreachable"},
+ .InRedirects = {.key = "Received Redirect/sec"},
+ .OutRedirects = {.key = "Sent Redirect/sec"},
+ .InEchos = {.key = "Received Echo/sec"},
+ .OutEchos = {.key = "Sent Echo/sec"},
+ .InRouterAdvert = {.key = NULL},
+ .OutRouterAdvert = {.key = NULL},
+ .InRouterSelect = {.key = NULL},
+ .OutRouterSelect = {.key = NULL},
+ .InTimeExcds = {.key = "Received Time Exceeded"},
+ .OutTimeExcds = {.key = "Sent Time Exceeded"},
+ .InParmProbs = {.key = "Received Parameter Problem"},
+ .OutParmProbs = {.key = "Sent Parameter Problem"},
+ .InTimestamps = {.key = "Received Timestamp/sec"},
+ .OutTimestamps = {.key = "Sent Timestamp/sec"},
+ .InTimestampReps = {.key = "Received Timestamp Reply/sec"},
+ .OutTimestampReps = {.key = "Sent Timestamp Reply/sec"},
+
+ .type = "ipv4",
+ .id = "icmpmsg",
+ .family = "icmp",
+ .context = "ipv4.icmpmsg",
+ .title = "IPv4 ICMP Packets",
+ .priority = NETDATA_CHART_PRIO_IPV4_ICMP_MESSAGES,
+ },
+ },
+ {
+ .protocol = "ICMPv6",
+ .packets =
+ {
+ .InEchoReps = {.key = "Received Echo Reply/sec"},
+ .OutEchoReps = {.key = "Received Echo Reply/sec"},
+ .InDestUnreachs = {.key = "Received Dest. Unreachable"},
+ .OutDestUnreachs = {.key = "Sent Destination Unreachable"},
+ .InRedirects = {.key = "Received Redirect/sec"},
+ .OutRedirects = {.key = "Sent Redirect/sec"},
+ .InEchos = {.key = "Received Echo/sec"},
+ .OutEchos = {.key = "Sent Echo/sec"},
+ .InRouterAdvert = {.key = NULL},
+ .OutRouterAdvert = {.key = NULL},
+ .InRouterSelect = {.key = NULL},
+ .OutRouterSelect = {.key = NULL},
+ .InTimeExcds = {.key = "Received Time Exceeded"},
+ .OutTimeExcds = {.key = "Sent Time Exceeded"},
+ .InParmProbs = {.key = "Received Parameter Problem"},
+ .OutParmProbs = {.key = "Sent Parameter Problem"},
+ .InTimestamps = {.key = "Received Timestamp/sec"},
+ .OutTimestamps = {.key = "Sent Timestamp/sec"},
+ .InTimestampReps = {.key = "Received Timestamp Reply/sec"},
+ .OutTimestampReps = {.key = "Sent Timestamp Reply/sec"},
+
+ .type = "ipv6",
+ .id = "icmpmsg",
+ .family = "icmp",
+ .context = "ipv6.icmpmsg",
+ .title = "IPv6 ICMP Packets",
+ .priority = NETDATA_CHART_PRIO_IPV6_ICMP_MESSAGES,
+ },
+ },
+
+ // 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
+ );
+
+ RRDSET *st = p->packets.st;
+
+ ADD_RRD_DIM_IF_KEY(received, "received", NULL, 1, RRD_ALGORITHM_INCREMENTAL);
+ ADD_RRD_DIM_IF_KEY(sent, "sent", NULL, -1, RRD_ALGORITHM_INCREMENTAL);
+ ADD_RRD_DIM_IF_KEY(forwarded, "forwarded", NULL, -1, RRD_ALGORITHM_INCREMENTAL);
+ ADD_RRD_DIM_IF_KEY(delivered, "delivered", NULL, 1, RRD_ALGORITHM_INCREMENTAL);
+ ADD_RRD_DIM_IF_KEY(InDiscards, "InDiscards", NULL, 1, RRD_ALGORITHM_INCREMENTAL);
+ ADD_RRD_DIM_IF_KEY(OutDiscards, "OutDiscards", NULL, -1, RRD_ALGORITHM_INCREMENTAL);
+ ADD_RRD_DIM_IF_KEY(InHdrErrors, "InHdrErrors", NULL, 1, RRD_ALGORITHM_INCREMENTAL);
+ ADD_RRD_DIM_IF_KEY(InAddrErrors, "InAddrErrors", NULL, 1, RRD_ALGORITHM_INCREMENTAL);
+ ADD_RRD_DIM_IF_KEY(InUnknownProtos, "InUnknownProtos", NULL, 1, RRD_ALGORITHM_INCREMENTAL);
+ ADD_RRD_DIM_IF_KEY(InTooBigErrors, "InTooBigErrors", NULL, 1, RRD_ALGORITHM_INCREMENTAL);
+ ADD_RRD_DIM_IF_KEY(InTruncatedPkts, "InTruncatedPkts", NULL, 1, RRD_ALGORITHM_INCREMENTAL);
+ ADD_RRD_DIM_IF_KEY(InNoRoutes, "InNoRoutes", NULL, 1, RRD_ALGORITHM_INCREMENTAL);
+ ADD_RRD_DIM_IF_KEY(OutNoRoutes, "OutNoRoutes", NULL, -1, RRD_ALGORITHM_INCREMENTAL);
+ ADD_RRD_DIM_IF_KEY(InEchoReps, "InType0", "InEchoReps", 1, RRD_ALGORITHM_INCREMENTAL);
+ ADD_RRD_DIM_IF_KEY(OutEchoReps, "OutType0", "OutEchoReps", -1, RRD_ALGORITHM_INCREMENTAL);
+ ADD_RRD_DIM_IF_KEY(InDestUnreachs, "InType3", "InDestUnreachs", 1, RRD_ALGORITHM_INCREMENTAL);
+ ADD_RRD_DIM_IF_KEY(OutDestUnreachs, "OutType3", "OutDestUnreachs", -1, RRD_ALGORITHM_INCREMENTAL);
+ ADD_RRD_DIM_IF_KEY(InRedirects, "InType5", "InRedirects", 1, RRD_ALGORITHM_INCREMENTAL);
+ ADD_RRD_DIM_IF_KEY(OutRedirects, "OutType5", "OutRedirects", -1, RRD_ALGORITHM_INCREMENTAL);
+ ADD_RRD_DIM_IF_KEY(InEchos, "InType8", "InEchos", 1, RRD_ALGORITHM_INCREMENTAL);
+ ADD_RRD_DIM_IF_KEY(OutEchos, "OutType8", "OutEchos", -1, RRD_ALGORITHM_INCREMENTAL);
+ ADD_RRD_DIM_IF_KEY(InRouterAdvert, "InType9", "InRouterAdvert", 1, RRD_ALGORITHM_INCREMENTAL);
+ ADD_RRD_DIM_IF_KEY(OutRouterAdvert, "OutType9", "OutRouterAdvert", -1, RRD_ALGORITHM_INCREMENTAL);
+ ADD_RRD_DIM_IF_KEY(InRouterSelect, "InType10", "InRouterSelect", 1, RRD_ALGORITHM_INCREMENTAL);
+ ADD_RRD_DIM_IF_KEY(OutRouterSelect, "OutType10", "OutRouterSelect", -1, RRD_ALGORITHM_INCREMENTAL);
+ ADD_RRD_DIM_IF_KEY(InTimeExcds, "InType11", "InTimeExcds", 1, RRD_ALGORITHM_INCREMENTAL);
+ ADD_RRD_DIM_IF_KEY(OutTimeExcds, "OutType11", "OutTimeExcds", -1, RRD_ALGORITHM_INCREMENTAL);
+ ADD_RRD_DIM_IF_KEY(InParmProbs, "InType12", "InParmProbs", 1, RRD_ALGORITHM_INCREMENTAL);
+ ADD_RRD_DIM_IF_KEY(OutParmProbs, "OutType12", "OutParmProbs", -1, RRD_ALGORITHM_INCREMENTAL);
+ ADD_RRD_DIM_IF_KEY(InTimestamps, "InType13", "InTimestamps", 1, RRD_ALGORITHM_INCREMENTAL);
+ ADD_RRD_DIM_IF_KEY(OutTimestamps, "OutType13", "OutTimestamps", -1, RRD_ALGORITHM_INCREMENTAL);
+ ADD_RRD_DIM_IF_KEY(InTimestampReps, "InType14", "InTimestampReps", 1, RRD_ALGORITHM_INCREMENTAL);
+ ADD_RRD_DIM_IF_KEY(OutTimestampReps, "OutType14", "OutTimestampReps", -1, RRD_ALGORITHM_INCREMENTAL);
+
+ }
+
+ SET_DIM_IF_KEY_AND_UPDATED(p, received);
+ SET_DIM_IF_KEY_AND_UPDATED(p, sent);
+
+ SET_DIM_IF_KEY_AND_UPDATED(p, forwarded);
+ SET_DIM_IF_KEY_AND_UPDATED(p, delivered);
+ SET_DIM_IF_KEY_AND_UPDATED(p, InDiscards);
+ SET_DIM_IF_KEY_AND_UPDATED(p, OutDiscards);
+ SET_DIM_IF_KEY_AND_UPDATED(p, InHdrErrors);
+ SET_DIM_IF_KEY_AND_UPDATED(p, InAddrErrors);
+ SET_DIM_IF_KEY_AND_UPDATED(p, InUnknownProtos);
+ SET_DIM_IF_KEY_AND_UPDATED(p, InTooBigErrors);
+ SET_DIM_IF_KEY_AND_UPDATED(p, InTruncatedPkts);
+ SET_DIM_IF_KEY_AND_UPDATED(p, InNoRoutes);
+ SET_DIM_IF_KEY_AND_UPDATED(p, OutNoRoutes);
+ SET_DIM_IF_KEY_AND_UPDATED(p, InEchoReps);
+ SET_DIM_IF_KEY_AND_UPDATED(p, OutEchoReps);
+ SET_DIM_IF_KEY_AND_UPDATED(p, InDestUnreachs);
+ SET_DIM_IF_KEY_AND_UPDATED(p, OutDestUnreachs);
+ SET_DIM_IF_KEY_AND_UPDATED(p, InRedirects);
+ SET_DIM_IF_KEY_AND_UPDATED(p, OutRedirects);
+ SET_DIM_IF_KEY_AND_UPDATED(p, InEchos);
+ SET_DIM_IF_KEY_AND_UPDATED(p, OutEchos);
+ SET_DIM_IF_KEY_AND_UPDATED(p, InRouterAdvert);
+ SET_DIM_IF_KEY_AND_UPDATED(p, OutRouterAdvert);
+ SET_DIM_IF_KEY_AND_UPDATED(p, InRouterSelect);
+ SET_DIM_IF_KEY_AND_UPDATED(p, OutRouterSelect);
+ SET_DIM_IF_KEY_AND_UPDATED(p, InTimeExcds);
+ SET_DIM_IF_KEY_AND_UPDATED(p, OutTimeExcds);
+ SET_DIM_IF_KEY_AND_UPDATED(p, InParmProbs);
+ SET_DIM_IF_KEY_AND_UPDATED(p, OutParmProbs);
+ SET_DIM_IF_KEY_AND_UPDATED(p, InTimestamps);
+ SET_DIM_IF_KEY_AND_UPDATED(p, OutTimestamps);
+ SET_DIM_IF_KEY_AND_UPDATED(p, InTimestampReps);
+ SET_DIM_IF_KEY_AND_UPDATED(p, OutTimestampReps);
+
+ 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;
+ ADD_PACKET_IF_KEY(p, packets, pDataBlock, pObjectType, received);
+ ADD_PACKET_IF_KEY(p, packets, pDataBlock, pObjectType, sent);
+ ADD_PACKET_IF_KEY(p, packets, pDataBlock, pObjectType, delivered);
+ ADD_PACKET_IF_KEY(p, packets, pDataBlock, pObjectType, forwarded);
+
+ ADD_PACKET_IF_KEY(p, packets, pDataBlock, pObjectType, InDiscards);
+ ADD_PACKET_IF_KEY(p, packets, pDataBlock, pObjectType, OutDiscards);
+ ADD_PACKET_IF_KEY(p, packets, pDataBlock, pObjectType, InHdrErrors);
+ ADD_PACKET_IF_KEY(p, packets, pDataBlock, pObjectType, InAddrErrors);
+ ADD_PACKET_IF_KEY(p, packets, pDataBlock, pObjectType, InUnknownProtos);
+ ADD_PACKET_IF_KEY(p, packets, pDataBlock, pObjectType, InTooBigErrors);
+ ADD_PACKET_IF_KEY(p, packets, pDataBlock, pObjectType, InTruncatedPkts);
+ ADD_PACKET_IF_KEY(p, packets, pDataBlock, pObjectType, InNoRoutes);
+ ADD_PACKET_IF_KEY(p, packets, pDataBlock, pObjectType, OutNoRoutes);
+ ADD_PACKET_IF_KEY(p, packets, pDataBlock, pObjectType, InEchoReps);
+ ADD_PACKET_IF_KEY(p, packets, pDataBlock, pObjectType, OutEchoReps);
+ ADD_PACKET_IF_KEY(p, packets, pDataBlock, pObjectType, InDestUnreachs);
+ ADD_PACKET_IF_KEY(p, packets, pDataBlock, pObjectType, OutDestUnreachs);
+
+ ADD_PACKET_IF_KEY(p, packets, pDataBlock, pObjectType, InRedirects);
+ ADD_PACKET_IF_KEY(p, packets, pDataBlock, pObjectType, OutRedirects);
+ ADD_PACKET_IF_KEY(p, packets, pDataBlock, pObjectType, InEchos);
+ ADD_PACKET_IF_KEY(p, packets, pDataBlock, pObjectType, OutEchos);
+ ADD_PACKET_IF_KEY(p, packets, pDataBlock, pObjectType, InRouterAdvert);
+ ADD_PACKET_IF_KEY(p, packets, pDataBlock, pObjectType, OutRouterAdvert);
+ ADD_PACKET_IF_KEY(p, packets, pDataBlock, pObjectType, InRouterSelect);
+ ADD_PACKET_IF_KEY(p, packets, pDataBlock, pObjectType, OutRouterSelect);
+ ADD_PACKET_IF_KEY(p, packets, pDataBlock, pObjectType, InTimeExcds);
+ ADD_PACKET_IF_KEY(p, packets, pDataBlock, pObjectType, OutTimeExcds);
+ ADD_PACKET_IF_KEY(p, packets, pDataBlock, pObjectType, InParmProbs);
+ ADD_PACKET_IF_KEY(p, packets, pDataBlock, pObjectType, OutParmProbs);
+ ADD_PACKET_IF_KEY(p, packets, pDataBlock, pObjectType, InTimestamps);
+ ADD_PACKET_IF_KEY(p, packets, pDataBlock, pObjectType, OutTimestamps);
+ ADD_PACKET_IF_KEY(p, packets, pDataBlock, pObjectType, InTimestampReps);
+ ADD_PACKET_IF_KEY(p, packets, pDataBlock, pObjectType, OutTimestampReps);
+
+ if(packets)
+ protocol_packets_chart_update(p, update_every);
+
+ return true;
+}
+
+// --------------------------------------------------------------------------------------------------------------------
+// network interfaces
+
+struct network_interface {
+ usec_t last_collected;
+ bool collected_metadata;
+
+ struct {
+ COUNTER_DATA received;
+ COUNTER_DATA sent;
+
+ RRDSET *st;
+ RRDDIM *rd_received;
+ RRDDIM *rd_sent;
+ } packets;
+
+ struct {
+ const RRDVAR_ACQUIRED *chart_var_speed;
+
+ COUNTER_DATA received;
+ COUNTER_DATA sent;
+
+ RRDSET *st;
+ RRDDIM *rd_received;
+ RRDDIM *rd_sent;
+ } traffic;
+
+ struct {
+ COUNTER_DATA current_bandwidth;
+ RRDSET *st;
+ RRDDIM *rd;
+ } speed;
+
+ struct {
+ COUNTER_DATA received;
+ COUNTER_DATA outbound;
+
+ RRDSET *st;
+ RRDDIM *rd_received;
+ RRDDIM *rd_outbound;
+ } discards;
+
+ struct {
+ COUNTER_DATA received;
+ COUNTER_DATA outbound;
+
+ RRDSET *st;
+ RRDDIM *rd_received;
+ RRDDIM *rd_outbound;
+ } errors;
+
+ struct {
+ COUNTER_DATA length;
+ RRDSET *st;
+ RRDDIM *rd;
+ } queue;
+
+ struct {
+ COUNTER_DATA connections;
+ RRDSET *st;
+ RRDDIM *rd;
+ } chimney;
+
+ struct {
+ COUNTER_DATA connections;
+ COUNTER_DATA packets;
+ COUNTER_DATA exceptions;
+ COUNTER_DATA average_packet_size;
+
+ RRDSET *st_connections;
+ RRDDIM *rd_connections;
+
+ RRDSET *st_packets;
+ RRDDIM *rd_packets;
+
+ RRDSET *st_exceptions;
+ RRDDIM *rd_exceptions;
+
+ RRDSET *st_average_packet_size;
+ RRDDIM *rd_average_packet_size;
+ } rsc;
+};
+
+static DICTIONARY *physical_interfaces = NULL, *virtual_interfaces = NULL;
+
+static void network_interface_init(struct network_interface *d) {
+ d->packets.received.key = "Packets Received/sec";
+ d->packets.sent.key = "Packets Sent/sec";
+ d->traffic.received.key = "Bytes Received/sec";
+ d->traffic.sent.key = "Bytes Sent/sec";
+ d->speed.current_bandwidth.key = "Current Bandwidth";
+ d->discards.received.key = "Packets Received Discarded";
+ d->discards.outbound.key = "Packets Outbound Discarded";
+ d->errors.received.key = "Packets Received Errors";
+ d->errors.outbound.key = "Packets Outbound Errors";
+ d->queue.length.key = "Output Queue Length";
+ d->chimney.connections.key = "Offloaded Connections";
+ d->rsc.connections.key = "TCP Active RSC Connections";
+ d->rsc.packets.key = "TCP RSC Coalesced Packets/sec";
+ d->rsc.exceptions.key = "TCP RSC Exceptions/sec";
+ d->rsc.average_packet_size.key = "TCP RSC Average Packet Size";
+}
+
+static void network_interface_cleanup(struct network_interface *d) {
+ rrdvar_chart_variable_release(d->traffic.st, d->traffic.chart_var_speed);
+ rrdset_is_obsolete___safe_from_collector_thread(d->packets.st);
+ rrdset_is_obsolete___safe_from_collector_thread(d->traffic.st);
+ rrdset_is_obsolete___safe_from_collector_thread(d->speed.st);
+ rrdset_is_obsolete___safe_from_collector_thread(d->discards.st);
+ rrdset_is_obsolete___safe_from_collector_thread(d->errors.st);
+ rrdset_is_obsolete___safe_from_collector_thread(d->queue.st);
+ rrdset_is_obsolete___safe_from_collector_thread(d->chimney.st);
+ rrdset_is_obsolete___safe_from_collector_thread(d->rsc.st_connections);
+ rrdset_is_obsolete___safe_from_collector_thread(d->rsc.st_packets);
+ rrdset_is_obsolete___safe_from_collector_thread(d->rsc.st_exceptions);
+ rrdset_is_obsolete___safe_from_collector_thread(d->rsc.st_average_packet_size);
+}
+
+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, usec_t now_ut) {
+ DICTIONARY *dict = physical ? physical_interfaces : virtual_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));
+ d->last_collected = now_ut;
+
+ 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 yet
+ 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);
+
+ 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);
+
+ d->traffic.chart_var_speed = rrdvar_chart_variable_add_and_acquire(d->traffic.st, "nic_speed_max");
+ rrdvar_chart_variable_set(d->traffic.st, d->traffic.chart_var_speed, NAN);
+ }
+
+ 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);
+
+ add_interface_labels(d->packets.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(perflibGetInstanceCounter(pDataBlock, pObjectType, pi, &d->speed.current_bandwidth)) {
+ if(unlikely(!d->speed.st)) {
+ d->speed.st = rrdset_create_localhost(
+ "net_speed"
+ , windows_shared_buffer
+ , NULL
+ , windows_shared_buffer
+ , "net.speed"
+ , "Interface Speed"
+ , "kilobits/s"
+ , PLUGIN_WINDOWS_NAME
+ , "PerflibNetwork"
+ , NETDATA_CHART_PRIO_FIRST_NET_IFACE + 10
+ , update_every
+ , RRDSET_TYPE_LINE
+ );
+
+ add_interface_labels(d->speed.st, windows_shared_buffer, physical);
+
+ d->speed.rd = rrddim_add(d->speed.st, "speed", NULL, 1, BITS_IN_A_KILOBIT, RRD_ALGORITHM_ABSOLUTE);
+ }
+
+ rrddim_set_by_pointer(d->speed.st, d->speed.rd, (collected_number)d->speed.current_bandwidth.current.Data);
+ rrdset_done(d->speed.st);
+
+ rrdvar_chart_variable_set(d->traffic.st, d->traffic.chart_var_speed,
+ (NETDATA_DOUBLE)d->speed.current_bandwidth.current.Data / BITS_IN_A_KILOBIT);
+ }
+
+ if(perflibGetInstanceCounter(pDataBlock, pObjectType, pi, &d->errors.received) &&
+ perflibGetInstanceCounter(pDataBlock, pObjectType, pi, &d->errors.outbound)) {
+
+ if (unlikely(!d->errors.st)) {
+ d->errors.st = rrdset_create_localhost(
+ "net_errors",
+ windows_shared_buffer,
+ NULL,
+ windows_shared_buffer,
+ "net.errors",
+ "Interface Errors",
+ "errors/s",
+ PLUGIN_WINDOWS_NAME,
+ "PerflibNetwork",
+ NETDATA_CHART_PRIO_FIRST_NET_IFACE + 3,
+ update_every,
+ RRDSET_TYPE_LINE);
+
+ add_interface_labels(d->errors.st, windows_shared_buffer, physical);
+
+ d->errors.rd_received = rrddim_add(d->errors.st, "inbound", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ d->errors.rd_outbound = rrddim_add(d->errors.st, "outbound", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ }
+
+ rrddim_set_by_pointer(d->errors.st, d->errors.rd_received, (collected_number)d->errors.received.current.Data);
+ rrddim_set_by_pointer(d->errors.st, d->errors.rd_outbound, (collected_number)d->errors.outbound.current.Data);
+ rrdset_done(d->errors.st);
+ }
+
+ if(perflibGetInstanceCounter(pDataBlock, pObjectType, pi, &d->discards.received) &&
+ perflibGetInstanceCounter(pDataBlock, pObjectType, pi, &d->discards.outbound)) {
+
+ if (unlikely(!d->discards.st)) {
+ d->discards.st = rrdset_create_localhost(
+ "net_drops",
+ windows_shared_buffer,
+ NULL,
+ windows_shared_buffer,
+ "net.drops",
+ "Interface Drops",
+ "drops/s",
+ PLUGIN_WINDOWS_NAME,
+ "PerflibNetwork",
+ NETDATA_CHART_PRIO_FIRST_NET_IFACE + 4,
+ update_every,
+ RRDSET_TYPE_LINE);
+
+ add_interface_labels(d->discards.st, windows_shared_buffer, physical);
+
+ d->discards.rd_received = rrddim_add(d->discards.st, "inbound", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ d->discards.rd_outbound = rrddim_add(d->discards.st, "outbound", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+ }
+
+ rrddim_set_by_pointer(d->discards.st, d->discards.rd_received, (collected_number)d->discards.received.current.Data);
+ rrddim_set_by_pointer(d->discards.st, d->discards.rd_outbound, (collected_number)d->discards.outbound.current.Data);
+ rrdset_done(d->discards.st);
+ }
+
+ if(perflibGetInstanceCounter(pDataBlock, pObjectType, pi, &d->queue.length)) {
+ if (unlikely(!d->queue.st)) {
+ d->queue.st = rrdset_create_localhost(
+ "net_queue_length",
+ windows_shared_buffer,
+ NULL,
+ windows_shared_buffer,
+ "net.queue_length",
+ "Interface Output Queue Length",
+ "packets",
+ PLUGIN_WINDOWS_NAME,
+ "PerflibNetwork",
+ NETDATA_CHART_PRIO_FIRST_NET_IFACE + 5,
+ update_every,
+ RRDSET_TYPE_LINE);
+
+ add_interface_labels(d->queue.st, windows_shared_buffer, physical);
+
+ d->queue.rd = rrddim_add(d->queue.st, "length", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
+ }
+
+ rrddim_set_by_pointer(d->queue.st, d->queue.rd, (collected_number)d->queue.length.current.Data);
+ rrdset_done(d->queue.st);
+ }
+
+ if(perflibGetInstanceCounter(pDataBlock, pObjectType, pi, &d->rsc.connections)) {
+ if (unlikely(!d->rsc.st_connections)) {
+ d->rsc.st_connections = rrdset_create_localhost(
+ "net_rsc_connections",
+ windows_shared_buffer,
+ NULL,
+ windows_shared_buffer,
+ "net.rsc_connections",
+ "Active TCP Connections Offloaded by RSC",
+ "connections",
+ PLUGIN_WINDOWS_NAME,
+ "PerflibNetwork",
+ NETDATA_CHART_PRIO_FIRST_NET_IFACE + 6,
+ update_every,
+ RRDSET_TYPE_LINE);
+
+ add_interface_labels(d->rsc.st_connections, windows_shared_buffer, physical);
+
+ d->rsc.rd_connections = rrddim_add(d->rsc.st_connections, "connections", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
+ }
+
+ rrddim_set_by_pointer(d->rsc.st_connections, d->rsc.rd_connections, (collected_number)d->rsc.connections.current.Data);
+ rrdset_done(d->rsc.st_connections);
+ }
+
+ if(perflibGetInstanceCounter(pDataBlock, pObjectType, pi, &d->rsc.packets)) {
+ if (unlikely(!d->rsc.st_packets)) {
+ d->rsc.st_packets = rrdset_create_localhost(
+ "net_rsc_packets",
+ windows_shared_buffer,
+ NULL,
+ windows_shared_buffer,
+ "net.rsc_packets",
+ "TCP RSC Coalesced Packets",
+ "packets/s",
+ PLUGIN_WINDOWS_NAME,
+ "PerflibNetwork",
+ NETDATA_CHART_PRIO_FIRST_NET_IFACE + 7,
+ update_every,
+ RRDSET_TYPE_LINE);
+
+ add_interface_labels(d->rsc.st_packets, windows_shared_buffer, physical);
+
+ d->rsc.rd_packets = rrddim_add(d->rsc.st_packets, "packets", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ }
+
+ rrddim_set_by_pointer(d->rsc.st_packets, d->rsc.rd_packets, (collected_number)d->rsc.packets.current.Data);
+ rrdset_done(d->rsc.st_packets);
+ }
+
+ if(perflibGetInstanceCounter(pDataBlock, pObjectType, pi, &d->rsc.exceptions)) {
+ if (unlikely(!d->rsc.st_exceptions)) {
+ d->rsc.st_exceptions = rrdset_create_localhost(
+ "net_rsc_exceptions",
+ windows_shared_buffer,
+ NULL,
+ windows_shared_buffer,
+ "net.rsc_exceptions",
+ "TCP RSC Exceptions",
+ "exceptions/s",
+ PLUGIN_WINDOWS_NAME,
+ "PerflibNetwork",
+ NETDATA_CHART_PRIO_FIRST_NET_IFACE + 8,
+ update_every,
+ RRDSET_TYPE_LINE);
+
+ add_interface_labels(d->rsc.st_exceptions, windows_shared_buffer, physical);
+
+ d->rsc.rd_exceptions = rrddim_add(d->rsc.st_exceptions, "exceptions", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ }
+
+ rrddim_set_by_pointer(d->rsc.st_exceptions, d->rsc.rd_exceptions, (collected_number)d->rsc.exceptions.current.Data);
+ rrdset_done(d->rsc.st_exceptions);
+ }
+
+ if(perflibGetInstanceCounter(pDataBlock, pObjectType, pi, &d->rsc.average_packet_size)) {
+ if (unlikely(!d->rsc.st_average_packet_size)) {
+ d->rsc.st_average_packet_size = rrdset_create_localhost(
+ "net_rsc_average_packet_size",
+ windows_shared_buffer,
+ NULL,
+ windows_shared_buffer,
+ "net.rsc_average_packet_size",
+ "TCP RSC Average Packet Size",
+ "bytes",
+ PLUGIN_WINDOWS_NAME,
+ "PerflibNetwork",
+ NETDATA_CHART_PRIO_FIRST_NET_IFACE + 9,
+ update_every,
+ RRDSET_TYPE_LINE);
+
+ add_interface_labels(d->rsc.st_average_packet_size, windows_shared_buffer, physical);
+
+ d->rsc.rd_average_packet_size = rrddim_add(d->rsc.st_average_packet_size, "average", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
+ }
+
+ rrddim_set_by_pointer(d->rsc.st_average_packet_size, d->rsc.rd_average_packet_size, (collected_number)d->rsc.average_packet_size.current.Data);
+ rrdset_done(d->rsc.st_average_packet_size);
+ }
+
+ if(perflibGetInstanceCounter(pDataBlock, pObjectType, pi, &d->chimney.connections)) {
+ if (unlikely(!d->chimney.st)) {
+ d->chimney.st = rrdset_create_localhost(
+ "net_chimney_connections",
+ windows_shared_buffer,
+ NULL,
+ windows_shared_buffer,
+ "net.chimney_connections",
+ "Active TCP Connections Offloaded with Chimney",
+ "connections",
+ PLUGIN_WINDOWS_NAME,
+ "PerflibNetwork",
+ NETDATA_CHART_PRIO_FIRST_NET_IFACE + 10,
+ update_every,
+ RRDSET_TYPE_LINE);
+
+ add_interface_labels(d->chimney.st, windows_shared_buffer, physical);
+
+ d->chimney.rd = rrddim_add(d->chimney.st, "connections", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
+ }
+
+ rrddim_set_by_pointer(d->chimney.st, d->chimney.rd, (collected_number)d->chimney.connections.current.Data);
+ rrdset_done(d->chimney.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);
+ }
+
+ // cleanup
+ {
+ struct network_interface *d;
+ dfe_start_write(dict, d) {
+ if(d->last_collected < now_ut) {
+ network_interface_cleanup(d);
+ dictionary_del(dict, d_dfe.name);
+ }
+ }
+ dfe_done(d);
+ dictionary_garbage_collect(dict);
+ }
+
+ 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;
+
+ usec_t now_ut = now_monotonic_usec();
+ do_network_interface(pDataBlock, update_every, true, now_ut);
+ do_network_interface(pDataBlock, update_every, false, now_ut);
+
+ 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;
+}