aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKonstantin Ananyev <konstantin.ananyev@intel.com>2021-07-07 17:25:00 +0000
committerKonstantin Ananyev <konstantin.ananyev@intel.com>2021-07-07 17:25:00 +0000
commitd2baf65c86ac164346f25828c54775bab8343841 (patch)
treee6c02274bbca78a902aa837813f041f749bdb610
parentace4313dfd1f17eac022e497bb412e8e290c05e3 (diff)
l4p/tcp: introduce tle_tcp_stream_abort() API
Introduce ability ot perform abnormal connection termination. Signed-off-by: Konstantin Ananyev <konstantin.ananyev@intel.com> Change-Id: I75b5153505348ceface903cd2c8e012707631168
-rw-r--r--lib/libtle_l4p/tcp_ctl.h55
-rw-r--r--lib/libtle_l4p/tcp_rxtx.c4
-rw-r--r--lib/libtle_l4p/tcp_stream.c87
-rw-r--r--lib/libtle_l4p/tcp_stream.h1
-rw-r--r--lib/libtle_l4p/tle_tcp.h24
5 files changed, 135 insertions, 36 deletions
diff --git a/lib/libtle_l4p/tcp_ctl.h b/lib/libtle_l4p/tcp_ctl.h
index 57f3ffc..814cc82 100644
--- a/lib/libtle_l4p/tcp_ctl.h
+++ b/lib/libtle_l4p/tcp_ctl.h
@@ -103,6 +103,10 @@ calc_rx_wnd(const struct tle_tcp_stream *s, uint32_t scale)
return _rte_ring_get_mask(s->rx.q) << scale;
}
+/*
+ * Helper functions for stream_close()
+ */
+
/* empty stream's send queue */
static inline void
empty_tq(struct tle_tcp_stream *s)
@@ -152,7 +156,7 @@ 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 & ~TLE_TCP_OP_CLOSE;
+ uop = s->tcb.uop & ~TLE_TCP_OP_CLOSE_ABORT;
memset(&s->tcb, 0, sizeof(s->tcb));
/* reset remote events */
@@ -192,6 +196,55 @@ tcp_stream_reset(struct tle_ctx *ctx, struct tle_tcp_stream *s)
}
}
+/*
+ * - set new uop (CLOSE, ABORT) atomically
+ * - mark stream down
+ * - reset events/callbacks
+ * - if no further actions are necessary, then reset the stream straightway
+ * @return
+ * - negative error code
+ * - zero if stream was terminated and no further action is required
+ * - current stream state (TLE_TCP_ST *) otherwise
+ */
+static inline int
+stream_close_prolog(struct tle_ctx *ctx, struct tle_tcp_stream *s, uint16_t nop)
+{
+ uint16_t uop;
+ uint32_t state;
+ static const struct tle_stream_cb zcb;
+
+ /* check was *nop* already invoked */
+ uop = s->tcb.uop;
+ if ((uop & nop) == nop)
+ return -EDEADLK;
+
+ /* record that *nop* was already invoked */
+ if (rte_atomic16_cmpset(&s->tcb.uop, uop, uop | nop) == 0)
+ return -EDEADLK;
+
+ /* mark stream as unavaialbe for RX/TX. */
+ tcp_stream_down(s);
+
+ /* reset events/callbacks */
+ s->rx.ev = NULL;
+ s->tx.ev = NULL;
+ s->err.ev = NULL;
+
+ s->rx.cb = zcb;
+ s->tx.cb = zcb;
+ s->err.cb = zcb;
+
+ state = s->tcb.state;
+
+ /* CLOSED, LISTEN, SYN_SENT - we can close the stream straighway */
+ if (state <= TLE_TCP_ST_SYN_SENT) {
+ tcp_stream_reset(ctx, s);
+ return 0;
+ }
+
+ return state;
+}
+
static inline struct tle_tcp_stream *
tcp_stream_get(struct tle_ctx *ctx, uint32_t flag)
{
diff --git a/lib/libtle_l4p/tcp_rxtx.c b/lib/libtle_l4p/tcp_rxtx.c
index 03b6c63..af885ca 100644
--- a/lib/libtle_l4p/tcp_rxtx.c
+++ b/lib/libtle_l4p/tcp_rxtx.c
@@ -2697,6 +2697,10 @@ tx_stream(struct tle_tcp_stream *s, uint32_t tms)
/* start RTO timer. */
if (s->tcb.snd.nxt != s->tcb.snd.una)
timer_start(s);
+ } else if (state == TLE_TCP_ST_CLOSED) {
+ if ((s->tcb.snd.close_flags & TCP_FLAG_RST) != 0)
+ 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 d97a6ce..59299f7 100644
--- a/lib/libtle_l4p/tcp_stream.c
+++ b/lib/libtle_l4p/tcp_stream.c
@@ -503,49 +503,22 @@ tle_tcp_stream_open(struct tle_ctx *ctx,
}
/*
- * Helper functions, used by close API.
+ * Helper function, used by close API.
*/
static inline int
stream_close(struct tle_ctx *ctx, struct tle_tcp_stream *s)
{
- uint16_t uop;
- uint32_t state;
- static const struct tle_stream_cb zcb;
-
- /* check was close() already invoked */
- uop = s->tcb.uop;
- if ((uop & TLE_TCP_OP_CLOSE) != 0)
- return -EDEADLK;
-
- /* record that close() was already invoked */
- if (rte_atomic16_cmpset(&s->tcb.uop, uop, uop | TLE_TCP_OP_CLOSE) == 0)
- return -EDEADLK;
-
- /* mark stream as unavaialbe for RX/TX. */
- tcp_stream_down(s);
-
- /* reset events/callbacks */
- s->rx.ev = NULL;
- s->tx.ev = NULL;
- s->err.ev = NULL;
-
- s->rx.cb = zcb;
- s->tx.cb = zcb;
- s->err.cb = zcb;
-
- state = s->tcb.state;
+ int32_t rc;
- /* CLOSED, LISTEN, SYN_SENT - we can close the stream straighway */
- if (state <= TLE_TCP_ST_SYN_SENT) {
- tcp_stream_reset(ctx, s);
- return 0;
- }
+ rc = stream_close_prolog(ctx, s, TLE_TCP_OP_CLOSE);
+ if (rc <= 0)
+ return rc;
/* generate FIN and proceed with normal connection termination */
- if (state == TLE_TCP_ST_ESTABLISHED || state == TLE_TCP_ST_CLOSE_WAIT) {
+ if (rc == TLE_TCP_ST_ESTABLISHED || rc == TLE_TCP_ST_CLOSE_WAIT) {
/* change state */
- s->tcb.state = (state == TLE_TCP_ST_ESTABLISHED) ?
+ s->tcb.state = (rc == TLE_TCP_ST_ESTABLISHED) ?
TLE_TCP_ST_FIN_WAIT_1 : TLE_TCP_ST_LAST_ACK;
/* mark stream as writable/readable again */
@@ -610,6 +583,52 @@ tle_tcp_stream_close(struct tle_stream *ts)
}
int
+tle_tcp_stream_abort(struct tle_stream *ts)
+{
+ int32_t rc;
+ struct tle_ctx *ctx;
+ struct tle_tcp_stream *s;
+
+ s = TCP_STREAM(ts);
+ if (ts == NULL || s->s.type >= TLE_VNUM)
+ return -EINVAL;
+
+ ctx = s->s.ctx;
+ rc = stream_close_prolog(ctx, s, TLE_TCP_OP_CLOSE_ABORT);
+ if (rc > 0) {
+
+ /*
+ * RFC 793, On ABORT call, for states:
+ * SYN-RECEIVED STATE
+ * ESTABLISHED STATE
+ * FIN-WAIT-1 STATE
+ * FIN-WAIT-2 STATE
+ * CLOSE-WAIT STATE
+ * Send a reset segment: <SEQ=SND.NXT><CTL=RST>
+ * ...; all segments queued for transmission (except for the
+ * RST formed above) or retransmission should be flushed,
+ * delete the TCB, enter CLOSED state, and return.
+ */
+
+ if (rc >= TLE_TCP_ST_ESTABLISHED && rc <= TLE_TCP_ST_CLOSE_WAIT)
+ s->tcb.snd.close_flags |= TCP_FLAG_RST;
+
+ /*
+ * set state to CLOSED, mark stream as writable/readable again
+ * and enqueue stream into to-send queue.
+ * That will cause later RST generation and stream termination.
+ */
+ s->tcb.state = TLE_TCP_ST_CLOSED;
+ tcp_stream_up(s);
+ txs_enqueue(ctx, s);
+ rc = 0;
+ }
+
+ tle_memtank_shrink(CTX_TCP_MTS(ctx));
+ return rc;
+}
+
+int
tle_tcp_stream_get_addr(const struct tle_stream *ts,
struct tle_tcp_stream_addr *addr)
{
diff --git a/lib/libtle_l4p/tcp_stream.h b/lib/libtle_l4p/tcp_stream.h
index f04052d..9b22b38 100644
--- a/lib/libtle_l4p/tcp_stream.h
+++ b/lib/libtle_l4p/tcp_stream.h
@@ -67,6 +67,7 @@ struct tcb {
uint8_t wscale;
uint8_t nb_retx; /* number of retransmission */
uint8_t nb_retm; /**< max number of retx attempts. */
+ uint8_t close_flags; /* tcp flags to send on close */
} snd;
struct tle_tcp_syn_opts so; /* initial syn options. */
};
diff --git a/lib/libtle_l4p/tle_tcp.h b/lib/libtle_l4p/tle_tcp.h
index df50a23..289683f 100644
--- a/lib/libtle_l4p/tle_tcp.h
+++ b/lib/libtle_l4p/tle_tcp.h
@@ -49,8 +49,11 @@ enum {
TLE_TCP_OP_CONNECT = 0x4,
TLE_TCP_OP_ESTABLISH = 0x8,
TLE_TCP_OP_CLOSE = 0x10,
+ TLE_TCP_OP_ABORT = 0x20,
};
+#define TLE_TCP_OP_CLOSE_ABORT (TLE_TCP_OP_CLOSE | TLE_TCP_OP_ABORT)
+
/**
* termination/error events from remote peer
*/
@@ -154,7 +157,7 @@ tle_tcp_stream_open(struct tle_ctx *ctx,
* - if stream contains unsent data, then actual close will be postponed
* till either remaining data will be TX-ed, or timeout will expire.
* All packets that belong to that stream and remain in the device
- * TX queue will be kept for father transmission.
+ * TX queue will be kept for further transmission.
* @param s
* Pointer to the stream to close.
* @return
@@ -165,6 +168,25 @@ tle_tcp_stream_open(struct tle_ctx *ctx,
int tle_tcp_stream_close(struct tle_stream *s);
/**
+ * abnormal stream termination.
+ * if the stream is in connected state, then:
+ * - abnormal connection termination would be performed.
+ * - if stream contains unread data, then it will be wiped out.
+ * - if stream contains unsent data, then it will be wiped out,
+ * without further attempt to TX it.
+ * All packets that belong to that stream and remain in the device
+ * TX queue will be kept for further transmission.
+ * @param s
+ * Pointer to the stream to close.
+ * @return
+ * zero on successful completion.
+ * - -EINVAL - invalid parameter passed to function
+ * - -EDEADLK - close was already invoked on that stream
+ */
+int tle_tcp_stream_abort(struct tle_stream *s);
+
+
+/**
* close a group of open streams.
* if the stream is in connected state, then:
* - connection termination would be performed.