@@ -231,17 +231,20 @@
/**
* Update traffic statistics for all peers
*
- * @param dco DCO device context
- * @param m the server context
+ * @param dco DCO device context
+ * @param m the server context
+ * @param raise_sigusr1_on_err whether to raise SIGUSR1 on error
**/
-int dco_get_peer_stats_multi(dco_context_t *dco, struct multi_context *m);
+int dco_get_peer_stats_multi(dco_context_t *dco, struct multi_context *m,
+ const bool raise_sigusr1_on_err);
/**
* Update traffic statistics for single peer
*
- * @param c instance context of the peer
+ * @param c instance context of the peer
+ * @param raise_sigusr1_on_err whether to raise SIGUSR1 on error
**/
-int dco_get_peer_stats(struct context *c);
+int dco_get_peer_stats(struct context *c, const bool raise_sigusr1_on_err);
/**
* Retrieve the list of ciphers supported by the current platform
@@ -373,13 +376,14 @@
}
static inline int
-dco_get_peer_stats_multi(dco_context_t *dco, struct multi_context *m)
+dco_get_peer_stats_multi(dco_context_t *dco, struct multi_context *m,
+ const bool raise_sigusr1_on_err)
{
return 0;
}
static inline int
-dco_get_peer_stats(struct context *c)
+dco_get_peer_stats(struct context *c, const bool raise_sigusr1_on_err)
{
return 0;
}
@@ -713,7 +713,8 @@
}
int
-dco_get_peer_stats_multi(dco_context_t *dco, struct multi_context *m)
+dco_get_peer_stats_multi(dco_context_t *dco, struct multi_context *m,
+ const bool raise_sigusr1_on_err)
{
struct ifdrv drv;
@@ -781,7 +782,7 @@
}
int
-dco_get_peer_stats(struct context *c)
+dco_get_peer_stats(struct context *c, const bool raise_sigusr1_on_err)
{
/* Not implemented. */
return 0;
@@ -952,7 +952,8 @@
}
int
-dco_get_peer_stats_multi(dco_context_t *dco, struct multi_context *m)
+dco_get_peer_stats_multi(dco_context_t *dco, struct multi_context *m,
+ const bool raise_sigusr1_on_err)
{
msg(D_DCO_DEBUG, "%s", __func__);
@@ -963,6 +964,14 @@
int ret = ovpn_nl_msg_send(dco, nl_msg, dco_parse_peer_multi, m, __func__);
nlmsg_free(nl_msg);
+
+ if (raise_sigusr1_on_err && ret < 0)
+ {
+ msg(M_WARN, "Error retrieving DCO peer stats: the underlying DCO peer"
+ "may have been deleted from the kernel without notifying "
+ "userspace. Restarting the session");
+ register_signal(m->top.sig, SIGUSR1, "dco peer stats error");
+ }
return ret;
}
@@ -1008,9 +1017,14 @@
}
int
-dco_get_peer_stats(struct context *c)
+dco_get_peer_stats(struct context *c, const bool raise_sigusr1_on_err)
{
- uint32_t peer_id = c->c2.tls_multi->dco_peer_id;
+ int peer_id = c->c2.tls_multi->dco_peer_id;
+ if (peer_id == -1)
+ {
+ return 0;
+ }
+
msg(D_DCO_DEBUG, "%s: peer-id %d", __func__, peer_id);
if (!c->c1.tuntap)
@@ -1030,6 +1044,14 @@
nla_put_failure:
nlmsg_free(nl_msg);
+
+ if (raise_sigusr1_on_err && ret < 0)
+ {
+ msg(M_WARN, "Error retrieving DCO peer stats: the underlying DCO peer"
+ "may have been deleted from the kernel without notifying "
+ "userspace. Restarting the session");
+ register_signal(c->sig, SIGUSR1, "dco peer stats error");
+ }
return ret;
}
@@ -712,14 +712,15 @@
}
int
-dco_get_peer_stats_multi(dco_context_t *dco, struct multi_context *m)
+dco_get_peer_stats_multi(dco_context_t *dco, struct multi_context *m,
+ const bool raise_sigusr1_on_err)
{
/* Not implemented. */
return 0;
}
int
-dco_get_peer_stats(struct context *c)
+dco_get_peer_stats(struct context *c, const bool raise_sigusr1_on_err)
{
struct tuntap *tt = c->c1.tuntap;
@@ -488,16 +488,14 @@
static void
check_inactivity_timeout(struct context *c)
{
- if (dco_enabled(&c->options) && dco_get_peer_stats(c) == 0)
+ if (dco_enabled(&c->options) && dco_get_peer_stats(c, true) == 0)
{
int64_t tot_bytes = c->c2.tun_read_bytes + c->c2.tun_write_bytes;
int64_t new_bytes = tot_bytes - c->c2.inactivity_bytes;
-
if (new_bytes > c->options.inactivity_minimum_bytes)
{
c->c2.inactivity_bytes = tot_bytes;
event_timeout_reset(&c->c2.inactivity_interval);
-
return;
}
}
@@ -4146,8 +4146,13 @@
counter_type dco_read_bytes = 0;
counter_type dco_write_bytes = 0;
- if (dco_enabled(&c->options) && (dco_get_peer_stats(c) == 0))
+ if (dco_enabled(&c->options))
{
+ if (dco_get_peer_stats(c, true) < 0)
+ {
+ return;
+ }
+
dco_read_bytes = c->c2.dco_read_bytes;
dco_write_bytes = c->c2.dco_write_bytes;
}
@@ -4166,7 +4171,8 @@
void
man_persist_client_stats(struct management *man, struct context *c)
{
- if (dco_enabled(&c->options) && (dco_get_peer_stats(c) == 0))
+ /* no need to raise SIGUSR1 since we are already closing the instance */
+ if (dco_enabled(&c->options) && (dco_get_peer_stats(c, false) == 0))
{
management_bytes_client(man, c->c2.dco_read_bytes, c->c2.dco_write_bytes);
}
@@ -549,7 +549,10 @@
{
if (dco_enabled(&m->top.options))
{
- dco_get_peer_stats_multi(&m->top.c1.tuntap->dco, m);
+ if (dco_get_peer_stats_multi(&m->top.c1.tuntap->dco, m, false) < 0)
+ {
+ return;
+ }
}
setenv_counter(c->c2.es, "bytes_received", c->c2.link_read_bytes + c->c2.dco_read_bytes);
@@ -856,7 +859,10 @@
if (dco_enabled(&m->top.options))
{
- dco_get_peer_stats_multi(&m->top.c1.tuntap->dco, m);
+ if (dco_get_peer_stats_multi(&m->top.c1.tuntap->dco, m, true) < 0)
+ {
+ return;
+ }
}
if (version == 1)
@@ -489,7 +489,10 @@
if (dco_enabled(&c->options))
{
- dco_get_peer_stats(c);
+ if (dco_get_peer_stats(c, true) < 0)
+ {
+ return;
+ }
}
status_printf(so, "OpenVPN STATISTICS");