From e0d62f616439955946d24ad83d49552da24afd5d Mon Sep 17 00:00:00 2001 From: Konstantin Ananyev Date: Thu, 13 May 2021 15:26:50 +0000 Subject: l4p/tcp: introduce tle_tcp_stream_establish() API tle_tcp_stream_establish() allows to create streams in established connection state. Signed-off-by: Konstantin Ananyev Change-Id: Ib302c4d7f229144d2624279f973f00041fb611b2 --- lib/libtle_l4p/syncookie.h | 49 ++++++++++------ lib/libtle_l4p/tcp_misc.h | 34 +++-------- lib/libtle_l4p/tcp_rxtx.c | 139 +++++++++++++++++++++++++++++++++++++------- lib/libtle_l4p/tcp_stream.c | 117 ++++++++++++++++++++++++++++++++----- lib/libtle_l4p/tcp_stream.h | 14 +++-- lib/libtle_l4p/tle_tcp.h | 32 ++++++++++ 6 files changed, 298 insertions(+), 87 deletions(-) diff --git a/lib/libtle_l4p/syncookie.h b/lib/libtle_l4p/syncookie.h index 61bfce4..6d4372d 100644 --- a/lib/libtle_l4p/syncookie.h +++ b/lib/libtle_l4p/syncookie.h @@ -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 diff --git a/lib/libtle_l4p/tcp_misc.h b/lib/libtle_l4p/tcp_misc.h index 01c1e67..46a0a5f 100644 --- a/lib/libtle_l4p/tcp_misc.h +++ b/lib/libtle_l4p/tcp_misc.h @@ -19,6 +19,7 @@ #include "net_misc.h" #include #include +#include #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; diff --git a/lib/libtle_l4p/tcp_rxtx.c b/lib/libtle_l4p/tcp_rxtx.c index b1aad60..0e8a39f 100644 --- a/lib/libtle_l4p/tcp_rxtx.c +++ b/lib/libtle_l4p/tcp_rxtx.c @@ -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) { diff --git a/lib/libtle_l4p/tcp_stream.c b/lib/libtle_l4p/tcp_stream.c index fce3b9a..c1a007a 100644 --- a/lib/libtle_l4p/tcp_stream.c +++ b/lib/libtle_l4p/tcp_stream.c @@ -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; diff --git a/lib/libtle_l4p/tcp_stream.h b/lib/libtle_l4p/tcp_stream.h index a3d00dc..a36b5fe 100644 --- a/lib/libtle_l4p/tcp_stream.h +++ b/lib/libtle_l4p/tcp_stream.h @@ -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 diff --git a/lib/libtle_l4p/tle_tcp.h b/lib/libtle_l4p/tle_tcp.h index b0cbda6..3155dfa 100644 --- a/lib/libtle_l4p/tle_tcp.h +++ b/lib/libtle_l4p/tle_tcp.h @@ -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. */ -- cgit 1.2.3-korg