core,API: Add bridge support
This change introduces a facility to bridge messages between two
bindings.
This is implemented through a new mctp_bridge_busses() API, which
applies a new routing policy, sending packets from one binding to the
other. This is in contrast to the current policy of dropping all
non-local packets.
To do this, the message context code needs to know both source and
destination EIDs, so add them to the mctp_msg_ctx_lookup() criteria.
Also, add a small test for bridge mode.
Signed-off-by: Jeremy Kerr <jk@ozlabs.org>
Change-Id: If532613525ddbf81df249e26d0f23825996f7bda
diff --git a/tests/test_bridge.c b/tests/test_bridge.c
new file mode 100644
index 0000000..496ae19
--- /dev/null
+++ b/tests/test_bridge.c
@@ -0,0 +1,102 @@
+/* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later */
+
+#include <assert.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <libmctp.h>
+#include <libmctp-alloc.h>
+
+#include "test-utils.h"
+
+struct mctp_binding_bridge {
+ struct mctp_binding binding;
+ int rx_count;
+ int tx_count;
+ uint8_t last_pkt_data;
+};
+
+struct test_ctx {
+ struct mctp *mctp;
+ struct mctp_binding_bridge *bindings[2];
+};
+
+static int mctp_binding_bridge_tx(struct mctp_binding *b,
+ struct mctp_pktbuf *pkt)
+{
+ struct mctp_binding_bridge *binding = container_of(b,
+ struct mctp_binding_bridge, binding);
+
+ binding->tx_count++;
+ assert(mctp_pktbuf_size(pkt) == sizeof(struct mctp_hdr) + 1);
+ binding->last_pkt_data = *(uint8_t *)mctp_pktbuf_data(pkt);
+
+ return 0;
+}
+
+static int mctp_binding_bridge_rx(struct mctp_binding_bridge *binding,
+ uint8_t key)
+{
+ struct mctp_pktbuf *pkt;
+ struct mctp_hdr *hdr;
+ uint8_t *buf;
+
+ pkt = mctp_pktbuf_alloc(&binding->binding,
+ sizeof(struct mctp_hdr) + 1);
+
+ hdr = mctp_pktbuf_hdr(pkt);
+ hdr->flags_seq_tag = MCTP_HDR_FLAG_SOM | MCTP_HDR_FLAG_EOM;
+
+ /* arbitrary src/dest, as we're bridging */
+ hdr->src = 1;
+ hdr->dest = 2;
+
+ buf = mctp_pktbuf_data(pkt);
+ *buf = key;
+
+ binding->rx_count++;
+ mctp_bus_rx(&binding->binding, pkt);
+}
+
+static struct mctp_binding_bridge *mctp_binding_bridge_init(void)
+{
+ struct mctp_binding_bridge *binding;
+
+ binding = __mctp_alloc(sizeof(*binding));
+ memset(binding, 0, sizeof(*binding));
+ binding->binding.name = "test";
+ binding->binding.version = 1;
+ binding->binding.tx = mctp_binding_bridge_tx;
+ binding->binding.pkt_size = MCTP_BMTU;
+ binding->binding.pkt_pad = 0;
+ return binding;
+}
+
+int main(void)
+{
+ struct test_ctx _ctx, *ctx = &_ctx;
+
+ ctx->mctp = mctp_init();
+ ctx->bindings[0] = mctp_binding_bridge_init();
+ ctx->bindings[1] = mctp_binding_bridge_init();
+
+ mctp_bridge_busses(ctx->mctp,
+ &ctx->bindings[0]->binding,
+ &ctx->bindings[1]->binding);
+
+ mctp_binding_set_tx_enabled(&ctx->bindings[0]->binding, true);
+ mctp_binding_set_tx_enabled(&ctx->bindings[1]->binding, true);
+
+ mctp_binding_bridge_rx(ctx->bindings[0], 0xaa);
+ assert(ctx->bindings[0]->tx_count == 0);
+ assert(ctx->bindings[1]->tx_count == 1);
+ assert(ctx->bindings[1]->last_pkt_data == 0xaa);
+
+ mctp_binding_bridge_rx(ctx->bindings[1], 0x55);
+ assert(ctx->bindings[1]->tx_count == 1);
+ assert(ctx->bindings[0]->tx_count == 1);
+ assert(ctx->bindings[0]->last_pkt_data == 0x55);
+
+ return EXIT_SUCCESS;
+}