aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorAndreas Eversberg <andreas@eversberg.eu>2023-09-24 16:43:45 +0000
committerAndreas Eversberg <jolly@eversberg.eu>2024-01-19 18:23:01 +0100
commit8d65c3ff4def5b1373c9ea10fdf7b96b046487f0 (patch)
tree95b97bb835ca53d29c8e4e7fbcf5fec902fac55d /src
parent6b0f9179b1f1c05e293e3a246d5d29c640eb73fd (diff)
Add option to automatically reset RIFO on underrun/overflow
Whenever the RIFO buffer fill drifts away from its target, it can be automatically reset and filled to the initial prefill_frame_count value. The average fill is measured over several seconds. A given deviation in percent of the prefill_frame_count is used to trigger that reset. If the deviation is not set (0), this feature is deactivated. There are two reasons for this to happen: The GPS clock is missing, so the receiving interface is not in sync with the transmitting interface. The delay changes significantly, due to congestion on the path between both peers. (poor internet connection) Change-Id: Id7ccbfbdb288990c01f185dec79a1022a68b4748
Diffstat (limited to 'src')
-rw-r--r--src/octoi/e1oip.c28
-rw-r--r--src/octoi/e1oip.h6
-rw-r--r--src/octoi/frame_rifo.c6
-rw-r--r--src/octoi/frame_rifo.h2
-rw-r--r--src/octoi/octoi_clnt_fsm.c2
-rw-r--r--src/octoi/octoi_clnt_vty.c1
-rw-r--r--src/octoi/octoi_srv_fsm.c2
-rw-r--r--src/octoi/octoi_srv_vty.c14
-rw-r--r--src/octoi/octoi_vty.h1
9 files changed, 51 insertions, 11 deletions
diff --git a/src/octoi/e1oip.c b/src/octoi/e1oip.c
index 85dd165..e2aad34 100644
--- a/src/octoi/e1oip.c
+++ b/src/octoi/e1oip.c
@@ -250,7 +250,7 @@ int e1oip_rcvmsg_tdm_data(struct e1oip_line *iline, struct msgb *msg)
"RxIP: %u extraneous bytes (len=%u, num_ts=%u, n_frames=%u)\n",
msgb_length(msg) % num_ts, msgb_length(msg), num_ts, n_frames);
}
- LOGPEER(peer, LOGL_INFO, "RxIP: frame=%05u ts_mask=0x%08x num_ts=%02u, n_frames=%u\n",
+ LOGPEER(peer, LOGL_DEBUG, "RxIP: frame=%05u ts_mask=0x%08x num_ts=%02u, n_frames=%u\n",
frame_nr, ts_mask, num_ts, n_frames);
} else {
if (msgb_l3len(msg) < 1) {
@@ -271,7 +271,26 @@ int e1oip_rcvmsg_tdm_data(struct e1oip_line *iline, struct msgb *msg)
rc = frame_rifo_in(&iline->e1t.rifo, frame_buf, fn32+i);
if (rc < 0)
iline_ctr_add(iline, LINE_CTR_E1oIP_E1T_OVERFLOW, 1);
+ /* Continue the for loop, if buffer reset is not configured. */
+ if (!iline->cfg.buffer_reset_percent)
+ continue;
+ /* Calculate average RIFO delay. */
+ int32_t d = fn32 + i - iline->e1t.rifo.next_out_fn;
+ iline->e1t.delay += d;
+ if (++iline->e1t.delay_cnt == FRAMES_BUFFER_RESET_AVG) {
+ int offset;
+ d = iline->e1t.delay / iline->e1t.delay_cnt;
+ iline->e1t.delay = iline->e1t.delay_cnt = 0;
+ offset = abs((int32_t)iline->cfg.prefill_frame_count - d) * 100 / iline->cfg.prefill_frame_count;
+ LOGPEER(peer, LOGL_INFO, "RxIP: Buffer fill %u frames, %u%% off target.\n", d, offset);
+ if (offset > iline->cfg.buffer_reset_percent) {
+ LOGPEER(peer, LOGL_ERROR, "RxIP: frame number out of range. Reset buffer.\n");
+ frame_rifo_init(&iline->e1t.rifo, fn32 + i);
+ iline->e1t.primed_rx_tdm = false;
+ }
+ }
}
+
/* update local state */
memcpy(iline->e1t.last_frame, frame_buf, BYTES_PER_FRAME);
if (update_next)
@@ -318,10 +337,11 @@ struct e1oip_line *e1oip_line_alloc(struct octoi_peer *peer)
}
void e1oip_line_configure(struct e1oip_line *iline, uint8_t batching_factor,
- uint32_t prefill_frame_count, bool force_send_all_ts)
+ uint32_t prefill_frame_count, uint8_t buffer_reset_percent, bool force_send_all_ts)
{
iline->cfg.batching_factor = batching_factor;
iline->cfg.prefill_frame_count = prefill_frame_count;
+ iline->cfg.buffer_reset_percent = buffer_reset_percent;
iline->cfg.force_send_all_ts = force_send_all_ts;
}
@@ -331,10 +351,12 @@ void e1oip_line_reset(struct e1oip_line *iline)
memset(&iline->e1o.last_frame, 0xff, sizeof(iline->e1o.last_frame));
iline->e1o.next_seq = 0;
- frame_rifo_init(&iline->e1t.rifo);
+ frame_rifo_init(&iline->e1t.rifo, 0);
memset(&iline->e1t.last_frame, 0xff, sizeof(iline->e1t.last_frame));
iline->e1t.next_fn32 = 0;
iline->e1t.primed_rx_tdm = false;
+ iline->e1t.delay = 0;
+ iline->e1t.delay_cnt = 0;
}
void e1oip_line_destroy(struct e1oip_line *iline)
diff --git a/src/octoi/e1oip.h b/src/octoi/e1oip.h
index a17c257..8aaa420 100644
--- a/src/octoi/e1oip.h
+++ b/src/octoi/e1oip.h
@@ -15,6 +15,8 @@
#define FRAMES_PER_SEC_THRESHOLD 7500
+#define FRAMES_BUFFER_RESET_AVG 40000
+
#define DEFAULT_BATCHING_FACTOR 32
#define DEFAULT_PREFILL_FRAME_COUNT 200 /* 25ms */
@@ -54,6 +56,7 @@ struct e1oip_line {
struct {
uint8_t batching_factor;
uint32_t prefill_frame_count;
+ uint8_t buffer_reset_percent;
bool force_send_all_ts;
} cfg;
@@ -70,6 +73,7 @@ struct e1oip_line {
uint8_t last_frame[BYTES_PER_FRAME]; /* last frame on the E1 side */
uint32_t next_fn32; /* next expected frame number */
bool primed_rx_tdm; /* Was RX RIFO primed */
+ int32_t delay, delay_cnt; /* Delay counter to calculate average delay */
} e1t;
};
@@ -84,7 +88,7 @@ struct e1oip_line *e1oip_line_alloc(struct octoi_peer *peer);
void e1oip_line_set_name(struct e1oip_line *line, const char *name);
void e1oip_line_reset(struct e1oip_line *iline);
void e1oip_line_configure(struct e1oip_line *iline, uint8_t batching_factor,
- uint32_t prefill_frame_count, bool force_send_all_ts);
+ uint32_t prefill_frame_count, uint8_t buffer_reset_percent, bool force_send_all_ts);
void e1oip_line_destroy(struct e1oip_line *iline);
int e1oip_rcvmsg_tdm_data(struct e1oip_line *iline, struct msgb *msg);
diff --git a/src/octoi/frame_rifo.c b/src/octoi/frame_rifo.c
index e3c22d9..00fb6a5 100644
--- a/src/octoi/frame_rifo.c
+++ b/src/octoi/frame_rifo.c
@@ -86,12 +86,12 @@ static bool bucket_bit_get(struct frame_rifo *rifo, uint32_t bucket_nr)
/*! Initialize a frame RIFO.
* \param rifo Caller-allocated memory for RIFO data structure */
-void frame_rifo_init(struct frame_rifo *rifo)
+void frame_rifo_init(struct frame_rifo *rifo, uint32_t fn)
{
memset(rifo->buf, 0xff, sizeof(rifo->buf));
rifo->next_out = rifo->buf;
- rifo->next_out_fn = 0;
- rifo->last_in_fn = -1;
+ rifo->next_out_fn = fn;
+ rifo->last_in_fn = fn - 1;
memset(rifo->bitvec, 0, sizeof(rifo->bitvec));
}
diff --git a/src/octoi/frame_rifo.h b/src/octoi/frame_rifo.h
index ac97506..19a9acb 100644
--- a/src/octoi/frame_rifo.h
+++ b/src/octoi/frame_rifo.h
@@ -27,7 +27,7 @@ static inline unsigned int frame_rifo_depth(struct frame_rifo *rifo)
return rifo->last_in_fn - rifo->next_out_fn + 1;
}
-void frame_rifo_init(struct frame_rifo *rifo);
+void frame_rifo_init(struct frame_rifo *rifo, uint32_t fn);
/* number of frames currently available in FIFO */
static inline unsigned int frame_rifo_frames(struct frame_rifo *rifo)
diff --git a/src/octoi/octoi_clnt_fsm.c b/src/octoi/octoi_clnt_fsm.c
index 2bfc8f9..d4cf90d 100644
--- a/src/octoi/octoi_clnt_fsm.c
+++ b/src/octoi/octoi_clnt_fsm.c
@@ -123,7 +123,7 @@ static void clnt_st_accepted_onenter(struct osmo_fsm_inst *fi, uint32_t prev_sta
struct clnt_state *st = fi->priv;
e1oip_line_configure(st->peer->iline, st->acc->batching_factor,
- st->acc->prefill_frame_count, st->acc->force_send_all_ts);
+ st->acc->prefill_frame_count, st->acc->buffer_reset_percent, st->acc->force_send_all_ts);
/* reset RIFO/FIFO etc. */
e1oip_line_reset(st->peer->iline);
iline_ctr_add(st->peer->iline, LINE_CTR_E1oIP_CONNECT_ACCEPT, 1);
diff --git a/src/octoi/octoi_clnt_vty.c b/src/octoi/octoi_clnt_vty.c
index 54ed60f..afca60c 100644
--- a/src/octoi/octoi_clnt_vty.c
+++ b/src/octoi/octoi_clnt_vty.c
@@ -283,6 +283,7 @@ void octoi_client_vty_init(void)
install_element(OCTOI_CLNT_ACCOUNT_NODE, &cfg_account_force_all_ts_cmd);
install_element(OCTOI_CLNT_ACCOUNT_NODE, &cfg_account_no_force_all_ts_cmd);
install_element(OCTOI_CLNT_ACCOUNT_NODE, &cfg_account_prefill_frame_count_cmd);
+ install_element(OCTOI_CLNT_ACCOUNT_NODE, &cfg_account_buffer_reset_cmd);
#ifdef HAVE_DAHDI_TRUNKDEV
install_element(OCTOI_CLNT_ACCOUNT_NODE, &cfg_account_trunkdev_name_cmd);
install_element(OCTOI_CLNT_ACCOUNT_NODE, &cfg_account_trunkdev_line_cmd);
diff --git a/src/octoi/octoi_srv_fsm.c b/src/octoi/octoi_srv_fsm.c
index b6914b7..81b27da 100644
--- a/src/octoi/octoi_srv_fsm.c
+++ b/src/octoi/octoi_srv_fsm.c
@@ -176,7 +176,7 @@ static void srv_st_accepted_onenter(struct osmo_fsm_inst *fi, uint32_t prev_stat
struct srv_state *st = fi->priv;
e1oip_line_configure(st->peer->iline, st->acc->batching_factor,
- st->acc->prefill_frame_count, st->acc->force_send_all_ts);
+ st->acc->prefill_frame_count, st->acc->buffer_reset_percent, st->acc->force_send_all_ts);
/* reset RIFO/FIFO etc. */
e1oip_line_reset(st->peer->iline);
iline_ctr_add(st->peer->iline, LINE_CTR_E1oIP_CONNECT_ACCEPT, 1);
diff --git a/src/octoi/octoi_srv_vty.c b/src/octoi/octoi_srv_vty.c
index 4fc4e47..05a99a4 100644
--- a/src/octoi/octoi_srv_vty.c
+++ b/src/octoi/octoi_srv_vty.c
@@ -412,7 +412,7 @@ gDEFUN(cfg_account_no_force_all_ts, cfg_account_no_force_all_ts_cmd,
}
gDEFUN(cfg_account_prefill_frame_count, cfg_account_prefill_frame_count_cmd,
- "prefill-frame-count <0-8000>",
+ "prefill-frame-count <0-900>",
"Number of E1 frames to pre-fill/pre-seed in Rx RIFO\n"
"Number of E1 frames to pre-fill/pre-seed in Rx RIFO\n")
{
@@ -422,6 +422,17 @@ gDEFUN(cfg_account_prefill_frame_count, cfg_account_prefill_frame_count_cmd,
return CMD_SUCCESS;
}
+gDEFUN(cfg_account_buffer_reset, cfg_account_buffer_reset_cmd,
+ "buffer-reset <0-100>",
+ "Reset Rx RIFO when fill in Rx RIFO drifts too much off normal\n"
+ "Give fill in percentage, use 0 to disable this feature\n")
+{
+ struct octoi_account *acc = vty->index;
+
+ acc->buffer_reset_percent = atoi(argv[0]);
+ return CMD_SUCCESS;
+}
+
void octoi_vty_show_one_account(struct vty *vty, const char *pfx, struct octoi_account *acc)
{
vty_out(vty, "%sAccount '%s': Mode=%s, Batching=%u, Prefill=%u%s", pfx,
@@ -563,6 +574,7 @@ void octoi_server_vty_init(void)
install_element(OCTOI_ACCOUNT_NODE, &cfg_account_force_all_ts_cmd);
install_element(OCTOI_ACCOUNT_NODE, &cfg_account_no_force_all_ts_cmd);
install_element(OCTOI_ACCOUNT_NODE, &cfg_account_prefill_frame_count_cmd);
+ install_element(OCTOI_ACCOUNT_NODE, &cfg_account_buffer_reset_cmd);
#ifdef HAVE_DAHDI_TRUNKDEV
install_element(OCTOI_ACCOUNT_NODE, &cfg_account_trunkdev_name_cmd);
install_element(OCTOI_ACCOUNT_NODE, &cfg_account_trunkdev_line_cmd);
diff --git a/src/octoi/octoi_vty.h b/src/octoi/octoi_vty.h
index 55fa7fe..a452e9d 100644
--- a/src/octoi/octoi_vty.h
+++ b/src/octoi/octoi_vty.h
@@ -11,6 +11,7 @@ extern struct cmd_element cfg_account_batching_factor_cmd;
extern struct cmd_element cfg_account_force_all_ts_cmd;
extern struct cmd_element cfg_account_no_force_all_ts_cmd;
extern struct cmd_element cfg_account_prefill_frame_count_cmd;
+extern struct cmd_element cfg_account_buffer_reset_cmd;
extern struct cmd_element cfg_account_trunkdev_name_cmd;
extern struct cmd_element cfg_account_trunkdev_line_cmd;