From c357bf397f2eff67a70d4e4f6c472381eb10416c Mon Sep 17 00:00:00 2001 From: Kristof Provost Date: Fri, 2 Dec 2022 16:59:38 +0100 Subject: [PATCH] if_ovpn: include peer counters in a OVPN_NOTIF_DEL_PEER message When we remove a peer userspace can no longer retrieve its counters. To ensure that userspace can get a full count of the entire session we now include the counters in the deletion message. Sponsored by: Rubicon Communications, LLC ("Netgate") Differential Revision: https://reviews.freebsd.org/D37606 --- sys/net/if_ovpn.c | 62 ++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 53 insertions(+), 9 deletions(-) diff --git a/sys/net/if_ovpn.c b/sys/net/if_ovpn.c index cf5f2cc6fcf6..a11dd0b4a6cb 100644 --- a/sys/net/if_ovpn.c +++ b/sys/net/if_ovpn.c @@ -114,14 +114,6 @@ struct ovpn_wire_header { uint8_t auth_tag[16]; }; -struct ovpn_notification { - enum ovpn_notif_type type; - enum ovpn_del_reason del_reason; - uint32_t peerid; -}; - -struct ovpn_softc; - struct ovpn_peer_counters { uint64_t pkt_in; uint64_t pkt_out; @@ -130,6 +122,17 @@ struct ovpn_peer_counters { }; #define OVPN_PEER_COUNTER_SIZE (sizeof(struct ovpn_peer_counters)/sizeof(uint64_t)) +struct ovpn_notification { + enum ovpn_notif_type type; + uint32_t peerid; + + /* Delete notification */ + enum ovpn_del_reason del_reason; + struct ovpn_peer_counters counters; +}; + +struct ovpn_softc; + struct ovpn_kpeer { RB_ENTRY(ovpn_kpeer) tree; int refcount; @@ -438,6 +441,16 @@ ovpn_notify_del_peer(struct ovpn_softc *sc, struct ovpn_kpeer *peer) n->peerid = peer->peerid; n->type = OVPN_NOTIF_DEL_PEER; n->del_reason = peer->del_reason; + + n->counters.pkt_in = counter_u64_fetch(peer->counters[offsetof( + struct ovpn_peer_counters, pkt_in)/sizeof(uint64_t)]); + n->counters.pkt_out = counter_u64_fetch(peer->counters[offsetof( + struct ovpn_peer_counters, pkt_out)/sizeof(uint64_t)]); + n->counters.bytes_in = counter_u64_fetch(peer->counters[offsetof( + struct ovpn_peer_counters, bytes_in)/sizeof(uint64_t)]); + n->counters.bytes_out = counter_u64_fetch(peer->counters[offsetof( + struct ovpn_peer_counters, bytes_out)/sizeof(uint64_t)]); + if (buf_ring_enqueue(sc->notifring, n) != 0) { free(n, M_OVPN); } else if (sc->so != NULL) { @@ -1335,6 +1348,32 @@ ovpn_poll_pkt(struct ovpn_softc *sc, nvlist_t **onvl) return (0); } +static void +ovpn_notif_add_counters(nvlist_t *parent, struct ovpn_notification *n) +{ + nvlist_t *nvl; + + nvl = nvlist_create(0); + if (nvl == NULL) + return; + + nvlist_add_number(nvl, "in", n->counters.pkt_in); + nvlist_add_number(nvl, "out", n->counters.pkt_out); + + nvlist_add_nvlist(parent, "packets", nvl); + nvlist_destroy(nvl); + + nvl = nvlist_create(0); + if (nvl == NULL) + return; + + nvlist_add_number(nvl, "in", n->counters.bytes_in); + nvlist_add_number(nvl, "out", n->counters.bytes_out); + + nvlist_add_nvlist(parent, "bytes", nvl); + nvlist_destroy(nvl); +} + static int opvn_get_pkt(struct ovpn_softc *sc, nvlist_t **onvl) { @@ -1353,8 +1392,13 @@ opvn_get_pkt(struct ovpn_softc *sc, nvlist_t **onvl) } nvlist_add_number(nvl, "peerid", n->peerid); nvlist_add_number(nvl, "notification", n->type); - if (n->type == OVPN_NOTIF_DEL_PEER) + if (n->type == OVPN_NOTIF_DEL_PEER) { nvlist_add_number(nvl, "del_reason", n->del_reason); + + /* No error handling, because we want to send the notification + * even if we can't attach the counters. */ + ovpn_notif_add_counters(nvl, n); + } free(n, M_OVPN); *onvl = nvl;