module.c revision b8f1ef2b
1/*
2 * Copyright (c) 2017  Intel Corporation.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 */
26
27#include <ngx_config.h>
28#include <ngx_core.h>
29
30#include "ngx_tldk.h"
31
32#include <rte_ethdev.h>
33#include <rte_lpm6.h>
34#include <rte_lpm.h>
35
36#include "be.h"
37#include "tldk_sock.h"
38
39extern ngx_module_t ngx_tldk_module;
40
41/* map from ngx_worker to corresponding TLDK ctx */
42struct tldk_ctx wrk2ctx[RTE_MAX_LCORE] = {};
43
44/* per be lcore tldk_ctx(s) */
45static struct lcore_ctxs_list lc_ctxs[RTE_MAX_LCORE];
46
47volatile int force_quit;
48
49static void *
50tldk_module_create_conf(ngx_cycle_t *cycle)
51{
52	tldk_conf_t *cf;
53
54	cf = ngx_pcalloc(cycle->pool, sizeof(*cf));
55	if (cf == NULL)
56		return NULL;
57	return cf;
58}
59
60static char *
61tldk_module_init_conf(ngx_cycle_t *cycle, void *conf)
62{
63	tldk_conf_t *cf;
64
65	cf = conf;
66	(void)cf;
67	return NGX_CONF_OK;
68}
69
70static void
71fini_context(struct tldk_ctx *tcx)
72{
73	tle_ctx_destroy(tcx->ctx);
74	rte_lpm_free(tcx->lpm4);
75	rte_lpm6_free(tcx->lpm6);
76	rte_mempool_free(tcx->mpool);
77	rte_mempool_free(tcx->frag_mpool);
78	memset(tcx, 0, sizeof(*tcx));
79}
80
81static int
82init_context(struct tldk_ctx *tcx, const struct tldk_ctx_conf *cf,
83		tldk_conf_t *cft)
84{
85	uint32_t lc, rc, sid;
86	struct tle_ctx_param cprm;
87
88	lc = cf->lcore;
89	sid = rte_lcore_to_socket_id(lc);
90	rc = be_lcore_lpm_init(tcx, sid, cf);
91	if (rc != 0)
92		return rc;
93
94	memset(&cprm, 0, sizeof(cprm));
95	cprm.socket_id = sid;
96	cprm.proto = TLE_PROTO_TCP;
97	cprm.max_streams = cf->nb_stream;
98	cprm.free_streams.min = cf->free_streams.nb_min;
99	cprm.free_streams.max = cf->free_streams.nb_max;
100	cprm.max_stream_rbufs = cf->nb_rbuf;
101	cprm.max_stream_sbufs = cf->nb_sbuf;
102	if (cf->be_in_worker != 0)
103		cprm.flags |= TLE_CTX_FLAG_ST;
104	cprm.timewait = cf->tcp_timewait;
105	cprm.lookup4 = be_lpm4_dst_lookup;
106	cprm.lookup4_data = tcx;
107	cprm.lookup6 = be_lpm6_dst_lookup;
108	cprm.lookup6_data = tcx;
109	cprm.secret_key.u64[0] = rte_rand();
110	cprm.secret_key.u64[1] = rte_rand();
111
112	tcx->ctx = tle_ctx_create(&cprm);
113	RTE_LOG(NOTICE, USER1,
114		"%s: tle_ctx_create(lcore=%u) for worker=%lu returns %p;\n",
115		__func__, lc, cf->worker, tcx->ctx);
116	if (tcx->ctx == NULL) {
117		rte_lpm_free(tcx->lpm4);
118		rte_lpm6_free(tcx->lpm6);
119		return -ENOMEM;
120	}
121
122	tcx->cf = cf;
123
124	/* create mempool for the context */
125	rc = be_mpool_init(tcx);
126	if (rc != 0)
127		return rc;
128
129	/* initialize queues of the device given in the context */
130	rc = be_queue_init(tcx, cft);
131	if (rc != 0)
132		return rc;
133
134	/* create devices of the context */
135	rc = be_add_dev(tcx, cft);
136	if (rc != 0)
137		return rc;
138
139	/*
140	 *1.create LPMs and add to the context
141	 *2.add routes for the given destinations to the context
142	 */
143	rc = be_dst_init(tcx, cft);
144	if (rc != 0)
145		return rc;
146
147	return 0;
148}
149
150void
151tldk_module_fini(ngx_cycle_t *cycle)
152{
153	tldk_conf_t *cf;
154	uint32_t i, wrk;
155
156	cf = (tldk_conf_t *)ngx_get_conf(cycle->conf_ctx, ngx_tldk_module);
157
158	/* signal all launched slave lcores to stop */
159	force_quit = 1;
160
161	/* wait all slave lcores to be stopped */
162	for (i = 0; i != cf->nb_ctx; i++)
163		rte_eal_wait_lcore(cf->ctx[i].lcore);
164
165	/* finish all TLDK contexts */
166	for (i = 0; i != cf->nb_ctx; i++) {
167		wrk = cf->ctx[i].worker;
168		/* free up all tx pkt buffers of the tldk_dev 'ses
169		 * of the tldk_ctx
170		 */
171		be_lcore_clear(wrk2ctx + wrk);
172		fini_context(wrk2ctx + wrk);
173	}
174
175	/* stop all ports */
176	for (i = 0; i != cf->nb_port; i++)
177		be_stop_port(cf->port[i].id);
178}
179
180/* configuration sanity check */
181static int
182process_conf(tldk_conf_t *cf)
183{
184	uint32_t i, j, port_id, mask;
185	uint16_t queue_id;
186	const struct tldk_ctx_conf *ctx;
187	struct tldk_port_conf *pcf;
188
189	/*
190	 * count the number of queues associated
191	 * with each port by iterating through all tldk_ctx'ses.
192	 * if same queue of the port is used in multiple tldk_ctx'ses
193	 * error will be returned.
194	 */
195	for (i = 0; i < cf->nb_ctx; i++) {
196		ctx = &cf->ctx[i];
197		for (j = 0; j < ctx->nb_dev; j++) {
198			port_id = ctx->dev[j].port;
199			queue_id = ctx->dev[j].queue;
200			pcf = &cf->port[port_id];
201
202			if (queue_id >= MAX_PORT_QUEUE)
203				return -EINVAL;
204
205			mask = 1 << queue_id;
206
207			if (pcf->queue_map & mask)
208				/* tldk_port_conf already has the queue */
209				return -EEXIST;
210
211			pcf->queue_map |= mask;
212			if (pcf->nb_queues <= queue_id)
213				pcf->nb_queues = queue_id + 1;
214		}
215	}
216
217	return 0;
218}
219
220static ngx_int_t
221tldk_module_init(ngx_cycle_t *cycle)
222{
223	int32_t rc;
224	uint32_t i, j, wrk, num, lc, ctx_lim;
225	tldk_conf_t *cf;
226	struct tldk_ctx *tcx;
227
228	cf = (tldk_conf_t *)ngx_get_conf(cycle->conf_ctx, ngx_tldk_module);
229
230	rc = rte_eal_init(cf->eal_argc, cf->eal_argv);
231	if (rc < 0) {
232		RTE_LOG(ERR, USER1,
233			"%s: rte_eal_init failed with error code: %d\n",
234			__func__, rc);
235		return NGX_ERROR;
236	}
237
238	rc = process_conf(cf);
239	if (rc < 0) {
240		RTE_LOG(ERR, USER1,
241			"%s: process_conf failed with error code: %d\n",
242			__func__, rc);
243		return NGX_ERROR;
244	}
245
246	/* port initialization */
247	rc = be_port_init(cf);
248	if (rc != 0) {
249		RTE_LOG(ERR, USER1,
250			"%s: be_port_init failed with error code: %d\n",
251			__func__, rc);
252
253		return NGX_ERROR;
254	}
255
256	/* initialise TLDK contexts */
257	for (i = 0; i != cf->nb_ctx; i++) {
258		wrk = cf->ctx[i].worker;
259		rc = init_context(wrk2ctx + wrk, cf->ctx + i, cf);
260		if (rc != 0)
261			break;
262	}
263
264	if (i != cf->nb_ctx) {
265		for (j = 0; j != i; j++) {
266			wrk = cf->ctx[j].worker;
267			fini_context(wrk2ctx + wrk);
268		}
269		RTE_LOG(ERR, USER1,
270			"%s: init_context failed with error code: %d\n",
271			__func__, rc);
272		return NGX_ERROR;
273	}
274
275	/* start the ports */
276	for (i = 0; i != cf->nb_port; i++) {
277		RTE_LOG(NOTICE, USER1, "%s: starting port %u\n",
278			__func__, cf->port[i].id);
279
280		rc = rte_eth_dev_start(cf->port[i].id);
281		if (rc != 0) {
282			RTE_LOG(ERR, USER1,
283				"%s: rte_eth_dev_start(%u) returned "
284				"error code: %d\n",
285				__func__, cf->port[i].id, rc);
286			goto freectx;
287		}
288	}
289
290	/* accumulate all tldk_ctx(s) that belongs to one be lcore */
291	for (i = 0; i != cf->nb_ctx; i++) {
292		tcx = &wrk2ctx[cf->ctx[i].worker];
293		/* setup rx callbacks */
294		rc = be_lcore_setup(tcx);
295		if (rc != 0) {
296			RTE_LOG(ERR, USER1,
297					"%s: be_lcore_setup failed with error "
298					"code: %d\n", __func__, rc);
299			goto freectx;
300		}
301
302		if (tcx->cf->be_in_worker)
303			continue;
304
305		lc = cf->ctx[i].lcore;
306		num = lc_ctxs[lc].nb_ctxs;
307		ctx_lim = RTE_DIM(lc_ctxs[lc].ctxs);
308
309		if (num < ctx_lim) {
310			lc_ctxs[lc].ctxs[num] = tcx;
311			lc_ctxs[lc].nb_ctxs++;
312		} else {
313			RTE_LOG(ERR, USER1,
314				"%s: cannot assign more than supported %u "
315				"ctx(s) for the given lcore %u\n",
316				__func__, ctx_lim, lc);
317			goto freectx;
318		}
319	}
320
321	/*
322	 * launch slave lcores with lcore_main_tcp to handle
323	 * multiple tldk_ctx(s) of that lcore.
324	 */
325	for (i = 0; i < RTE_MAX_LCORE; i++) {
326		if (lc_ctxs[i].nb_ctxs != 0) {
327			if (be_check_lcore(i) != 0 ||
328					rte_eal_remote_launch(be_lcore_main,
329						&lc_ctxs[i], i) != 0) {
330				RTE_LOG(ERR, USER1,
331						"%s: failed to launch "
332						"be_lcore_main for core =%u\n",
333						__func__, i);
334				goto freectx;
335			}
336		}
337	}
338
339	return NGX_OK;
340
341freectx:
342	tldk_module_fini(cycle);
343	return NGX_ERROR;
344}
345
346static int
347tldk_open_listening(ngx_cycle_t *cycle, struct tldk_ctx *tcx)
348{
349	uint32_t i;
350	ngx_listening_t *ls;
351	char host[NI_MAXHOST];
352	char srv[NI_MAXSERV];
353
354	ls = cycle->listening.elts;
355	for (i = 0; i != cycle->listening.nelts; i++) {
356
357		if (ls[i].ignore != 0 || ls[i].listen == 0)
358			continue;
359
360		ngx_close_socket(ls[i].fd);
361		ls[i].fd = -1;
362
363		getnameinfo(ls[i].sockaddr, ls[i].socklen,
364			host, sizeof(host), srv, sizeof(srv),
365			NI_NUMERICHOST | NI_NUMERICSERV);
366
367		ls[i].fd = tldk_open_bind_listen(tcx,
368			ls[i].sockaddr->sa_family, ls[i].type,
369			ls[i].sockaddr, ls[i].socklen,
370			ls[i].backlog);
371
372		RTE_LOG(NOTICE, USER1, "%s(worker=%lu): "
373			"listen() for %s:%s returns %d, errno=%d;\n",
374			__func__, ngx_worker, host, srv, ls[i].fd, errno);
375
376		if (ls[i].fd == -1)
377			return NGX_ERROR;
378	}
379
380	return NGX_OK;
381}
382
383static void
384tldk_process_fini(ngx_cycle_t *cycle)
385{
386	struct tldk_ctx *tcx;
387	tcx =  wrk2ctx + ngx_worker;
388
389	tldk_stbl_fini();
390	if (tcx->cf->be_in_worker != 0)
391		be_lcore_clear(tcx);
392}
393
394
395static ngx_int_t
396tldk_process_init(ngx_cycle_t *cycle)
397{
398	ngx_event_conf_t  *ecf;
399	int32_t rc;
400
401	if (ngx_process != NGX_PROCESS_WORKER)
402		return NGX_OK;
403
404	rc = tldk_stbl_init(cycle, wrk2ctx + ngx_worker);
405	if (rc != 0)
406		return NGX_ERROR;
407
408	rc = tldk_open_listening(cycle, wrk2ctx + ngx_worker);
409	if (rc != 0)
410		return NGX_ERROR;
411
412	/* use tldk event module from now on*/
413	ecf = ngx_event_get_conf(cycle->conf_ctx, ngx_event_core_module);
414	ecf->use = ngx_tldk_event_module.ctx_index;
415
416	return NGX_OK;
417}
418
419static char *
420tldk_conf_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
421{
422	char *rv;
423	ngx_conf_t save;
424
425	save = *cf;
426	cf->handler = tldk_block_parse;
427	cf->handler_conf = conf;
428	rv = ngx_conf_parse(cf, NULL);
429	*cf = save;
430
431	return rv;
432}
433
434static char *
435tldk_ctx_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
436{
437	char *rv;
438	tldk_conf_t *tcf;
439	struct tldk_ctx_conf *tcx;
440	ngx_conf_t save;
441
442	tcf = (tldk_conf_t *)((void **)conf)[0];
443	if (tcf->nb_ctx >= RTE_DIM(tcf->ctx))
444		return NGX_CONF_ERROR;
445
446	/* setup default non-zero values, if any */
447	tcx = tcf->ctx + tcf->nb_ctx;
448	tcx->tcp_timewait = TLE_TCP_TIMEWAIT_DEFAULT;
449
450	save = *cf;
451	cf->handler = tldk_ctx_parse;
452	cf->handler_conf = conf;
453	rv = ngx_conf_parse(cf, NULL);
454	*cf = save;
455
456	if (rv == NGX_CONF_OK)
457		tcf->nb_ctx++;
458
459	return rv;
460}
461
462/*
463 * define NGX TLDK module.
464 */
465
466static ngx_command_t tldk_commands[] = {
467
468	{
469		.name = ngx_string("tldk_main"),
470		.type = NGX_MAIN_CONF|NGX_CONF_BLOCK|NGX_CONF_NOARGS,
471		.set = tldk_conf_block,
472	},
473	{
474		.name = ngx_string("tldk_ctx"),
475		.type = NGX_MAIN_CONF|NGX_CONF_BLOCK|NGX_CONF_NOARGS,
476		.set = tldk_ctx_block,
477	},
478	ngx_null_command,
479};
480
481static ngx_core_module_t tldk_module_ctx = {
482	ngx_string("tldk"),
483	tldk_module_create_conf,
484	tldk_module_init_conf
485};
486
487ngx_module_t ngx_tldk_module = {
488	NGX_MODULE_V1,
489	&tldk_module_ctx,             /* module context */
490	tldk_commands,                /* module directives */
491	NGX_CORE_MODULE,              /* module type */
492	NULL,                         /* init master */
493	tldk_module_init,             /* init module */
494	tldk_process_init,            /* init process */
495	NULL,                         /* init thread */
496	NULL,                         /* exit thread */
497	tldk_process_fini,            /* exit process */
498	tldk_module_fini,             /* exit master */
499	NGX_MODULE_V1_PADDING
500};
501