fixeria has submitted this change. ( https://gerrit.osmocom.org/c/osmo-trx/+/43109?usp=email )
(
4 is the latest approved patch-set. No files were changed between the latest approved patch-set and the submitted one. )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, 118 insertions(+), 5 deletions(-)
Approvals: laforge: Looks good to me, but someone else must approve Jenkins Builder: Verified pespin: Looks good to me, but someone else must approve fixeria: Looks good to me, approved
diff --git a/libosmo-trx/include/osmocom/trx/trxc_client.h b/libosmo-trx/include/osmocom/trx/trxc_client.h index dc9f290..0f0d5ec 100644 --- a/libosmo-trx/include/osmocom/trx/trxc_client.h +++ b/libosmo-trx/include/osmocom/trx/trxc_client.h @@ -57,6 +57,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); int 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); /*! set the tx_msg call-back (mandatory before the first command is sent) */ void osmo_trxc_client_set_tx_msg_cb(struct osmo_trxc_client *client, osmo_trxc_client_tx_msg_cb *cb); diff --git a/libosmo-trx/src/trxc_client.c b/libosmo-trx/src/trxc_client.c index 95f300c..fead54f 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; }; @@ -60,6 +64,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; @@ -108,9 +113,20 @@ OSMO_ASSERT(!llist_empty(&client->cmd_queue)); e = llist_first_entry(&client->cmd_queue, struct trxc_cmd_entry, list);
- LOGCL(client, LOGL_NOTICE, "No response from transceiver for '" CMD_NAME_FMT "'\n", - CMD_NAME_ARGS(e)); + LOGCL(client, LOGL_NOTICE, + "No response from transceiver for '" + CMD_NAME_FMT "' (n_retrans=%u, max_retrans=%u)\n", + CMD_NAME_ARGS(e), e->n_retrans, client->max_retrans);
+ 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); }
@@ -209,6 +225,16 @@ return 0; }
+/*! 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 @@ -416,6 +442,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 4b93a30..2773b2e 100644 --- a/tests/libosmo-trx/trxc_client_test.c +++ b/tests/libosmo-trx/trxc_client_test.c @@ -161,6 +161,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) { @@ -304,6 +337,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..c7a8e1b 100644 --- a/tests/libosmo-trx/trxc_client_test.err +++ b/tests/libosmo-trx/trxc_client_test.err @@ -20,15 +20,39 @@ DLGLOBAL NOTICE phy0.trx0: Rx response without a pending command 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 NOTICE phy0.trx0: No response from transceiver for 'CMD POWERON' (n_retrans=0, max_retrans=0) DLGLOBAL DEBUG phy0.trx0: Tx 'CMD POWERON' -DLGLOBAL NOTICE phy0.trx0: No response from transceiver for 'CMD POWERON' +DLGLOBAL NOTICE phy0.trx0: No response from transceiver for 'CMD POWERON' (n_retrans=1, max_retrans=0) DLGLOBAL DEBUG phy0.trx0: Tx 'CMD POWERON' 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' (n_retrans=0, max_retrans=3) +DLGLOBAL DEBUG phy0.trx0: Tx 'CMD POWERON' +DLGLOBAL NOTICE phy0.trx0: No response from transceiver for 'CMD POWERON' (n_retrans=1, max_retrans=3) +DLGLOBAL DEBUG phy0.trx0: Tx 'CMD POWERON' +DLGLOBAL NOTICE phy0.trx0: No response from transceiver for 'CMD POWERON' (n_retrans=2, max_retrans=3) +DLGLOBAL DEBUG phy0.trx0: Tx 'CMD POWERON' +DLGLOBAL NOTICE phy0.trx0: No response from transceiver for 'CMD POWERON' (n_retrans=3, max_retrans=3) +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' (n_retrans=0, max_retrans=3) +DLGLOBAL DEBUG phy0.trx0: Tx 'CMD POWERON' +DLGLOBAL NOTICE phy0.trx0: No response from transceiver for 'CMD POWERON' (n_retrans=1, max_retrans=3) +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' (n_retrans=0, max_retrans=3) +DLGLOBAL DEBUG phy0.trx0: Tx 'CMD RXTUNE 890000' +DLGLOBAL NOTICE phy0.trx0: No response from transceiver for 'CMD RXTUNE 890000' (n_retrans=1, max_retrans=3) +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 NOTICE phy0.trx0: No response from transceiver for 'CMD POWERON' (n_retrans=0, max_retrans=0) DLGLOBAL DEBUG phy0.trx0: Tx 'CMD POWERON' DLGLOBAL INFO phy0.trx0: Rx 'RSP POWERON 0' DLGLOBAL INFO phy0.trx0: Enqueueing 'CMD RXTUNE 890000' 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'