l4p/tcp: introduce tle_tcp_stream_abort() API 35/33035/1
authorKonstantin Ananyev <konstantin.ananyev@intel.com>
Wed, 7 Jul 2021 17:25:00 +0000 (17:25 +0000)
committerKonstantin Ananyev <konstantin.ananyev@intel.com>
Wed, 7 Jul 2021 17:25:00 +0000 (17:25 +0000)
Introduce ability ot perform abnormal connection termination.

Signed-off-by: Konstantin Ananyev <konstantin.ananyev@intel.com>
Change-Id: I75b5153505348ceface903cd2c8e012707631168

lib/libtle_l4p/tcp_ctl.h
lib/libtle_l4p/tcp_rxtx.c
lib/libtle_l4p/tcp_stream.c
lib/libtle_l4p/tcp_stream.h
lib/libtle_l4p/tle_tcp.h

index 57f3ffc..814cc82 100644 (file)
@@ -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)
 {
index 03b6c63..af885ca 100644 (file)
@@ -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);
        }
 }
 
index d97a6ce..59299f7 100644 (file)
@@ -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 */
@@ -609,6 +582,52 @@ tle_tcp_stream_close(struct tle_stream *ts)
        return rc;
 }
 
+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)
index f04052d..9b22b38 100644 (file)
@@ -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. */
 };
index df50a23..289683f 100644 (file)
@@ -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
@@ -164,6 +167,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: