Skip to content
Snippets Groups Projects
Commit 9002f89f authored by Daniel Salzman's avatar Daniel Salzman
Browse files

xdp-tcp: tiny code cleanup

parent 6e2621e6
No related branches found
No related tags found
1 merge request!1394xdp-tcp: evolution and bugfixes
/* Copyright (C) 2021 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
/* Copyright (C) 2022 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
......@@ -196,7 +196,8 @@ static void handle_udp(xdp_handle_ctx_t *ctx, knot_layer_t *layer,
static void handle_tcp(xdp_handle_ctx_t *ctx, knot_layer_t *layer,
knotd_qdata_params_t *params)
{
int ret = knot_tcp_recv(ctx->relays, ctx->msg_recv, ctx->msg_recv_count, ctx->tcp_table, ctx->syn_table, XDP_TCP_IGNORE_NONE);
int ret = knot_tcp_recv(ctx->relays, ctx->msg_recv, ctx->msg_recv_count,
ctx->tcp_table, ctx->syn_table, XDP_TCP_IGNORE_NONE);
if (ret != KNOT_EOK) {
log_notice("TCP, failed to process some packets (%s)", knot_strerror(ret));
return;
......@@ -209,6 +210,7 @@ static void handle_tcp(xdp_handle_ctx_t *ctx, knot_layer_t *layer,
for (uint32_t i = 0; i < ctx->msg_recv_count; i++) {
knot_tcp_relay_t *rl = &ctx->relays[i];
// Process all complete DNS queries in one TCP stream.
for (size_t j = 0; j < rl->inbufs_count; j++) {
// Consume the query.
handle_init(params, layer, rl->msg, &rl->inbufs[j]);
......@@ -222,8 +224,8 @@ static void handle_tcp(xdp_handle_ctx_t *ctx, knot_layer_t *layer,
continue;
}
(void)knot_tcp_reply_data(rl, ctx->tcp_table, false, ans->wire, ans->size);
// ignore unprobable ENOMEM here
(void)knot_tcp_reply_data(rl, ctx->tcp_table, false,
ans->wire, ans->size);
}
handle_finish(layer);
......@@ -257,11 +259,13 @@ void xdp_handle_send(xdp_handle_ctx_t *ctx)
uint32_t unused;
(void)knot_xdp_send(ctx->sock, ctx->msg_send_udp, ctx->msg_udp_count, &unused);
if (ctx->tcp) {
int ret = knot_tcp_send(ctx->sock, ctx->relays, ctx->msg_recv_count, XDP_BATCHLEN);
int ret = knot_tcp_send(ctx->sock, ctx->relays, ctx->msg_recv_count,
XDP_BATCHLEN);
if (ret != KNOT_EOK) {
log_notice("TCP, failed to send some packets");
}
}
(void)knot_xdp_send_finish(ctx->sock);
if (ctx->tcp) {
......
/* Copyright (C) 2021 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
/* Copyright (C) 2022 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
......
/* Copyright (C) 2021 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
/* Copyright (C) 2022 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
......@@ -53,7 +53,8 @@ inline static void msg_init(knot_xdp_msg_t *msg, knot_xdp_msg_flag_t flags)
inline static void msg_init_reply(knot_xdp_msg_t *msg, const knot_xdp_msg_t *query)
{
msg_init_base(msg, query->flags & (KNOT_XDP_MSG_IPV6 | KNOT_XDP_MSG_TCP | KNOT_XDP_MSG_MSS | KNOT_XDP_MSG_WSC));
msg_init_base(msg, query->flags & (KNOT_XDP_MSG_IPV6 | KNOT_XDP_MSG_TCP |
KNOT_XDP_MSG_MSS | KNOT_XDP_MSG_WSC));
memcpy(msg->eth_from, query->eth_to, ETH_ALEN);
memcpy(msg->eth_to, query->eth_from, ETH_ALEN);
......
/* Copyright (C) 2021 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
/* Copyright (C) 2022 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
......
/* Copyright (C) 2021 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
/* Copyright (C) 2022 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
......@@ -270,22 +270,22 @@ static void conn_update(knot_tcp_conn_t *conn, const knot_xdp_msg_t *msg)
}
_public_
int knot_tcp_recv(knot_tcp_relay_t *relays, knot_xdp_msg_t *msgs, uint32_t count,
int knot_tcp_recv(knot_tcp_relay_t *relays, knot_xdp_msg_t msgs[], uint32_t msg_count,
knot_tcp_table_t *tcp_table, knot_tcp_table_t *syn_table,
knot_tcp_ignore_t ignore)
{
if (count == 0) {
if (msg_count == 0) {
return KNOT_EOK;
}
if (relays == NULL || msgs == NULL || tcp_table == NULL) {
return KNOT_EINVAL;
}
memset(relays, 0, count * sizeof(*relays));
memset(relays, 0, msg_count * sizeof(*relays));
knot_tcp_relay_t *relay = relays;
int ret = KNOT_EOK;
for (knot_xdp_msg_t *msg = msgs; msg != msgs + count && ret == KNOT_EOK; msg++) {
for (knot_xdp_msg_t *msg = msgs; msg != msgs + msg_count && ret == KNOT_EOK; msg++) {
if (!(msg->flags & KNOT_XDP_MSG_TCP)) {
continue;
}
......@@ -439,7 +439,7 @@ int knot_tcp_recv(knot_tcp_relay_t *relays, knot_xdp_msg_t *msgs, uint32_t count
_public_
int knot_tcp_reply_data(knot_tcp_relay_t *relay, knot_tcp_table_t *tcp_table,
bool ignore_lastbyte, uint8_t *data, size_t len)
bool ignore_lastbyte, uint8_t *data, uint32_t len)
{
if (relay == NULL || tcp_table == NULL || relay->conn == NULL) {
return KNOT_EINVAL;
......@@ -462,18 +462,15 @@ static knot_xdp_msg_t *first_msg(knot_xdp_msg_t *msgs, uint32_t n_msgs)
return msgs - 1; // will be incremented just before first use
}
static int send_msgs(knot_xdp_msg_t *msgs, uint32_t n_msgs, knot_xdp_socket_t *socket)
static void send_msgs(knot_xdp_msg_t *msgs, uint32_t n_msgs, knot_xdp_socket_t *socket)
{
uint32_t sent = 0;
if (n_msgs == 0) {
return KNOT_EOK;
}
assert(socket);
assert(msgs);
int ret = knot_xdp_send(socket, msgs, n_msgs, &sent);
if (ret != KNOT_EOK) {
printf("TCP send[%u/%u]: %s\n", sent, n_msgs, knot_strerror(ret));
if (n_msgs > 0) {
uint32_t unused;
(void)knot_xdp_send(socket, msgs, n_msgs, &unused);
}
return KNOT_EOK; // ignore errcode from send
}
static void msg_init_from_conn(knot_xdp_msg_t *msg, knot_tcp_conn_t *conn)
......@@ -493,11 +490,11 @@ static void msg_init_from_conn(knot_xdp_msg_t *msg, knot_tcp_conn_t *conn)
}
static int next_msg(knot_xdp_msg_t *msgs, uint32_t n_msgs, knot_xdp_msg_t **cur,
knot_xdp_socket_t *socket, knot_tcp_relay_t *rl)
knot_xdp_socket_t *socket, knot_tcp_relay_t *rl)
{
(*cur)++;
if (*cur - msgs >= n_msgs) {
(void)send_msgs(msgs, n_msgs, socket);
send_msgs(msgs, n_msgs, socket);
*cur = first_msg(msgs, n_msgs);
(*cur)++;
}
......@@ -523,8 +520,8 @@ static int next_msg(knot_xdp_msg_t *msgs, uint32_t n_msgs, knot_xdp_msg_t **cur,
}
_public_
int knot_tcp_send(knot_xdp_socket_t *socket, knot_tcp_relay_t relays[], uint32_t relay_count,
uint32_t max_at_once)
int knot_tcp_send(knot_xdp_socket_t *socket, knot_tcp_relay_t relays[],
uint32_t relay_count, uint32_t max_at_once)
{
if (relay_count == 0) {
return KNOT_EOK;
......@@ -536,12 +533,14 @@ int knot_tcp_send(knot_xdp_socket_t *socket, knot_tcp_relay_t relays[], uint32_t
knot_xdp_send_prepare(socket);
knot_xdp_msg_t msgs[max_at_once], *first = first_msg(msgs, max_at_once), *msg = first;
int ret = KNOT_EOK;
for (uint32_t i = 0; i < relay_count; i++) {
knot_tcp_relay_t *rl = &relays[i];
#define NEXT_MSG if ((ret = next_msg(msgs, max_at_once, &msg, socket, rl)) != KNOT_EOK) { return ret; }
#define NEXT_MSG { \
int ret = next_msg(msgs, max_at_once, &msg, socket, rl); \
if (ret != KNOT_EOK) { return ret; } \
}
if (rl->auto_answer != 0) {
NEXT_MSG
......@@ -600,19 +599,18 @@ int knot_tcp_send(knot_xdp_socket_t *socket, knot_tcp_relay_t relays[], uint32_t
can_data--;
ob = ob->next;
}
}
#undef NEXT_MSG
}
ret = send_msgs(msgs, msg - first, socket);
send_msgs(msgs, msg - first, socket);
(void)knot_xdp_send_finish(socket);
return ret;
return KNOT_EOK;
}
void sweep_reset(knot_tcp_table_t *tcp_table, knot_tcp_relay_t *rl,
ssize_t *free_conns, ssize_t *free_inbuf, ssize_t *free_outbuf,
uint32_t *reset_count)
static void sweep_reset(knot_tcp_table_t *tcp_table, knot_tcp_relay_t *rl,
ssize_t *free_conns, ssize_t *free_inbuf, ssize_t *free_outbuf,
uint32_t *reset_count)
{
rl->answer = XDP_TCP_RESET | XDP_TCP_FREE;
tcp_table_remove(tcp_table_re_lookup(rl->conn, tcp_table), tcp_table); // also updates tcp_table->next_*
......@@ -629,9 +627,9 @@ void sweep_reset(knot_tcp_table_t *tcp_table, knot_tcp_relay_t *rl,
_public_
int knot_tcp_sweep(knot_tcp_table_t *tcp_table,
uint32_t close_timeout, uint32_t reset_timeout,
uint32_t resend_timeout, uint32_t limit_n_conn,
uint32_t resend_timeout, uint32_t limit_conn_count,
size_t limit_ibuf_size, size_t limit_obuf_size,
knot_tcp_relay_t *relays, size_t max_relays,
knot_tcp_relay_t *relays, uint32_t max_relays,
uint32_t *close_count, uint32_t *reset_count)
{
if (tcp_table == NULL || relays == NULL || max_relays < 1) {
......@@ -642,7 +640,7 @@ int knot_tcp_sweep(knot_tcp_table_t *tcp_table,
memset(relays, 0, max_relays * sizeof(*relays));
knot_tcp_relay_t *rl = relays, *rl_max = rl + max_relays;
ssize_t free_conns = (ssize_t)(tcp_table->usage - limit_n_conn);
ssize_t free_conns = (ssize_t)(tcp_table->usage - limit_conn_count);
ssize_t free_inbuf = (ssize_t)(tcp_table->inbufs_total - MIN(limit_ibuf_size, SSIZE_MAX));
ssize_t free_outbuf = (ssize_t)(tcp_table->outbufs_total - MIN(limit_obuf_size, SSIZE_MAX));
......@@ -709,10 +707,11 @@ int knot_tcp_sweep(knot_tcp_table_t *tcp_table,
}
_public_
void knot_tcp_cleanup(knot_tcp_table_t *tcp_table, knot_tcp_relay_t *relays, size_t n_relays)
void knot_tcp_cleanup(knot_tcp_table_t *tcp_table, knot_tcp_relay_t relays[],
uint32_t relay_count)
{
(void)tcp_table;
for (uint32_t i = 0; i < n_relays; i++) {
for (uint32_t i = 0; i < relay_count; i++) {
if (relays[i].answer & XDP_TCP_FREE) {
del_conn(relays[i].conn);
}
......
......@@ -75,7 +75,7 @@ typedef struct knot_tcp_conn {
uint32_t acked;
uint32_t window_size;
uint32_t last_active;
uint32_t establish_rtt;
uint32_t establish_rtt; // in microseconds
knot_tcp_state_t state;
struct iovec inbuf;
struct knot_tcp_outbuf *outbufs;
......@@ -118,9 +118,13 @@ inline static uint32_t knot_tcp_next_seqno(const knot_xdp_msg_t *msg)
return res;
}
inline static bool knot_tcp_relay_empty(const knot_tcp_relay_t *r)
/*!
* \brief Check if the relay is empty.
*/
inline static bool knot_tcp_relay_empty(const knot_tcp_relay_t *relay)
{
return r->action == XDP_TCP_NOOP && r->answer == XDP_TCP_NOOP && r->auto_answer == 0 && r->inbufs_count == 0;
return relay->action == XDP_TCP_NOOP && relay->answer == XDP_TCP_NOOP &&
relay->auto_answer == 0 && relay->inbufs_count == 0;
}
/*!
......@@ -143,33 +147,34 @@ knot_tcp_table_t *knot_tcp_table_new(size_t size, knot_tcp_table_t *secret_share
void knot_tcp_table_free(knot_tcp_table_t *table);
/*!
* \brief Process received packets, prepare automatick responses (e.g. ACK), pick incoming data.
* \brief Process received packets, prepare automatic responses (e.g. ACK), pick incoming data.
*
* \param relays Out: relays to be filled with message/connection details.
* \param msgs Packets received by knot_xdp_recv();
* \param count Number of received packets.
* \param msgs Packets received by knot_xdp_recv().
* \param msg_count Number of received packets.
* \param tcp_table Table of TCP connections.
* \param syn_table Optional: extra table for handling partially established connections.
* \param ignore Ignore specific TCP packets indication.
*
* \return KNOT_E*
*/
int knot_tcp_recv(knot_tcp_relay_t *relays, knot_xdp_msg_t *msgs, uint32_t count,
int knot_tcp_recv(knot_tcp_relay_t *relays, knot_xdp_msg_t msgs[], uint32_t msg_count,
knot_tcp_table_t *tcp_table, knot_tcp_table_t *syn_table,
knot_tcp_ignore_t ignore);
/*!
* \brief Prepare data (payload) to be sent as a response on specific relay.
*
* \param relay Relay with active connection.
* \param tcp_table TCP table.
* \param relay Relay with active connection.
* \param tcp_table TCP table.
* \param ignore_lastbyte Evil mode: drop last byte of the payload.
* \param data Data payload, possibly > MSS and > window.
* \param len Payload length, < 64k.
* \param data Data payload, possibly > MSS and > window.
* \param len Payload length, < 64k.
*
* \return KNOT_E*
*/
int knot_tcp_reply_data(knot_tcp_relay_t *relay, knot_tcp_table_t *tcp_table,
bool ignore_lastbyte, uint8_t *data, size_t len);
bool ignore_lastbyte, uint8_t *data, uint32_t len);
/*!
* \brief Send TCP packets.
......@@ -181,8 +186,8 @@ int knot_tcp_reply_data(knot_tcp_relay_t *relay, knot_tcp_table_t *tcp_table,
*
* \return KNOT_E*
*/
int knot_tcp_send(knot_xdp_socket_t *socket, knot_tcp_relay_t relays[], uint32_t relay_count,
uint32_t max_at_once);
int knot_tcp_send(knot_xdp_socket_t *socket, knot_tcp_relay_t relays[],
uint32_t relay_count, uint32_t max_at_once);
/*!
* \brief Cleanup old TCP connections, perform timeout checks.
......@@ -190,30 +195,32 @@ int knot_tcp_send(knot_xdp_socket_t *socket, knot_tcp_relay_t relays[], uint32_t
* \param tcp_table TCP connection table to clean up.
* \param close_timeout Gracefully close connections older than this (usecs).
* \param reset_timeout Reset connections older than this (usecs).
* \param limit_n_conn Limit of active connections in TCP table, reset if more.
* \param resend_timeout Resend unAcked data older than this (usecs).
* \param limit_conn_count Limit of active connections in TCP table, reset if more.
* \param limit_ibuf_size Limit of memory usage by input buffers, reset if exceeded.
* \param limit_obuf_size Limit of memory usage by output buffers, reset if exceeded.
* \param relays Out: relays to be filled with close/reset instructions for knot_tcp_send().
* \param max_relays Maximum relays to be used.
* \param close_count Out: number of connection closed.
* \param reset_count Out: number of connections reset.
* \param close_count Out: number of connections closed (can be NULL).
* \param reset_count Out: number of connections reset (can be NULL).
*
* \return KNOT_E*
*/
int knot_tcp_sweep(knot_tcp_table_t *tcp_table,
uint32_t close_timeout, uint32_t reset_timeout,
uint32_t resend_timeout, uint32_t limit_n_conn,
uint32_t resend_timeout, uint32_t limit_conn_count,
size_t limit_ibuf_size, size_t limit_obuf_size,
knot_tcp_relay_t *relays, size_t max_relays,
knot_tcp_relay_t *relays, uint32_t max_relays,
uint32_t *close_count, uint32_t *reset_count);
/*!
* \brief Free resources of closed/reset connections.
*
* \param tcp_table TCP table with connections.
* \param relays Relays with closed/resettted (or other, ignored) connections.
* \param n_relays Number of relays.
* \param relays Relays with closed/reset (or other, ignored) connections.
* \param relay_count Number of relays.
*/
void knot_tcp_cleanup(knot_tcp_table_t *tcp_table, knot_tcp_relay_t *relays, size_t n_relays);
void knot_tcp_cleanup(knot_tcp_table_t *tcp_table, knot_tcp_relay_t relays[],
uint32_t relay_count);
/*! @} */
/* Copyright (C) 2021 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
/* Copyright (C) 2022 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
......@@ -18,7 +18,6 @@
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include "libknot/xdp/tcp_iobuf.h"
#include "libknot/error.h"
......
/* Copyright (C) 2021 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
/* Copyright (C) 2022 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
......@@ -25,7 +25,6 @@
#pragma once
#include <assert.h>
#include <string.h>
#include <sys/uio.h>
......@@ -57,7 +56,7 @@ int tcp_inbuf_update(struct iovec *buffer, struct iovec data,
/*!
* \brief Add payload to be sent by TCP, to output buffers.
*
* \param ob Output buffers to be updated.
* \param bufs Output buffers to be updated.
* \param data Payload to be sent.
* \param len Payload length.
* \param ignore_lastbyte Evil mode: drop last byte of the payload.
......@@ -72,7 +71,7 @@ int tcp_outbufs_add(knot_tcp_outbuf_t **bufs, uint8_t *data, size_t len,
/*!
* \brief Remove+free acked data from output buffers.
*
* \param ob Output buffers to be updated.
* \param bufs Output buffers to be updated.
* \param ackno Ackno of received ACK.
* \param outbufs_total In/out: total outbuf statistic to be updated.
*/
......@@ -81,7 +80,7 @@ void tcp_outbufs_ack(knot_tcp_outbuf_t **bufs, uint32_t ackno, size_t *outbufs_t
/*!
* \brief Prepare output buffers to be sent now.
*
* \param ob Output buffers to be updated.
* \param bufs Output buffers to be updated.
* \param window_size Connection outgoing window size.
* \param resend Send also possibly already sent data.
* \param send_start Out: first output buffer to be sent.
......
/* Copyright (C) 2021 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
/* Copyright (C) 2022 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment