From fcc5ccc4be2fbca697b2a4a2e447dc9206b83f44 Mon Sep 17 00:00:00 2001 From: Alberto Leiva Popper Date: Mon, 26 Feb 2024 17:34:27 -0600 Subject: [PATCH] Add stats on userspace joold Will serve stats through an UDP socket. Start joold with a third argument representing the port number: $ joold netsocket.json modsocket.json 45678 Then query using a simple UDP request: $ echo "" | nc -u 127.0.0.1 45678 KERNEL_SENT_PKTS,4 KERNEL_SENT_BYTES,208 NET_RCVD_PKTS,0 NET_RCVD_BYTES,0 NET_SENT_PKTS,4 NET_SENT_BYTES,208 - KERNEL_SENT_PKTS: Packets sent to the kernel module. (Should match the local instance's JSTAT_JOOLD_PKT_RCVD.) - KERNEL_SENT_BYTES: Session bytes sent to the kernel module. (Should match the local instance's JSTAT_JOOLD_SSS_RCVD multiplied by the session size.) - NET_RCVD_PKTS: Packets received from the network. (Should match the remote instance's JSTAT_JOOLD_PKT_SENT.) - NET_RCVD_BYTES: Session bytes received from the network. (Should match the remote instance's JSTAT_JOOLD_SSS_SENT multiplied by the session size.) - NET_SENT_PKTS: Packets sent to the network. (Should match the remote joold's NET_RCVD_PKTS.) - NET_SENT_BYTES: Session bytes sent to the network. (Should match the remote joold's NET_RCVD_BYTES.) Will not start the server if the port is absent. --- src/usr/joold/Makefile.am | 3 +- src/usr/joold/joold.c | 4 ++ src/usr/joold/modsocket.c | 7 ++ src/usr/joold/netsocket.c | 14 +++- src/usr/joold/statsocket.c | 136 +++++++++++++++++++++++++++++++++++++ src/usr/joold/statsocket.h | 6 ++ 6 files changed, 168 insertions(+), 2 deletions(-) create mode 100644 src/usr/joold/statsocket.c create mode 100644 src/usr/joold/statsocket.h diff --git a/src/usr/joold/Makefile.am b/src/usr/joold/Makefile.am index 2be1dcdbd..7979e51c9 100644 --- a/src/usr/joold/Makefile.am +++ b/src/usr/joold/Makefile.am @@ -6,7 +6,8 @@ joold_SOURCES = \ joold.c \ log.c log.h \ modsocket.c modsocket.h \ - netsocket.c netsocket.h + netsocket.c netsocket.h \ + statsocket.c statsocket.h joold_CFLAGS = ${WARNINGCFLAGS} joold_CFLAGS += -I${top_srcdir}/src diff --git a/src/usr/joold/joold.c b/src/usr/joold/joold.c index 26053e397..f9438f08b 100644 --- a/src/usr/joold/joold.c +++ b/src/usr/joold/joold.c @@ -7,6 +7,7 @@ #include "common/xlat.h" #include "usr/joold/modsocket.h" #include "usr/joold/netsocket.h" +#include "usr/joold/statsocket.h" static void cancel_thread(pthread_t thread) { @@ -44,6 +45,9 @@ int main(int argc, char **argv) netsocket_teardown(); goto end; } + error = statsocket_start(argc, argv); + if (error) + goto clean; error = pthread_create(&mod2net_thread, NULL, modsocket_listen, NULL); if (error) { diff --git a/src/usr/joold/modsocket.c b/src/usr/joold/modsocket.c index 809636d85..adb30e549 100644 --- a/src/usr/joold/modsocket.c +++ b/src/usr/joold/modsocket.c @@ -1,6 +1,7 @@ #include "modsocket.h" #include +#include #include #include #include @@ -15,6 +16,9 @@ static struct joolnl_socket jsocket; static char *iname; +atomic_int modsocket_pkts_sent; +atomic_int modsocket_bytes_sent; + /* Called by the net socket whenever joold receives data from the network. */ void modsocket_send(void *request, size_t request_len) { @@ -82,6 +86,9 @@ static int updated_entries_cb(struct nl_msg *msg, void *arg) */ netsocket_send(nla_data(root), nla_len(root)); do_ack(); + + modsocket_pkts_sent++; + modsocket_bytes_sent += nla_len(root); return 0; einval: diff --git a/src/usr/joold/netsocket.c b/src/usr/joold/netsocket.c index 935add88a..5691bea81 100644 --- a/src/usr/joold/netsocket.c +++ b/src/usr/joold/netsocket.c @@ -2,6 +2,7 @@ #include #include +#include #include #include #include @@ -48,6 +49,11 @@ static struct addrinfo *addr_candidates; /** Candidate from @addr_candidates that we managed to bind the socket with. */ static struct addrinfo *bound_address; +atomic_int netsocket_pkts_rcvd; +atomic_int netsocket_bytes_rcvd; +atomic_int netsocket_pkts_sent; +atomic_int netsocket_bytes_sent; + static struct in_addr *get_addr4(struct addrinfo *addr) { return &((struct sockaddr_in *)addr->ai_addr)->sin_addr; @@ -482,6 +488,9 @@ void *netsocket_listen(void *arg) continue; } + netsocket_pkts_rcvd++; + netsocket_bytes_rcvd += bytes; + syslog(LOG_DEBUG, "Received %d bytes from the network.", bytes); modsocket_send(buffer, bytes); } while (true); @@ -499,6 +508,9 @@ void netsocket_send(void *buffer, size_t size) bound_address->ai_addrlen); if (bytes < 0) pr_perror("Could not send a packet to the network", errno); - else + else { syslog(LOG_DEBUG, "Sent %d bytes to the network.\n", bytes); + netsocket_pkts_sent++; + netsocket_bytes_sent += bytes; + } } diff --git a/src/usr/joold/statsocket.c b/src/usr/joold/statsocket.c new file mode 100644 index 000000000..55bd4ac4e --- /dev/null +++ b/src/usr/joold/statsocket.c @@ -0,0 +1,136 @@ +#include "usr/joold/statsocket.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "log.h" + +static int create_socket(char const *port, int *fd) +{ + int sk; + struct addrinfo hints = { 0 }; + struct addrinfo *ais, *ai; + int err; + + syslog(LOG_INFO, "Setting up statsocket (port %s)...", port); + + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_DGRAM; + hints.ai_flags |= AI_PASSIVE; + + err = getaddrinfo(NULL, port, &hints, &ais); + if (err) { + syslog(LOG_ERR, "getaddrinfo() failed: %s", gai_strerror(err)); + return err; + } + + for (ai = ais; ai; ai = ai->ai_next) { + syslog(LOG_INFO, "Trying an address candidate..."); + + sk = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol); + if (sk < 0) { + pr_perror("socket() failed", errno); + continue; + } + + if (bind(sk, ai->ai_addr, ai->ai_addrlen)) { + pr_perror("bind() failed", errno); + close(sk); + continue; + } + + syslog(LOG_INFO, "Statsocket created successfully."); + freeaddrinfo(ais); + *fd = sk; + return 0; + } + + syslog(LOG_ERR, "None of the candidates yielded a valid statsocket."); + freeaddrinfo(ais); + return 1; +} + +extern atomic_int modsocket_pkts_sent; +extern atomic_int modsocket_bytes_sent; +extern atomic_int netsocket_pkts_rcvd; +extern atomic_int netsocket_bytes_rcvd; +extern atomic_int netsocket_pkts_sent; +extern atomic_int netsocket_bytes_sent; + +#define BUFFER_SIZE 1024 + +void *serve_stats(void *arg) +{ + int sk; + struct sockaddr_storage peer_addr; + socklen_t peer_addr_len; + int nread, nstr, nwritten; + char buffer[BUFFER_SIZE]; + + sk = *((int *)arg); + free(arg); + + while (true) { + peer_addr_len = sizeof(peer_addr); + nread = recvfrom(sk, buffer, BUFFER_SIZE, 0, + (struct sockaddr *) &peer_addr, + &peer_addr_len); + if (nread == -1) + continue; /* Ignore failed request */ + + nstr = snprintf(buffer, BUFFER_SIZE, + "KERNEL_SENT_PKTS,%d\nKERNEL_SENT_BYTES,%d\n" + "NET_RCVD_PKTS,%d\nNET_RCVD_BYTES,%d\n" + "NET_SENT_PKTS,%d\nNET_SENT_BYTES,%d\n", + modsocket_pkts_sent, modsocket_bytes_sent, + netsocket_pkts_rcvd, netsocket_bytes_rcvd, + netsocket_pkts_sent, netsocket_bytes_sent); + if (nstr >= BUFFER_SIZE) + snprintf(buffer, BUFFER_SIZE, "Bug!"); + + nwritten = sendto(sk, buffer, nstr, 0, + (struct sockaddr *) &peer_addr, + peer_addr_len); + if (nwritten != nstr) + syslog(LOG_ERR, "statsocket error: %s\n", strerror(errno)); + } +} + +int statsocket_start(int argc, char **argv) +{ + int sk, *sk2; + pthread_t thread; + int error; + + if (argc < 3) { + syslog(LOG_INFO, "statsocket port unavailable; skipping statsocket."); + return 0; + } + + error = create_socket(argv[2], &sk); + if (error) + return error; + + sk2 = malloc(sizeof(int)); + if (!sk2) + return -ENOMEM; + *sk2 = sk; + + error = pthread_create(&thread, NULL, serve_stats, sk2); + if (error) { + free(sk2); + close(sk); + } + + return error; +} diff --git a/src/usr/joold/statsocket.h b/src/usr/joold/statsocket.h new file mode 100644 index 000000000..c9fafeb9e --- /dev/null +++ b/src/usr/joold/statsocket.h @@ -0,0 +1,6 @@ +#ifndef SRC_USR_JOOLD_STATSOCKET_H_ +#define SRC_USR_JOOLD_STATSOCKET_H_ + +int statsocket_start(int argc, char **argv); + +#endif /* SRC_USR_JOOLD_STATSOCKET_H_ */