From ace4313dfd1f17eac022e497bb412e8e290c05e3 Mon Sep 17 00:00:00 2001 From: Konstantin Ananyev Date: Tue, 6 Jul 2021 15:08:48 +0000 Subject: l4p/tcp: introduce tle_tcp_stream_get_state() API tle_tcp_stream_get_state() allows user to query information regarding stream state, control ops and remote termination events. Signed-off-by: Konstantin Ananyev Change-Id: Ica22a5fe2e63fdece882935b76572142433a4ae1 --- lib/libtle_l4p/tcp_ctl.h | 9 +++-- lib/libtle_l4p/tcp_rxtx.c | 87 +++++++++++++++++++++++++-------------------- lib/libtle_l4p/tcp_stream.c | 48 +++++++++++++++++-------- lib/libtle_l4p/tcp_stream.h | 25 ++----------- lib/libtle_l4p/tle_tcp.h | 61 +++++++++++++++++++++++++++++++ 5 files changed, 150 insertions(+), 80 deletions(-) diff --git a/lib/libtle_l4p/tcp_ctl.h b/lib/libtle_l4p/tcp_ctl.h index 7dde8ff..57f3ffc 100644 --- a/lib/libtle_l4p/tcp_ctl.h +++ b/lib/libtle_l4p/tcp_ctl.h @@ -152,16 +152,19 @@ tcp_stream_reset(struct tle_ctx *ctx, struct tle_tcp_stream *s) rte_atomic32_set(&s->tx.arm, 0); /* reset TCB */ - uop = s->tcb.uop & ~TCP_OP_CLOSE; + uop = s->tcb.uop & ~TLE_TCP_OP_CLOSE; memset(&s->tcb, 0, sizeof(s->tcb)); + /* reset remote events */ + s->err.rev = 0; + /* reset cached destination */ memset(&s->tx.dst, 0, sizeof(s->tx.dst)); - if (uop != TCP_OP_ACCEPT) { + if (uop != TLE_TCP_OP_ACCEPT) { /* free stream's destination port */ stream_clear_ctx(ctx, &s->s); - if (uop == TCP_OP_LISTEN) + if (uop == TLE_TCP_OP_LISTEN) empty_lq(s); } diff --git a/lib/libtle_l4p/tcp_rxtx.c b/lib/libtle_l4p/tcp_rxtx.c index 4f43557..03b6c63 100644 --- a/lib/libtle_l4p/tcp_rxtx.c +++ b/lib/libtle_l4p/tcp_rxtx.c @@ -63,7 +63,7 @@ rx_obtain_listen_stream(const struct tle_dev *dev, const union pkt_info *pi, return NULL; /* check that we have a proper stream. */ - if (s->tcb.state != TCP_ST_LISTEN) { + if (s->tcb.state != TLE_TCP_ST_LISTEN) { tcp_stream_release(s); s = NULL; } @@ -80,7 +80,7 @@ rx_acquire_stream(struct tle_stream *ts) if (tcp_stream_acquire(s) < 0) return NULL; - else if (s->tcb.state == TCP_ST_CLOSED) { + else if (s->tcb.state == TLE_TCP_ST_CLOSED) { tcp_stream_release(s); return NULL; } @@ -104,7 +104,7 @@ rx_obtain_stream(const struct tle_dev *dev, struct stbl *st, if (tcp_stream_acquire(s) < 0) return NULL; /* check that we have a proper stream. */ - else if (s->tcb.state == TCP_ST_CLOSED) { + else if (s->tcb.state == TLE_TCP_ST_CLOSED) { tcp_stream_release(s); s = NULL; } @@ -828,13 +828,13 @@ stream_term(struct tle_tcp_stream *s) { struct sdr *dr; - s->tcb.state = TCP_ST_CLOSED; + s->tcb.state = TLE_TCP_ST_CLOSED; rte_smp_wmb(); timer_stop(s); /* close() was already invoked, schedule final cleanup */ - if ((s->tcb.uop & TCP_OP_CLOSE) != 0) { + if ((s->tcb.uop & TLE_TCP_OP_CLOSE) != 0) { dr = CTX_TCP_SDR(s->s.ctx); STAILQ_INSERT_TAIL(&dr->be, &s->s, link); @@ -933,14 +933,14 @@ accept_prep_stream(struct tle_tcp_stream *ps, struct stbl *st, cs->tcb.snd.ssthresh = cs->tcb.snd.wnd; cs->tcb.snd.rto_tw = ps->tcb.snd.rto_tw; - cs->tcb.state = TCP_ST_ESTABLISHED; + cs->tcb.state = TLE_TCP_ST_ESTABLISHED; /* add stream to the table */ cs->ste = stbl_add_stream(st, pi, cs); if (cs->ste == NULL) return -ENOBUFS; - cs->tcb.uop |= TCP_OP_ACCEPT; + cs->tcb.uop |= TLE_TCP_OP_ACCEPT; tcp_stream_up(cs); return 0; } @@ -1058,7 +1058,7 @@ static void stream_timewait(struct tle_tcp_stream *s, uint32_t rto) { if (rto != 0) { - s->tcb.state = TCP_ST_TIME_WAIT; + s->tcb.state = TLE_TCP_ST_TIME_WAIT; s->tcb.snd.rto = rto; timer_reset(s); } else @@ -1072,27 +1072,29 @@ rx_fin_state(struct tle_tcp_stream *s, struct resp_info *rsp) int32_t ackfin; s->tcb.rcv.nxt += 1; + s->err.rev |= TLE_TCP_REV_FIN; ackfin = (s->tcb.snd.una == s->tcb.snd.fss); state = s->tcb.state; - if (state == TCP_ST_ESTABLISHED) { - s->tcb.state = TCP_ST_CLOSE_WAIT; + if (state == TLE_TCP_ST_ESTABLISHED) { + s->tcb.state = TLE_TCP_ST_CLOSE_WAIT; /* raise err.ev & err.cb */ if (s->err.ev != NULL) tle_event_raise(s->err.ev); else if (s->err.cb.func != NULL) s->err.cb.func(s->err.cb.data, &s->s); - } else if (state == TCP_ST_FIN_WAIT_1 || state == TCP_ST_CLOSING) { + } else if (state == TLE_TCP_ST_FIN_WAIT_1 || + state == TLE_TCP_ST_CLOSING) { rsp->flags |= TCP_FLAG_ACK; if (ackfin != 0) stream_timewait(s, s->tcb.snd.rto_tw); else - s->tcb.state = TCP_ST_CLOSING; - } else if (state == TCP_ST_FIN_WAIT_2) { + s->tcb.state = TLE_TCP_ST_CLOSING; + } else if (state == TLE_TCP_ST_FIN_WAIT_2) { rsp->flags |= TCP_FLAG_ACK; stream_timewait(s, s->tcb.snd.rto_tw); - } else if (state == TCP_ST_LAST_ACK && ackfin != 0) { + } else if (state == TLE_TCP_ST_LAST_ACK && ackfin != 0) { stream_term(s); } } @@ -1122,7 +1124,7 @@ rx_fin(struct tle_tcp_stream *s, uint32_t state, if (ret != 0) return ret; - if (state < TCP_ST_ESTABLISHED) + if (state < TLE_TCP_ST_ESTABLISHED) return -EINVAL; if (plen != 0) { @@ -1169,7 +1171,7 @@ rx_rst(struct tle_tcp_stream *s, uint32_t state, uint32_t flags, * In the SYN-SENT state (a RST received in response to an initial SYN), * the RST is acceptable if the ACK field acknowledges the SYN. */ - if (state == TCP_ST_SYN_SENT) { + if (state == TLE_TCP_ST_SYN_SENT) { rc = ((flags & TCP_FLAG_ACK) == 0 || si->ack != s->tcb.snd.nxt) ? -ERANGE : 0; @@ -1178,8 +1180,10 @@ rx_rst(struct tle_tcp_stream *s, uint32_t state, uint32_t flags, else rc = check_seqn(&s->tcb, si->seq, 0); - if (rc == 0) + if (rc == 0) { + s->err.rev |= TLE_TCP_REV_RST; stream_term(s); + } return rc; } @@ -1534,12 +1538,12 @@ rx_ackfin(struct tle_tcp_stream *s) empty_tq(s); state = s->tcb.state; - if (state == TCP_ST_LAST_ACK) + if (state == TLE_TCP_ST_LAST_ACK) stream_term(s); - else if (state == TCP_ST_FIN_WAIT_1) { + else if (state == TLE_TCP_ST_FIN_WAIT_1) { timer_stop(s); - s->tcb.state = TCP_ST_FIN_WAIT_2; - } else if (state == TCP_ST_CLOSING) { + s->tcb.state = TLE_TCP_ST_FIN_WAIT_2; + } else if (state == TLE_TCP_ST_CLOSING) { stream_timewait(s, s->tcb.snd.rto_tw); } } @@ -1581,7 +1585,7 @@ rx_synack(struct tle_tcp_stream *s, uint32_t ts, uint32_t state, struct tle_tcp_syn_opts so; struct rte_tcp_hdr *th; - if (state != TCP_ST_SYN_SENT) + if (state != TLE_TCP_ST_SYN_SENT) return -EINVAL; /* @@ -1628,7 +1632,7 @@ rx_synack(struct tle_tcp_stream *s, uint32_t ts, uint32_t state, rsp->flags |= TCP_FLAG_ACK; timer_stop(s); - s->tcb.state = TCP_ST_ESTABLISHED; + s->tcb.state = TLE_TCP_ST_ESTABLISHED; rte_smp_wmb(); if (s->tx.ev != NULL) @@ -1704,7 +1708,8 @@ rx_stream(struct tle_tcp_stream *s, uint32_t ts, i += (ret > 0); /* normal data/ack packets */ - } else if (state >= TCP_ST_ESTABLISHED && state <= TCP_ST_LAST_ACK) { + } else if (state >= TLE_TCP_ST_ESTABLISHED && + state <= TLE_TCP_ST_LAST_ACK) { /* process incoming data packets. */ dack_info_init(&tack, &s->tcb); @@ -1807,7 +1812,7 @@ rx_postsyn(struct tle_dev *dev, struct stbl *st, uint32_t type, uint32_t ts, k = 0; state = s->tcb.state; - if (state == TCP_ST_LISTEN) { + if (state == TLE_TCP_ST_LISTEN) { /* one connection per flow */ cs = NULL; @@ -2222,8 +2227,8 @@ tle_tcp_stream_connect(struct tle_stream *ts, const struct sockaddr *addr) return -EINVAL; if (tcp_stream_try_acquire(s) > 0) { - rc = rte_atomic16_cmpset(&s->tcb.state, TCP_ST_CLOSED, - TCP_ST_SYN_SENT); + rc = rte_atomic16_cmpset(&s->tcb.state, TLE_TCP_ST_CLOSED, + TLE_TCP_ST_SYN_SENT); rc = (rc == 0) ? -EDEADLK : 0; } else rc = -EINVAL; @@ -2234,7 +2239,7 @@ tle_tcp_stream_connect(struct tle_stream *ts, const struct sockaddr *addr) } /* fill stream, prepare and transmit syn pkt */ - s->tcb.uop |= TCP_OP_CONNECT; + s->tcb.uop |= TLE_TCP_OP_CONNECT; rc = tx_syn(s, addr); tcp_stream_release(s); @@ -2295,7 +2300,7 @@ tle_tcp_stream_establish(struct tle_ctx *ctx, } do { - s->tcb.uop |= TCP_OP_ESTABLISH; + s->tcb.uop |= TLE_TCP_OP_ESTABLISH; /* check and use stream addresses and parameters */ rc = tcp_stream_fill_prm(s, prm); @@ -2317,7 +2322,7 @@ tle_tcp_stream_establish(struct tle_ctx *ctx, /* fill TCB from user provided data */ tcb_establish(s, ci); - s->tcb.state = TCP_ST_ESTABLISHED; + s->tcb.state = TLE_TCP_ST_ESTABLISHED; tcp_stream_up(s); } while (0); @@ -2463,7 +2468,7 @@ tle_tcp_stream_send(struct tle_stream *ts, struct rte_mbuf *pkt[], uint16_t num) } state = s->tcb.state; - if (state != TCP_ST_ESTABLISHED && state != TCP_ST_CLOSE_WAIT) { + if (state != TLE_TCP_ST_ESTABLISHED && state != TLE_TCP_ST_CLOSE_WAIT) { rte_errno = ENOTCONN; tcp_stream_release(s); return 0; @@ -2567,7 +2572,7 @@ tle_tcp_stream_writev(struct tle_stream *ts, struct rte_mempool *mp, } state = s->tcb.state; - if (state != TCP_ST_ESTABLISHED && state != TCP_ST_CLOSE_WAIT) { + if (state != TLE_TCP_ST_ESTABLISHED && state != TLE_TCP_ST_CLOSE_WAIT) { rte_errno = ENOTCONN; tcp_stream_release(s); return -1; @@ -2663,8 +2668,8 @@ tx_data_fin(struct tle_tcp_stream *s, uint32_t tms, uint32_t state) tx_nxt_data(s, tms); /* we also have to send a FIN */ - if (state != TCP_ST_ESTABLISHED && - state != TCP_ST_CLOSE_WAIT && + if (state != TLE_TCP_ST_ESTABLISHED && + state != TLE_TCP_ST_CLOSE_WAIT && tcp_txq_nxt_cnt(s) == 0 && s->tcb.snd.fss != s->tcb.snd.nxt) { s->tcb.snd.fss = ++s->tcb.snd.nxt; @@ -2679,12 +2684,13 @@ tx_stream(struct tle_tcp_stream *s, uint32_t tms) state = s->tcb.state; - if (state == TCP_ST_SYN_SENT) { + if (state == TLE_TCP_ST_SYN_SENT) { /* send the SYN, start the rto timer */ send_ack(s, tms, TCP_FLAG_SYN); timer_start(s); - } else if (state >= TCP_ST_ESTABLISHED && state <= TCP_ST_LAST_ACK) { + } else if (state >= TLE_TCP_ST_ESTABLISHED && + state <= TLE_TCP_ST_LAST_ACK) { tx_data_fin(s, tms, state); @@ -2718,7 +2724,8 @@ rto_stream(struct tle_tcp_stream *s, uint32_t tms) if (s->tcb.snd.nb_retx < s->tcb.snd.nb_retm) { - if (state >= TCP_ST_ESTABLISHED && state <= TCP_ST_LAST_ACK) { + if (state >= TLE_TCP_ST_ESTABLISHED && + state <= TLE_TCP_ST_LAST_ACK) { /* update SND.CWD and SND.SSTHRESH */ rto_cwnd_update(&s->tcb); @@ -2733,7 +2740,7 @@ rto_stream(struct tle_tcp_stream *s, uint32_t tms) tx_data_fin(s, tms, state); - } else if (state == TCP_ST_SYN_SENT) { + } else if (state == TLE_TCP_ST_SYN_SENT) { /* resending SYN */ s->tcb.so.ts.val = tms; @@ -2750,7 +2757,8 @@ rto_stream(struct tle_tcp_stream *s, uint32_t tms) send_ack(s, tms, TCP_FLAG_SYN); - } else if (state == TCP_ST_TIME_WAIT) { + } else if (state == TLE_TCP_ST_TIME_WAIT) { + s->err.rev |= TLE_TCP_REV_RTO; stream_term(s); } @@ -2760,6 +2768,7 @@ rto_stream(struct tle_tcp_stream *s, uint32_t tms) timer_restart(s); } else { + s->err.rev |= TLE_TCP_REV_RTO; send_rst(s, s->tcb.snd.nxt); stream_term(s); } diff --git a/lib/libtle_l4p/tcp_stream.c b/lib/libtle_l4p/tcp_stream.c index dbed84e..d97a6ce 100644 --- a/lib/libtle_l4p/tcp_stream.c +++ b/lib/libtle_l4p/tcp_stream.c @@ -514,11 +514,11 @@ stream_close(struct tle_ctx *ctx, struct tle_tcp_stream *s) /* check was close() already invoked */ uop = s->tcb.uop; - if ((uop & TCP_OP_CLOSE) != 0) + if ((uop & TLE_TCP_OP_CLOSE) != 0) return -EDEADLK; /* record that close() was already invoked */ - if (rte_atomic16_cmpset(&s->tcb.uop, uop, uop | TCP_OP_CLOSE) == 0) + if (rte_atomic16_cmpset(&s->tcb.uop, uop, uop | TLE_TCP_OP_CLOSE) == 0) return -EDEADLK; /* mark stream as unavaialbe for RX/TX. */ @@ -536,17 +536,17 @@ stream_close(struct tle_ctx *ctx, struct tle_tcp_stream *s) state = s->tcb.state; /* CLOSED, LISTEN, SYN_SENT - we can close the stream straighway */ - if (state <= TCP_ST_SYN_SENT) { + if (state <= TLE_TCP_ST_SYN_SENT) { tcp_stream_reset(ctx, s); return 0; } /* generate FIN and proceed with normal connection termination */ - if (state == TCP_ST_ESTABLISHED || state == TCP_ST_CLOSE_WAIT) { + if (state == TLE_TCP_ST_ESTABLISHED || state == TLE_TCP_ST_CLOSE_WAIT) { /* change state */ - s->tcb.state = (state == TCP_ST_ESTABLISHED) ? - TCP_ST_FIN_WAIT_1 : TCP_ST_LAST_ACK; + s->tcb.state = (state == TLE_TCP_ST_ESTABLISHED) ? + TLE_TCP_ST_FIN_WAIT_1 : TLE_TCP_ST_LAST_ACK; /* mark stream as writable/readable again */ tcp_stream_up(s); @@ -666,15 +666,15 @@ tle_tcp_stream_listen(struct tle_stream *ts) /* app may listen for multiple times to change backlog, * we will just return success for such cases. */ - if (s->tcb.state == TCP_ST_LISTEN) + if (s->tcb.state == TLE_TCP_ST_LISTEN) return 0; /* mark stream as not closable. */ if (tcp_stream_try_acquire(s) > 0) { - rc = rte_atomic16_cmpset(&s->tcb.state, TCP_ST_CLOSED, - TCP_ST_LISTEN); + rc = rte_atomic16_cmpset(&s->tcb.state, TLE_TCP_ST_CLOSED, + TLE_TCP_ST_LISTEN); if (rc != 0) { - s->tcb.uop |= TCP_OP_LISTEN; + s->tcb.uop |= TLE_TCP_OP_LISTEN; s->tcb.rcv.wnd = calc_rx_wnd(s, TCP_WSCALE_DEFAULT); rc = 0; } else @@ -696,7 +696,8 @@ stream_update_cfg(struct tle_stream *ts,struct tle_tcp_stream_cfg *prm) s = TCP_STREAM(ts); - if (tcp_stream_try_acquire(s) < 0 || (s->tcb.uop & TCP_OP_CLOSE) != 0) { + if (tcp_stream_try_acquire(s) < 0 || + (s->tcb.uop & TLE_TCP_OP_CLOSE) != 0) { tcp_stream_release(s); return -EINVAL; } @@ -734,8 +735,8 @@ stream_update_cfg(struct tle_stream *ts,struct tle_tcp_stream_cfg *prm) else if (s->tx.cb.func != NULL) s->tx.cb.func(s->tx.cb.data, &s->s); } - if (s->tcb.state == TCP_ST_CLOSE_WAIT || - s->tcb.state == TCP_ST_CLOSED) { + if (s->tcb.state == TLE_TCP_ST_CLOSE_WAIT || + s->tcb.state == TLE_TCP_ST_CLOSED) { if (s->err.ev != NULL) tle_event_raise(s->err.ev); else if (s->err.cb.func != NULL) @@ -769,9 +770,26 @@ tle_tcp_stream_get_mss(const struct tle_stream * ts) { struct tle_tcp_stream *s; - if (ts == NULL) + s = TCP_STREAM(ts); + if (ts == NULL || s->s.type >= TLE_VNUM) return -EINVAL; - s = TCP_STREAM(ts); return s->tcb.snd.mss; } + +int +tle_tcp_stream_get_state(const struct tle_stream * ts, + struct tle_tcp_stream_state *st) +{ + struct tle_tcp_stream *s; + + s = TCP_STREAM(ts); + if (ts == NULL || s->s.type >= TLE_VNUM) + return -EINVAL; + + st->state = s->tcb.state; + st->uop = s->tcb.uop; + st->rev = s->err.rev; + + return 0; +} diff --git a/lib/libtle_l4p/tcp_stream.h b/lib/libtle_l4p/tcp_stream.h index a36b5fe..f04052d 100644 --- a/lib/libtle_l4p/tcp_stream.h +++ b/lib/libtle_l4p/tcp_stream.h @@ -30,29 +30,6 @@ extern "C" { #endif -enum { - TCP_ST_CLOSED, - TCP_ST_LISTEN, - TCP_ST_SYN_SENT, - TCP_ST_SYN_RCVD, - TCP_ST_ESTABLISHED, - TCP_ST_FIN_WAIT_1, - TCP_ST_FIN_WAIT_2, - TCP_ST_CLOSE_WAIT, - TCP_ST_CLOSING, - TCP_ST_LAST_ACK, - TCP_ST_TIME_WAIT, - TCP_ST_NUM -}; - -enum { - TCP_OP_LISTEN = 0x1, - TCP_OP_ACCEPT = 0x2, - TCP_OP_CONNECT = 0x4, - TCP_OP_ESTABLISH = 0x8, - TCP_OP_CLOSE = 0x10, -}; - struct tcb { volatile uint16_t state; volatile uint16_t uop; /* operations by user performed */ @@ -111,6 +88,8 @@ struct tle_tcp_stream { struct { struct tle_event *ev; struct tle_stream_cb cb; + /*bitmask of remote events */ + uint16_t rev; } err; struct { diff --git a/lib/libtle_l4p/tle_tcp.h b/lib/libtle_l4p/tle_tcp.h index 76f3476..df50a23 100644 --- a/lib/libtle_l4p/tle_tcp.h +++ b/lib/libtle_l4p/tle_tcp.h @@ -22,6 +22,44 @@ extern "C" { #endif +/** + * TCP stream states + */ +enum { + TLE_TCP_ST_CLOSED, + TLE_TCP_ST_LISTEN, + TLE_TCP_ST_SYN_SENT, + TLE_TCP_ST_SYN_RCVD, + TLE_TCP_ST_ESTABLISHED, + TLE_TCP_ST_FIN_WAIT_1, + TLE_TCP_ST_FIN_WAIT_2, + TLE_TCP_ST_CLOSE_WAIT, + TLE_TCP_ST_CLOSING, + TLE_TCP_ST_LAST_ACK, + TLE_TCP_ST_TIME_WAIT, + TLE_TCP_ST_NUM +}; + +/** + * User control operations for TCP stream + */ +enum { + TLE_TCP_OP_LISTEN = 0x1, + TLE_TCP_OP_ACCEPT = 0x2, + TLE_TCP_OP_CONNECT = 0x4, + TLE_TCP_OP_ESTABLISH = 0x8, + TLE_TCP_OP_CLOSE = 0x10, +}; + +/** + * termination/error events from remote peer + */ +enum { + TLE_TCP_REV_FIN = 0x1, /** FIN received from peer*/ + TLE_TCP_REV_RST = 0x2, /** RST received from peer */ + TLE_TCP_REV_RTO = 0x4, /** receive timed-out */ +}; + /** * TCP stream creation parameters. */ @@ -80,6 +118,18 @@ struct tle_tcp_conn_info { struct tle_tcp_syn_opts so; }; +/** + * TCP stream state information. + */ +struct tle_tcp_stream_state { + /** current TCP state (one of TLE_TCP_ST_*) */ + uint16_t state; + /** bitmask of control ops performed by user (TLE_TCP_OP_*) */ + uint16_t uop; + /** bitmask of remote termination events (TLE_TCP_REV_*) */ + uint16_t rev; +}; + /** * create a new stream within given TCP context. * @param ctx @@ -158,6 +208,17 @@ tle_tcp_stream_get_addr(const struct tle_stream *s, */ int tle_tcp_stream_get_mss(const struct tle_stream *ts); +/** + * Get current TCP stream state + * @param ts + * Stream to retrieve state information from. + * @return + * zero on successful completion. + * - EINVAL - invalid parameter passed to function + */ +int tle_tcp_stream_get_state(const struct tle_stream *ts, + struct tle_tcp_stream_state *st); + struct tle_stream * tle_tcp_stream_establish(struct tle_ctx *ctx, const struct tle_tcp_stream_param *prm, -- cgit 1.2.3-korg