}
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;
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;
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. */
/* 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);
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);
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);
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)
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);
}
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 {
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]);
}
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;
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,
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,
* 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;
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;
}
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,
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);
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))
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;
struct tle_ctx *ctx;
struct tle_stream *ts;
struct tle_tcp_stream *cs;
- union tsopt to;
+ union tle_tcp_tsopt to;
*csp = NULL;
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;
}
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;
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 */
if (n >= len)
return -ENODATA;
- rte_pktmbuf_adj(mb, n);
+ *mb = _rte_pktmbuf_adj(*mb, n);
*seqn = seq + n;
*plen = len - n;
}
{
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;
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)
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++;
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) {
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);
}
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)
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));
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 */
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 {
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;
}
{
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.
tcp_stream_release(s);
}
+ tle_memtank_grow(mts);
return n;
}
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)
{
timer_restart(s);
} else {
- send_rst(s, s->tcb.snd.una);
+ send_rst(s, s->tcb.snd.nxt);
stream_term(s);
}
}