diff options
Diffstat (limited to 'src/collectors/windows.plugin/perflib-network.c')
-rw-r--r-- | src/collectors/windows.plugin/perflib-network.c | 1500 |
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; +} |