freebsd-src/sys/netlink/ktest_netlink_message_writer.c
Gleb Smirnoff 17083b94a9 netlink: use protocol specific receive buffer
Implement Netlink socket receive buffer as a simple TAILQ of nl_buf's,
same part of struct sockbuf that is used for send buffer already.
This shaves a lot of code and a lot of extra processing.  The pcb rids
of the I/O queues as the socket buffer is exactly the queue.  The
message writer is simplified a lot, as we now always deal with linear
buf.  Notion of different buffer types goes away as way as different
kinds of writers.  The only things remaining are: a socket writer and
a group writer.
The impact on the network stack is that we no longer use mbufs, so
a workaround from d187154750 disappears.

Note on message throttling.  Now the taskqueue throttling mechanism
needs to look at both socket buffers protected by their respective
locks and on flags in the pcb that are protected by the pcb lock.
There is definitely some room for optimization, but this changes tries
to preserve as much as possible.

Note on new nl_soreceive().  It emulates soreceive_generic().  It
must undergo further optimization, see large comment put in there.

Note on tests/sys/netlink/test_netlink_message_writer.py. This test
boiled down almost to nothing with mbufs removed.  However, I left
it with minimal functionality (it basically checks that allocating N
bytes we get N bytes) as it is one of not so many examples of ktest
framework that allows to test KPIs with python.

Note on Linux support. It got much simplier: Netlink message writer
loses notion of Linux support lifetime, it is same regardless of
process ABI.  On socket write from Linux process we perform
conversion immediately in nl_receive_message() and on an output
conversion to Linux happens in in nl_send_one(). XXX: both
conversions use M_NOWAIT allocation, which used to be the case
before this change, too.

Reviewed by:		melifaro
Differential Revision:	https://reviews.freebsd.org/D42524
2024-01-02 13:04:01 -08:00

114 lines
3.5 KiB
C

/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2023 Alexander V. Chernikov
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <tests/ktest.h>
#include <sys/cdefs.h>
#include <sys/systm.h>
#include <sys/malloc.h>
#include <netlink/netlink.h>
#include <netlink/netlink_ctl.h>
#include <netlink/netlink_var.h>
#include <netlink/netlink_message_writer.h>
#define KTEST_CALLER
#include <netlink/ktest_netlink_message_writer.h>
#ifdef INVARIANTS
struct test_nlbuf_attrs {
uint32_t size;
uint32_t expected_avail;
int waitok;
};
#define _OUT(_field) offsetof(struct test_nlbuf_attrs, _field)
static const struct nlattr_parser nla_p_nlbuf_w[] = {
{ .type = 1, .off = _OUT(size), .cb = nlattr_get_uint32 },
{ .type = 2, .off = _OUT(expected_avail), .cb = nlattr_get_uint32 },
{ .type = 3, .off = _OUT(waitok), .cb = nlattr_get_uint32 },
};
#undef _OUT
NL_DECLARE_ATTR_PARSER(nlbuf_w_parser, nla_p_nlbuf_w);
static int
test_nlbuf_parser(struct ktest_test_context *ctx, struct nlattr *nla)
{
struct test_nlbuf_attrs *attrs = npt_alloc(ctx->npt, sizeof(*attrs));
ctx->arg = attrs;
if (attrs != NULL)
return (nl_parse_nested(nla, &nlbuf_w_parser, ctx->npt, attrs));
return (ENOMEM);
}
static int
test_nlbuf_writer_allocation(struct ktest_test_context *ctx)
{
struct test_nlbuf_attrs *attrs = ctx->arg;
struct nl_writer nw = {};
u_int alloc_len;
bool ret;
ret = nlmsg_get_buf_wrapper(&nw, attrs->size, attrs->waitok);
if (!ret)
return (EINVAL);
alloc_len = nw.buf->buflen;
KTEST_LOG(ctx, "requested %u, allocated %d", attrs->size, alloc_len);
/* Mark enomem to avoid reallocation */
nw.enomem = true;
if (nlmsg_reserve_data(&nw, alloc_len, void *) == NULL) {
KTEST_LOG(ctx, "unable to get %d bytes from the writer", alloc_len);
return (EINVAL);
}
nl_buf_free(nw.buf);
if (alloc_len < attrs->expected_avail) {
KTEST_LOG(ctx, "alloc_len %d, expected %u",
alloc_len, attrs->expected_avail);
return (EINVAL);
}
return (0);
}
#endif
static const struct ktest_test_info tests[] = {
#ifdef INVARIANTS
{
.name = "test_nlbuf_writer_allocation",
.desc = "test different buffer sizes in the netlink writer",
.func = &test_nlbuf_writer_allocation,
.parse = &test_nlbuf_parser,
},
#endif
};
KTEST_MODULE_DECLARE(ktest_netlink_message_writer, tests);