fixeria has uploaded this change for review.
libosmo-trx/client: add optional limit for retransmissions
The client used to retransmit an unacknowledged command forever, like
osmo-bts-trx does. trxcon, however, gives up after 3 retransmission
attempts, concluding that the transceiver is offline. Add a new API
function osmo_trxc_client_set_max_retrans() enabling this behavior:
once a command has been retransmitted the given number of times
without a response, the client escalates to the fatal_error call-back
(with rsp == NULL) and freezes the command queue. The default (0)
retains the old behavior (no limit).
This is a preparation for porting trxcon to libosmo-trx.
Change-Id: Ib90a032b38c69ae26023e726992d3f5f7e502fcf
---
M libosmo-trx/include/osmocom/trx/trxc_client.h
M libosmo-trx/src/trxc_client.c
M tests/libosmo-trx/trxc_client_test.c
M tests/libosmo-trx/trxc_client_test.err
M tests/libosmo-trx/trxc_client_test.ok
5 files changed, 111 insertions(+), 0 deletions(-)
git pull ssh://gerrit.osmocom.org:29418/osmo-trx refs/changes/09/43109/1
diff --git a/libosmo-trx/include/osmocom/trx/trxc_client.h b/libosmo-trx/include/osmocom/trx/trxc_client.h
index 7984b93..a182f40 100644
--- a/libosmo-trx/include/osmocom/trx/trxc_client.h
+++ b/libosmo-trx/include/osmocom/trx/trxc_client.h
@@ -48,6 +48,7 @@
int osmo_trxc_client_set_name(struct osmo_trxc_client *client, const char *fmt, ...);
void osmo_trxc_client_set_log_cat(struct osmo_trxc_client *client, int log_cat);
void osmo_trxc_client_set_retrans(struct osmo_trxc_client *client, unsigned int sec);
+void osmo_trxc_client_set_max_retrans(struct osmo_trxc_client *client, unsigned int n);
/*! escalate to the fatal_error call-back on NACK */
#define OSMO_TRXC_F_CRITICAL (1 << 0)
diff --git a/libosmo-trx/src/trxc_client.c b/libosmo-trx/src/trxc_client.c
index 39b2a43..f9c393b 100644
--- a/libosmo-trx/src/trxc_client.c
+++ b/libosmo-trx/src/trxc_client.c
@@ -44,11 +44,15 @@
/*! Default retransmit timeout (in seconds) */
#define TRXC_CLIENT_RETRANS_SEC 2
+static int trxc_client_fatal(struct osmo_trxc_client *client,
+ const struct osmo_trxc_msg *rsp);
+
/*! A single command in the queue */
struct trxc_cmd_entry {
struct llist_head list;
struct osmo_trxc_msg msg; /* type == OSMO_TRXC_MT_CMD */
uint32_t flags; /* OSMO_TRXC_F_* */
+ unsigned int n_retrans; /* number of retransmissions so far */
osmo_trxc_client_rsp_cb *rsp_cb;
void *cb_data;
};
@@ -58,6 +62,7 @@
char *name; /* log prefix */
int log_cat; /* logging category (default DLGLOBAL) */
unsigned int retrans_sec; /* retransmit timeout */
+ unsigned int max_retrans; /* maximum number of retransmissions (0 = no limit) */
struct llist_head cmd_queue; /* list of struct trxc_cmd_entry */
struct trxc_cmd_entry *last_acked;
@@ -113,6 +118,15 @@
LOGCL(client, LOGL_NOTICE, "No response from transceiver for '" CMD_NAME_FMT "'\n",
CMD_NAME_ARGS(e));
+ if (client->max_retrans != 0 && e->n_retrans >= client->max_retrans) {
+ LOGCL(client, LOGL_FATAL, "Giving up on '" CMD_NAME_FMT "' after %u "
+ "retransmissions, transceiver offline?\n",
+ CMD_NAME_ARGS(e), e->n_retrans);
+ trxc_client_fatal(client, NULL);
+ return; /* keep the command queue frozen, do not re-arm the timer */
+ }
+
+ e->n_retrans++;
trxc_client_send_next(client);
}
@@ -192,6 +206,16 @@
client->retrans_sec = sec;
}
+/*! Set the maximum number of retransmissions of a command (default: 0).
+ * Once a command has been retransmitted the given number of times without
+ * a response, the engine gives up and escalates to the fatal_error
+ * call-back (with rsp == NULL); the command queue remains frozen.
+ * The special value 0 means no limit: retransmit indefinitely. */
+void osmo_trxc_client_set_max_retrans(struct osmo_trxc_client *client, unsigned int n)
+{
+ client->max_retrans = n;
+}
+
/*! Enqueue a new command for transmission.
*
* The new command is added to the end of the queue; there's at most one
@@ -398,6 +422,9 @@
* implement a fallback (see the SETFORMAT negotiation). */
}
+ /* the transceiver is responsive (again) */
+ e->n_retrans = 0;
+
client->in_rx = true;
if (e->rsp_cb != NULL)
rc = e->rsp_cb(client, &rsp, e->cb_data);
diff --git a/tests/libosmo-trx/trxc_client_test.c b/tests/libosmo-trx/trxc_client_test.c
index e042e10..eb9930d 100644
--- a/tests/libosmo-trx/trxc_client_test.c
+++ b/tests/libosmo-trx/trxc_client_test.c
@@ -164,6 +164,39 @@
osmo_trxc_client_free(client);
}
+static void test_max_retrans(void)
+{
+ struct osmo_trxc_client *client = client_alloc();
+
+ printf("=== %s ===\n", __func__);
+
+ /* give up after 3 retransmissions (like trxcon does) */
+ osmo_trxc_client_set_max_retrans(client, 3);
+
+ osmo_trxc_client_poweron(client, &rsp_cb, "poweron");
+ /* no response: 3 retransmissions, then fatal_error escalation */
+ for (unsigned int i = 0; i < 5; i++)
+ fake_time_passes(2);
+
+ osmo_trxc_client_free(client);
+
+ /* a response resets the retransmission counter */
+ client = client_alloc();
+ osmo_trxc_client_set_max_retrans(client, 3);
+
+ osmo_trxc_client_poweron(client, &rsp_cb, "poweron");
+ fake_time_passes(2);
+ fake_time_passes(2);
+ rx_rsp(client, "RSP POWERON 0");
+ osmo_trxc_client_rxtune(client, 890000, &rsp_cb, "rxtune");
+ /* the previous 2 retransmissions shall not count for RXTUNE */
+ fake_time_passes(2);
+ fake_time_passes(2);
+ rx_rsp(client, "RSP RXTUNE 0 890000");
+
+ osmo_trxc_client_free(client);
+}
+
static int rsp_retry_cb(struct osmo_trxc_client *client,
const struct osmo_trxc_msg *rsp, void *cb_data)
{
@@ -307,6 +340,7 @@
test_queueing();
test_dup_rsp();
test_retrans();
+ test_max_retrans();
test_rsp_cb_retry();
test_fatal_error();
test_negotiate_format();
diff --git a/tests/libosmo-trx/trxc_client_test.err b/tests/libosmo-trx/trxc_client_test.err
index e280bf1..115a9de 100644
--- a/tests/libosmo-trx/trxc_client_test.err
+++ b/tests/libosmo-trx/trxc_client_test.err
@@ -27,6 +27,30 @@
DLGLOBAL INFO phy0.trx0: Rx 'RSP POWERON 0'
DLGLOBAL INFO phy0.trx0: Enqueueing 'CMD POWERON'
DLGLOBAL DEBUG phy0.trx0: Tx 'CMD POWERON'
+DLGLOBAL NOTICE phy0.trx0: No response from transceiver for 'CMD POWERON'
+DLGLOBAL DEBUG phy0.trx0: Tx 'CMD POWERON'
+DLGLOBAL NOTICE phy0.trx0: No response from transceiver for 'CMD POWERON'
+DLGLOBAL DEBUG phy0.trx0: Tx 'CMD POWERON'
+DLGLOBAL NOTICE phy0.trx0: No response from transceiver for 'CMD POWERON'
+DLGLOBAL DEBUG phy0.trx0: Tx 'CMD POWERON'
+DLGLOBAL NOTICE phy0.trx0: No response from transceiver for 'CMD POWERON'
+DLGLOBAL FATAL phy0.trx0: Giving up on 'CMD POWERON' after 3 retransmissions, transceiver offline?
+DLGLOBAL INFO phy0.trx0: Enqueueing 'CMD POWERON'
+DLGLOBAL DEBUG phy0.trx0: Tx 'CMD POWERON'
+DLGLOBAL NOTICE phy0.trx0: No response from transceiver for 'CMD POWERON'
+DLGLOBAL DEBUG phy0.trx0: Tx 'CMD POWERON'
+DLGLOBAL NOTICE phy0.trx0: No response from transceiver for 'CMD POWERON'
+DLGLOBAL DEBUG phy0.trx0: Tx 'CMD POWERON'
+DLGLOBAL INFO phy0.trx0: Rx 'RSP POWERON 0'
+DLGLOBAL INFO phy0.trx0: Enqueueing 'CMD RXTUNE 890000'
+DLGLOBAL DEBUG phy0.trx0: Tx 'CMD RXTUNE 890000'
+DLGLOBAL NOTICE phy0.trx0: No response from transceiver for 'CMD RXTUNE 890000'
+DLGLOBAL DEBUG phy0.trx0: Tx 'CMD RXTUNE 890000'
+DLGLOBAL NOTICE phy0.trx0: No response from transceiver for 'CMD RXTUNE 890000'
+DLGLOBAL DEBUG phy0.trx0: Tx 'CMD RXTUNE 890000'
+DLGLOBAL INFO phy0.trx0: Rx 'RSP RXTUNE 0 890000'
+DLGLOBAL INFO phy0.trx0: Enqueueing 'CMD POWERON'
+DLGLOBAL DEBUG phy0.trx0: Tx 'CMD POWERON'
DLGLOBAL INFO phy0.trx0: Rx 'RSP POWERON 1'
DLGLOBAL NOTICE phy0.trx0: No response from transceiver for 'CMD POWERON'
DLGLOBAL DEBUG phy0.trx0: Tx 'CMD POWERON'
diff --git a/tests/libosmo-trx/trxc_client_test.ok b/tests/libosmo-trx/trxc_client_test.ok
index 5e908ce..0c0d09d 100644
--- a/tests/libosmo-trx/trxc_client_test.ok
+++ b/tests/libosmo-trx/trxc_client_test.ok
@@ -28,6 +28,31 @@
rx_rsp: 'RSP POWERON 0'
rsp_cb(poweron): 'RSP POWERON 0'
(time passes: 10 s)
+=== test_max_retrans ===
+tx_msg: 'CMD POWERON'
+(time passes: 2 s)
+tx_msg: 'CMD POWERON'
+(time passes: 2 s)
+tx_msg: 'CMD POWERON'
+(time passes: 2 s)
+tx_msg: 'CMD POWERON'
+(time passes: 2 s)
+fatal_error: '(null)'
+(time passes: 2 s)
+tx_msg: 'CMD POWERON'
+(time passes: 2 s)
+tx_msg: 'CMD POWERON'
+(time passes: 2 s)
+tx_msg: 'CMD POWERON'
+rx_rsp: 'RSP POWERON 0'
+rsp_cb(poweron): 'RSP POWERON 0'
+tx_msg: 'CMD RXTUNE 890000'
+(time passes: 2 s)
+tx_msg: 'CMD RXTUNE 890000'
+(time passes: 2 s)
+tx_msg: 'CMD RXTUNE 890000'
+rx_rsp: 'RSP RXTUNE 0 890000'
+rsp_cb(rxtune): 'RSP RXTUNE 0 890000'
=== test_rsp_cb_retry ===
tx_msg: 'CMD POWERON'
rx_rsp: 'RSP POWERON 1'
To view, visit change 43109. To unsubscribe, or for help writing mail filters, visit settings.