jolly has uploaded this change for review. ( https://gerrit.osmocom.org/c/osmo-e1d/+/34554?usp=email )
Change subject: Automatically reset RIFO on underrun/overflow ...................................................................... Automatically reset RIFO on underrun/overflow Whenever the RIFO buffer underruns or overflows, it it reset and is filled to the initial prefill_frame_count value. 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. An upper limit is defined by max_frame_count. By default, it is set to twice the value of max_frame_count. It specifies when the RIFO will overflow. A lower value prevents too much delay, but also causes a RIFO reset at a lower fill level. Change-Id: Id7ccbfbdb288990c01f185dec79a1022a68b4748 --- M include/osmocom/octoi/octoi.h M src/octoi/e1oip.c M src/octoi/e1oip.h M src/octoi/frame_rifo.c M src/octoi/frame_rifo.h M src/octoi/octoi_clnt_fsm.c M src/octoi/octoi_clnt_vty.c M src/octoi/octoi_srv_fsm.c M src/octoi/octoi_srv_vty.c M src/octoi/octoi_vty.h M tests/rifo/rifo_test.c 11 files changed, 90 insertions(+), 28 deletions(-) git pull ssh://gerrit.osmocom.org:29418/osmo-e1d refs/changes/54/34554/1 diff --git a/include/osmocom/octoi/octoi.h b/include/osmocom/octoi/octoi.h index 645af3f..73c0889 100644 --- a/include/osmocom/octoi/octoi.h +++ b/include/osmocom/octoi/octoi.h @@ -24,6 +24,7 @@ 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) */ + uint32_t max_frame_count; /* FIFO maximum frames count (Rx) */ 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..adb5319 100644 --- a/src/octoi/e1oip.c +++ b/src/octoi/e1oip.c @@ -268,10 +268,15 @@ frame_buf[ts_nr] = e1th->data[i*num_ts + j]; } /* FIXME: what to do about TS0? */ - rc = frame_rifo_in(&iline->e1t.rifo, frame_buf, fn32+i); - if (rc < 0) + rc = frame_rifo_in(&iline->e1t.rifo, frame_buf, fn32+i, iline->cfg.max_frame_count); + if (rc < 0) { + LOGPEER(peer, LOGL_ERROR, "RxIP: frame number out of range. Reset buffer.\n"); iline_ctr_add(iline, LINE_CTR_E1oIP_E1T_OVERFLOW, 1); + 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) @@ -308,6 +313,7 @@ iline->cfg.batching_factor = DEFAULT_BATCHING_FACTOR; iline->cfg.prefill_frame_count = DEFAULT_PREFILL_FRAME_COUNT; + iline->cfg.max_frame_count = DEFAULT_MAX_FRAME_COUNT; e1oip_line_reset(iline); @@ -317,11 +323,12 @@ return iline; } -void e1oip_line_configure(struct e1oip_line *iline, uint8_t batching_factor, - uint32_t prefill_frame_count, bool force_send_all_ts) +void e1oip_line_configure(struct e1oip_line *iline, uint8_t batching_factor, uint32_t prefill_frame_count, + uint32_t max_frame_count, bool force_send_all_ts) { iline->cfg.batching_factor = batching_factor; iline->cfg.prefill_frame_count = prefill_frame_count; + iline->cfg.max_frame_count = max_frame_count; iline->cfg.force_send_all_ts = force_send_all_ts; } @@ -331,7 +338,7 @@ 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; diff --git a/src/octoi/e1oip.h b/src/octoi/e1oip.h index 9357d48..5b6b5c9 100644 --- a/src/octoi/e1oip.h +++ b/src/octoi/e1oip.h @@ -17,6 +17,7 @@ #define DEFAULT_BATCHING_FACTOR 32 #define DEFAULT_PREFILL_FRAME_COUNT 200 /* 25ms */ +#define DEFAULT_MAX_FRAME_COUNT 400 /* 50ms */ enum e1oip_line_ctr { LINE_CTR_E1oIP_UNDERRUN, @@ -53,6 +54,7 @@ struct { uint8_t batching_factor; uint32_t prefill_frame_count; + uint32_t max_frame_count; bool force_send_all_ts; } cfg; @@ -84,8 +86,8 @@ 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); +void e1oip_line_configure(struct e1oip_line *iline, uint8_t batching_factor, uint32_t prefill_frame_count, + uint32_t max_frame_count, 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..8c892f2 100644 --- a/src/octoi/frame_rifo.c +++ b/src/octoi/frame_rifo.c @@ -86,12 +86,12 @@ /*! 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)); } @@ -101,16 +101,15 @@ * \param rifo The RIFO to which we want to put (append) multiple frames * \param frame Pointer to memory containing the frame data * \param fn Absolute frame number at which to insert the frame. + * \param Maximum number of frames to write in fifo. * \returns 0 on success; -1 on error (overflow) */ -int frame_rifo_in(struct frame_rifo *rifo, const uint8_t *frame, uint32_t fn) +int frame_rifo_in(struct frame_rifo *rifo, const uint8_t *frame, uint32_t fn, int max_frame_count) { uint32_t bucket; uint8_t *dst; - if (!frame_rifo_fn_in_range(rifo, fn)) - { + if (!frame_rifo_fn_in_range(rifo, fn, max_frame_count)) return -ERANGE; - } bucket = bucket_for_fn(rifo, fn); dst = rifo->buf + bucket * BYTES_PER_FRAME; diff --git a/src/octoi/frame_rifo.h b/src/octoi/frame_rifo.h index ac97506..46a8beb 100644 --- a/src/octoi/frame_rifo.h +++ b/src/octoi/frame_rifo.h @@ -14,11 +14,12 @@ indexed by physical offset in buf */ }; + /* can this frame number be stores in the rifo */ -static inline bool frame_rifo_fn_in_range(const struct frame_rifo *ff, uint32_t fn) +static inline bool frame_rifo_fn_in_range(const struct frame_rifo *ff, uint32_t fn, uint32_t max_frame_count) { uint32_t d = fn - ff->next_out_fn; - return d < FRAMES_PER_FIFO; + return d < FRAMES_PER_FIFO && d < max_frame_count; } /* current depth of RIFO */ @@ -27,7 +28,7 @@ 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) @@ -45,7 +46,7 @@ } /* put a received frame into the FIFO */ -int frame_rifo_in(struct frame_rifo *rifo, const uint8_t *frame, uint32_t fn); +int frame_rifo_in(struct frame_rifo *rifo, const uint8_t *frame, uint32_t fn, int max_frame_count); /* pull one frame out of the FIFO */ int frame_rifo_out(struct frame_rifo *rifo, uint8_t *out); diff --git a/src/octoi/octoi_clnt_fsm.c b/src/octoi/octoi_clnt_fsm.c index 2bfc8f9..11e805d 100644 --- a/src/octoi/octoi_clnt_fsm.c +++ b/src/octoi/octoi_clnt_fsm.c @@ -122,8 +122,8 @@ { 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); + e1oip_line_configure(st->peer->iline, st->acc->batching_factor, st->acc->prefill_frame_count, + st->acc->max_frame_count, 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..1ed1d97 100644 --- a/src/octoi/octoi_clnt_vty.c +++ b/src/octoi/octoi_clnt_vty.c @@ -282,7 +282,9 @@ install_element(OCTOI_CLNT_ACCOUNT_NODE, &cfg_account_batching_factor_cmd); 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); + set_frames_per_fifo_str(); install_element(OCTOI_CLNT_ACCOUNT_NODE, &cfg_account_prefill_frame_count_cmd); + install_element(OCTOI_CLNT_ACCOUNT_NODE, &cfg_account_max_frame_count_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..a17228c 100644 --- a/src/octoi/octoi_srv_fsm.c +++ b/src/octoi/octoi_srv_fsm.c @@ -175,8 +175,8 @@ { 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); + e1oip_line_configure(st->peer->iline, st->acc->batching_factor, st->acc->prefill_frame_count, + st->acc->max_frame_count, 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..0d6e0f9 100644 --- a/src/octoi/octoi_srv_vty.c +++ b/src/octoi/octoi_srv_vty.c @@ -66,6 +66,7 @@ ac->batching_factor = DEFAULT_BATCHING_FACTOR; ac->prefill_frame_count = DEFAULT_PREFILL_FRAME_COUNT; + ac->max_frame_count = DEFAULT_MAX_FRAME_COUNT; return ac; } @@ -411,14 +412,38 @@ return CMD_SUCCESS; } +static char cfg_account_prefill_frame_count_str[64]; +static char cfg_account_max_frame_count_str[64]; + +void set_frames_per_fifo_str(void) +{ + sprintf(cfg_account_prefill_frame_count_str, "prefill-frame-count <0-%u>", FRAMES_PER_FIFO); + sprintf(cfg_account_max_frame_count_str, "max-frame-count <0-%u>", FRAMES_PER_FIFO); +} + gDEFUN(cfg_account_prefill_frame_count, cfg_account_prefill_frame_count_cmd, - "prefill-frame-count <0-8000>", + cfg_account_prefill_frame_count_str, "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") { struct octoi_account *acc = vty->index; acc->prefill_frame_count = atoi(argv[0]); + if (acc->prefill_frame_count > acc->max_frame_count) + acc->max_frame_count = acc->prefill_frame_count; + return CMD_SUCCESS; +} + +gDEFUN(cfg_account_max_frame_count, cfg_account_max_frame_count_cmd, + cfg_account_max_frame_count_str, + "Number of E1 frames to maximum allow in Rx RIFO\n" + "Number of E1 frames to maximum allow in Rx RIFO\n") +{ + struct octoi_account *acc = vty->index; + + acc->max_frame_count = atoi(argv[0]); + if (acc->max_frame_count < acc->prefill_frame_count) + acc->prefill_frame_count = acc->max_frame_count; return CMD_SUCCESS; } @@ -551,7 +576,6 @@ void octoi_server_vty_init(void) { - install_element_ve(&show_server_cmd); install_node(&account_node, NULL); @@ -562,7 +586,9 @@ install_element(OCTOI_ACCOUNT_NODE, &cfg_account_batching_factor_cmd); install_element(OCTOI_ACCOUNT_NODE, &cfg_account_force_all_ts_cmd); install_element(OCTOI_ACCOUNT_NODE, &cfg_account_no_force_all_ts_cmd); + set_frames_per_fifo_str(); install_element(OCTOI_ACCOUNT_NODE, &cfg_account_prefill_frame_count_cmd); + install_element(OCTOI_ACCOUNT_NODE, &cfg_account_max_frame_count_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..24c3929 100644 --- a/src/octoi/octoi_vty.h +++ b/src/octoi/octoi_vty.h @@ -10,7 +10,9 @@ 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 void set_frames_per_fifo_str(void); extern struct cmd_element cfg_account_prefill_frame_count_cmd; +extern struct cmd_element cfg_account_max_frame_count_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..887db7b 100644 --- a/tests/rifo/rifo_test.c +++ b/tests/rifo/rifo_test.c @@ -23,14 +23,14 @@ 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; } static void rifo_in(struct frame_rifo *rifo, uint8_t *frame, uint32_t fn) { - int rc = frame_rifo_in(rifo, frame, fn); + int rc = frame_rifo_in(rifo, frame, fn, FRAMES_PER_FIFO); unsigned int depth = frame_rifo_depth(rifo); printf("RIFO_IN(%s, start fn + %s%d)=%d [depth=%s%d, frames=%u]\n", osmo_hexdump_nospc(frame, BYTES_PER_FRAME), FN_PRINT(fn), rc, @@ -48,7 +48,7 @@ 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; @@ -156,7 +156,7 @@ // Put 1 frame and get it memset(frame, 0xa5, sizeof(frame)); - frame_rifo_in(&rifo, frame, init_next_out_fn); + frame_rifo_in(&rifo, frame, init_next_out_fn, FRAMES_PER_FIFO); frame_rifo_out(&rifo, frame); // Put 11 frames at absolute frame numbers FRAMES_PER_FIFO - -- To view, visit https://gerrit.osmocom.org/c/osmo-e1d/+/34554?usp=email To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings Gerrit-Project: osmo-e1d Gerrit-Branch: master Gerrit-Change-Id: Id7ccbfbdb288990c01f185dec79a1022a68b4748 Gerrit-Change-Number: 34554 Gerrit-PatchSet: 1 Gerrit-Owner: jolly <andr...@eversberg.eu> Gerrit-MessageType: newchange