From 5a24e0b540417cdca85c1fe84e889a586b20e42d Mon Sep 17 00:00:00 2001 From: Daniel Salzman <daniel.salzman@nic.cz> Date: Sun, 4 Jul 2021 13:10:49 +0200 Subject: [PATCH] XDP-TCP: various code cleanup --- src/libknot/xdp/tcp.c | 122 ++++++++++++++++++++--------------- src/libknot/xdp/tcp.h | 24 ++++--- tests/libknot/test_xdp_tcp.c | 4 +- 3 files changed, 86 insertions(+), 64 deletions(-) diff --git a/src/libknot/xdp/tcp.c b/src/libknot/xdp/tcp.c index 74685b669b..93c12a9946 100644 --- a/src/libknot/xdp/tcp.c +++ b/src/libknot/xdp/tcp.c @@ -14,22 +14,22 @@ along with this program. If not, see <https://www.gnu.org/licenses/>. */ -#include "libknot/xdp/tcp.h" - #include <assert.h> #include <stdlib.h> #include <string.h> #include <time.h> -#include "libdnssec/random.h" +#include "libknot/xdp/tcp.h" #include "libknot/attribute.h" #include "libknot/error.h" #include "libknot/xdp/tcp_iobuf.h" +#include "libdnssec/random.h" #include "contrib/macros.h" #include "contrib/openbsd/siphash.h" #include "contrib/ucw/lists.h" -static uint32_t get_timestamp(void) { +static uint32_t get_timestamp(void) +{ struct timespec t; clock_gettime(CLOCK_MONOTONIC, &t); uint64_t res = (uint64_t)t.tv_sec * 1000000; @@ -40,13 +40,11 @@ static uint32_t get_timestamp(void) { static size_t sockaddr_data_len(const struct sockaddr_in6 *rem, const struct sockaddr_in6 *loc) { assert(rem->sin6_family == loc->sin6_family); - switch (rem->sin6_family) { - case AF_INET: + if (rem->sin6_family == AF_INET) { return offsetof(struct sockaddr_in, sin_zero); - case AF_INET6: - return sizeof(rem->sin6_family) + sizeof(rem->sin6_port) + sizeof(rem->sin6_flowinfo) + sizeof(rem->sin6_addr); - default: - return 0; + } else { + assert(rem->sin6_family == AF_INET6); + return offsetof(struct sockaddr_in6, sin6_scope_id); } } @@ -77,34 +75,36 @@ static node_t *tcp_conn_node(knot_tcp_conn_t *conn) _public_ knot_tcp_table_t *knot_tcp_table_new(size_t size) { - knot_tcp_table_t *t = calloc(1, sizeof(*t) + size * sizeof(t->conns[0]) + sizeof(list_t)); - if (t == NULL) { - return t; + knot_tcp_table_t *table = calloc(1, sizeof(*table) + sizeof(list_t) + + size * sizeof(table->conns[0])); + if (table == NULL) { + return table; } - t->size = size; - init_list(tcp_table_timeout(t)); + table->size = size; + init_list(tcp_table_timeout(table)); - for (size_t i = 0; i < sizeof(t->hash_secret) / sizeof(*t->hash_secret); i++) { - t->hash_secret[i] = dnssec_random_uint32_t(); + for (size_t i = 0; i < sizeof(table->hash_secret) / sizeof(*table->hash_secret); i++) { + table->hash_secret[i] = dnssec_random_uint32_t(); } - return t; + return table; } _public_ -void knot_tcp_table_free(knot_tcp_table_t *t) +void knot_tcp_table_free(knot_tcp_table_t *table) { - if (t != NULL) { - knot_tcp_conn_t *n, *next; - WALK_LIST_DELSAFE(n, next, *tcp_table_timeout(t)) { - free(n); + if (table != NULL) { + knot_tcp_conn_t *conn, *next; + WALK_LIST_DELSAFE(conn, next, *tcp_table_timeout(table)) { + free(conn); } - free(t); + free(table); } } -static knot_tcp_conn_t **tcp_table_lookup(const struct sockaddr_in6 *rem, const struct sockaddr_in6 *loc, +static knot_tcp_conn_t **tcp_table_lookup(const struct sockaddr_in6 *rem, + const struct sockaddr_in6 *loc, uint64_t *hash, knot_tcp_table_t *table) { *hash = hash_four_tuple(rem, loc, table->hash_secret); @@ -122,7 +122,7 @@ static knot_tcp_conn_t **tcp_table_lookup(const struct sockaddr_in6 *rem, const return res; } -static void tcp_table_del(knot_tcp_conn_t **todel) +static void tcp_table_del_conn(knot_tcp_conn_t **todel) { knot_tcp_conn_t *conn = *todel; if (conn != NULL) { @@ -133,21 +133,22 @@ static void tcp_table_del(knot_tcp_conn_t **todel) } } -static void tcp_table_del2(knot_tcp_conn_t **todel, knot_tcp_table_t *table) +static void tcp_table_del(knot_tcp_conn_t **todel, knot_tcp_table_t *table) { assert(table->usage > 0); table->inbufs_total -= (*todel)->inbuf.iov_len; - tcp_table_del(todel); + tcp_table_del_conn(todel); table->usage--; } -static void tcp_table_del3(knot_tcp_conn_t *todel, knot_tcp_table_t *table) +static void tcp_table_del_lookup(knot_tcp_conn_t *todel, knot_tcp_table_t *table) { // re-lookup is needed to find the **pointer in the table uint64_t unused_hash; - knot_tcp_conn_t **pconn = tcp_table_lookup(&todel->ip_rem, &todel->ip_loc, &unused_hash, table); + knot_tcp_conn_t **pconn = tcp_table_lookup(&todel->ip_rem, &todel->ip_loc, + &unused_hash, table); assert(*pconn == todel); - tcp_table_del2(pconn, table); + tcp_table_del(pconn, table); } // WARNING you shall ensure that it's not in the table already! @@ -207,7 +208,7 @@ int knot_xdp_tcp_relay(knot_xdp_socket_t *socket, knot_xdp_msg_t msgs[], uint32_ if (msg_count == 0) { return KNOT_EOK; } - if (socket == NULL || msgs == NULL || relays == NULL) { + if (socket == NULL || msgs == NULL || tcp_table == NULL || relays == NULL) { return KNOT_EINVAL; } @@ -236,7 +237,8 @@ int knot_xdp_tcp_relay(knot_xdp_socket_t *socket, knot_xdp_msg_t msgs[], uint32_ } uint64_t conn_hash; - knot_tcp_conn_t **conn = tcp_table_lookup(&msg->ip_from, &msg->ip_to, &conn_hash, tcp_table); + knot_tcp_conn_t **conn = tcp_table_lookup(&msg->ip_from, &msg->ip_to, + &conn_hash, tcp_table); bool seq_ack_match = check_seq_ack(msg, *conn); if (seq_ack_match) { assert((*conn)->mss != 0); @@ -257,7 +259,8 @@ int knot_xdp_tcp_relay(knot_xdp_socket_t *socket, knot_xdp_msg_t msgs[], uint32_ relay.action = XDP_TCP_DATA; struct iovec msg_payload = msg->payload, tofree; - ret = knot_tcp_input_buffers(&(*conn)->inbuf, &msg_payload, &tofree, &tcp_table->inbufs_total); + ret = knot_tcp_input_buffers(&(*conn)->inbuf, &msg_payload, + &tofree, &tcp_table->inbufs_total); if (tofree.iov_len > 0 && ret == KNOT_EOK) { relay.data.iov_base = tofree.iov_base + sizeof(uint16_t); @@ -285,9 +288,12 @@ int knot_xdp_tcp_relay(knot_xdp_socket_t *socket, knot_xdp_msg_t msgs[], uint32_ case (KNOT_XDP_MSG_SYN | KNOT_XDP_MSG_ACK): if (*conn == NULL) { bool synack = (msg->flags & KNOT_XDP_MSG_ACK); - resp_ack(msg, synack ? KNOT_XDP_MSG_ACK : (KNOT_XDP_MSG_SYN | KNOT_XDP_MSG_ACK)); + resp_ack(msg, synack ? KNOT_XDP_MSG_ACK : + (KNOT_XDP_MSG_SYN | KNOT_XDP_MSG_ACK)); relay.action = synack ? XDP_TCP_ESTABLISH : XDP_TCP_SYN; - ret = tcp_table_add(msg, conn_hash, (syn_table == NULL || synack) ? tcp_table : syn_table, &relay.conn); + ret = tcp_table_add(msg, conn_hash, + (syn_table == NULL || synack) ? tcp_table : syn_table, + &relay.conn); knot_tcp_relay_dynarray_add(relays, &relay); relay.conn->state = XDP_TCP_ESTABLISHING; relay.conn->seqno++; @@ -304,7 +310,7 @@ int knot_xdp_tcp_relay(knot_xdp_socket_t *socket, knot_xdp_msg_t msgs[], uint32_ if (syn_table != NULL && msg->payload.iov_len == 0 && *(conn = tcp_table_lookup(&msg->ip_from, &msg->ip_to, &syn_hash, syn_table)) != NULL && check_seq_ack(msg, *conn)) { - tcp_table_del2(conn, syn_table); + tcp_table_del(conn, syn_table); *conn = NULL; relay.action = XDP_TCP_ESTABLISH; ret = tcp_table_add(msg, conn_hash, tcp_table, &relay.conn); @@ -321,7 +327,7 @@ int knot_xdp_tcp_relay(knot_xdp_socket_t *socket, knot_xdp_msg_t msgs[], uint32_ (*conn)->state = XDP_TCP_NORMAL; break; case XDP_TCP_CLOSING: - tcp_table_del2(conn, tcp_table); + tcp_table_del(conn, tcp_table); break; } } @@ -334,7 +340,7 @@ int knot_xdp_tcp_relay(knot_xdp_socket_t *socket, knot_xdp_msg_t msgs[], uint32_ resp_ack(msg, KNOT_XDP_MSG_ACK); relay.action = XDP_TCP_CLOSE; knot_tcp_relay_dynarray_add(relays, &relay); - tcp_table_del2(conn, tcp_table); + tcp_table_del(conn, tcp_table); } else if (msg->payload.iov_len == 0) { // otherwise ignore FIN resp_ack(msg, KNOT_XDP_MSG_FIN | KNOT_XDP_MSG_ACK); relay.action = XDP_TCP_CLOSE; @@ -348,7 +354,7 @@ int knot_xdp_tcp_relay(knot_xdp_socket_t *socket, knot_xdp_msg_t msgs[], uint32_ if (seq_ack_match) { relay.action = XDP_TCP_RESET; knot_tcp_relay_dynarray_add(relays, &relay); - tcp_table_del2(conn, tcp_table); + tcp_table_del(conn, tcp_table); } break; default: @@ -368,19 +374,24 @@ int knot_xdp_tcp_relay(knot_xdp_socket_t *socket, knot_xdp_msg_t msgs[], uint32_ } _public_ -int knot_xdp_tcp_send_data(knot_tcp_relay_dynarray_t *relays, const knot_tcp_relay_t *rl, void *data, size_t len) +int knot_xdp_tcp_send_data(knot_tcp_relay_dynarray_t *relays, const knot_tcp_relay_t *relay, + void *data, size_t data_len) { - assert(len <= UINT16_MAX); - uint16_t prefix = htobe16(len); + if (relays == NULL || relay == NULL || data == NULL) { + return KNOT_EINVAL; + } + + assert(data_len <= UINT16_MAX); + uint16_t prefix = htobe16(data_len); #define PREFIX_LEN (prefix == 0 ? 0 : sizeof(prefix)) - while (len > 0) { - knot_tcp_relay_t *clone = knot_tcp_relay_dynarray_add(relays, rl); + while (data_len > 0) { + knot_tcp_relay_t *clone = knot_tcp_relay_dynarray_add(relays, relay); if (clone == NULL) { return KNOT_ENOMEM; } - size_t chunk = MIN(len + PREFIX_LEN, rl->conn->mss); + size_t chunk = MIN(data_len + PREFIX_LEN, relay->conn->mss); assert(chunk >= PREFIX_LEN); clone->data.iov_base = malloc(chunk); @@ -397,7 +408,7 @@ int knot_xdp_tcp_send_data(knot_tcp_relay_dynarray_t *relays, const knot_tcp_rel clone->free_data = XDP_TCP_FREE_DATA; data += chunk; - len -= chunk; + data_len -= chunk; prefix = 0; } return KNOT_EOK; @@ -406,9 +417,14 @@ int knot_xdp_tcp_send_data(knot_tcp_relay_dynarray_t *relays, const knot_tcp_rel _public_ void knot_xdp_tcp_relay_free(knot_tcp_relay_dynarray_t *relays) { + if (relays == NULL) { + return; + } + knot_dynarray_foreach(knot_tcp_relay, knot_tcp_relay_t, i, *relays) { if (i->free_data != XDP_TCP_FREE_NONE) { - free(i->data.iov_base - (i->free_data == XDP_TCP_FREE_PREFIX ? sizeof(uint16_t) : 0)); + free(i->data.iov_base - + (i->free_data == XDP_TCP_FREE_PREFIX ? sizeof(uint16_t) : 0)); } } knot_tcp_relay_dynarray_free(relays); @@ -463,8 +479,8 @@ int knot_xdp_tcp_send(knot_xdp_socket_t *socket, knot_tcp_relay_t relays[], rl->data.iov_len > msg->payload.iov_len) { ret = KNOT_ESPACE; } else { - // FIXME align kxdpgun with new behaviour - memcpy(msg->payload.iov_base, rl->data.iov_base, rl->data.iov_len); + memcpy(msg->payload.iov_base, rl->data.iov_base, + rl->data.iov_len); msg->payload.iov_len = rl->data.iov_len; } assert(rl->conn != NULL); @@ -513,6 +529,10 @@ int knot_xdp_tcp_timeout(knot_tcp_table_t *tcp_table, knot_xdp_socket_t *socket, uint32_t reset_at_least, size_t reset_inbufs, uint32_t *close_count, uint32_t *reset_count) { + if (tcp_table == NULL) { + return KNOT_EINVAL; + } + knot_tcp_relay_t rl = { 0 }; knot_tcp_relay_dynarray_t relays = { 0 }; uint32_t now = get_timestamp(), i = 0; @@ -560,7 +580,7 @@ int knot_xdp_tcp_timeout(knot_tcp_table_t *tcp_table, knot_xdp_socket_t *socket, *reset_count = list_size(&to_remove); } WALK_LIST_DELSAFE(conn, next, to_remove) { - tcp_table_del3(conn, tcp_table); + tcp_table_del_lookup(conn, tcp_table); } } diff --git a/src/libknot/xdp/tcp.h b/src/libknot/xdp/tcp.h index 115113127a..8c15b528dd 100644 --- a/src/libknot/xdp/tcp.h +++ b/src/libknot/xdp/tcp.h @@ -84,7 +84,6 @@ typedef struct { knot_tcp_action_t answer; struct iovec data; knot_tcp_relay_free_t free_data; - bool send_psh; knot_tcp_conn_t *conn; } knot_tcp_relay_t; @@ -93,6 +92,9 @@ typedef struct { knot_dynarray_declare(knot_tcp_relay, knot_tcp_relay_t, DYNARRAY_VISIBILITY_PUBLIC, TCP_RELAY_DEFAULT_COUNT) +/*! + * \brief Return next TCP sequence number. + */ inline static uint32_t knot_tcp_next_seqno(const knot_xdp_msg_t *msg) { uint32_t res = msg->seqno + msg->payload.iov_len; @@ -116,9 +118,9 @@ knot_tcp_table_t *knot_tcp_table_new(size_t size); /*! * \brief Free TCP connection hash table including all connection records. * - * \note The freed connections are not closed nor resetted. + * \note The freed connections are not closed nor reset. */ -void knot_tcp_table_free(knot_tcp_table_t *t); +void knot_tcp_table_free(knot_tcp_table_t *table); /*! * \brief Process received packets, send ACKs, pick incoming data. @@ -140,14 +142,14 @@ int knot_xdp_tcp_relay(knot_xdp_socket_t *socket, knot_xdp_msg_t msgs[], uint32_ * \brief Answer one relay with one or more relays with data payload. * * \param relays Relays. - * \param rl The relay to answer to. + * \param relay The relay to answer to. * \param data Data payload, possibly > MSS. - * \param len Payload length. + * \param data_len Payload length. * * \return KNOT_EOK, KNOT_ENOMEM */ -int knot_xdp_tcp_send_data(knot_tcp_relay_dynarray_t *relays, const knot_tcp_relay_t *rl, void *data, size_t len); - +int knot_xdp_tcp_send_data(knot_tcp_relay_dynarray_t *relays, const knot_tcp_relay_t *relay, + void *data, size_t data_len); /*! * \brief Free resources in 'relays'. @@ -174,10 +176,12 @@ int knot_xdp_tcp_send(knot_xdp_socket_t *socket, knot_tcp_relay_t relays[], * \param max_at_once Don't close more connections at once. * \param close_timeout Gracefully close connections older than this (usecs). * \param reset_timeout Reset connections older than this (usecs). - * \param reset_at_least Reset at least this number of oldest conecction, even when not yet timeouted. - * \param reset_inbufs Reset oldest connection with buffered partial DNS messages to free up this amount of space. + * \param reset_at_least Reset at least this number of oldest conecctions, even + * when not yet timeouted. + * \param reset_inbufs Reset oldest connection with buffered partial DNS messages + * to free up this amount of space. * \param close_count Optional: Out: number of closed connections. - * \param reset_count Optional: Out: number of resetted connections. + * \param reset_count Optional: Out: number of reset connections. * * \return KNOT_E* */ diff --git a/tests/libknot/test_xdp_tcp.c b/tests/libknot/test_xdp_tcp.c index 3b0abb513a..b43170e987 100644 --- a/tests/libknot/test_xdp_tcp.c +++ b/tests/libknot/test_xdp_tcp.c @@ -63,7 +63,7 @@ static void tcp_cleanup(knot_tcp_table_t *tcp_table, uint32_t timeout, knot_tcp_conn_t *conn, *next; WALK_LIST_DELSAFE(conn, next, *tcp_table_timeout(tcp_table)) { if (i++ < at_least || now - conn->last_active >= timeout) { - tcp_table_del3(conn, tcp_table); + tcp_table_del_lookup(conn, tcp_table); if (cleaned != NULL) { (*cleaned)++; } @@ -460,8 +460,6 @@ static void init_mock(knot_xdp_socket_t **socket, void *send_mock) int main(int argc, char *argv[]) { - UNUSED(argc); - UNUSED(argv); plan_lazy(); test_table = knot_tcp_table_new(TEST_TABLE_SIZE); -- GitLab