/* SPDX-License-Identifier: GPL-2.0-or-later * Copyright Red Hat * Author: David Gibson * * Tracking for logical "flows" of packets. */ #include #include #include #include #include "util.h" #include "passt.h" #include "inany.h" #include "siphash.h" #include "flow.h" #include "tcp_conn.h" #include "flow_table.h" const char *flow_type_str[] = { [FLOW_NONE] = "", [FLOW_TCP] = "TCP connection", [FLOW_TCP_SPLICE] = "TCP connection (spliced)", }; /* Global Flow Table */ union flow flowtab[FLOW_MAX]; /** flowside_fmt - Format a flowside as a string * @fs: flowside to format * @buf: Buffer into which to store the formatted version * @size: Size of @buf * * Return: pointer to formatted string describing @fs, or NULL on error */ const char *flowside_fmt(const struct flowside *fs, char *buf, size_t size) { char ebuf[INET6_ADDRSTRLEN], fbuf[INET6_ADDRSTRLEN]; if (!inet_ntop(AF_INET6, &fs->eaddr, ebuf, sizeof(ebuf)) || !inet_ntop(AF_INET6, &fs->faddr, fbuf, sizeof(fbuf))) return NULL; snprintf(buf, size, "[%s]:%hu <-> [%s]:%hu", fbuf, fs->fport, ebuf, fs->eport); return (const char *)buf; } /** * flow_table_compact() - Perform compaction on flow table * @c: Execution context * @hole: Pointer to recently closed flow */ void flow_table_compact(struct ctx *c, union flow *hole) { union flow *from; if (FLOW_IDX(hole) == --c->flow_count) { debug("flow: table compaction: maximum index was %li (%p)", FLOW_IDX(hole), hole); memset(hole, 0, sizeof(*hole)); return; } from = flowtab + c->flow_count; memcpy(hole, from, sizeof(*hole)); switch (from->f.type) { case FLOW_TCP: tcp_tap_conn_update(c, &from->tcp, &hole->tcp); break; case FLOW_TCP_SPLICE: tcp_splice_conn_update(c, &hole->tcp_splice); break; default: die("Unexpected %s in tcp_table_compact()", FLOW_TYPE(&from->f)); } debug("flow: table compaction (%s): old index %li, new index %li, " "from: %p, to: %p", FLOW_TYPE(&from->f), FLOW_IDX(from), FLOW_IDX(hole), from, hole); memset(from, 0, sizeof(*from)); } /** flowside_getsockname - Initialize flowside f{addr,port} from a bound socket * @fs: flowside to initialize * @s: bound socket * * #syscalls getsockname */ int flowside_getsockname(struct flowside *fs, int s) { struct sockaddr_storage sa; socklen_t sl = sizeof(sa); /* FIXME: Workaround clang-tidy not realizing that getsockname() writes * the socket address. See * https://github.com/llvm/llvm-project/issues/58992 */ memset(&sa, 0, sizeof(struct sockaddr_in6)); if (getsockname(s, (struct sockaddr *)&sa, &sl) < 0) return -errno; inany_from_sockaddr(&fs->faddr, &fs->fport, (const struct sockaddr *)&sa); return 0; }