fixeria has uploaded this change for review. ( https://gerrit.osmocom.org/c/osmo-trx/+/43109?usp=email )
Change subject: libosmo-trx/client: add optional limit for retransmissions ......................................................................
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'