fixeria submitted this change.
5 is the latest approved patch-set.
No files were changed between the latest approved patch-set and the submitted one.
proxy: queue BURST.req and dispatch per TDMA frame tick
Enqueue incoming BURST.req per endpoint instead of forwarding
immediately, and drain the queue on each TDMA clock tick: forward
entries whose fn is due, drop late ones, keep the rest waiting.
Change-Id: Ib147983e97638d2a2e487ccf76184912caf0941d
Related: OS#6672
---
M proxy/Makefile.am
A proxy/include/osmocom/proxy/burst_fwd.h
M proxy/include/osmocom/proxy/path_sim.h
M proxy/include/osmocom/proxy/trx.h
M proxy/src/burst_fwd.c
M proxy/src/clck_gen.c
M proxy/src/path_sim.c
M proxy/src/trx.c
8 files changed, 198 insertions(+), 11 deletions(-)
diff --git a/proxy/Makefile.am b/proxy/Makefile.am
index d0eb6cf..8fcde9e 100644
--- a/proxy/Makefile.am
+++ b/proxy/Makefile.am
@@ -3,6 +3,7 @@
$(NULL)
noinst_HEADERS = \
+ include/osmocom/proxy/burst_fwd.h \
include/osmocom/proxy/burst_synch.h \
include/osmocom/proxy/clck_gen.h \
include/osmocom/proxy/logging.h \
diff --git a/proxy/include/osmocom/proxy/burst_fwd.h b/proxy/include/osmocom/proxy/burst_fwd.h
new file mode 100644
index 0000000..7ecddba
--- /dev/null
+++ b/proxy/include/osmocom/proxy/burst_fwd.h
@@ -0,0 +1,5 @@
+#pragma once
+
+#include <stdint.h>
+
+void burst_fwd_dispatch(uint32_t fn);
diff --git a/proxy/include/osmocom/proxy/path_sim.h b/proxy/include/osmocom/proxy/path_sim.h
index 58bd9bb..25b68a0 100644
--- a/proxy/include/osmocom/proxy/path_sim.h
+++ b/proxy/include/osmocom/proxy/path_sim.h
@@ -33,6 +33,7 @@
const struct proxy_trx_chan *src,
const struct path_sim_cfg *cfg);
int path_sim_measure(uint32_t freq_hz, const struct path_sim_cfg *cfg);
+void path_sim_fill_nope(struct osmo_trxd_burst_ind *bi, const struct path_sim_cfg *cfg);
struct path_sim_cfg *path_sim_cfg_alloc(void *talloc_ctx);
diff --git a/proxy/include/osmocom/proxy/trx.h b/proxy/include/osmocom/proxy/trx.h
index 633c9fa..e3191d6 100644
--- a/proxy/include/osmocom/proxy/trx.h
+++ b/proxy/include/osmocom/proxy/trx.h
@@ -7,6 +7,7 @@
#include <osmocom/core/logging.h>
#include <osmocom/trx/trxc.h>
+#include <osmocom/trx/trxd.h>
#include <osmocom/proxy/path_sim.h>
@@ -23,6 +24,12 @@
struct proxy_trx_ts {
struct osmo_trxc_setslot cfg;
bool valid; /*!< has SETSLOT been received for this TS? */
+ /*! Scratch: this timeslot's Rx burst indication staged for the
+ * current TDMA frame tick, so dispatch can send it to L1 without
+ * regard to the order bursts were forwarded in. Reset to NOPE.ind
+ * at the start of each tick, then a real forwarded burst overwrites
+ * it if one lands here. See burst_fwd_dispatch() in burst_fwd.c. */
+ struct osmo_trxd_burst_ind bi;
};
/*! One Mobile Allocation entry: the Rx/Tx frequency pair for one ARFCN. */
@@ -50,6 +57,10 @@
struct path_sim_state path_sim; /*!< RF path simulation state (path_sim.c) */
struct proxy_trx_ts ts[PROXY_TRX_NUM_TS]; /*!< per-timeslot config (SETSLOT) */
struct proxy_trx_fh *fh; /*!< frequency hopping config (SETFH), NULL if disabled */
+ /*! Queue of struct msgb, each wrapping a copy of one BURST.req
+ * (struct osmo_trxd_burst_req) awaiting its TDMA frame tick, sorted
+ * by fn (ascending). See burst_fwd.c. */
+ struct llist_head tx_burst_queue;
};
/*! One virtual transceiver endpoint */
diff --git a/proxy/src/burst_fwd.c b/proxy/src/burst_fwd.c
index cc64743..f56f316 100644
--- a/proxy/src/burst_fwd.c
+++ b/proxy/src/burst_fwd.c
@@ -26,7 +26,11 @@
#include <string.h>
#include <osmocom/core/bits.h>
+#include <osmocom/core/talloc.h>
#include <osmocom/core/linuxlist.h>
+#include <osmocom/core/msgb.h>
+
+#include <osmocom/gsm/gsm0502.h>
#include <osmocom/trx/ep.h>
@@ -34,6 +38,7 @@
#include <osmocom/proxy/trx.h>
#include <osmocom/proxy/path_sim.h>
#include <osmocom/proxy/burst_synch.h>
+#include <osmocom/proxy/burst_fwd.h>
#include <osmocom/proxy/logging.h>
#define OSMO_TRXD_F_COMMON_MASK ( \
@@ -43,6 +48,13 @@
OSMO_TRXD_F_TRX_NUM \
)
+/*! The BURST.req copy wrapped in a queued struct msgb
+ * (see struct proxy_trx_chan::tx_burst_queue). */
+static inline struct osmo_trxd_burst_req *msgb_burst_req(const struct msgb *msg)
+{
+ return (struct osmo_trxd_burst_req *)msgb_data(msg);
+}
+
static void burst_fwd_to_chan(struct proxy_trx *src, unsigned int src_chan,
struct proxy_trx *dst, unsigned int dst_chan,
const struct osmo_trxd_burst_req *br)
@@ -69,25 +81,22 @@
br, &src->chans[src_chan],
g_proxy_ctx->path_sim);
- osmo_trx_ep_send_burst_ind(dst->ep, dst_chan, &bi);
+ /* Stage the burst rather than sending it right away: dispatch sends
+ * every dst channel's Rx indications in ascending tn order once all
+ * sources have been processed for this TDMA frame tick (see
+ * burst_fwd_dispatch()). */
+ dst->chans[dst_chan].ts[br->tn].bi = bi;
}
/*! Forward a Tx burst request to every powered-on endpoint/channel
* whose Rx frequency matches the source channel's Tx frequency (resolved
* per TDMA frame number if frequency hopping (SETFH) is configured). */
-void osmo_trx_ep_rx_burst_req(struct osmo_trx_ep *ep, unsigned int chan,
- const struct osmo_trxd_burst_req *br)
+static void burst_fwd_burst_req(struct proxy_trx *src, unsigned int chan,
+ const struct osmo_trxd_burst_req *br)
{
- struct proxy_trx *src = osmo_trx_ep_get_priv(ep);
struct proxy_trx *dst = NULL;
uint32_t tx_freq;
- if (!src->powered) {
- LOGP_TRXCH(src, chan, DTRXD, LOGL_NOTICE,
- "Rx BURST.req while not powered on, dropping\n");
- return;
- }
-
if (src->chans[chan].fh != NULL)
proxy_trx_fh_resolve(src->chans[chan].fh, br->fn, NULL, &tx_freq);
else
@@ -114,3 +123,147 @@
}
}
}
+
+/*! Enqueue a Tx burst request for later dispatch by the TDMA clock
+ * generator: real transceivers typically receive bursts a few frames ahead
+ * of their actual air time, so forwarding must happen at the matching TDMA
+ * frame tick, not immediately upon receipt (see burst_fwd_dispatch()). */
+void osmo_trx_ep_rx_burst_req(struct osmo_trx_ep *ep, unsigned int chan,
+ const struct osmo_trxd_burst_req *br)
+{
+ struct proxy_trx *src = osmo_trx_ep_get_priv(ep);
+ struct proxy_trx_chan *c = &src->chans[chan];
+ struct msgb *msg, *cur;
+
+ if (!src->powered) {
+ LOGP_TRXCH(src, chan, DTRXD, LOGL_NOTICE,
+ "Rx BURST.req while not powered on, dropping\n");
+ return;
+ }
+
+ msg = msgb_alloc_c(src, sizeof(*br), "trxd_burst_req");
+ OSMO_ASSERT(msg != NULL);
+ memcpy(msgb_put(msg, sizeof(*br)), br, sizeof(*br));
+
+ /* The queue is kept sorted by TDMA FN (ascending) so that dispatch,
+ * which is timing critical, only ever needs to look at the head of
+ * the queue instead of scanning it in full on every TDMA frame tick.
+ * Bursts normally arrive already in ascending FN order (a few frames
+ * ahead of their air time), so a new entry almost always belongs at
+ * the tail: scan backwards from there so the common case is O(1). */
+ llist_for_each_entry_reverse(cur, &c->tx_burst_queue, list) {
+ if (gsm0502_fncmp(msgb_burst_req(cur)->fn, br->fn) <= 0) {
+ llist_add(&msg->list, &cur->list);
+ return;
+ }
+ }
+ llist_add(&msg->list, &c->tx_burst_queue);
+}
+
+/*! Reset every powered channel's per-tn staging area to NOPE.ind for the
+ * given TDMA frame number, so real forwarded bursts only need to overwrite
+ * the entries they land on (see burst_fwd_to_chan()). */
+static void burst_fwd_reset_bi(uint32_t fn)
+{
+ struct proxy_trx *trx;
+
+ llist_for_each_entry(trx, &g_proxy_ctx->trx_list, list) {
+ if (!trx->powered)
+ continue;
+
+ for (unsigned int chan = 0; chan < trx->num_chans; chan++) {
+ struct proxy_trx_chan *c = &trx->chans[chan];
+
+ for (unsigned int tn = 0; tn < PROXY_TRX_NUM_TS; tn++) {
+ c->ts[tn].bi = (struct osmo_trxd_burst_ind){ .fn = fn, .tn = tn };
+ path_sim_fill_nope(&c->ts[tn].bi, g_proxy_ctx->path_sim);
+ }
+ }
+ }
+}
+
+/*! Send every powered channel's staged Rx indications (see
+ * burst_fwd_reset_bi(), burst_fwd_to_chan()) for this TDMA frame tick,
+ * in ascending tn order. */
+static void burst_fwd_send_bi(void)
+{
+ struct proxy_trx *trx;
+
+ llist_for_each_entry(trx, &g_proxy_ctx->trx_list, list) {
+ if (!trx->powered)
+ continue;
+
+ for (unsigned int chan = 0; chan < trx->num_chans; chan++) {
+ struct proxy_trx_chan *c = &trx->chans[chan];
+
+ for (unsigned int tn = 0; tn < PROXY_TRX_NUM_TS; tn++) {
+ struct proxy_trx_ts *ts = &c->ts[tn];
+ struct osmo_trxd_burst_ind *bi = &ts->bi;
+
+ /* unconfigured (no SETSLOT) timeslot: send nothing at all */
+ if (!ts->valid)
+ continue;
+
+ /* TRXDv0 has no MTS field to carry the NOPE.ind flag in */
+ if ((bi->flags & OSMO_TRXD_F_NOPE_IND) &&
+ osmo_trx_ep_get_pdu_ver(trx->ep, chan) < 1)
+ continue;
+
+ osmo_trx_ep_send_burst_ind(trx->ep, chan, bi);
+ }
+
+ /* flush batched PDUs (no-op below TRXDv2) */
+ osmo_trx_ep_send_burst_fin(trx->ep, chan);
+ }
+ }
+}
+
+/*! Dispatch every queued BURST.req whose TDMA frame number is due:
+ * forward those with fn == fn, drop those with fn < fn (arrived too late),
+ * and leave the rest queued. */
+void burst_fwd_dispatch(uint32_t fn)
+{
+ struct proxy_trx *trx;
+
+ /* Three passes over this TDMA frame tick:
+ * 1. pre-fill every dst channel's Rx staging area with NOPE.ind; */
+ burst_fwd_reset_bi(fn);
+
+ /* 2. dispatch the per-channel Tx queues, overwriting the staged
+ * NOPE.ind of whatever real bursts land; */
+ llist_for_each_entry(trx, &g_proxy_ctx->trx_list, list) {
+ if (!trx->powered)
+ continue;
+
+ for (unsigned int chan = 0; chan < trx->num_chans; chan++) {
+ struct proxy_trx_chan *c = &trx->chans[chan];
+ struct msgb *msg, *msg2;
+
+ /* tx_burst_queue is sorted by fn (ascending), so it's
+ * enough to consume its head and stop at the first
+ * entry that is not yet due. */
+ llist_for_each_entry_safe(msg, msg2, &c->tx_burst_queue, list) {
+ struct osmo_trxd_burst_req *br = msgb_burst_req(msg);
+ int rc = gsm0502_fncmp(br->fn, fn);
+
+ if (rc > 0) /* br->fn is still ahead of fn */
+ break;
+
+ llist_del(&msg->list);
+
+ if (OSMO_UNLIKELY(rc < 0)) { /* br->fn is behind fn */
+ LOGP_TRXCH(trx, chan, DTRXD, LOGL_ERROR,
+ "Rx BURST.req for fn=%u too late (now fn=%u), "
+ "dropping\n", br->fn, fn);
+ } else {
+ burst_fwd_burst_req(trx, chan, br);
+ }
+
+ msgb_free(msg);
+ }
+ }
+ }
+
+ /* 3. send every staged Rx indication out to L1. */
+ burst_fwd_send_bi();
+}
diff --git a/proxy/src/clck_gen.c b/proxy/src/clck_gen.c
index 813530c..ff6c64c 100644
--- a/proxy/src/clck_gen.c
+++ b/proxy/src/clck_gen.c
@@ -37,6 +37,7 @@
#include <osmocom/proxy/proxy.h>
#include <osmocom/proxy/trx.h>
#include <osmocom/proxy/clck_gen.h>
+#include <osmocom/proxy/burst_fwd.h>
#include <osmocom/proxy/logging.h>
/*! Default "IND CLOCK" period, in frames */
@@ -78,7 +79,7 @@
}
}
- /* TODO: drive per-frame burst forwarding (burst_queue/burst_fwd) */
+ burst_fwd_dispatch(gen->fn);
GSM_TDMA_FN_INC(gen->fn);
}
diff --git a/proxy/src/path_sim.c b/proxy/src/path_sim.c
index 260cce2..1b069ed 100644
--- a/proxy/src/path_sim.c
+++ b/proxy/src/path_sim.c
@@ -190,6 +190,20 @@
bi->flags |= OSMO_TRXD_F_CI_CB;
}
+/*! Fill in a NOPE.ind for a timeslot where no BURST.req was received at all
+ * this TDMA frame tick (as opposed to path_sim_apply(), which reports on an
+ * actually forwarded burst that got dropped/muted along the way). Reports
+ * the configured noise floor, same as path_sim_measure() would for an idle
+ * frequency. */
+void path_sim_fill_nope(struct osmo_trxd_burst_ind *bi, const struct path_sim_cfg *cfg)
+{
+ bi->flags |= OSMO_TRXD_F_NOPE_IND | OSMO_TRXD_F_CI_CB;
+ bi->burst_len = 0;
+ bi->toa256 = PATH_SIM_TOA256_NOISE_DEFAULT;
+ bi->rssi = cfg->noise_dbm;
+ bi->ci_cb = PATH_SIM_CI_NOISE_DEFAULT;
+}
+
static int path_sim_measure_rssi(const struct proxy_trx_chan *tx, const struct path_sim_cfg *cfg)
{
if (tx->path_sim.flags & PATH_SIM_F_FAKE_RSSI)
diff --git a/proxy/src/trx.c b/proxy/src/trx.c
index da315d1..96bfb48 100644
--- a/proxy/src/trx.c
+++ b/proxy/src/trx.c
@@ -135,6 +135,7 @@
path_sim_state_reset(&trx->chans[i].path_sim, trx->tx_power,
path_sim_cfg_get_nom_toa256(g_proxy_ctx->path_sim),
path_sim_cfg_get_nom_ci_cb(g_proxy_ctx->path_sim));
+ INIT_LLIST_HEAD(&trx->chans[i].tx_burst_queue);
}
}
To view, visit change 43612. To unsubscribe, or for help writing mail filters, visit settings.