0
0
mirror of https://github.com/OpenVPN/openvpn3.git synced 2024-09-20 04:02:15 +02:00

dco-win: add support for peer stats

Make DCOTransportSource aware of tun stats.

Implemenent DCOTransportSource interface. Withing
stats delta callback, fetch peer stats and return delta
between last and current stats (same as in DCO Linux).

Fixes OVPN3-947.

Signed-off-by: Lev Stipakov <lev@openvpn.net>
This commit is contained in:
Lev Stipakov 2023-03-29 14:08:33 +03:00
parent fe9df4f431
commit 71b3391dee
2 changed files with 78 additions and 19 deletions

View File

@ -21,7 +21,9 @@
#pragma once
class OvpnDcoWinClient : public Client, public KoRekey::Receiver
class OvpnDcoWinClient : public Client,
public KoRekey::Receiver,
public SessionStats::DCOTransportSource
{
friend class ClientConfig;
typedef RCPtr<OvpnDcoWinClient> Ptr;
@ -285,6 +287,8 @@ class OvpnDcoWinClient : public Client, public KoRekey::Receiver
if (!self->halt)
self->queue_read_();
} });
config->transport.stats->dco_configure(this);
}
void queue_read_()
@ -332,6 +336,8 @@ class OvpnDcoWinClient : public Client, public KoRekey::Receiver
{
if (!halt)
{
get_stats_();
halt = true;
async_resolve_cancel();
@ -399,7 +405,7 @@ class OvpnDcoWinClient : public Client, public KoRekey::Receiver
}
}};
const DWORD ec = dco_ioctl_(OVPN_IOCTL_NEW_PEER, &peer, sizeof(peer), &ov);
const DWORD ec = dco_ioctl_(OVPN_IOCTL_NEW_PEER, &peer, sizeof(peer), NULL, 0, &ov);
if (ec == ERROR_SUCCESS)
complete();
else if (ec != ERROR_IO_PENDING)
@ -463,9 +469,34 @@ class OvpnDcoWinClient : public Client, public KoRekey::Receiver
dco_ioctl_(OVPN_IOCTL_SWAP_KEYS);
}
void get_stats_()
{
const SessionStats::DCOTransportSource::Data old_stats = last_stats;
try
{
OVPN_STATS stats{0};
DWORD res = dco_ioctl_(OVPN_IOCTL_GET_STATS, 0, 0, &stats, sizeof(stats));
if (res == ERROR_SUCCESS)
{
last_stats = SessionStats::DCOTransportSource::Data(stats.TransportBytesReceived, stats.TransportBytesSent, stats.TunBytesReceived, stats.TunBytesSent);
}
}
catch (const ErrorCode &e)
{
// no device handle - ignore
if (e.code() != Error::TUN_SETUP_FAILED)
throw e;
}
last_delta = last_stats - old_stats;
}
DWORD dco_ioctl_(DWORD code,
LPVOID data = NULL,
DWORD size = 0,
LPVOID in_buf = NULL,
DWORD in_buf_size = 0,
LPVOID out_buf = NULL,
DWORD out_buf_size = 0,
openvpn_io::windows::overlapped_ptr *ov = nullptr)
{
static const std::map<const DWORD, const char *> code_str{
@ -483,7 +514,7 @@ class OvpnDcoWinClient : public Client, public KoRekey::Receiver
HANDLE th(handle->native_handle());
LPOVERLAPPED ov_ = (ov ? ov->get() : NULL);
if (!DeviceIoControl(th, code, data, size, NULL, 0, NULL, ov_))
if (!DeviceIoControl(th, code, in_buf, in_buf_size, out_buf, out_buf_size, NULL, ov_))
{
const DWORD error_code = GetLastError();
if (ov)
@ -515,10 +546,27 @@ class OvpnDcoWinClient : public Client, public KoRekey::Receiver
return nullptr;
}
virtual SessionStats::DCOTransportSource::Data dco_transport_stats_delta() override
{
if (halt)
{
/* retrieve the last stats update and erase it to avoid race conditions with other queries */
SessionStats::DCOTransportSource::Data delta = last_delta;
last_delta = SessionStats::DCOTransportSource::Data();
return delta;
}
get_stats_();
return last_delta;
}
TunWin::SetupBase::Ptr tun_setup_;
BufferAllocated buf_;
Protocol proto_;
openvpn_io::ip::udp::endpoint endpoint_;
TunWin::DcoTunPersist::Ptr tun_persist;
SessionStats::DCOTransportSource::Data last_stats;
SessionStats::DCOTransportSource::Data last_delta;
};

View File

@ -128,28 +128,37 @@ class SessionStats : public RC<thread_safe_refcount>
struct Data
{
count_t bytes_in;
count_t bytes_out;
count_t transport_bytes_in = 0;
count_t transport_bytes_out = 0;
count_t tun_bytes_in = 0;
count_t tun_bytes_out = 0;
Data()
: bytes_in(0),
bytes_out(0)
Data() = default;
Data(count_t transport_bytes_in_arg, count_t transport_bytes_out_arg)
: transport_bytes_in(transport_bytes_in_arg),
transport_bytes_out(transport_bytes_out_arg)
{
}
Data(count_t bytes_in_arg, count_t bytes_out_arg)
: bytes_in(bytes_in_arg),
bytes_out(bytes_out_arg)
Data(count_t transport_bytes_in_arg, count_t transport_bytes_out_arg, count_t tun_bytes_in_arg, count_t tun_bytes_out_arg)
: transport_bytes_in(transport_bytes_in_arg),
transport_bytes_out(transport_bytes_out_arg),
tun_bytes_in(tun_bytes_in_arg), tun_bytes_out(tun_bytes_out_arg)
{
}
Data operator-(const Data &rhs) const
{
Data data;
if (bytes_in > rhs.bytes_in)
data.bytes_in = bytes_in - rhs.bytes_in;
if (bytes_out > rhs.bytes_out)
data.bytes_out = bytes_out - rhs.bytes_out;
if (transport_bytes_in > rhs.transport_bytes_in)
data.transport_bytes_in = transport_bytes_in - rhs.transport_bytes_in;
if (transport_bytes_out > rhs.transport_bytes_out)
data.transport_bytes_out = transport_bytes_out - rhs.transport_bytes_out;
if (tun_bytes_in > rhs.tun_bytes_in)
data.tun_bytes_in = tun_bytes_in - rhs.tun_bytes_in;
if (tun_bytes_out > rhs.tun_bytes_out)
data.tun_bytes_out = tun_bytes_out - rhs.tun_bytes_out;
return data;
}
};
@ -167,8 +176,10 @@ class SessionStats : public RC<thread_safe_refcount>
if (dco_)
{
const DCOTransportSource::Data data = dco_->dco_transport_stats_delta();
stats_[BYTES_IN] += data.bytes_in;
stats_[BYTES_OUT] += data.bytes_out;
stats_[BYTES_IN] += data.transport_bytes_in;
stats_[BYTES_OUT] += data.transport_bytes_out;
stats_[TUN_BYTES_IN] += data.tun_bytes_in;
stats_[TUN_BYTES_OUT] += data.tun_bytes_out;
}
}