l4p/tcp: introduce tle_tcp_stream_establish() API 09/32309/1
authorKonstantin Ananyev <konstantin.ananyev@intel.com>
Thu, 13 May 2021 15:26:50 +0000 (15:26 +0000)
committerKonstantin Ananyev <konstantin.ananyev@intel.com>
Thu, 13 May 2021 17:32:55 +0000 (17:32 +0000)
tle_tcp_stream_establish() allows to create streams in established
connection state.

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

lib/libtle_l4p/syncookie.h
lib/libtle_l4p/tcp_misc.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 61bfce4..6d4372d 100644 (file)
@@ -178,41 +178,52 @@ sync_check_ack(const union pkt_info *pi, uint32_t seq, uint32_t ack,
 }
 
 static inline void
-sync_fill_tcb(struct tcb *tcb, const union seg_info *si, const union tsopt *to)
+fill_tcb_rcv(struct tcb *tcb, uint32_t seq, uint32_t wscale,
+       const union tle_tcp_tsopt *to)
 {
-       uint32_t ack, mss, seq, wscale;
-
-       seq = si->seq;
-
        tcb->rcv.nxt = seq;
        tcb->rcv.irs = seq - 1;
-       tcb->snd.wu.wl1 = seq;
-
-       ack = si->ack;
+       tcb->rcv.ts = to->val;
+       tcb->rcv.wscale = (wscale == TCP_WSCALE_NONE) ?
+               TCP_WSCALE_NONE : TCP_WSCALE_DEFAULT;
+}
 
+static inline void
+fill_tcb_snd(struct tcb *tcb, uint32_t seq, uint32_t ack, uint32_t mss,
+               uint32_t wnd, uint32_t wscale, const union tle_tcp_tsopt *to)
+{
        tcb->snd.nxt = ack;
        tcb->snd.una = ack;
        tcb->snd.iss = ack - 1;
        tcb->snd.rcvr = ack - 1;
-       tcb->snd.wu.wl2 = ack;
 
-       mss = si->mss;
+       tcb->snd.wu.wl1 = seq;
+       tcb->snd.wu.wl2 = ack;
 
        tcb->snd.mss = mss;
-       tcb->so.mss = mss;
-
        tcb->snd.ts = to->ecr;
-       tcb->rcv.ts = to->val;
-       tcb->so.ts.raw = to->raw;
 
+       tcb->snd.wscale = wscale;
+       tcb->snd.wnd = wnd << wscale;
+}
+
+static inline void
+sync_fill_tcb(struct tcb *tcb, const union seg_info *si,
+       const union tle_tcp_tsopt *to)
+{
+       uint32_t ack, mss, seq, wscale;
+
+       seq = si->seq;
+       ack = si->ack;
+       mss = si->mss;
        wscale = to->ecr & SYNC_TMS_WSCALE_MASK;
 
-       tcb->snd.wscale = wscale;
-       tcb->snd.wnd = si->wnd << wscale;
-       tcb->so.wscale = wscale;
+       fill_tcb_snd(tcb, seq, ack, mss, si->wnd, wscale, to);
+       fill_tcb_rcv(tcb, seq, wscale, to);
 
-       tcb->rcv.wscale = (wscale == TCP_WSCALE_NONE) ?
-               TCP_WSCALE_NONE : TCP_WSCALE_DEFAULT;
+       tcb->so.mss = mss;
+       tcb->so.ts.raw = to->raw;
+       tcb->so.wscale = wscale;
 }
 
 #ifdef __cplusplus
index 01c1e67..46a0a5f 100644 (file)
@@ -19,6 +19,7 @@
 #include "net_misc.h"
 #include <rte_tcp.h>
 #include <rte_cycles.h>
+#include <tle_tcp.h>
 
 #ifdef __cplusplus
 extern "C" {
@@ -159,17 +160,6 @@ union seqlen {
 #define        TCP_OPT_KL_WSC          TCP_OPT_KL(TCP_OPT_KIND_WSC, TCP_OPT_LEN_WSC)
 #define        TCP_OPT_KL_TMS          TCP_OPT_KL(TCP_OPT_KIND_TMS, TCP_OPT_LEN_TMS)
 
-/*
- * Timestamp option.
- */
-union tsopt {
-       uint64_t raw;
-       struct {
-               uint32_t val;
-               uint32_t ecr;
-       };
-};
-
 struct tcpopt {
        union {
                uint16_t raw;
@@ -181,16 +171,10 @@ struct tcpopt {
        union {
                uint16_t mss;
                uint8_t  wscale;
-               union tsopt ts;
+               union tle_tcp_tsopt ts;
        };
 } __attribute__((__packed__));
 
-struct syn_opts {
-       uint16_t mss;
-       uint8_t  wscale;
-       union tsopt ts;
-};
-
 struct resp_info {
        uint32_t flags;
 };
@@ -217,9 +201,9 @@ struct dack_info {
                uint32_t badseq;    /* bad seq/ack */
                uint32_t ofo;       /* OFO incoming data */
        } segs;
-       uint32_t ack;       /* highest received ACK */
-       union tsopt ts;     /* TS of highest ACK */
-       union wui wu;       /* window update information */
+       uint32_t ack;               /* highest received ACK */
+       union tle_tcp_tsopt ts;     /* TS of highest ACK */
+       union wui wu;               /* window update information */
        uint32_t wnd;
        struct {               /* 3 duplicate ACKs were observed after */
                uint32_t seg;  /* # of meaningful ACK segments */
@@ -272,7 +256,7 @@ get_seg_info(const struct rte_tcp_hdr *th, union seg_info *si)
 }
 
 static inline void
-get_syn_opts(struct syn_opts *so, uintptr_t p, uint32_t len)
+get_syn_opts(struct tle_tcp_syn_opts *so, uintptr_t p, uint32_t len)
 {
        uint32_t i, kind;
        const struct tcpopt *opt;
@@ -310,7 +294,7 @@ get_syn_opts(struct syn_opts *so, uintptr_t p, uint32_t len)
  * at least TCP_TX_OPT_LEN_MAX bytes available.
  */
 static inline void
-fill_syn_opts(void *p, const struct syn_opts *so)
+fill_syn_opts(void *p, const struct tle_tcp_syn_opts *so)
 {
        uint8_t *to;
        struct tcpopt *opt;
@@ -364,10 +348,10 @@ fill_tms_opts(void *p, uint32_t val, uint32_t ecr)
        opt[2] = rte_cpu_to_be_32(ecr);
 }
 
-static inline union tsopt
+static inline union tle_tcp_tsopt
 get_tms_opts(uintptr_t p, uint32_t len)
 {
-       union tsopt ts;
+       union tle_tcp_tsopt ts;
        uint32_t i, kind;
        const uint32_t *opt;
        const struct tcpopt *to;
index b1aad60..0e8a39f 100644 (file)
@@ -710,10 +710,10 @@ check_seqn(const struct tcb *tcb, uint32_t seqn, uint32_t len)
        return 0;
 }
 
-static inline union tsopt
+static inline union tle_tcp_tsopt
 rx_tms_opt(const struct tcb *tcb, const struct rte_mbuf *mb)
 {
-       union tsopt ts;
+       union tle_tcp_tsopt ts;
        uintptr_t opt;
        const struct rte_tcp_hdr *th;
 
@@ -732,7 +732,8 @@ rx_tms_opt(const struct tcb *tcb, const struct rte_mbuf *mb)
  * RFC 1323 4.2.1
  */
 static inline int
-rx_check_seq(struct tcb *tcb, uint32_t seq, uint32_t len, const union tsopt ts)
+rx_check_seq(struct tcb *tcb, uint32_t seq, uint32_t len,
+       const union tle_tcp_tsopt ts)
 {
        int32_t rc;
 
@@ -771,7 +772,7 @@ rx_check_ack(const struct tcb *tcb, uint32_t ack)
 
 static inline int
 rx_check_seqack(struct tcb *tcb, uint32_t seq, uint32_t ack, uint32_t len,
-       const union tsopt ts)
+       const union tle_tcp_tsopt ts)
 {
        int32_t rc;
 
@@ -781,7 +782,7 @@ rx_check_seqack(struct tcb *tcb, uint32_t seq, uint32_t ack, uint32_t len,
 }
 
 static inline int
-restore_syn_opt(union seg_info *si, union tsopt *to,
+restore_syn_opt(union seg_info *si, union tle_tcp_tsopt *to,
        const union pkt_info *pi, uint32_t ts, const struct rte_mbuf *mb,
        uint32_t hash_alg, rte_xmm_t *secret_key)
 {
@@ -845,16 +846,32 @@ stream_fill_dest(struct tle_tcp_stream *s)
        return (rc < 0) ? rc : 0;
 }
 
+/*
+ * estimate the rto
+ * for now rtt is calculated based on the tcp TMS option,
+ * later add real-time one
+ */
+static inline void
+estimate_stream_rto(struct tle_tcp_stream *s, uint32_t tms)
+{
+       uint32_t rtt;
+
+       if (s->tcb.so.ts.ecr) {
+               rtt = tms - s->tcb.so.ts.ecr;
+               rto_estimate(&s->tcb, rtt);
+       } else
+               s->tcb.snd.rto = TCP_RTO_DEFAULT;
+}
+
 /*
  * helper function, prepares a new accept stream.
  */
 static inline int
 accept_prep_stream(struct tle_tcp_stream *ps, struct stbl *st,
-       struct tle_tcp_stream *cs, const union tsopt *to,
+       struct tle_tcp_stream *cs, const union tle_tcp_tsopt *to,
        uint32_t tms, const union pkt_info *pi, const union seg_info *si)
 {
        int32_t rc;
-       uint32_t rtt;
 
        /* some TX still pending for that stream. */
        if (TCP_STREAM_TX_PENDING(cs))
@@ -880,16 +897,7 @@ accept_prep_stream(struct tle_tcp_stream *ps, struct stbl *st,
        sync_fill_tcb(&cs->tcb, si, to);
        cs->tcb.rcv.wnd = calc_rx_wnd(cs, cs->tcb.rcv.wscale);
 
-       /*
-        * estimate the rto
-        * for now rtt is calculated based on the tcp TMS option,
-        * later add real-time one
-        */
-       if (cs->tcb.so.ts.ecr) {
-               rtt = tms - cs->tcb.so.ts.ecr;
-               rto_estimate(&cs->tcb, rtt);
-       } else
-               cs->tcb.snd.rto = TCP_RTO_DEFAULT;
+       estimate_stream_rto(cs, tms);
 
        /* copy streams type & flags. */
        cs->s.type = ps->s.type;
@@ -938,7 +946,7 @@ rx_ack_listen(struct tle_tcp_stream *s, struct stbl *st,
        struct tle_ctx *ctx;
        struct tle_stream *ts;
        struct tle_tcp_stream *cs;
-       union tsopt to;
+       union tle_tcp_tsopt to;
 
        *csp = NULL;
 
@@ -1086,7 +1094,7 @@ rx_fin(struct tle_tcp_stream *s, uint32_t state,
 {
        uint32_t hlen, plen, seq;
        int32_t ret;
-       union tsopt ts;
+       union tle_tcp_tsopt ts;
 
        hlen = PKT_L234_HLEN(mb);
        plen = mb->pkt_len - hlen;
@@ -1231,7 +1239,7 @@ rto_cwnd_update(struct tcb *tcb)
 
 static inline void
 ack_info_update(struct dack_info *tack, const union seg_info *si,
-       int32_t badseq, uint32_t dlen, const union tsopt ts)
+       int32_t badseq, uint32_t dlen, const union tle_tcp_tsopt ts)
 {
        if (badseq != 0) {
                tack->segs.badseq++;
@@ -1291,7 +1299,7 @@ rx_data_ack(struct tle_tcp_stream *s, struct dack_info *tack,
        uint32_t i, j, k, n, t;
        uint32_t hlen, plen, seq, tlen;
        int32_t ret;
-       union tsopt ts;
+       union tle_tcp_tsopt ts;
 
        k = 0;
        for (i = 0; i != num; i = j) {
@@ -1553,7 +1561,7 @@ rx_synack(struct tle_tcp_stream *s, uint32_t ts, uint32_t state,
        const union seg_info *si, struct rte_mbuf *mb,
        struct resp_info *rsp)
 {
-       struct syn_opts so;
+       struct tle_tcp_syn_opts so;
        struct rte_tcp_hdr *th;
 
        if (state != TCP_ST_SYN_SENT)
@@ -2166,6 +2174,93 @@ tle_tcp_stream_connect(struct tle_stream *ts, const struct sockaddr *addr)
        return rc;
 }
 
+/*
+ * Helper function for tle_tcp_stream_establish().
+ * updates stream's TCB.
+ */
+static inline void
+tcb_establish(struct tle_tcp_stream *s, const struct tle_tcp_conn_info *ci)
+{
+       uint32_t tms;
+
+       tms = tcp_get_tms(s->s.ctx->cycles_ms_shift);
+
+       s->tcb.so = ci->so;
+       fill_tcb_snd(&s->tcb, ci->seq, ci->ack, ci->so.mss,
+               ci->wnd, ci->so.wscale, &ci->so.ts);
+       fill_tcb_rcv(&s->tcb, ci->seq, ci->so.wscale, &ci->so.ts);
+
+       s->tcb.rcv.wnd = calc_rx_wnd(s, s->tcb.rcv.wscale);
+
+       /* setup congestion variables */
+       s->tcb.snd.cwnd = initial_cwnd(s->tcb.snd.mss, s->tcb.snd.cwnd);
+       s->tcb.snd.ssthresh = s->tcb.snd.wnd;
+
+       estimate_stream_rto(s, tms);
+}
+
+/*
+ * !!! add flgs to distinguish - add or not stream into the table.
+ */
+struct tle_stream *
+tle_tcp_stream_establish(struct tle_ctx *ctx,
+       const struct tle_tcp_stream_param *prm,
+       const struct tle_tcp_conn_info *ci)
+{
+       int32_t rc;
+       struct tle_tcp_stream *s;
+       struct stbl *st;
+
+       if (ctx == NULL || prm == NULL || ci == NULL) {
+               rte_errno = -EINVAL;
+               return NULL;
+       }
+
+       /* allocate new stream */
+       s = tcp_stream_get(ctx, TLE_MTANK_ALLOC_CHUNK | TLE_MTANK_ALLOC_GROW);
+       if (s == NULL) {
+               rte_errno = ENFILE;
+               return NULL;
+       }
+
+       do {
+               s->tcb.uop |= TCP_OP_ESTABLISH;
+
+               /* check and use stream addresses and parameters */
+               rc = tcp_stream_fill_prm(s, prm);
+               if (rc != 0)
+                       break;
+
+               /* retrieve and cache destination information. */
+               rc = stream_fill_dest(s);
+               if (rc != 0)
+                       break;
+
+               /* add the stream to the stream table */
+               st = CTX_TCP_STLB(s->s.ctx);
+               s->ste = stbl_add_stream_lock(st, s);
+               if (s->ste == NULL) {
+                       rc = -ENOBUFS;
+                       break;
+               }
+
+               /* fill TCB from user provided data */
+               tcb_establish(s, ci);
+               s->tcb.state = TCP_ST_ESTABLISHED;
+               tcp_stream_up(s);
+
+       } while (0);
+
+       /* cleanup on failure */
+       if (rc != 0) {
+               tcp_stream_reset(ctx, s);
+               rte_errno = -rc;
+               s = NULL;
+       }
+
+       return &s->s;
+}
+
 uint16_t
 tle_tcp_stream_recv(struct tle_stream *ts, struct rte_mbuf *pkt[], uint16_t num)
 {
index fce3b9a..c1a007a 100644 (file)
@@ -361,6 +361,106 @@ check_stream_prm(const struct tle_ctx *ctx,
        return 0;
 }
 
+static void
+tcp_stream_fill_cfg(struct tle_tcp_stream *s, const struct tle_ctx_param *cprm,
+       const struct tle_tcp_stream_cfg *scfg)
+{
+       /* setup stream notification menchanism */
+       s->rx.ev = scfg->recv_ev;
+       s->rx.cb = scfg->recv_cb;
+       s->tx.ev = scfg->send_ev;
+       s->tx.cb = scfg->send_cb;
+       s->err.ev = scfg->err_ev;
+       s->err.cb = scfg->err_cb;
+
+       /* store other params */
+       s->flags = cprm->flags;
+       s->tcb.snd.nb_retm = (scfg->nb_retries != 0) ? scfg->nb_retries :
+               TLE_TCP_DEFAULT_RETRIES;
+       s->tcb.snd.cwnd = (cprm->icw == 0) ? TCP_INITIAL_CWND_MAX :
+                               cprm->icw;
+       s->tcb.snd.rto_tw = (cprm->timewait == TLE_TCP_TIMEWAIT_DEFAULT) ?
+                               TCP_RTO_2MSL : cprm->timewait;
+}
+
+static int
+stream_fill_type_addrs_type(struct tle_stream *s, const struct sockaddr *laddr,
+       const struct sockaddr *raddr)
+{
+       const struct sockaddr_in *lin4, *rin4;
+       const struct sockaddr_in6 *lin6, *rin6;
+
+       const size_t sz = sizeof(tle_ipv6_any);
+
+       lin4 = (const struct sockaddr_in *)laddr;
+       lin6 = (const struct sockaddr_in6 *)laddr;
+
+       rin4 = (const struct sockaddr_in *)raddr;
+       rin6 = (const struct sockaddr_in6 *)raddr;
+
+       if (laddr->sa_family == AF_INET) {
+
+               if (lin4->sin_addr.s_addr == INADDR_ANY ||
+                               rin4->sin_addr.s_addr == INADDR_ANY ||
+                               lin4->sin_port == 0 || rin4->sin_port == 0)
+                       return -EINVAL;
+
+               s->port.src = rin4->sin_port;
+               s->port.dst = lin4->sin_port;
+
+               s->ipv4.addr.src = rin4->sin_addr.s_addr;
+               s->ipv4.addr.dst = lin4->sin_addr.s_addr;
+
+               s->ipv4.mask.src = INADDR_NONE;
+               s->ipv4.mask.dst = INADDR_NONE;
+
+               s->type = TLE_V4;
+
+       } else if (laddr->sa_family == AF_INET6) {
+
+               if (memcmp(&lin6->sin6_addr, &tle_ipv6_any, sz) == 0 ||
+                               memcmp(&rin6->sin6_addr, &tle_ipv6_any,
+                               sz) == 0 ||
+                               lin6->sin6_port == 0 || rin6->sin6_port == 0)
+                       return -EINVAL;
+
+               s->port.src = rin6->sin6_port;
+               s->port.dst = lin6->sin6_port;
+
+               memcpy(&s->ipv6.addr.src, &rin6->sin6_addr, sz);
+               memcpy(&s->ipv6.addr.dst, &lin6->sin6_addr, sz);
+
+               memcpy(&s->ipv6.mask.src, &tle_ipv6_none, sz);
+               memcpy(&s->ipv6.mask.dst, &tle_ipv6_none, sz);
+
+               s->type = TLE_V6;
+
+       } else
+               return -EINVAL;
+
+       s->pmsk.raw = UINT32_MAX;
+       return 0;
+}
+
+int
+tcp_stream_fill_prm(struct tle_tcp_stream *s,
+       const struct tle_tcp_stream_param *prm)
+{
+       int32_t rc;
+       struct tle_ctx *ctx;
+
+       ctx = s->s.ctx;
+       if (ctx == NULL || prm == NULL || check_stream_prm(ctx, prm) != 0)
+               return -EINVAL;
+
+       rc = stream_fill_type_addrs_type(&s->s,
+               (const struct sockaddr *)&prm->addr.local,
+               (const struct sockaddr *)&prm->addr.remote);
+       if (rc == 0)
+               tcp_stream_fill_cfg(s, &ctx->prm, &prm->cfg);
+       return rc;
+}
+
 struct tle_stream *
 tle_tcp_stream_open(struct tle_ctx *ctx,
        const struct tle_tcp_stream_param *prm)
@@ -394,22 +494,7 @@ tle_tcp_stream_open(struct tle_ctx *ctx,
                return NULL;
        }
 
-       /* setup stream notification menchanism */
-       s->rx.ev = prm->cfg.recv_ev;
-       s->rx.cb = prm->cfg.recv_cb;
-       s->tx.ev = prm->cfg.send_ev;
-       s->tx.cb = prm->cfg.send_cb;
-       s->err.ev = prm->cfg.err_ev;
-       s->err.cb = prm->cfg.err_cb;
-
-       /* store other params */
-       s->flags = ctx->prm.flags;
-       s->tcb.snd.nb_retm = (prm->cfg.nb_retries != 0) ? prm->cfg.nb_retries :
-               TLE_TCP_DEFAULT_RETRIES;
-       s->tcb.snd.cwnd = (ctx->prm.icw == 0) ? TCP_INITIAL_CWND_MAX :
-                               ctx->prm.icw;
-       s->tcb.snd.rto_tw = (ctx->prm.timewait == TLE_TCP_TIMEWAIT_DEFAULT) ?
-                               TCP_RTO_2MSL : ctx->prm.timewait;
+       tcp_stream_fill_cfg(s, &ctx->prm, &prm->cfg);
 
        tcp_stream_up(s);
        return &s->s;
index a3d00dc..a36b5fe 100644 (file)
@@ -46,10 +46,11 @@ enum {
 };
 
 enum {
-       TCP_OP_LISTEN =  0x1,
-       TCP_OP_ACCEPT =  0x2,
-       TCP_OP_CONNECT = 0x4,
-       TCP_OP_CLOSE =   0x8,
+       TCP_OP_LISTEN =    0x1,
+       TCP_OP_ACCEPT =    0x2,
+       TCP_OP_CONNECT =   0x4,
+       TCP_OP_ESTABLISH = 0x8,
+       TCP_OP_CLOSE =     0x10,
 };
 
 struct tcb {
@@ -90,7 +91,7 @@ struct tcb {
                uint8_t nb_retx; /* number of retransmission */
                uint8_t nb_retm; /**< max number of retx attempts. */
        } snd;
-       struct syn_opts so; /* initial syn options. */
+       struct tle_tcp_syn_opts so; /* initial syn options. */
 };
 
 struct tle_tcp_stream {
@@ -189,6 +190,9 @@ struct tcp_streams {
 #define CTX_TCP_SDR(ctx)       (&CTX_TCP_STREAMS(ctx)->dr)
 #define CTX_TCP_MTS(ctx)       (CTX_TCP_STREAMS(ctx)->mts)
 
+extern int tcp_stream_fill_prm(struct tle_tcp_stream *s,
+       const struct tle_tcp_stream_param *prm);
+
 #ifdef __cplusplus
 }
 #endif
index b0cbda6..3155dfa 100644 (file)
@@ -51,6 +51,33 @@ struct tle_tcp_stream_param {
        struct tle_tcp_stream_cfg cfg;
 };
 
+/**
+ * Timestamp option.
+ */
+union tle_tcp_tsopt {
+       uint64_t raw;
+       struct {
+               uint32_t val;
+               uint32_t ecr;
+       };
+};
+
+/**
+ * SYN time option values.
+ */
+struct tle_tcp_syn_opts {
+       uint16_t mss;
+       uint8_t  wscale;
+       union tle_tcp_tsopt ts;
+};
+
+struct tle_tcp_conn_info {
+       uint16_t wnd;
+       uint32_t seq;
+       uint32_t ack;
+       struct tle_tcp_syn_opts so;
+};
+
 /**
  * create a new stream within given TCP context.
  * @param ctx
@@ -129,6 +156,11 @@ tle_tcp_stream_get_addr(const struct tle_stream *s,
  */
 int tle_tcp_stream_get_mss(const struct tle_stream *ts);
 
+struct tle_stream *
+tle_tcp_stream_establish(struct tle_ctx *ctx,
+       const struct tle_tcp_stream_param *prm,
+       const struct tle_tcp_conn_info *ci);
+
 /**
  * Client mode connect API.
  */