diff options
-rw-r--r-- | include/osmocom/octoi/octoi.h | 1 | ||||
-rw-r--r-- | src/octoi/e1oip.c | 28 | ||||
-rw-r--r-- | src/octoi/e1oip.h | 6 | ||||
-rw-r--r-- | src/octoi/frame_rifo.c | 6 | ||||
-rw-r--r-- | src/octoi/frame_rifo.h | 2 | ||||
-rw-r--r-- | src/octoi/octoi_clnt_fsm.c | 2 | ||||
-rw-r--r-- | src/octoi/octoi_clnt_vty.c | 1 | ||||
-rw-r--r-- | src/octoi/octoi_srv_fsm.c | 2 | ||||
-rw-r--r-- | src/octoi/octoi_srv_vty.c | 14 | ||||
-rw-r--r-- | src/octoi/octoi_vty.h | 1 | ||||
-rw-r--r-- | tests/rifo/rifo_test.c | 4 |
11 files changed, 54 insertions, 13 deletions
diff --git a/include/osmocom/octoi/octoi.h b/include/osmocom/octoi/octoi.h index 645af3f..b80f8be 100644 --- a/include/osmocom/octoi/octoi.h +++ b/include/osmocom/octoi/octoi.h @@ -24,6 +24,7 @@ struct octoi_account { uint8_t batching_factor; /* E1 frames per UDP packet (Tx) */ bool force_send_all_ts; /* force transmission of all timeslots */ uint32_t prefill_frame_count; /* FIFO prefill/preseed count (Rx) */ + uint8_t buffer_reset_percent; /* When to reset Rx RIFO in percent */ union { struct { char *usb_serial; /* USB serial string (ASCII) of icE1usb */ 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; diff --git a/tests/rifo/rifo_test.c b/tests/rifo/rifo_test.c index ec90ce7..381ca49 100644 --- a/tests/rifo/rifo_test.c +++ b/tests/rifo/rifo_test.c @@ -23,7 +23,7 @@ static uint32_t init_next_out_fn; static void rifo_init(struct frame_rifo *rifo) { - frame_rifo_init(rifo); + frame_rifo_init(rifo, 0); rifo->next_out_fn = init_next_out_fn; rifo->last_in_fn = init_next_out_fn - 1; } @@ -48,7 +48,7 @@ static int rifo_out(struct frame_rifo *rifo, uint8_t *out) static void missing_frames(uint8_t modulo) { struct frame_rifo rifo; - frame_rifo_init(&rifo); + frame_rifo_init(&rifo, 0); rifo.next_out_fn = init_next_out_fn; rifo.last_in_fn = init_next_out_fn - 1; |