flow, tcp: Add logging helpers for connection related messages

Most of the messages logged by the TCP code (be they errors, debug or
trace messages) are related to a specific connection / flow.  We're fairly
consistent about prefixing these with the type of connection and the
connection / flow index.  However there are a few places where we put the
index later in the message or omit it entirely.  The template with the
prefix is also a little bulky to carry around for every message,
particularly for spliced connections.

To help keep this consistent, introduce some helpers to log messages
linked to a specific flow.  It takes the flow as a parameter and adds a
uniform prefix to each message.  This makes things slightly neater now, but
more importantly will help keep formatting consistent as we add more things
to the flow table.

Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
Signed-off-by: Stefano Brivio <sbrivio@redhat.com>
This commit is contained in:
David Gibson 2023-11-30 13:02:13 +11:00 committed by Stefano Brivio
parent 96590b0560
commit eb8b1a233b
4 changed files with 96 additions and 79 deletions

18
flow.c
View file

@ -66,3 +66,21 @@ void flow_table_compact(struct ctx *c, union flow *hole)
memset(from, 0, sizeof(*from)); memset(from, 0, sizeof(*from));
} }
/** flow_log_ - Log flow-related message
* @f: flow the message is related to
* @pri: Log priority
* @fmt: Format string
* @...: printf-arguments
*/
void flow_log_(const struct flow_common *f, int pri, const char *fmt, ...)
{
char msg[BUFSIZ];
va_list args;
va_start(args, fmt);
(void)vsnprintf(msg, sizeof(msg), fmt, args);
va_end(args);
logmsg(pri, "Flow %u (%s): %s", flow_idx(f), FLOW_TYPE(f), msg);
}

14
flow.h
View file

@ -43,4 +43,18 @@ union flow;
void flow_table_compact(struct ctx *c, union flow *hole); void flow_table_compact(struct ctx *c, union flow *hole);
void flow_log_(const struct flow_common *f, int pri, const char *fmt, ...)
__attribute__((format(printf, 3, 4)));
#define flow_log(f_, pri, ...) flow_log_(&(f_)->f, (pri), __VA_ARGS__)
#define flow_dbg(f, ...) flow_log((f), LOG_DEBUG, __VA_ARGS__)
#define flow_err(f, ...) flow_log((f), LOG_ERR, __VA_ARGS__)
#define flow_trace(f, ...) \
do { \
if (log_trace) \
flow_dbg((f), __VA_ARGS__); \
} while (0)
#endif /* FLOW_H */ #endif /* FLOW_H */

68
tcp.c
View file

@ -624,7 +624,7 @@ static void conn_flag_do(const struct ctx *c, struct tcp_tap_conn *conn,
unsigned long flag); unsigned long flag);
#define conn_flag(c, conn, flag) \ #define conn_flag(c, conn, flag) \
do { \ do { \
trace("TCP: flag at %s:%i", __func__, __LINE__); \ flow_trace(conn, "flag at %s:%i", __func__, __LINE__); \
conn_flag_do(c, conn, flag); \ conn_flag_do(c, conn, flag); \
} while (0) } while (0)
@ -695,7 +695,8 @@ static void tcp_timer_ctl(const struct ctx *c, struct tcp_tap_conn *conn)
fd = timerfd_create(CLOCK_MONOTONIC, 0); fd = timerfd_create(CLOCK_MONOTONIC, 0);
if (fd == -1 || fd > FD_REF_MAX) { if (fd == -1 || fd > FD_REF_MAX) {
debug("TCP: failed to get timer: %s", strerror(errno)); flow_dbg(conn, "failed to get timer: %s",
strerror(errno));
if (fd > -1) if (fd > -1)
close(fd); close(fd);
conn->timer = -1; conn->timer = -1;
@ -704,7 +705,8 @@ static void tcp_timer_ctl(const struct ctx *c, struct tcp_tap_conn *conn)
conn->timer = fd; conn->timer = fd;
if (epoll_ctl(c->epollfd, EPOLL_CTL_ADD, conn->timer, &ev)) { if (epoll_ctl(c->epollfd, EPOLL_CTL_ADD, conn->timer, &ev)) {
debug("TCP: failed to add timer: %s", strerror(errno)); flow_dbg(conn, "failed to add timer: %s",
strerror(errno));
close(conn->timer); close(conn->timer);
conn->timer = -1; conn->timer = -1;
return; return;
@ -724,8 +726,8 @@ static void tcp_timer_ctl(const struct ctx *c, struct tcp_tap_conn *conn)
it.it_value.tv_sec = ACT_TIMEOUT; it.it_value.tv_sec = ACT_TIMEOUT;
} }
debug("TCP: index %u, timer expires in %lu.%03lus", FLOW_IDX(conn), flow_dbg(conn, "timer expires in %lu.%03lus", it.it_value.tv_sec,
it.it_value.tv_sec, it.it_value.tv_nsec / 1000 / 1000); it.it_value.tv_nsec / 1000 / 1000);
timerfd_settime(conn->timer, 0, &it, NULL); timerfd_settime(conn->timer, 0, &it, NULL);
} }
@ -746,10 +748,8 @@ static void conn_flag_do(const struct ctx *c, struct tcp_tap_conn *conn,
return; return;
conn->flags &= flag; conn->flags &= flag;
if (flag_index >= 0) { if (flag_index >= 0)
debug("TCP: index %u: %s dropped", FLOW_IDX(conn), flow_dbg(conn, "%s dropped", tcp_flag_str[flag_index]);
tcp_flag_str[flag_index]);
}
} else { } else {
int flag_index = fls(flag); int flag_index = fls(flag);
@ -767,10 +767,8 @@ static void conn_flag_do(const struct ctx *c, struct tcp_tap_conn *conn,
} }
conn->flags |= flag; conn->flags |= flag;
if (flag_index >= 0) { if (flag_index >= 0)
debug("TCP: index %u: %s", FLOW_IDX(conn), flow_dbg(conn, "%s", tcp_flag_str[flag_index]);
tcp_flag_str[flag_index]);
}
} }
if (flag == STALLED || flag == ~STALLED) if (flag == STALLED || flag == ~STALLED)
@ -817,15 +815,14 @@ static void conn_event_do(const struct ctx *c, struct tcp_tap_conn *conn,
if (conn->flags & ACTIVE_CLOSE) if (conn->flags & ACTIVE_CLOSE)
new += 5; new += 5;
if (prev != new) { if (prev != new)
debug("TCP: index %u, %s: %s -> %s", FLOW_IDX(conn), flow_dbg(conn, "%s: %s -> %s",
num == -1 ? "CLOSED" : tcp_event_str[num], num == -1 ? "CLOSED" : tcp_event_str[num],
prev == -1 ? "CLOSED" : tcp_state_str[prev], prev == -1 ? "CLOSED" : tcp_state_str[prev],
(new == -1 || num == -1) ? "CLOSED" : tcp_state_str[new]); (new == -1 || num == -1) ? "CLOSED" : tcp_state_str[new]);
} else { else
debug("TCP: index %u, %s", FLOW_IDX(conn), flow_dbg(conn, "%s",
num == -1 ? "CLOSED" : tcp_event_str[num]); num == -1 ? "CLOSED" : tcp_event_str[num]);
}
if ((event == TAP_FIN_RCVD) && !(conn->events & SOCK_FIN_RCVD)) if ((event == TAP_FIN_RCVD) && !(conn->events & SOCK_FIN_RCVD))
conn_flag(c, conn, ACTIVE_CLOSE); conn_flag(c, conn, ACTIVE_CLOSE);
@ -838,7 +835,7 @@ static void conn_event_do(const struct ctx *c, struct tcp_tap_conn *conn,
#define conn_event(c, conn, event) \ #define conn_event(c, conn, event) \
do { \ do { \
trace("TCP: event at %s:%i", __func__, __LINE__); \ flow_trace(conn, "event at %s:%i", __func__, __LINE__); \
conn_event_do(c, conn, event); \ conn_event_do(c, conn, event); \
} while (0) } while (0)
@ -1206,9 +1203,8 @@ static void tcp_hash_insert(const struct ctx *c, struct tcp_tap_conn *conn)
conn->next_index = tc_hash[b] ? FLOW_IDX(tc_hash[b]) : -1U; conn->next_index = tc_hash[b] ? FLOW_IDX(tc_hash[b]) : -1U;
tc_hash[b] = conn; tc_hash[b] = conn;
debug("TCP: hash table insert: index %u, sock %i, bucket: %i, next: " flow_dbg(conn, "hash table insert: sock %i, bucket: %i, next: %p",
"%p", FLOW_IDX(conn), conn->sock, b, conn->sock, b, (void *)conn_at_idx(conn->next_index));
(void *)conn_at_idx(conn->next_index));
} }
/** /**
@ -1233,8 +1229,8 @@ static void tcp_hash_remove(const struct ctx *c,
} }
} }
debug("TCP: hash table remove: index %u, sock %i, bucket: %i, new: %p", flow_dbg(conn, "hash table remove: sock %i, bucket: %i, new: %p",
FLOW_IDX(conn), conn->sock, b, conn->sock, b,
(void *)(prev ? conn_at_idx(prev->next_index) : tc_hash[b])); (void *)(prev ? conn_at_idx(prev->next_index) : tc_hash[b]));
} }
@ -1318,8 +1314,7 @@ static void tcp_conn_destroy(struct ctx *c, union flow *flow)
static void tcp_rst_do(struct ctx *c, struct tcp_tap_conn *conn); static void tcp_rst_do(struct ctx *c, struct tcp_tap_conn *conn);
#define tcp_rst(c, conn) \ #define tcp_rst(c, conn) \
do { \ do { \
debug("TCP: index %u, reset at %s:%i", FLOW_IDX(conn), \ flow_dbg((conn), "TCP reset at %s:%i", __func__, __LINE__); \
__func__, __LINE__); \
tcp_rst_do(c, conn); \ tcp_rst_do(c, conn); \
} while (0) } while (0)
@ -1997,7 +1992,7 @@ static void tcp_conn_from_tap(struct ctx *c,
mss = tcp_conn_tap_mss(conn, opts, optlen); mss = tcp_conn_tap_mss(conn, opts, optlen);
if (setsockopt(s, SOL_TCP, TCP_MAXSEG, &mss, sizeof(mss))) if (setsockopt(s, SOL_TCP, TCP_MAXSEG, &mss, sizeof(mss)))
trace("TCP: failed to set TCP_MAXSEG on socket %i", s); flow_trace(conn, "failed to set TCP_MAXSEG on socket %i", s);
MSS_SET(conn, mss); MSS_SET(conn, mss);
tcp_get_tap_ws(conn, opts, optlen); tcp_get_tap_ws(conn, opts, optlen);
@ -2158,7 +2153,7 @@ static int tcp_data_from_sock(struct ctx *c, struct tcp_tap_conn *conn)
if (SEQ_LT(already_sent, 0)) { if (SEQ_LT(already_sent, 0)) {
/* RFC 761, section 2.1. */ /* RFC 761, section 2.1. */
trace("TCP: ACK sequence gap: ACK for %u, sent: %u", flow_trace(conn, "ACK sequence gap: ACK for %u, sent: %u",
conn->seq_ack_from_tap, conn->seq_to_tap); conn->seq_ack_from_tap, conn->seq_to_tap);
conn->seq_to_tap = conn->seq_ack_from_tap; conn->seq_to_tap = conn->seq_ack_from_tap;
already_sent = 0; already_sent = 0;
@ -2391,7 +2386,8 @@ static int tcp_data_from_tap(struct ctx *c, struct tcp_tap_conn *conn,
tcp_tap_window_update(conn, max_ack_seq_wnd); tcp_tap_window_update(conn, max_ack_seq_wnd);
if (retr) { if (retr) {
trace("TCP: fast re-transmit, ACK: %u, previous sequence: %u", flow_trace(conn,
"fast re-transmit, ACK: %u, previous sequence: %u",
max_ack_seq, conn->seq_to_tap); max_ack_seq, conn->seq_to_tap);
conn->seq_ack_from_tap = max_ack_seq; conn->seq_ack_from_tap = max_ack_seq;
conn->seq_to_tap = max_ack_seq; conn->seq_to_tap = max_ack_seq;
@ -2541,8 +2537,7 @@ int tcp_tap_handler(struct ctx *c, uint8_t pif, int af,
return 1; return 1;
} }
trace("TCP: packet length %zu from tap for index %u", flow_trace(conn, "packet length %zu from tap", len);
len, FLOW_IDX(conn));
if (th->rst) { if (th->rst) {
conn_event(c, conn, CLOSED); conn_event(c, conn, CLOSED);
@ -2782,17 +2777,16 @@ void tcp_timer_handler(struct ctx *c, union epoll_ref ref)
tcp_timer_ctl(c, conn); tcp_timer_ctl(c, conn);
} else if (conn->flags & ACK_FROM_TAP_DUE) { } else if (conn->flags & ACK_FROM_TAP_DUE) {
if (!(conn->events & ESTABLISHED)) { if (!(conn->events & ESTABLISHED)) {
debug("TCP: index %u, handshake timeout", FLOW_IDX(conn)); flow_dbg(conn, "handshake timeout");
tcp_rst(c, conn); tcp_rst(c, conn);
} else if (CONN_HAS(conn, SOCK_FIN_SENT | TAP_FIN_ACKED)) { } else if (CONN_HAS(conn, SOCK_FIN_SENT | TAP_FIN_ACKED)) {
debug("TCP: index %u, FIN timeout", FLOW_IDX(conn)); flow_dbg(conn, "FIN timeout");
tcp_rst(c, conn); tcp_rst(c, conn);
} else if (conn->retrans == TCP_MAX_RETRANS) { } else if (conn->retrans == TCP_MAX_RETRANS) {
debug("TCP: index %u, retransmissions count exceeded", flow_dbg(conn, "retransmissions count exceeded");
FLOW_IDX(conn));
tcp_rst(c, conn); tcp_rst(c, conn);
} else { } else {
debug("TCP: index %u, ACK timeout, retry", FLOW_IDX(conn)); flow_dbg(conn, "ACK timeout, retry");
conn->retrans++; conn->retrans++;
conn->seq_to_tap = conn->seq_ack_from_tap; conn->seq_to_tap = conn->seq_ack_from_tap;
tcp_data_from_sock(c, conn); tcp_data_from_sock(c, conn);
@ -2810,7 +2804,7 @@ void tcp_timer_handler(struct ctx *c, union epoll_ref ref)
*/ */
timerfd_settime(conn->timer, 0, &new, &old); timerfd_settime(conn->timer, 0, &new, &old);
if (old.it_value.tv_sec == ACT_TIMEOUT) { if (old.it_value.tv_sec == ACT_TIMEOUT) {
debug("TCP: index %u, activity timeout", FLOW_IDX(conn)); flow_dbg(conn, "activity timeout");
tcp_rst(c, conn); tcp_rst(c, conn);
} }
} }

View file

@ -139,8 +139,7 @@ static int tcp_splice_epoll_ctl(const struct ctx *c,
if (epoll_ctl(c->epollfd, m, conn->s[0], &ev[0]) || if (epoll_ctl(c->epollfd, m, conn->s[0], &ev[0]) ||
epoll_ctl(c->epollfd, m, conn->s[1], &ev[1])) { epoll_ctl(c->epollfd, m, conn->s[1], &ev[1])) {
int ret = -errno; int ret = -errno;
err("TCP (spliced): index %u, ERROR on epoll_ctl(): %s", flow_err(conn, "ERROR on epoll_ctl(): %s", strerror(errno));
FLOW_IDX(conn), strerror(errno));
return ret; return ret;
} }
@ -165,10 +164,9 @@ static void conn_flag_do(const struct ctx *c, struct tcp_splice_conn *conn,
return; return;
conn->flags &= flag; conn->flags &= flag;
if (flag_index >= 0) { if (flag_index >= 0)
debug("TCP (spliced): index %u: %s dropped", FLOW_IDX(conn), flow_dbg(conn, "%s dropped",
tcp_splice_flag_str[flag_index]); tcp_splice_flag_str[flag_index]);
}
} else { } else {
int flag_index = fls(flag); int flag_index = fls(flag);
@ -176,10 +174,8 @@ static void conn_flag_do(const struct ctx *c, struct tcp_splice_conn *conn,
return; return;
conn->flags |= flag; conn->flags |= flag;
if (flag_index >= 0) { if (flag_index >= 0)
debug("TCP (spliced): index %u: %s", FLOW_IDX(conn), flow_dbg(conn, "%s", tcp_splice_flag_str[flag_index]);
tcp_splice_flag_str[flag_index]);
}
} }
if (flag == CLOSING) { if (flag == CLOSING) {
@ -190,8 +186,7 @@ static void conn_flag_do(const struct ctx *c, struct tcp_splice_conn *conn,
#define conn_flag(c, conn, flag) \ #define conn_flag(c, conn, flag) \
do { \ do { \
trace("TCP (spliced): flag at %s:%i", \ flow_trace(conn, "flag at %s:%i", __func__, __LINE__); \
__func__, __LINE__); \
conn_flag_do(c, conn, flag); \ conn_flag_do(c, conn, flag); \
} while (0) } while (0)
@ -211,10 +206,8 @@ static void conn_event_do(const struct ctx *c, struct tcp_splice_conn *conn,
return; return;
conn->events &= event; conn->events &= event;
if (flag_index >= 0) { if (flag_index >= 0)
debug("TCP (spliced): index %u, ~%s", FLOW_IDX(conn), flow_dbg(conn, "~%s", tcp_splice_event_str[flag_index]);
tcp_splice_event_str[flag_index]);
}
} else { } else {
int flag_index = fls(event); int flag_index = fls(event);
@ -222,10 +215,8 @@ static void conn_event_do(const struct ctx *c, struct tcp_splice_conn *conn,
return; return;
conn->events |= event; conn->events |= event;
if (flag_index >= 0) { if (flag_index >= 0)
debug("TCP (spliced): index %u, %s", FLOW_IDX(conn), flow_dbg(conn, "%s", tcp_splice_event_str[flag_index]);
tcp_splice_event_str[flag_index]);
}
} }
if (tcp_splice_epoll_ctl(c, conn)) if (tcp_splice_epoll_ctl(c, conn))
@ -234,8 +225,7 @@ static void conn_event_do(const struct ctx *c, struct tcp_splice_conn *conn,
#define conn_event(c, conn, event) \ #define conn_event(c, conn, event) \
do { \ do { \
trace("TCP (spliced): event at %s:%i", \ flow_trace(conn, "event at %s:%i",__func__, __LINE__); \
__func__, __LINE__); \
conn_event_do(c, conn, event); \ conn_event_do(c, conn, event); \
} while (0) } while (0)
@ -281,7 +271,7 @@ void tcp_splice_destroy(struct ctx *c, union flow *flow)
conn->events = SPLICE_CLOSED; conn->events = SPLICE_CLOSED;
conn->flags = 0; conn->flags = 0;
debug("TCP (spliced): index %u, CLOSED", FLOW_IDX(conn)); flow_dbg(conn, "CLOSED");
flow_table_compact(c, flow); flow_table_compact(c, flow);
} }
@ -314,7 +304,7 @@ static int tcp_splice_connect_finish(const struct ctx *c,
if (conn->pipe[side][0] < 0) { if (conn->pipe[side][0] < 0) {
if (pipe2(conn->pipe[side], O_NONBLOCK | O_CLOEXEC)) { if (pipe2(conn->pipe[side], O_NONBLOCK | O_CLOEXEC)) {
err("TCP (spliced): cannot create %d->%d pipe: %s", flow_err(conn, "cannot create %d->%d pipe: %s",
side, !side, strerror(errno)); side, !side, strerror(errno));
conn_flag(c, conn, CLOSING); conn_flag(c, conn, CLOSING);
return -EIO; return -EIO;
@ -322,7 +312,8 @@ static int tcp_splice_connect_finish(const struct ctx *c,
if (fcntl(conn->pipe[side][0], F_SETPIPE_SZ, if (fcntl(conn->pipe[side][0], F_SETPIPE_SZ,
c->tcp.pipe_size)) { c->tcp.pipe_size)) {
trace("TCP (spliced): cannot set %d->%d pipe size to %zu", flow_trace(conn,
"cannot set %d->%d pipe size to %zu",
side, !side, c->tcp.pipe_size); side, !side, c->tcp.pipe_size);
} }
} }
@ -363,7 +354,7 @@ static int tcp_splice_connect(const struct ctx *c, struct tcp_splice_conn *conn,
if (setsockopt(conn->s[1], SOL_TCP, TCP_QUICKACK, if (setsockopt(conn->s[1], SOL_TCP, TCP_QUICKACK,
&((int){ 1 }), sizeof(int))) { &((int){ 1 }), sizeof(int))) {
trace("TCP (spliced): failed to set TCP_QUICKACK on socket %i", flow_trace(conn, "failed to set TCP_QUICKACK on socket %i",
conn->s[1]); conn->s[1]);
} }
@ -475,7 +466,7 @@ bool tcp_splice_conn_from_sock(const struct ctx *c,
} }
if (setsockopt(s, SOL_TCP, TCP_QUICKACK, &((int){ 1 }), sizeof(int))) if (setsockopt(s, SOL_TCP, TCP_QUICKACK, &((int){ 1 }), sizeof(int)))
trace("TCP (spliced): failed to set TCP_QUICKACK on %i", s); flow_trace(conn, "failed to set TCP_QUICKACK on %i", s);
conn->f.type = FLOW_TCP_SPLICE; conn->f.type = FLOW_TCP_SPLICE;
conn->s[0] = s; conn->s[0] = s;
@ -555,7 +546,7 @@ retry:
readlen = splice(conn->s[fromside], NULL, readlen = splice(conn->s[fromside], NULL,
conn->pipe[fromside][1], NULL, c->tcp.pipe_size, conn->pipe[fromside][1], NULL, c->tcp.pipe_size,
SPLICE_F_MOVE | SPLICE_F_NONBLOCK); SPLICE_F_MOVE | SPLICE_F_NONBLOCK);
trace("TCP (spliced): %zi from read-side call", readlen); flow_trace(conn, "%zi from read-side call", readlen);
if (readlen < 0) { if (readlen < 0) {
if (errno == EINTR) if (errno == EINTR)
goto retry; goto retry;
@ -581,7 +572,7 @@ eintr:
written = splice(conn->pipe[fromside][0], NULL, written = splice(conn->pipe[fromside][0], NULL,
conn->s[!fromside], NULL, to_write, conn->s[!fromside], NULL, to_write,
SPLICE_F_MOVE | more | SPLICE_F_NONBLOCK); SPLICE_F_MOVE | more | SPLICE_F_NONBLOCK);
trace("TCP (spliced): %zi from write-side call (passed %zi)", flow_trace(conn, "%zi from write-side call (passed %zi)",
written, to_write); written, to_write);
/* Most common case: skip updating counters. */ /* Most common case: skip updating counters. */
@ -794,8 +785,8 @@ void tcp_splice_timer(struct ctx *c, union flow *flow)
if ((conn->flags & set) && !(conn->flags & act)) { if ((conn->flags & set) && !(conn->flags & act)) {
if (setsockopt(conn->s[side], SOL_SOCKET, SO_RCVLOWAT, if (setsockopt(conn->s[side], SOL_SOCKET, SO_RCVLOWAT,
&((int){ 1 }), sizeof(int))) { &((int){ 1 }), sizeof(int))) {
trace("TCP (spliced): can't set SO_RCVLOWAT on " flow_trace(conn, "can't set SO_RCVLOWAT on %d",
"%i", conn->s[side]); conn->s[side]);
} }
conn_flag(c, conn, ~set); conn_flag(c, conn, ~set);
} }