[PATCH 0/6] Of course there are more flow table preliminaries
This series has some further preliminaries for the flow table. Specifically this is focused on some clean ups to handling of indicies for flows and sides. We also add some additional test programs for platform requirements. This is based on the series adding UDP error handling. David Gibson (6): flow, icmp, tcp: Clean up helpers for getting flow from index flow, tcp_splice: Prefer 'sidei' for variables referring to side index flow: Introduce flow_foreach_sidei() macro tcp_splice: Use parameterised macros for per-side event/flag bits doc: Test behaviour of closing duplicate UDP sockets doc: Extend zero-recv test with methods using msghdr doc/platform-requirements/.gitignore | 1 + doc/platform-requirements/Makefile | 4 +- doc/platform-requirements/recv-zero.c | 60 +++++++-- doc/platform-requirements/udp-close-dup.c | 105 +++++++++++++++ flow.h | 16 +-- flow_table.h | 48 +++++-- icmp.c | 22 +++- tcp.c | 28 +++- tcp_conn.h | 15 +-- tcp_splice.c | 152 ++++++++++++---------- 10 files changed, 332 insertions(+), 119 deletions(-) create mode 100644 doc/platform-requirements/udp-close-dup.c -- 2.45.2
TCP (both regular and spliced) and ICMP both have macros to retrieve the
relevant protcol specific flow structure from a flow index. In most cases
what we actually want is to get the specific flow from a sidx. Replace
those simple macros with a more precise inline, which also asserts that
the flow is of the type we expect.
While we're they're also add a pif_at_sidx() helper to get the interface of
a specific flow & side, which is useful in some places.
Finally, fix some minor style issues in the comments on some of the
existing sidx related helpers.
Signed-off-by: David Gibson
In various places we have variables named 'side' or similar which always
have the value 0 or 1 (INISIDE or TGTSIDE). Given a flow, this refers to
a specific side of it. Upcoming flow table work will make it more useful
for "side" to refer to a specific side of a specific flow. To make things
less confusing then, prefer the name term "side index" and name 'sidei' for
variables with just the 0 or 1 value.
Signed-off-by: David Gibson
On Wed, 17 Jul 2024 14:52:19 +1000
David Gibson
@@ -164,17 +164,17 @@ struct flow_common {
/** * struct flow_sidx - ID for one side of a specific flow - * @side: Side referenced (0 or 1) + * @side: Index of side referenced (0 or 1) * @flow: Index of flow referenced
Nit (I can fix this up on merge, and I didn't finish reviewing yet): the comment to the struct should also use sidei/flowi.
*/ typedef struct flow_sidx { - unsigned side :1; - unsigned flow :FLOW_INDEX_BITS; + unsigned sidei :1; + unsigned flowi :FLOW_INDEX_BITS; } flow_sidx_t;
-- Stefano
On Wed, Jul 17, 2024 at 07:20:17AM +0200, Stefano Brivio wrote:
On Wed, 17 Jul 2024 14:52:19 +1000 David Gibson
wrote: @@ -164,17 +164,17 @@ struct flow_common {
/** * struct flow_sidx - ID for one side of a specific flow - * @side: Side referenced (0 or 1) + * @side: Index of side referenced (0 or 1) * @flow: Index of flow referenced
Nit (I can fix this up on merge, and I didn't finish reviewing yet): the comment to the struct should also use sidei/flowi.
If this is the only issue, go ahead and fix on merge. If there are any more nits I'll make a new spin.
*/ typedef struct flow_sidx { - unsigned side :1; - unsigned flow :FLOW_INDEX_BITS; + unsigned sidei :1; + unsigned flowi :FLOW_INDEX_BITS; } flow_sidx_t;
-- David Gibson (he or they) | I'll have my music baroque, and my code david AT gibson.dropbear.id.au | minimalist, thank you, not the other way | around. http://www.ozlabs.org/~dgibson
On Wed, Jul 17, 2024 at 03:28:05PM +1000, David Gibson wrote:
On Wed, Jul 17, 2024 at 07:20:17AM +0200, Stefano Brivio wrote:
On Wed, 17 Jul 2024 14:52:19 +1000 David Gibson
wrote: @@ -164,17 +164,17 @@ struct flow_common {
/** * struct flow_sidx - ID for one side of a specific flow - * @side: Side referenced (0 or 1) + * @side: Index of side referenced (0 or 1) * @flow: Index of flow referenced
Nit (I can fix this up on merge, and I didn't finish reviewing yet): the comment to the struct should also use sidei/flowi.
If this is the only issue, go ahead and fix on merge. If there are any more nits I'll make a new spin.
Actually, never mind. I discovered I hadn't rebased onto the latest and there's a conflict, so I'll respin anyway.
*/ typedef struct flow_sidx { - unsigned side :1; - unsigned flow :FLOW_INDEX_BITS; + unsigned sidei :1; + unsigned flowi :FLOW_INDEX_BITS; } flow_sidx_t;
-- David Gibson (he or they) | I'll have my music baroque, and my code david AT gibson.dropbear.id.au | minimalist, thank you, not the other way | around. http://www.ozlabs.org/~dgibson
On Wed, 17 Jul 2024 15:50:32 +1000
David Gibson
On Wed, Jul 17, 2024 at 03:28:05PM +1000, David Gibson wrote:
On Wed, Jul 17, 2024 at 07:20:17AM +0200, Stefano Brivio wrote:
On Wed, 17 Jul 2024 14:52:19 +1000 David Gibson
wrote: @@ -164,17 +164,17 @@ struct flow_common {
/** * struct flow_sidx - ID for one side of a specific flow - * @side: Side referenced (0 or 1) + * @side: Index of side referenced (0 or 1) * @flow: Index of flow referenced
Nit (I can fix this up on merge, and I didn't finish reviewing yet): the comment to the struct should also use sidei/flowi.
If this is the only issue, go ahead and fix on merge. If there are any more nits I'll make a new spin.
Actually, never mind. I discovered I hadn't rebased onto the latest and there's a conflict, so I'll respin anyway.
It's trivial, just a bit of fuzz on 1/6, no need as far as I'm concerned. -- Stefano
On Wed, Jul 17, 2024 at 09:20:42AM +0200, Stefano Brivio wrote:
On Wed, 17 Jul 2024 15:50:32 +1000 David Gibson
wrote: On Wed, Jul 17, 2024 at 03:28:05PM +1000, David Gibson wrote:
On Wed, Jul 17, 2024 at 07:20:17AM +0200, Stefano Brivio wrote:
On Wed, 17 Jul 2024 14:52:19 +1000 David Gibson
wrote: @@ -164,17 +164,17 @@ struct flow_common {
/** * struct flow_sidx - ID for one side of a specific flow - * @side: Side referenced (0 or 1) + * @side: Index of side referenced (0 or 1) * @flow: Index of flow referenced
Nit (I can fix this up on merge, and I didn't finish reviewing yet): the comment to the struct should also use sidei/flowi.
If this is the only issue, go ahead and fix on merge. If there are any more nits I'll make a new spin.
Actually, never mind. I discovered I hadn't rebased onto the latest and there's a conflict, so I'll respin anyway.
It's trivial, just a bit of fuzz on 1/6, no need as far as I'm concerned.
Ok. Well go ahead and apply then, if you have no additional revisions to suggest. -- David Gibson (he or they) | I'll have my music baroque, and my code david AT gibson.dropbear.id.au | minimalist, thank you, not the other way | around. http://www.ozlabs.org/~dgibson
We have a handful of places where we use a loop to step through each side
of a flow or flows, and we're probably going to have mroe in future.
Introduce a macro to implement this loop for convenience.
Signed-off-by: David Gibson
Both the events and flags fields in tcp_splice_conn have several bits
which are per-side, e.g. OUT_WAIT_0 for side 0 and OUT_WAIT_1 for side 1.
This necessitates some rather awkward ternary expressions when we need
to get the relevant bit for a particular side.
Simplify this by using a parameterised macro for the bit values. This
needs a ternary expression inside the macros, but makes the places we use
it substantially clearer.
That simplification in turn allows us to use a loop across each side to
implement several things which are currently open coded to do equivalent
things for each side in turn.
Signed-off-by: David Gibson
To simplify lifetime management of "listening" UDP sockets, UDP flow
support needs to duplicate existing bound sockets. Those duplicates will
be close()d when their corresponding flow expires, but we expect the
original to still receive datagrams as always. That is, we expect the
close() on the duplicate to remove the duplicated fd, but not to close the
underlying UDP socket.
Add a test program to doc/platform-requirements to verify this requirement.
Signed-off-by: David Gibson
This test program verifies that we can receive and discard datagrams by
using recv() with a NULL buffer and zero-length. Extend it to verify it
also works using recvmsg() and either an iov with a zero-length NULL
buffer or an iov that itself is NULL and zero-length.
Signed-off-by: David Gibson
On Wed, 17 Jul 2024 14:52:23 +1000
David Gibson
This test program verifies that we can receive and discard datagrams by using recv() with a NULL buffer and zero-length. Extend it to verify it also works using recvmsg() and either an iov with a zero-length NULL buffer or an iov that itself is NULL and zero-length.
Signed-off-by: David Gibson
--- doc/platform-requirements/recv-zero.c | 60 +++++++++++++++++++++++---- 1 file changed, 52 insertions(+), 8 deletions(-) diff --git a/doc/platform-requirements/recv-zero.c b/doc/platform-requirements/recv-zero.c index f161e5c2..ab27704d 100644 --- a/doc/platform-requirements/recv-zero.c +++ b/doc/platform-requirements/recv-zero.c @@ -23,11 +23,27 @@
#define DSTPORT 13257U
+enum discard_method { + DISCARD_NULL_BUF, + DISCARD_ZERO_IOV, + DISCARD_NULL_IOV, + NUM_METHODS, +}; + /* 127.0.0.1:DSTPORT */ static const struct sockaddr_in lo_dst = SOCKADDR_INIT(INADDR_LOOPBACK, DSTPORT);
-static void test_discard(void) +static void test_discard(enum discard_method method) { + struct iovec zero_iov = { .iov_base = NULL, .iov_len = 0, }; + struct msghdr mh_zero = { + .msg_iov = &zero_iov, + .msg_iovlen = 1, + }; + struct msghdr mh_null = { + .msg_iov = NULL, + .msg_iovlen = 0, + }; long token1, token2; int recv_s, send_s; ssize_t rc; @@ -46,11 +62,36 @@ static void test_discard(void) send_token(send_s, token1); send_token(send_s, token2);
- /* cppcheck-suppress nullPointer */ - rc = recv(recv_s, NULL, 0, MSG_DONTWAIT); - if (rc < 0) - die("discarding recv(): %s\n", strerror(errno)); - + switch (method) { + case DISCARD_NULL_BUF: + /* cppcheck-suppress nullPointer */ + rc = recv(recv_s, NULL, 0, MSG_DONTWAIT); + if (rc < 0) + die("discarding recv(): %s\n", strerror(errno)); + break; + + case DISCARD_ZERO_IOV: + rc = recvmsg(recv_s, &mh_zero, MSG_DONTWAIT); + if (rc < 0) + die("recvmsg() with zero-length buffer: %s\n", + strerror(errno)); + if (!((unsigned)mh_zero.msg_flags & MSG_TRUNC)) + die("Missing MSG_TRUNC flag\n"); + break; + + case DISCARD_NULL_IOV: + rc = recvmsg(recv_s, &mh_null, MSG_DONTWAIT); + if (rc < 0) + die("recvmsg() with zero-length iov: %s\n", + strerror(errno)); + if (!((unsigned)mh_null.msg_flags & MSG_TRUNC)) + die("Missing MSG_TRUNC flag\n"); + break; + + default: + die("Bad method\n"); + } + recv_token(recv_s, token2);
/* cppcheck-suppress nullPointer */ @@ -63,12 +104,15 @@ static void test_discard(void)
int main(int argc, char *argv[]) { + enum discard_method method; + (void)argc; (void)argv;
- test_discard(); + for (method = 0; method < NUM_METHODS; method++) + test_discard(method);
- printf("Discarding datagrams with a 0-length recv() seems to work\n"); + printf("Discarding datagrams with a 0-length receives seems to work\n");
Nit: also fixed up on merge: "with 0-length receives".
exit(0); }
-- Stefano
On Wed, 17 Jul 2024 14:52:17 +1000
David Gibson
This series has some further preliminaries for the flow table. Specifically this is focused on some clean ups to handling of indicies for flows and sides. We also add some additional test programs for platform requirements.
This is based on the series adding UDP error handling.
David Gibson (6): flow, icmp, tcp: Clean up helpers for getting flow from index flow, tcp_splice: Prefer 'sidei' for variables referring to side index flow: Introduce flow_foreach_sidei() macro tcp_splice: Use parameterised macros for per-side event/flag bits doc: Test behaviour of closing duplicate UDP sockets doc: Extend zero-recv test with methods using msghdr
Applied. -- Stefano
participants (2)
-
David Gibson
-
Stefano Brivio