l4p/tcp: introduce tle_tcp_stream_establish() API
[tldk.git] / lib / libtle_l4p / tcp_rxtx.c
index b12b974..0e8a39f 100644 (file)
@@ -183,7 +183,7 @@ get_ip_pid(struct tle_dev *dev, uint32_t num, uint32_t type, uint32_t st)
 }
 
 static inline void
-fill_tcph(struct tcp_hdr *l4h, const struct tcb *tcb, union l4_ports port,
+fill_tcph(struct rte_tcp_hdr *l4h, const struct tcb *tcb, union l4_ports port,
        uint32_t seq, uint8_t hlen, uint8_t flags)
 {
        uint16_t wnd;
@@ -217,7 +217,7 @@ tcp_fill_mbuf(struct rte_mbuf *m, const struct tle_tcp_stream *s,
        uint32_t pid, uint32_t swcsm)
 {
        uint32_t l4, len, plen;
-       struct tcp_hdr *l4h;
+       struct rte_tcp_hdr *l4h;
        char *l2h;
 
        len = dst->l2_len + dst->l3_len;
@@ -239,7 +239,7 @@ tcp_fill_mbuf(struct rte_mbuf *m, const struct tle_tcp_stream *s,
        rte_memcpy(l2h, dst->hdr, len);
 
        /* setup TCP header & options */
-       l4h = (struct tcp_hdr *)(l2h + len);
+       l4h = (struct rte_tcp_hdr *)(l2h + len);
        fill_tcph(l4h, &s->tcb, port, seq, l4, flags);
 
        /* setup mbuf TX offload related fields. */
@@ -249,8 +249,8 @@ tcp_fill_mbuf(struct rte_mbuf *m, const struct tle_tcp_stream *s,
        /* update proto specific fields. */
 
        if (s->s.type == TLE_V4) {
-               struct ipv4_hdr *l3h;
-               l3h = (struct ipv4_hdr *)(l2h + dst->l2_len);
+               struct rte_ipv4_hdr *l3h;
+               l3h = (struct rte_ipv4_hdr *)(l2h + dst->l2_len);
                l3h->packet_id = rte_cpu_to_be_16(pid);
                l3h->total_length = rte_cpu_to_be_16(plen + dst->l3_len + l4);
 
@@ -263,8 +263,8 @@ tcp_fill_mbuf(struct rte_mbuf *m, const struct tle_tcp_stream *s,
                if ((ol_flags & PKT_TX_IP_CKSUM) == 0 && swcsm != 0)
                        l3h->hdr_checksum = _ipv4x_cksum(l3h, m->l3_len);
        } else {
-               struct ipv6_hdr *l3h;
-               l3h = (struct ipv6_hdr *)(l2h + dst->l2_len);
+               struct rte_ipv6_hdr *l3h;
+               l3h = (struct rte_ipv6_hdr *)(l2h + dst->l2_len);
                l3h->payload_len = rte_cpu_to_be_16(plen + l4);
                if ((ol_flags & PKT_TX_TCP_CKSUM) != 0)
                        l4h->cksum = rte_ipv6_phdr_cksum(l3h, ol_flags);
@@ -285,11 +285,11 @@ static inline void
 tcp_update_mbuf(struct rte_mbuf *m, uint32_t type, const struct tcb *tcb,
        uint32_t seq, uint32_t pid)
 {
-       struct tcp_hdr *l4h;
+       struct rte_tcp_hdr *l4h;
        uint32_t len;
 
        len = m->l2_len + m->l3_len;
-       l4h = rte_pktmbuf_mtod_offset(m, struct tcp_hdr *, len);
+       l4h = rte_pktmbuf_mtod_offset(m, struct rte_tcp_hdr *, len);
 
        l4h->sent_seq = rte_cpu_to_be_32(seq);
        l4h->recv_ack = rte_cpu_to_be_32(tcb->rcv.nxt);
@@ -298,8 +298,9 @@ tcp_update_mbuf(struct rte_mbuf *m, uint32_t type, const struct tcb *tcb,
                fill_tms_opts(l4h + 1, tcb->snd.ts, tcb->rcv.ts);
 
        if (type == TLE_V4) {
-               struct ipv4_hdr *l3h;
-               l3h = rte_pktmbuf_mtod_offset(m, struct ipv4_hdr *, m->l2_len);
+               struct rte_ipv4_hdr *l3h;
+               l3h = rte_pktmbuf_mtod_offset(m, struct rte_ipv4_hdr *,
+                       m->l2_len);
                l3h->hdr_checksum = 0;
                l3h->packet_id = rte_cpu_to_be_16(pid);
                if ((m->ol_flags & PKT_TX_IP_CKSUM) == 0)
@@ -312,14 +313,14 @@ tcp_update_mbuf(struct rte_mbuf *m, uint32_t type, const struct tcb *tcb,
                l4h->cksum = 0;
 
                if (type == TLE_V4) {
-                       struct ipv4_hdr *l3h;
-                       l3h = rte_pktmbuf_mtod_offset(m, struct ipv4_hdr *,
+                       struct rte_ipv4_hdr *l3h;
+                       l3h = rte_pktmbuf_mtod_offset(m, struct rte_ipv4_hdr *,
                                m->l2_len);
                        l4h->cksum = _ipv4_udptcp_mbuf_cksum(m, len, l3h);
 
                } else {
-                       struct ipv6_hdr *l3h;
-                       l3h = rte_pktmbuf_mtod_offset(m, struct ipv6_hdr *,
+                       struct rte_ipv6_hdr *l3h;
+                       l3h = rte_pktmbuf_mtod_offset(m, struct rte_ipv6_hdr *,
                                m->l2_len);
                        l4h->cksum = _ipv6_udptcp_mbuf_cksum(m, len, l3h);
                }
@@ -473,10 +474,9 @@ tx_nxt_data(struct tle_tcp_stream *s, uint32_t tms)
 static inline void
 free_una_data(struct tle_tcp_stream *s, uint32_t len)
 {
-       uint32_t i, n, num, plen;
+       uint32_t i, num, plen;
        struct rte_mbuf **mi;
 
-       n = 0;
        plen = 0;
 
        do {
@@ -487,12 +487,14 @@ free_una_data(struct tle_tcp_stream *s, uint32_t len)
                        break;
 
                /* free acked data */
-               for (i = 0; i != num && n != len; i++, n = plen) {
-                       plen += PKT_L4_PLEN(mi[i]);
-                       if (plen > len) {
+               for (i = 0; i != num && plen != len; i++) {
+                       uint32_t next_pkt_len = PKT_L4_PLEN(mi[i]);
+                       if (plen + next_pkt_len > len) {
                                /* keep SND.UNA at the start of the packet */
-                               len -= RTE_MIN(len, plen - len);
+                               len = plen;
                                break;
+                       } else {
+                               plen += next_pkt_len;
                        }
                        rte_pktmbuf_free(mi[i]);
                }
@@ -634,7 +636,7 @@ sync_ack(struct tle_tcp_stream *s, const union pkt_info *pi,
        struct tle_dev *dev;
        const void *da;
        struct tle_dest dst;
-       const struct tcp_hdr *th;
+       const struct rte_tcp_hdr *th;
 
        type = s->s.type;
 
@@ -648,10 +650,14 @@ sync_ack(struct tle_tcp_stream *s, const union pkt_info *pi,
        if (rc < 0)
                return rc;
 
-       th = rte_pktmbuf_mtod_offset(m, const struct tcp_hdr *,
+       th = rte_pktmbuf_mtod_offset(m, const struct rte_tcp_hdr *,
                m->l2_len + m->l3_len);
        get_syn_opts(&s->tcb.so, (uintptr_t)(th + 1), m->l4_len - sizeof(*th));
 
+       /* reset wscale option if timestamp is not present */
+       if (s->tcb.so.ts.val == 0)
+               s->tcb.so.wscale = 0;
+
        s->tcb.rcv.nxt = si->seq + 1;
        seq = sync_gen_seq(pi, s->tcb.rcv.nxt, ts, s->tcb.so.mss,
                                s->s.ctx->prm.hash_alg,
@@ -704,12 +710,12 @@ 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 tcp_hdr *th;
+       const struct rte_tcp_hdr *th;
 
        if (tcb->so.ts.val != 0) {
                opt = rte_pktmbuf_mtod_offset(mb, uintptr_t,
@@ -726,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;
 
@@ -765,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;
 
@@ -775,13 +782,13 @@ 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)
 {
        int32_t rc;
        uint32_t len;
-       const struct tcp_hdr *th;
+       const struct rte_tcp_hdr *th;
 
        /* check that ACK, etc fields are what we expected. */
        rc = sync_check_ack(pi, si->seq, si->ack - 1, ts,
@@ -792,7 +799,7 @@ restore_syn_opt(union seg_info *si, union tsopt *to,
 
        si->mss = rc;
 
-       th = rte_pktmbuf_mtod_offset(mb, const struct tcp_hdr *,
+       th = rte_pktmbuf_mtod_offset(mb, const struct rte_tcp_hdr *,
                mb->l2_len + mb->l3_len);
        len = mb->l4_len - sizeof(*th);
        to[0] = get_tms_opts((uintptr_t)(th + 1), len);
@@ -839,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))
@@ -874,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;
@@ -932,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;
 
@@ -946,15 +960,15 @@ rx_ack_listen(struct tle_tcp_stream *s, struct stbl *st,
                return rc;
 
        /* allocate new stream */
-       ts = get_stream(ctx);
-       cs = TCP_STREAM(ts);
-       if (ts == NULL)
+       cs = tcp_stream_get(ctx, 0);
+       if (cs == NULL)
                return ENFILE;
 
        /* prepare stream to handle new connection */
        if (accept_prep_stream(s, st, cs, &to, tms, pi, si) == 0) {
 
                /* put new stream in the accept queue */
+               ts = &cs->s;
                if (_rte_ring_enqueue_burst(s->rx.q,
                                (void * const *)&ts, 1) == 1) {
                        *csp = cs;
@@ -972,7 +986,7 @@ rx_ack_listen(struct tle_tcp_stream *s, struct stbl *st,
 }
 
 static inline int
-data_pkt_adjust(const struct tcb *tcb, struct rte_mbuf *mb, uint32_t hlen,
+data_pkt_adjust(const struct tcb *tcb, struct rte_mbuf **mb, uint32_t hlen,
        uint32_t *seqn, uint32_t *plen)
 {
        uint32_t len, n, seq;
@@ -980,7 +994,7 @@ data_pkt_adjust(const struct tcb *tcb, struct rte_mbuf *mb, uint32_t hlen,
        seq = *seqn;
        len = *plen;
 
-       rte_pktmbuf_adj(mb, hlen);
+       rte_pktmbuf_adj(*mb, hlen);
        if (len == 0)
                return -ENODATA;
        /* cut off the start of the packet */
@@ -989,7 +1003,7 @@ data_pkt_adjust(const struct tcb *tcb, struct rte_mbuf *mb, uint32_t hlen,
                if (n >= len)
                        return -ENODATA;
 
-               rte_pktmbuf_adj(mb, n);
+               *mb = _rte_pktmbuf_adj(*mb, n);
                *seqn = seq + n;
                *plen = len - n;
        }
@@ -1080,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;
@@ -1096,7 +1110,7 @@ rx_fin(struct tle_tcp_stream *s, uint32_t state,
 
        if (plen != 0) {
 
-               ret = data_pkt_adjust(&s->tcb, mb, hlen, &seq, &plen);
+               ret = data_pkt_adjust(&s->tcb, &mb, hlen, &seq, &plen);
                if (ret != 0)
                        return ret;
                if (rx_data_enqueue(s, seq, plen, &mb, 1) != 1)
@@ -1225,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++;
@@ -1285,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) {
@@ -1302,7 +1316,7 @@ rx_data_ack(struct tle_tcp_stream *s, struct dack_info *tack,
 
                if (ret == 0) {
                        /* skip duplicate data, if any */
-                       ret = data_pkt_adjust(&s->tcb, mb[i], hlen,
+                       ret = data_pkt_adjust(&s->tcb, &mb[i], hlen,
                                &seq, &plen);
                }
 
@@ -1329,20 +1343,16 @@ rx_data_ack(struct tle_tcp_stream *s, struct dack_info *tack,
                        ret = rx_check_seqack(&s->tcb, si[j].seq, si[j].ack,
                                plen, ts);
 
+                       if (ret != 0)
+                               break;
+
                        /* account for segment received */
                        ack_info_update(tack, &si[j], ret != 0, plen, ts);
 
-                       if (ret != 0) {
-                               rp[k] = mb[j];
-                               rc[k] = -ret;
-                               k++;
-                               break;
-                       }
                        rte_pktmbuf_adj(mb[j], hlen);
                }
 
                n = j - i;
-               j += (ret != 0);
 
                /* account for OFO data */
                if (seq != s->tcb.rcv.nxt)
@@ -1551,19 +1561,25 @@ 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 tcp_hdr *th;
+       struct tle_tcp_syn_opts so;
+       struct rte_tcp_hdr *th;
 
        if (state != TCP_ST_SYN_SENT)
                return -EINVAL;
 
-       /* invalid SEG.SEQ */
+       /*
+        * RFC 793 3.9: in the SYN-SENT state
+        * If SEG.ACK =< ISS, or SEG.ACK > SND.NXT, send a reset
+        * <SEQ=SEG.ACK><CTL=RST>
+        * and discard the segment.
+        * The connection remains in the same state.
+        */
        if (si->ack != (uint32_t)s->tcb.snd.nxt) {
-               rsp->flags = TCP_FLAG_RST;
+               send_rst(s, si->ack);
                return 0;
        }
 
-       th = rte_pktmbuf_mtod_offset(mb, struct tcp_hdr *,
+       th = rte_pktmbuf_mtod_offset(mb, struct rte_tcp_hdr *,
                mb->l2_len + mb->l3_len);
        get_syn_opts(&so, (uintptr_t)(th + 1), mb->l4_len - sizeof(*th));
 
@@ -1714,10 +1730,7 @@ rx_stream(struct tle_tcp_stream *s, uint32_t ts,
                i = 0;
 
        /* we have a response packet to send. */
-       if (rsp.flags == TCP_FLAG_RST) {
-               send_rst(s, si[i].ack);
-               stream_term(s);
-       } else if (rsp.flags != 0) {
+       if (rsp.flags != 0) {
                send_ack(s, ts, rsp.flags);
 
                /* start the timer for FIN packet */
@@ -1883,7 +1896,6 @@ tle_tcp_rx_bulk(struct tle_dev *dev, struct rte_mbuf *pkt[],
        struct stbl *st;
        struct tle_ctx *ctx;
        uint32_t i, j, k, mt, n, t, ts;
-       uint64_t csf;
        union pkt_info pi[num];
        union seg_info si[num];
        union {
@@ -1904,14 +1916,7 @@ tle_tcp_rx_bulk(struct tle_dev *dev, struct rte_mbuf *pkt[],
                get_pkt_info(pkt[i], &pi[i], &si[i]);
 
                t = pi[i].tf.type;
-               csf = dev->rx.ol_flags[t] &
-                       (PKT_RX_IP_CKSUM_BAD | PKT_RX_L4_CKSUM_BAD);
-
-               /* check csums in SW */
-               if (pi[i].csf == 0 && csf != 0 && check_pkt_csum(pkt[i], csf,
-                               pi[i].tf.type, IPPROTO_TCP) != 0)
-                       pi[i].csf = csf;
-
+               pi[i].csf = check_pkt_csum(pkt[i], pi[i].csf, t, IPPROTO_TCP);
                stu.t[t] = mt;
        }
 
@@ -1959,12 +1964,15 @@ tle_tcp_stream_accept(struct tle_stream *ts, struct tle_stream *rs[],
 {
        uint32_t n;
        struct tle_tcp_stream *s;
+       struct tle_memtank *mts;
 
        s = TCP_STREAM(ts);
        n = _rte_ring_dequeue_burst(s->rx.q, (void **)rs, num);
        if (n == 0)
                return 0;
 
+       mts = CTX_TCP_MTS(ts->ctx);
+
        /*
         * if we still have packets to read,
         * then rearm stream RX event.
@@ -1975,6 +1983,7 @@ tle_tcp_stream_accept(struct tle_stream *ts, struct tle_stream *rs[],
                tcp_stream_release(s);
        }
 
+       tle_memtank_grow(mts);
        return n;
 }
 
@@ -2165,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)
 {
@@ -2593,7 +2689,7 @@ rto_stream(struct tle_tcp_stream *s, uint32_t tms)
                timer_restart(s);
 
        } else {
-               send_rst(s, s->tcb.snd.una);
+               send_rst(s, s->tcb.snd.nxt);
                stream_term(s);
        }
 }