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