1aa97dd1cSKonstantin Ananyev/*
27e18fa1bSKonstantin Ananyev * Copyright (c) 2016-2017  Intel Corporation.
3aa97dd1cSKonstantin Ananyev * Licensed under the Apache License, Version 2.0 (the "License");
4aa97dd1cSKonstantin Ananyev * you may not use this file except in compliance with the License.
5aa97dd1cSKonstantin Ananyev * You may obtain a copy of the License at:
6aa97dd1cSKonstantin Ananyev *
7aa97dd1cSKonstantin Ananyev *     http://www.apache.org/licenses/LICENSE-2.0
8aa97dd1cSKonstantin Ananyev *
9aa97dd1cSKonstantin Ananyev * Unless required by applicable law or agreed to in writing, software
10aa97dd1cSKonstantin Ananyev * distributed under the License is distributed on an "AS IS" BASIS,
11aa97dd1cSKonstantin Ananyev * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12aa97dd1cSKonstantin Ananyev * See the License for the specific language governing permissions and
13aa97dd1cSKonstantin Ananyev * limitations under the License.
14aa97dd1cSKonstantin Ananyev */
15aa97dd1cSKonstantin Ananyev
16aa97dd1cSKonstantin Ananyev#include <string.h>
17aa97dd1cSKonstantin Ananyev#include <rte_malloc.h>
18aa97dd1cSKonstantin Ananyev#include <rte_errno.h>
19aa97dd1cSKonstantin Ananyev#include <rte_ethdev.h>
20aa97dd1cSKonstantin Ananyev#include <rte_ip.h>
21aa97dd1cSKonstantin Ananyev#include <rte_tcp.h>
22aa97dd1cSKonstantin Ananyev
23aa97dd1cSKonstantin Ananyev#include "tcp_stream.h"
24aa97dd1cSKonstantin Ananyev#include "tcp_timer.h"
25aa97dd1cSKonstantin Ananyev#include "stream_table.h"
26aa97dd1cSKonstantin Ananyev#include "misc.h"
27aa97dd1cSKonstantin Ananyev#include "tcp_ctl.h"
28aa97dd1cSKonstantin Ananyev#include "tcp_ofo.h"
29aa97dd1cSKonstantin Ananyev#include "tcp_txq.h"
30aa97dd1cSKonstantin Ananyev
31b8f1ef2bSKonstantin Ananyev#define MAX_STREAM_BURST	0x40
32b8f1ef2bSKonstantin Ananyev
33aa97dd1cSKonstantin Ananyevstatic void
34aa97dd1cSKonstantin Ananyevunuse_stream(struct tle_tcp_stream *s)
35aa97dd1cSKonstantin Ananyev{
36aa97dd1cSKonstantin Ananyev	s->s.type = TLE_VNUM;
377e18fa1bSKonstantin Ananyev	rte_atomic32_set(&s->use, INT32_MIN);
38aa97dd1cSKonstantin Ananyev}
39aa97dd1cSKonstantin Ananyev
40aa97dd1cSKonstantin Ananyevstatic void
41aa97dd1cSKonstantin Ananyevtcp_fini_streams(struct tle_ctx *ctx)
42aa97dd1cSKonstantin Ananyev{
43aa97dd1cSKonstantin Ananyev	struct tcp_streams *ts;
44aa97dd1cSKonstantin Ananyev
45aa97dd1cSKonstantin Ananyev	ts = CTX_TCP_STREAMS(ctx);
46aa97dd1cSKonstantin Ananyev	if (ts != NULL) {
47aa97dd1cSKonstantin Ananyev
48b8f1ef2bSKonstantin Ananyev		stbl_fini(&ts->st);
49aa97dd1cSKonstantin Ananyev		tle_timer_free(ts->tmr);
50aa97dd1cSKonstantin Ananyev		rte_free(ts->tsq);
51b8f1ef2bSKonstantin Ananyev		tle_memtank_dump(stdout, ts->mts, TLE_MTANK_DUMP_STAT);
52b8f1ef2bSKonstantin Ananyev		tle_memtank_sanity_check(ts->mts, 0);
53b8f1ef2bSKonstantin Ananyev		tle_memtank_destroy(ts->mts);
54aa97dd1cSKonstantin Ananyev
55aa97dd1cSKonstantin Ananyev		STAILQ_INIT(&ts->dr.fe);
56aa97dd1cSKonstantin Ananyev		STAILQ_INIT(&ts->dr.be);
57aa97dd1cSKonstantin Ananyev	}
58aa97dd1cSKonstantin Ananyev
59aa97dd1cSKonstantin Ananyev	rte_free(ts);
60aa97dd1cSKonstantin Ananyev	ctx->streams.buf = NULL;
61aa97dd1cSKonstantin Ananyev	STAILQ_INIT(&ctx->streams.free);
62aa97dd1cSKonstantin Ananyev}
63aa97dd1cSKonstantin Ananyev
64aa97dd1cSKonstantin Ananyevstatic struct rte_ring *
65aa97dd1cSKonstantin Ananyevalloc_ring(uint32_t n, uint32_t flags, int32_t socket)
66aa97dd1cSKonstantin Ananyev{
67aa97dd1cSKonstantin Ananyev	struct rte_ring *r;
68aa97dd1cSKonstantin Ananyev	size_t sz;
69aa97dd1cSKonstantin Ananyev	char name[RTE_RING_NAMESIZE];
70aa97dd1cSKonstantin Ananyev
71aa97dd1cSKonstantin Ananyev	n = rte_align32pow2(n);
72fbba0a3bSMohammad Abdul Awal	sz =  rte_ring_get_memsize(n);
73aa97dd1cSKonstantin Ananyev
74aa97dd1cSKonstantin Ananyev	r = rte_zmalloc_socket(NULL, sz, RTE_CACHE_LINE_SIZE, socket);
75aa97dd1cSKonstantin Ananyev	if (r == NULL) {
76aa97dd1cSKonstantin Ananyev		TCP_LOG(ERR, "%s: allocation of %zu bytes on socket %d "
77aa97dd1cSKonstantin Ananyev			"failed with error code: %d\n",
78aa97dd1cSKonstantin Ananyev			__func__, sz, socket, rte_errno);
79aa97dd1cSKonstantin Ananyev		return NULL;
80aa97dd1cSKonstantin Ananyev	}
81aa97dd1cSKonstantin Ananyev
82aa97dd1cSKonstantin Ananyev	snprintf(name, sizeof(name), "%p@%zu", r, sz);
83aa97dd1cSKonstantin Ananyev	rte_ring_init(r, name, n, flags);
84aa97dd1cSKonstantin Ananyev	return r;
85aa97dd1cSKonstantin Ananyev}
86aa97dd1cSKonstantin Ananyev
8747eb00f2SKonstantin Ananyevstatic void
8847eb00f2SKonstantin Ananyevcalc_stream_szofs(struct tle_ctx *ctx, struct stream_szofs *szofs)
89aa97dd1cSKonstantin Ananyev{
9047eb00f2SKonstantin Ananyev	uint32_t n, na, sz, tsz;
91aa97dd1cSKonstantin Ananyev
9247eb00f2SKonstantin Ananyev	sz = sizeof(struct tle_tcp_stream);
93aa97dd1cSKonstantin Ananyev
94aa97dd1cSKonstantin Ananyev	n = RTE_MAX(ctx->prm.max_stream_rbufs, 1U);
9547eb00f2SKonstantin Ananyev	tcp_ofo_calc_elems(n, &szofs->ofo.nb_obj, &szofs->ofo.nb_max, &tsz);
9647eb00f2SKonstantin Ananyev	szofs->ofo.ofs = sz;
97aa97dd1cSKonstantin Ananyev
9847eb00f2SKonstantin Ananyev	sz += tsz;
9947eb00f2SKonstantin Ananyev	sz = RTE_ALIGN_CEIL(sz, RTE_CACHE_LINE_SIZE);
100aa97dd1cSKonstantin Ananyev
10147eb00f2SKonstantin Ananyev	na = rte_align32pow2(n);
10247eb00f2SKonstantin Ananyev	szofs->rxq.ofs = sz;
10347eb00f2SKonstantin Ananyev	szofs->rxq.nb_obj = na;
10447eb00f2SKonstantin Ananyev
10547eb00f2SKonstantin Ananyev	sz += rte_ring_get_memsize(na);
10647eb00f2SKonstantin Ananyev	sz = RTE_ALIGN_CEIL(sz, RTE_CACHE_LINE_SIZE);
107aa97dd1cSKonstantin Ananyev
108aa97dd1cSKonstantin Ananyev	n = RTE_MAX(ctx->prm.max_stream_sbufs, 1U);
10947eb00f2SKonstantin Ananyev	na = rte_align32pow2(n);
11047eb00f2SKonstantin Ananyev	szofs->txq.ofs = sz;
11147eb00f2SKonstantin Ananyev	szofs->txq.nb_obj = na;
112aa97dd1cSKonstantin Ananyev
11347eb00f2SKonstantin Ananyev	sz += rte_ring_get_memsize(na);
11447eb00f2SKonstantin Ananyev	sz = RTE_ALIGN_CEIL(sz, RTE_CACHE_LINE_SIZE);
115aa97dd1cSKonstantin Ananyev
11647eb00f2SKonstantin Ananyev	szofs->drb.nb_obj = drb_nb_elem(ctx);
11747eb00f2SKonstantin Ananyev	szofs->drb.nb_max = calc_stream_drb_num(ctx, szofs->drb.nb_obj);
11847eb00f2SKonstantin Ananyev	szofs->drb.nb_rng = rte_align32pow2(szofs->drb.nb_max);
11947eb00f2SKonstantin Ananyev	szofs->drb.rng_sz = rte_ring_get_memsize(szofs->drb.nb_rng);
12047eb00f2SKonstantin Ananyev	szofs->drb.blk_sz = tle_drb_calc_size(szofs->drb.nb_obj);
12147eb00f2SKonstantin Ananyev	szofs->drb.ofs = sz;
122aa97dd1cSKonstantin Ananyev
12347eb00f2SKonstantin Ananyev	sz += szofs->drb.rng_sz + szofs->drb.blk_sz * szofs->drb.nb_max;
12447eb00f2SKonstantin Ananyev	sz = RTE_ALIGN_CEIL(sz, RTE_CACHE_LINE_SIZE);
125aa97dd1cSKonstantin Ananyev
12647eb00f2SKonstantin Ananyev	szofs->size = sz;
12747eb00f2SKonstantin Ananyev}
128aa97dd1cSKonstantin Ananyev
129b8f1ef2bSKonstantin Ananyevstatic void
13047eb00f2SKonstantin Ananyevinit_stream(struct tle_ctx *ctx, struct tle_tcp_stream *s,
13147eb00f2SKonstantin Ananyev	const struct stream_szofs *szofs)
13247eb00f2SKonstantin Ananyev{
13347eb00f2SKonstantin Ananyev	uint32_t f, i;
13447eb00f2SKonstantin Ananyev	struct tle_drb *drb;
13547eb00f2SKonstantin Ananyev
13647eb00f2SKonstantin Ananyev	f = ((ctx->prm.flags & TLE_CTX_FLAG_ST) == 0) ? 0 :
13747eb00f2SKonstantin Ananyev		(RING_F_SP_ENQ |  RING_F_SC_DEQ);
13847eb00f2SKonstantin Ananyev
13947eb00f2SKonstantin Ananyev	/* init RX part. */
140aa97dd1cSKonstantin Ananyev
14147eb00f2SKonstantin Ananyev	s->rx.ofo = (void *)((uintptr_t)s + szofs->ofo.ofs);
14247eb00f2SKonstantin Ananyev	tcp_ofo_init(s->rx.ofo, szofs->ofo.nb_obj, szofs->ofo.nb_max);
143aa97dd1cSKonstantin Ananyev
14447eb00f2SKonstantin Ananyev	s->rx.q = (void *)((uintptr_t)s + szofs->rxq.ofs);
14547eb00f2SKonstantin Ananyev	rte_ring_init(s->rx.q, __func__, szofs->rxq.nb_obj, f | RING_F_SP_ENQ);
14647eb00f2SKonstantin Ananyev
14747eb00f2SKonstantin Ananyev	/* init TX part. */
14847eb00f2SKonstantin Ananyev
14947eb00f2SKonstantin Ananyev	s->tx.q = (void *)((uintptr_t)s + szofs->txq.ofs);
15047eb00f2SKonstantin Ananyev	rte_ring_init(s->tx.q, __func__, szofs->txq.nb_obj, f | RING_F_SC_DEQ);
15147eb00f2SKonstantin Ananyev
15247eb00f2SKonstantin Ananyev	s->tx.drb.r = (void *)((uintptr_t)s + szofs->drb.ofs);
15347eb00f2SKonstantin Ananyev	rte_ring_init(s->tx.drb.r, __func__, szofs->drb.nb_rng, f);
15447eb00f2SKonstantin Ananyev
15547eb00f2SKonstantin Ananyev	for (i = 0; i != szofs->drb.nb_max; i++) {
156aa97dd1cSKonstantin Ananyev		drb = (struct tle_drb *)((uintptr_t)s->tx.drb.r +
15747eb00f2SKonstantin Ananyev			szofs->drb.rng_sz + szofs->drb.blk_sz * i);
158aa97dd1cSKonstantin Ananyev		drb->udata = s;
15947eb00f2SKonstantin Ananyev		drb->size = szofs->drb.nb_obj;
160aa97dd1cSKonstantin Ananyev		rte_ring_enqueue(s->tx.drb.r, drb);
161aa97dd1cSKonstantin Ananyev	}
162aa97dd1cSKonstantin Ananyev
16347eb00f2SKonstantin Ananyev	s->tx.drb.nb_elem = szofs->drb.nb_obj;
16447eb00f2SKonstantin Ananyev	s->tx.drb.nb_max = szofs->drb.nb_max;
165aa97dd1cSKonstantin Ananyev
166aa97dd1cSKonstantin Ananyev	/* mark stream as avaialble to use. */
167aa97dd1cSKonstantin Ananyev
168aa97dd1cSKonstantin Ananyev	s->s.ctx = ctx;
169aa97dd1cSKonstantin Ananyev	unuse_stream(s);
170aa97dd1cSKonstantin Ananyev}
171aa97dd1cSKonstantin Ananyev
172aa97dd1cSKonstantin Ananyevstatic void
173aa97dd1cSKonstantin Ananyevtcp_free_drbs(struct tle_stream *s, struct tle_drb *drb[], uint32_t nb_drb)
174aa97dd1cSKonstantin Ananyev{
175aa97dd1cSKonstantin Ananyev	struct tle_tcp_stream *us;
176aa97dd1cSKonstantin Ananyev
177aa97dd1cSKonstantin Ananyev	us = (struct tle_tcp_stream *)s;
178fbba0a3bSMohammad Abdul Awal	_rte_ring_enqueue_burst(us->tx.drb.r, (void **)drb, nb_drb);
179aa97dd1cSKonstantin Ananyev}
180aa97dd1cSKonstantin Ananyev
181aa97dd1cSKonstantin Ananyevstatic struct tle_timer_wheel *
182b8f1ef2bSKonstantin Ananyevalloc_timers(const struct tle_ctx *ctx)
183aa97dd1cSKonstantin Ananyev{
184b8f1ef2bSKonstantin Ananyev	struct tle_timer_wheel *twl;
185aa97dd1cSKonstantin Ananyev	struct tle_timer_wheel_args twprm;
186aa97dd1cSKonstantin Ananyev
187aa97dd1cSKonstantin Ananyev	twprm.tick_size = TCP_RTO_GRANULARITY;
188b8f1ef2bSKonstantin Ananyev	twprm.max_timer = ctx->prm.max_streams;
189b8f1ef2bSKonstantin Ananyev	twprm.socket_id = ctx->prm.socket_id;
190b8f1ef2bSKonstantin Ananyev
191b8f1ef2bSKonstantin Ananyev	twl = tle_timer_create(&twprm, tcp_get_tms(ctx->cycles_ms_shift));
192b8f1ef2bSKonstantin Ananyev	if (twl == NULL)
193b8f1ef2bSKonstantin Ananyev		TCP_LOG(ERR, "alloc_timers(ctx=%p) failed with error=%d\n",
194b8f1ef2bSKonstantin Ananyev			ctx, rte_errno);
195b8f1ef2bSKonstantin Ananyev	return twl;
196b8f1ef2bSKonstantin Ananyev}
197b8f1ef2bSKonstantin Ananyev
198b8f1ef2bSKonstantin Ananyevstatic void *
199b8f1ef2bSKonstantin Ananyevmts_alloc(size_t sz, void *udata)
200b8f1ef2bSKonstantin Ananyev{
201b8f1ef2bSKonstantin Ananyev	struct tle_ctx *ctx;
202b8f1ef2bSKonstantin Ananyev
203b8f1ef2bSKonstantin Ananyev	ctx = udata;
204b8f1ef2bSKonstantin Ananyev	return rte_zmalloc_socket(NULL, sz, RTE_CACHE_LINE_SIZE,
205b8f1ef2bSKonstantin Ananyev		ctx->prm.socket_id);
206b8f1ef2bSKonstantin Ananyev}
207b8f1ef2bSKonstantin Ananyev
208b8f1ef2bSKonstantin Ananyevstatic void
209b8f1ef2bSKonstantin Ananyevmts_free(void *p, void *udata)
210b8f1ef2bSKonstantin Ananyev{
211b8f1ef2bSKonstantin Ananyev	RTE_SET_USED(udata);
212b8f1ef2bSKonstantin Ananyev	rte_free(p);
213b8f1ef2bSKonstantin Ananyev}
214b8f1ef2bSKonstantin Ananyev
215b8f1ef2bSKonstantin Ananyevstatic void
216b8f1ef2bSKonstantin Ananyevmts_init(void *pa[], uint32_t num, void *udata)
217b8f1ef2bSKonstantin Ananyev{
218b8f1ef2bSKonstantin Ananyev	uint32_t i;
219b8f1ef2bSKonstantin Ananyev	struct tle_ctx *ctx;
220b8f1ef2bSKonstantin Ananyev	struct tcp_streams *ts;
221b8f1ef2bSKonstantin Ananyev
222b8f1ef2bSKonstantin Ananyev	ctx = udata;
223b8f1ef2bSKonstantin Ananyev	ts = CTX_TCP_STREAMS(ctx);
224b8f1ef2bSKonstantin Ananyev
225b8f1ef2bSKonstantin Ananyev	for (i = 0; i != num; i++)
226b8f1ef2bSKonstantin Ananyev		init_stream(ctx, pa[i], &ts->szofs);
227b8f1ef2bSKonstantin Ananyev}
228b8f1ef2bSKonstantin Ananyev
229b8f1ef2bSKonstantin Ananyevstatic struct tle_memtank *
230b8f1ef2bSKonstantin Ananyevalloc_mts(struct tle_ctx *ctx, uint32_t stream_size)
231b8f1ef2bSKonstantin Ananyev{
232b8f1ef2bSKonstantin Ananyev	struct tle_memtank *mts;
233b8f1ef2bSKonstantin Ananyev	struct tle_memtank_prm prm;
234b8f1ef2bSKonstantin Ananyev
235b8f1ef2bSKonstantin Ananyev	static const struct tle_memtank_prm cprm = {
236b8f1ef2bSKonstantin Ananyev		.obj_align = RTE_CACHE_LINE_SIZE,
237b8f1ef2bSKonstantin Ananyev		.flags = TLE_MTANK_OBJ_DBG,
238b8f1ef2bSKonstantin Ananyev		.alloc = mts_alloc,
239b8f1ef2bSKonstantin Ananyev		.free = mts_free,
240b8f1ef2bSKonstantin Ananyev		.init = mts_init,
241b8f1ef2bSKonstantin Ananyev	};
242b8f1ef2bSKonstantin Ananyev
243b8f1ef2bSKonstantin Ananyev	prm = cprm;
244b8f1ef2bSKonstantin Ananyev	prm.udata = ctx;
245b8f1ef2bSKonstantin Ananyev
246b8f1ef2bSKonstantin Ananyev	prm.obj_size = stream_size;
247b8f1ef2bSKonstantin Ananyev
248b8f1ef2bSKonstantin Ananyev	prm.min_free = (ctx->prm.free_streams.min != 0) ?
249b8f1ef2bSKonstantin Ananyev		ctx->prm.free_streams.min : ctx->prm.max_streams;
250b8f1ef2bSKonstantin Ananyev	prm.max_free = (ctx->prm.free_streams.max > prm.min_free) ?
251b8f1ef2bSKonstantin Ananyev		ctx->prm.free_streams.max : prm.min_free;
252b8f1ef2bSKonstantin Ananyev
253b8f1ef2bSKonstantin Ananyev	prm.nb_obj_chunk = MAX_STREAM_BURST;
254b8f1ef2bSKonstantin Ananyev	prm.max_obj = ctx->prm.max_streams;
255b8f1ef2bSKonstantin Ananyev
256b8f1ef2bSKonstantin Ananyev	mts = tle_memtank_create(&prm);
257b8f1ef2bSKonstantin Ananyev	if (mts == NULL)
258b8f1ef2bSKonstantin Ananyev		TCP_LOG(ERR, "%s(ctx=%p) failed with error=%d\n",
259b8f1ef2bSKonstantin Ananyev			__func__, ctx, rte_errno);
260b8f1ef2bSKonstantin Ananyev	else
261b8f1ef2bSKonstantin Ananyev		tle_memtank_grow(mts);
262b8f1ef2bSKonstantin Ananyev
263b8f1ef2bSKonstantin Ananyev	return mts;
264aa97dd1cSKonstantin Ananyev}
265aa97dd1cSKonstantin Ananyev
266aa97dd1cSKonstantin Ananyevstatic int
267aa97dd1cSKonstantin Ananyevtcp_init_streams(struct tle_ctx *ctx)
268aa97dd1cSKonstantin Ananyev{
269b8f1ef2bSKonstantin Ananyev	uint32_t f;
270aa97dd1cSKonstantin Ananyev	int32_t rc;
271aa97dd1cSKonstantin Ananyev	struct tcp_streams *ts;
27247eb00f2SKonstantin Ananyev	struct stream_szofs szofs;
273aa97dd1cSKonstantin Ananyev
2747e18fa1bSKonstantin Ananyev	f = ((ctx->prm.flags & TLE_CTX_FLAG_ST) == 0) ? 0 :
2757e18fa1bSKonstantin Ananyev		(RING_F_SP_ENQ |  RING_F_SC_DEQ);
2767e18fa1bSKonstantin Ananyev
27747eb00f2SKonstantin Ananyev	calc_stream_szofs(ctx, &szofs);
278b8f1ef2bSKonstantin Ananyev	TCP_LOG(NOTICE, "ctx:%p, caluclated stream size: %u\n",
279b8f1ef2bSKonstantin Ananyev		ctx, szofs.size);
28047eb00f2SKonstantin Ananyev
281b8f1ef2bSKonstantin Ananyev	ts = rte_zmalloc_socket(NULL, sizeof(*ts), RTE_CACHE_LINE_SIZE,
282aa97dd1cSKonstantin Ananyev		ctx->prm.socket_id);
28347eb00f2SKonstantin Ananyev	if (ts == NULL)
284aa97dd1cSKonstantin Ananyev		return -ENOMEM;
28547eb00f2SKonstantin Ananyev
28647eb00f2SKonstantin Ananyev	ts->szofs = szofs;
287aa97dd1cSKonstantin Ananyev
288aa97dd1cSKonstantin Ananyev	STAILQ_INIT(&ts->dr.fe);
289aa97dd1cSKonstantin Ananyev	STAILQ_INIT(&ts->dr.be);
290aa97dd1cSKonstantin Ananyev
291aa97dd1cSKonstantin Ananyev	ctx->streams.buf = ts;
292aa97dd1cSKonstantin Ananyev	STAILQ_INIT(&ctx->streams.free);
293aa97dd1cSKonstantin Ananyev
294b8f1ef2bSKonstantin Ananyev	rc = stbl_init(&ts->st, ctx->prm.max_streams, ctx->prm.socket_id);
295b8f1ef2bSKonstantin Ananyev
296b8f1ef2bSKonstantin Ananyev	if (rc == 0) {
297b8f1ef2bSKonstantin Ananyev		ts->tsq = alloc_ring(ctx->prm.max_streams, f | RING_F_SC_DEQ,
298b8f1ef2bSKonstantin Ananyev			ctx->prm.socket_id);
299b8f1ef2bSKonstantin Ananyev		ts->tmr = alloc_timers(ctx);
300b8f1ef2bSKonstantin Ananyev		ts->mts = alloc_mts(ctx, szofs.size);
301b8f1ef2bSKonstantin Ananyev
302b8f1ef2bSKonstantin Ananyev		if (ts->tsq == NULL || ts->tmr == NULL || ts->mts == NULL)
303aa97dd1cSKonstantin Ananyev			rc = -ENOMEM;
304aa97dd1cSKonstantin Ananyev
305b8f1ef2bSKonstantin Ananyev		tle_memtank_dump(stdout, ts->mts, TLE_MTANK_DUMP_STAT);
30647eb00f2SKonstantin Ananyev	}
307aa97dd1cSKonstantin Ananyev
308aa97dd1cSKonstantin Ananyev	if (rc != 0) {
309b8f1ef2bSKonstantin Ananyev		TCP_LOG(ERR, "initalisation of tcp streams failed");
310aa97dd1cSKonstantin Ananyev		tcp_fini_streams(ctx);
311aa97dd1cSKonstantin Ananyev	}
312aa97dd1cSKonstantin Ananyev
313aa97dd1cSKonstantin Ananyev	return rc;
314aa97dd1cSKonstantin Ananyev}
315aa97dd1cSKonstantin Ananyev
316aa97dd1cSKonstantin Ananyevstatic void __attribute__((constructor))
317aa97dd1cSKonstantin Ananyevtcp_stream_setup(void)
318aa97dd1cSKonstantin Ananyev{
319aa97dd1cSKonstantin Ananyev	static const struct stream_ops tcp_ops = {
320aa97dd1cSKonstantin Ananyev		.init_streams = tcp_init_streams,
321aa97dd1cSKonstantin Ananyev		.fini_streams = tcp_fini_streams,
322aa97dd1cSKonstantin Ananyev		.free_drbs = tcp_free_drbs,
323aa97dd1cSKonstantin Ananyev	};
324aa97dd1cSKonstantin Ananyev
325aa97dd1cSKonstantin Ananyev	tle_stream_ops[TLE_PROTO_TCP] = tcp_ops;
326aa97dd1cSKonstantin Ananyev}
327aa97dd1cSKonstantin Ananyev
328aa97dd1cSKonstantin Ananyev/*
329aa97dd1cSKonstantin Ananyev * Helper routine, check that input event and callback are mutually exclusive.
330aa97dd1cSKonstantin Ananyev */
331aa97dd1cSKonstantin Ananyevstatic int
332aa97dd1cSKonstantin Ananyevcheck_cbev(const struct tle_event *ev, const struct tle_stream_cb *cb)
333aa97dd1cSKonstantin Ananyev{
334aa97dd1cSKonstantin Ananyev	if (ev != NULL && cb->func != NULL)
335aa97dd1cSKonstantin Ananyev		return -EINVAL;
336aa97dd1cSKonstantin Ananyev	return 0;
337aa97dd1cSKonstantin Ananyev}
338aa97dd1cSKonstantin Ananyev
339aa97dd1cSKonstantin Ananyevstatic int
340aa97dd1cSKonstantin Ananyevcheck_stream_prm(const struct tle_ctx *ctx,
341aa97dd1cSKonstantin Ananyev	const struct tle_tcp_stream_param *prm)
342aa97dd1cSKonstantin Ananyev{
343aa97dd1cSKonstantin Ananyev	if ((prm->addr.local.ss_family != AF_INET &&
344aa97dd1cSKonstantin Ananyev			prm->addr.local.ss_family != AF_INET6) ||
345aa97dd1cSKonstantin Ananyev			prm->addr.local.ss_family != prm->addr.remote.ss_family)
346aa97dd1cSKonstantin Ananyev		return -EINVAL;
347aa97dd1cSKonstantin Ananyev
348aa97dd1cSKonstantin Ananyev	/* callback and event notifications mechanisms are mutually exclusive */
349aa97dd1cSKonstantin Ananyev	if (check_cbev(prm->cfg.recv_ev, &prm->cfg.recv_cb) != 0 ||
350aa97dd1cSKonstantin Ananyev			check_cbev(prm->cfg.recv_ev, &prm->cfg.recv_cb) != 0 ||
351aa97dd1cSKonstantin Ananyev			check_cbev(prm->cfg.err_ev, &prm->cfg.err_cb) != 0)
352aa97dd1cSKonstantin Ananyev		return -EINVAL;
353aa97dd1cSKonstantin Ananyev
354aa97dd1cSKonstantin Ananyev	/* check does context support desired address family. */
355aa97dd1cSKonstantin Ananyev	if ((prm->addr.local.ss_family == AF_INET &&
356aa97dd1cSKonstantin Ananyev			ctx->prm.lookup4 == NULL) ||
357aa97dd1cSKonstantin Ananyev			(prm->addr.local.ss_family == AF_INET6 &&
358aa97dd1cSKonstantin Ananyev			ctx->prm.lookup6 == NULL))
359aa97dd1cSKonstantin Ananyev		return -EINVAL;
360aa97dd1cSKonstantin Ananyev
361aa97dd1cSKonstantin Ananyev	return 0;
362aa97dd1cSKonstantin Ananyev}
363aa97dd1cSKonstantin Ananyev
364aa97dd1cSKonstantin Ananyevstruct tle_stream *
365aa97dd1cSKonstantin Ananyevtle_tcp_stream_open(struct tle_ctx *ctx,
366aa97dd1cSKonstantin Ananyev	const struct tle_tcp_stream_param *prm)
367aa97dd1cSKonstantin Ananyev{
368b8f1ef2bSKonstantin Ananyev	struct tcp_streams *ts;
369aa97dd1cSKonstantin Ananyev	struct tle_tcp_stream *s;
370aa97dd1cSKonstantin Ananyev	int32_t rc;
371aa97dd1cSKonstantin Ananyev
372aa97dd1cSKonstantin Ananyev	if (ctx == NULL || prm == NULL || check_stream_prm(ctx, prm) != 0) {
373aa97dd1cSKonstantin Ananyev		rte_errno = EINVAL;
374aa97dd1cSKonstantin Ananyev		return NULL;
375aa97dd1cSKonstantin Ananyev	}
376aa97dd1cSKonstantin Ananyev
377b8f1ef2bSKonstantin Ananyev	ts = CTX_TCP_STREAMS(ctx);
378aa97dd1cSKonstantin Ananyev
379b8f1ef2bSKonstantin Ananyev	s = tcp_stream_get(ctx, TLE_MTANK_ALLOC_CHUNK | TLE_MTANK_ALLOC_GROW);
380b8f1ef2bSKonstantin Ananyev	if (s == NULL) {
381b8f1ef2bSKonstantin Ananyev		rte_errno = ENFILE;
382aa97dd1cSKonstantin Ananyev		return NULL;
383aa97dd1cSKonstantin Ananyev	}
384aa97dd1cSKonstantin Ananyev
385aa97dd1cSKonstantin Ananyev	/* setup L4 ports and L3 addresses fields. */
386aa97dd1cSKonstantin Ananyev	rc = stream_fill_ctx(ctx, &s->s,
387aa97dd1cSKonstantin Ananyev		(const struct sockaddr *)&prm->addr.local,
388aa97dd1cSKonstantin Ananyev		(const struct sockaddr *)&prm->addr.remote);
389aa97dd1cSKonstantin Ananyev
390aa97dd1cSKonstantin Ananyev	if (rc != 0) {
391b8f1ef2bSKonstantin Ananyev		tle_memtank_free(ts->mts, (void **)&s, 1,
392b8f1ef2bSKonstantin Ananyev			TLE_MTANK_FREE_SHRINK);
393aa97dd1cSKonstantin Ananyev		rte_errno = rc;
394aa97dd1cSKonstantin Ananyev		return NULL;
395aa97dd1cSKonstantin Ananyev	}
396aa97dd1cSKonstantin Ananyev
397aa97dd1cSKonstantin Ananyev	/* setup stream notification menchanism */
398aa97dd1cSKonstantin Ananyev	s->rx.ev = prm->cfg.recv_ev;
399aa97dd1cSKonstantin Ananyev	s->rx.cb = prm->cfg.recv_cb;
400aa97dd1cSKonstantin Ananyev	s->tx.ev = prm->cfg.send_ev;
401aa97dd1cSKonstantin Ananyev	s->tx.cb = prm->cfg.send_cb;
402aa97dd1cSKonstantin Ananyev	s->err.ev = prm->cfg.err_ev;
403aa97dd1cSKonstantin Ananyev	s->err.cb = prm->cfg.err_cb;
404aa97dd1cSKonstantin Ananyev
405aa97dd1cSKonstantin Ananyev	/* store other params */
4067e18fa1bSKonstantin Ananyev	s->flags = ctx->prm.flags;
407aa97dd1cSKonstantin Ananyev	s->tcb.snd.nb_retm = (prm->cfg.nb_retries != 0) ? prm->cfg.nb_retries :
408aa97dd1cSKonstantin Ananyev		TLE_TCP_DEFAULT_RETRIES;
409