diff options
Diffstat (limited to 'lib/libtle_l4p/tcp_rxtx.c')
-rw-r--r-- | lib/libtle_l4p/tcp_rxtx.c | 162 |
1 files changed, 119 insertions, 43 deletions
diff --git a/lib/libtle_l4p/tcp_rxtx.c b/lib/libtle_l4p/tcp_rxtx.c index 6085814..ceaa2bc 100644 --- a/lib/libtle_l4p/tcp_rxtx.c +++ b/lib/libtle_l4p/tcp_rxtx.c @@ -27,6 +27,7 @@ #include "tcp_ctl.h" #include "tcp_rxq.h" #include "tcp_txq.h" +#include "tcp_tx_seg.h" #define TCP_MAX_PKT_SEG 0x20 @@ -640,7 +641,9 @@ sync_ack(struct tle_tcp_stream *s, const union pkt_info *pi, get_syn_opts(&s->tcb.so, (uintptr_t)(th + 1), m->l4_len - sizeof(*th)); s->tcb.rcv.nxt = si->seq + 1; - seq = sync_gen_seq(pi, s->tcb.rcv.nxt, ts, s->tcb.so.mss); + seq = sync_gen_seq(pi, s->tcb.rcv.nxt, ts, s->tcb.so.mss, + s->s.ctx->prm.hash_alg, + &s->s.ctx->prm.secret_key); s->tcb.so.ts.ecr = s->tcb.so.ts.val; s->tcb.so.ts.val = sync_gen_ts(ts, s->tcb.so.wscale); s->tcb.so.wscale = (s->tcb.so.wscale == TCP_WSCALE_NONE) ? @@ -761,14 +764,17 @@ rx_check_seqack(struct tcb *tcb, uint32_t seq, uint32_t ack, uint32_t len, static inline int restore_syn_opt(struct syn_opts *so, const union pkt_info *pi, - const union seg_info *si, uint32_t ts, const struct rte_mbuf *mb) + const union seg_info *si, 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; /* check that ACK, etc fields are what we expected. */ - rc = sync_check_ack(pi, si->seq, si->ack - 1, ts); + rc = sync_check_ack(pi, si->seq, si->ack - 1, ts, + hash_alg, + secret_key); if (rc < 0) return rc; @@ -917,12 +923,12 @@ rx_ack_listen(struct tle_tcp_stream *s, struct stbl *st, if (pi->tf.flags != TCP_FLAG_ACK || rx_check_stream(s, pi) != 0) return -EINVAL; - rc = restore_syn_opt(&so, pi, si, tms, mb); + ctx = s->s.ctx; + rc = restore_syn_opt(&so, pi, si, tms, mb, ctx->prm.hash_alg, + &ctx->prm.secret_key); if (rc < 0) return rc; - ctx = s->s.ctx; - /* allocate new stream */ ts = get_stream(ctx); cs = TCP_STREAM(ts); @@ -1532,7 +1538,7 @@ rx_synack(struct tle_tcp_stream *s, uint32_t ts, uint32_t state, s->tcb.so = so; s->tcb.snd.una = s->tcb.snd.nxt; - s->tcb.snd.mss = so.mss; + s->tcb.snd.mss = calc_smss(so.mss, &s->tx.dst); s->tcb.snd.wnd = si->wnd << so.wscale; s->tcb.snd.wu.wl1 = si->seq; s->tcb.snd.wu.wl2 = si->ack; @@ -1546,6 +1552,11 @@ rx_synack(struct tle_tcp_stream *s, uint32_t ts, uint32_t state, s->tcb.rcv.irs = si->seq; s->tcb.rcv.nxt = si->seq + 1; + /* if peer doesn't support WSCALE opt, recalculate RCV.WND */ + s->tcb.rcv.wscale = (so.wscale == TCP_WSCALE_NONE) ? + TCP_WSCALE_NONE : TCP_WSCALE_DEFAULT; + s->tcb.rcv.wnd = calc_rx_wnd(s, s->tcb.rcv.wscale); + /* calculate initial rto */ rto_estimate(&s->tcb, ts - s->tcb.snd.ts); @@ -2053,7 +2064,9 @@ tx_syn(struct tle_tcp_stream *s, const struct sockaddr *addr) s->tcb.so.mss = calc_smss(s->tx.dst.mtu, &s->tx.dst); /* note that rcv.nxt is 0 here for sync_gen_seq.*/ - seq = sync_gen_seq(&pi, s->tcb.rcv.nxt, tms, s->tcb.so.mss); + seq = sync_gen_seq(&pi, s->tcb.rcv.nxt, tms, s->tcb.so.mss, + s->s.ctx->prm.hash_alg, + &s->s.ctx->prm.secret_key); s->tcb.snd.iss = seq; s->tcb.snd.rcvr = seq; s->tcb.snd.una = seq; @@ -2142,13 +2155,42 @@ tle_tcp_stream_recv(struct tle_stream *ts, struct rte_mbuf *pkt[], uint16_t num) return n; } +static inline int32_t +tx_segments(struct tle_tcp_stream *s, uint64_t ol_flags, + struct rte_mbuf *segs[], uint32_t num) +{ + uint32_t i; + int32_t rc; + + for (i = 0; i != num; i++) { + /* Build L2/L3/L4 header */ + rc = tcp_fill_mbuf(segs[i], s, &s->tx.dst, ol_flags, s->s.port, + 0, TCP_FLAG_ACK, 0, 0); + if (rc != 0) { + free_segments(segs, num); + break; + } + } + + if (i == num) { + /* queue packets for further transmission. */ + rc = rte_ring_mp_enqueue_bulk(s->tx.q, (void **)segs, num); + if (rc != 0) + free_segments(segs, num); + } + + return rc; +} + uint16_t tle_tcp_stream_send(struct tle_stream *ts, struct rte_mbuf *pkt[], uint16_t num) { - uint32_t i, j, mss, n, state, type; + uint32_t i, j, k, mss, n, state, type; + int32_t rc; uint64_t ol_flags; struct tle_tcp_stream *s; struct tle_dev *dev; + struct rte_mbuf *segs[TCP_MAX_PKT_SEG]; s = TCP_STREAM(ts); @@ -2161,53 +2203,87 @@ tle_tcp_stream_send(struct tle_stream *ts, struct rte_mbuf *pkt[], uint16_t num) state = s->tcb.state; if (state != TCP_ST_ESTABLISHED && state != TCP_ST_CLOSE_WAIT) { rte_errno = ENOTCONN; - n = 0; - } else { - mss = s->tcb.snd.mss; - dev = s->tx.dst.dev; - type = s->s.type; - ol_flags = dev->tx.ol_flags[type]; + rwl_release(&s->tx.use); + return 0; + } - /* prepare and check for TX */ - for (i = 0; i != num; i++) { + mss = s->tcb.snd.mss; + dev = s->tx.dst.dev; + type = s->s.type; + ol_flags = dev->tx.ol_flags[type]; - /* !!! need to be modified !!! */ + k = 0; + rc = 0; + while (k != num) { + /* prepare and check for TX */ + for (i = k; i != num; i++) { if (pkt[i]->pkt_len > mss || - pkt[i]->nb_segs > TCP_MAX_PKT_SEG) { - rte_errno = EBADMSG; + pkt[i]->nb_segs > TCP_MAX_PKT_SEG) break; - } else if (tcp_fill_mbuf(pkt[i], s, &s->tx.dst, - ol_flags, s->s.port, 0, TCP_FLAG_ACK, - 0, 0) != 0) + rc = tcp_fill_mbuf(pkt[i], s, &s->tx.dst, ol_flags, + s->s.port, 0, TCP_FLAG_ACK, 0, 0); + if (rc != 0) break; } - /* queue packets for further transmision. */ - n = rte_ring_mp_enqueue_burst(s->tx.q, (void **)pkt, i); + if (i != k) { + /* queue packets for further transmission. */ + n = rte_ring_mp_enqueue_burst(s->tx.q, (void **)pkt + k, + (i - k)); + k += n; + + /* + * for unsent, but already modified packets: + * remove pkt l2/l3 headers, restore ol_flags + */ + if (i != k) { + ol_flags = ~dev->tx.ol_flags[type]; + for (j = k; j != i; j++) { + rte_pktmbuf_adj(pkt[j], pkt[j]->l2_len + + pkt[j]->l3_len + + pkt[j]->l4_len); + pkt[j]->ol_flags &= ol_flags; + } + break; + } + } - /* notify BE about more data to send */ - if (n != 0) - txs_enqueue(s->s.ctx, s); + if (rc != 0) { + rte_errno = -rc; + break; - /* - * for unsent, but already modified packets: - * remove pkt l2/l3 headers, restore ol_flags - */ - if (n != i) { - ol_flags = ~dev->tx.ol_flags[type]; - for (j = n; j != i; j++) { - rte_pktmbuf_adj(pkt[j], pkt[j]->l2_len + - pkt[j]->l3_len + pkt[j]->l4_len); - pkt[j]->ol_flags &= ol_flags; + /* segment large packet and enqueue for sending */ + } else if (i != num) { + /* segment the packet. */ + rc = tcp_segmentation(pkt[i], segs, RTE_DIM(segs), + &s->tx.dst, mss); + if (rc < 0) { + rte_errno = -rc; + break; } - /* if possible, rearm stream write event. */ - } else if (rte_ring_free_count(s->tx.q) != 0 && - s->tx.ev != NULL) - tle_event_raise(s->tx.ev); + + rc = tx_segments(s, dev->tx.ol_flags[type], segs, rc); + if (rc == 0) { + /* free the large mbuf */ + rte_pktmbuf_free(pkt[i]); + /* set the mbuf as consumed */ + k++; + } else + /* no space left in tx queue */ + break; + } } + /* notify BE about more data to send */ + if (k != 0) + txs_enqueue(s->s.ctx, s); + /* if possible, re-arm stream write event. */ + if (rte_ring_free_count(s->tx.q) != 0 && s->tx.ev != NULL) + tle_event_raise(s->tx.ev); + rwl_release(&s->tx.use); - return n; + + return k; } /* send data and FIN (if needed) */ |