Attention is currently required from: flichtenheld, plaisthos.
Hello plaisthos, flichtenheld,
I'd like you to do a code review.
Please visit
http://gerrit.openvpn.net/c/openvpn/+/1143?usp=email
to review the following change.
Change subject: dco-win: add support for multipeer stats
......................................................................
dco-win: add support for multipeer stats
Use the new driver API to fetch per-peer link and VPN byte counters
in both client and server modes.
Two usage modes are supported:
- Single peer: pass the peer ID and a fixed-size output buffer. If the
IOCTL is not supported (old driver), fall back to the legacy API.
- All peers: first call the IOCTL with a small output buffer to get
the required size, then allocate a buffer and call again to fetch
stats for all peers.
Change-Id: I525d7300e49f9a5a18e7146ee35ccc2af8184b8a
Signed-off-by: Lev Stipakov <[email protected]>
---
M src/openvpn/dco_win.c
M src/openvpn/dco_win.h
M src/openvpn/ovpn_dco_win.h
3 files changed, 184 insertions(+), 3 deletions(-)
git pull ssh://gerrit.openvpn.net:29418/openvpn refs/changes/43/1143/1
diff --git a/src/openvpn/dco_win.c b/src/openvpn/dco_win.c
index 5317ac1..bf3f151 100644
--- a/src/openvpn/dco_win.c
+++ b/src/openvpn/dco_win.c
@@ -30,6 +30,7 @@
#include "forward.h"
#include "tun.h"
#include "crypto.h"
+#include "multi.h"
#include "ssl_common.h"
#include "openvpn.h"
@@ -190,6 +191,8 @@
{
dco_context_t *dco = &c->c1.tuntap->dco;
+ dco->c = c;
+
switch (c->mode)
{
case MODE_POINT_TO_POINT:
@@ -714,12 +717,132 @@
int
dco_get_peer_stats_multi(dco_context_t *dco, const bool raise_sigusr1_on_err)
{
- /* Not implemented. */
- return 0;
+ struct gc_arena gc = gc_new();
+
+ int ret = 0;
+ struct tuntap *tt = dco->tt;
+
+ if (!tuntap_defined(tt))
+ {
+ ret = -1;
+ goto done;
+ }
+
+ OVPN_GET_PEER_STATS ps = {
+ .PeerId = -1
+ };
+
+ DWORD required_size = 0, bytes_returned = 0;
+ /* first, figure out buffer size */
+ if (!DeviceIoControl(tt->hand, OVPN_IOCTL_GET_PEER_STATS, &ps, sizeof(ps),
&required_size, sizeof(DWORD), &bytes_returned, NULL))
+ {
+ if (GetLastError() == ERROR_MORE_DATA)
+ {
+ if (bytes_returned != sizeof(DWORD))
+ {
+ msg(M_WARN, "%s: invalid bytes returned for size query (%lu,
expected %zu)", __func__, bytes_returned, sizeof(DWORD));
+ ret = -1;
+ goto done;
+ }
+ /* required_size now contains the size written by the driver */
+ if (required_size == 0)
+ {
+ ret = 0; /* no peers to process */
+ goto done;
+ }
+ if (required_size < sizeof(OVPN_PEER_STATS))
+ {
+ msg(M_WARN, "%s: invalid required size %lu (minimum %zu)",
__func__, required_size, sizeof(OVPN_PEER_STATS));
+ ret = -1;
+ goto done;
+ }
+ }
+ else
+ {
+ msg(M_WARN | M_ERRNO, "%s: failed to fetch required buffer size",
__func__);
+ ret = -1;
+ goto done;
+ }
+ }
+ else
+ {
+ /* unexpected success? */
+ if (bytes_returned == 0)
+ {
+ ret = 0; /* no peers to process */
+ goto done;
+ }
+
+ msg(M_WARN, "%s: first DeviceIoControl call succeeded unexpectedly
(%lu bytes returned)", __func__, bytes_returned);
+ ret = -1;
+ goto done;
+ }
+
+
+ /* allocate the buffer and fetch stats */
+ OVPN_PEER_STATS *peer_stats = gc_malloc(required_size, true, &gc);
+ if (!peer_stats)
+ {
+ msg(M_WARN, "%s: failed to allocate buffer of size %lu", __func__,
required_size);
+ ret = -1;
+ goto done;
+ }
+
+ if (!DeviceIoControl(tt->hand, OVPN_IOCTL_GET_PEER_STATS, &ps, sizeof(ps),
peer_stats, required_size, &bytes_returned, NULL))
+ {
+ /* unlikely case when a peer has been added since fetching buffer
size, not an error! */
+ if (GetLastError() == ERROR_MORE_DATA)
+ {
+ msg(M_WARN, "%s: peer has been added, skip fetching stats",
__func__);
+ ret = 0;
+ goto done;
+ }
+
+ msg(M_WARN | M_ERRNO, "%s: failed to fetch multipeer stats", __func__);
+ ret = -1;
+ goto done;
+ }
+
+ /* iterate over stats and update peers */
+ for (int i = 0; i < bytes_returned / sizeof(OVPN_PEER_STATS); ++i)
+ {
+ OVPN_PEER_STATS *stat = &peer_stats[i];
+
+ if (stat->PeerId >= dco->c->multi->max_clients)
+ {
+ msg(M_WARN, "%s: received out of bound peer_id %u (max=%u)",
__func__, stat->PeerId,
+ dco->c->multi->max_clients);
+ continue;
+ }
+
+ struct multi_instance *mi = dco->c->multi->instances[stat->PeerId];
+ if (!mi)
+ {
+ msg(M_WARN, "%s: received data for a non-existing peer %u",
__func__, stat->PeerId);
+ continue;
+ }
+
+ /* update peer stats */
+ struct context_2 *c2 = &mi->context.c2;
+ c2->dco_read_bytes = stat->LinkRxBytes;
+ c2->dco_write_bytes = stat->LinkTxBytes;
+ c2->tun_read_bytes = stat->VpnRxBytes;
+ c2->tun_write_bytes = stat->VpnTxBytes;
+ }
+
+done:
+ gc_free(&gc);
+
+ if (raise_sigusr1_on_err && ret < 0)
+ {
+ register_signal(dco->c->sig, SIGUSR1, "dco peer stats error");
+ }
+
+ return ret;
}
int
-dco_get_peer_stats(struct context *c, const bool raise_sigusr1_on_err)
+dco_get_peer_stats_fallback(struct context *c, const bool raise_sigusr1_on_err)
{
struct tuntap *tt = c->c1.tuntap;
@@ -747,6 +870,48 @@
return 0;
}
+int
+dco_get_peer_stats(struct context *c, const bool raise_sigusr1_on_err)
+{
+ struct tuntap *tt = c->c1.tuntap;
+
+ if (!tuntap_defined(tt))
+ {
+ return -1;
+ }
+
+ /* first, try a new ioctl */
+ OVPN_GET_PEER_STATS ps = { .PeerId = c->c2.tls_multi->dco_peer_id };
+
+ OVPN_PEER_STATS peer_stats = { 0 };
+ DWORD bytes_returned = 0;
+ if (!DeviceIoControl(tt->hand, OVPN_IOCTL_GET_PEER_STATS, &ps, sizeof(ps),
&peer_stats, sizeof(peer_stats),
+ &bytes_returned, NULL))
+ {
+ if (GetLastError() == ERROR_INVALID_FUNCTION)
+ {
+ /* are we using the old driver? */
+ return dco_get_peer_stats_fallback(c, raise_sigusr1_on_err);
+ }
+
+ msg(M_WARN | M_ERRNO, "%s: DeviceIoControl(OVPN_IOCTL_GET_PEER_STATS)
failed", __func__);
+ return -1;
+ }
+
+ if (bytes_returned != sizeof(OVPN_PEER_STATS))
+ {
+ msg(M_WARN | M_ERRNO, "%s: DeviceIoControl(OVPN_IOCTL_GET_PEER_STATS)
returnted invalid size", __func__);
+ return -1;
+ }
+
+ c->c2.dco_read_bytes = peer_stats.LinkRxBytes;
+ c->c2.dco_write_bytes = peer_stats.LinkTxBytes;
+ c->c2.tun_read_bytes = peer_stats.VpnRxBytes;
+ c->c2.tun_write_bytes = peer_stats.VpnTxBytes;
+
+ return 0;
+}
+
void
dco_event_set(dco_context_t *dco, struct event_set *es, void *arg)
{
diff --git a/src/openvpn/dco_win.h b/src/openvpn/dco_win.h
index a7f4865..4f3f028 100644
--- a/src/openvpn/dco_win.h
+++ b/src/openvpn/dco_win.h
@@ -57,6 +57,8 @@
uint64_t dco_read_bytes;
uint64_t dco_write_bytes;
+
+ struct context *c;
};
typedef struct dco_context dco_context_t;
diff --git a/src/openvpn/ovpn_dco_win.h b/src/openvpn/ovpn_dco_win.h
index baf7214..9e1378a 100644
--- a/src/openvpn/ovpn_dco_win.h
+++ b/src/openvpn/ovpn_dco_win.h
@@ -83,6 +83,14 @@
LONG64 TunBytesReceived;
} OVPN_STATS, * POVPN_STATS;
+typedef struct _OVPN_PEER_STATS {
+ int PeerId;
+ LONG64 LinkRxBytes;
+ LONG64 LinkTxBytes;
+ LONG64 VpnRxBytes;
+ LONG64 VpnTxBytes;
+} OVPN_PEER_STATS, * POVPN_PEER_STATS;
+
typedef enum _OVPN_KEY_SLOT {
OVPN_KEY_SLOT_PRIMARY,
OVPN_KEY_SLOT_SECONDARY
@@ -185,6 +193,10 @@
int IPv6;
} OVPN_MP_IROUTE, * POVPN_MP_IROUTE;
+typedef struct _OVPN_GET_PEER_STATS {
+ int PeerId; // -1 for all peers stats
+} OVPN_GET_PEER_STATS, * POVPN_GET_PEER_STATS;
+
#define OVPN_IOCTL_NEW_PEER CTL_CODE(FILE_DEVICE_UNKNOWN, 1,
METHOD_BUFFERED, FILE_ANY_ACCESS)
#define OVPN_IOCTL_GET_STATS CTL_CODE(FILE_DEVICE_UNKNOWN, 2,
METHOD_BUFFERED, FILE_ANY_ACCESS)
#define OVPN_IOCTL_NEW_KEY CTL_CODE(FILE_DEVICE_UNKNOWN, 3,
METHOD_BUFFERED, FILE_ANY_ACCESS)
@@ -207,3 +219,5 @@
#define OVPN_IOCTL_MP_ADD_IROUTE CTL_CODE(FILE_DEVICE_UNKNOWN, 17,
METHOD_BUFFERED, FILE_ANY_ACCESS)
#define OVPN_IOCTL_MP_DEL_IROUTE CTL_CODE(FILE_DEVICE_UNKNOWN, 18,
METHOD_BUFFERED, FILE_ANY_ACCESS)
+
+#define OVPN_IOCTL_GET_PEER_STATS CTL_CODE(FILE_DEVICE_UNKNOWN, 19,
METHOD_BUFFERED, FILE_ANY_ACCESS)
--
To view, visit http://gerrit.openvpn.net/c/openvpn/+/1143?usp=email
To unsubscribe, or for help writing mail filters, visit
http://gerrit.openvpn.net/settings
Gerrit-Project: openvpn
Gerrit-Branch: master
Gerrit-Change-Id: I525d7300e49f9a5a18e7146ee35ccc2af8184b8a
Gerrit-Change-Number: 1143
Gerrit-PatchSet: 1
Gerrit-Owner: stipa <[email protected]>
Gerrit-Reviewer: flichtenheld <[email protected]>
Gerrit-Reviewer: plaisthos <[email protected]>
Gerrit-CC: openvpn-devel <[email protected]>
Gerrit-Attention: plaisthos <[email protected]>
Gerrit-Attention: flichtenheld <[email protected]>
Gerrit-MessageType: newchange
_______________________________________________
Openvpn-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/openvpn-devel