parse.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 <ngx_config.h>
28#include <ngx_core.h>
29
30#include <ngx_tldk.h>
31
32union parse_val {
33	uint64_t u64;
34	struct {
35		uint16_t family;
36		 union {
37			struct in_addr addr4;
38			struct in6_addr addr6;
39		};
40	} in;
41	struct ether_addr mac;
42	rte_cpuset_t cpuset;
43};
44
45struct key_handler {
46	const char *name;
47	int (*func)(const char *, void *);
48};
49
50static int
51parse_uint_val(const char *val, void *prm)
52{
53	union parse_val *rv;
54	unsigned long v;
55	char *end;
56
57	rv = prm;
58	errno = 0;
59	v = strtoul(val, &end, 0);
60	if (errno != 0 || end[0] != 0 || v > UINT32_MAX)
61		return -EINVAL;
62
63	rv->u64 = v;
64	return 0;
65}
66
67static int
68parse_ipv4_val(const char *val, void *prm)
69{
70	union parse_val *rv;
71
72	rv = prm;
73	if (inet_pton(AF_INET, val, &rv->in.addr4) != 1)
74		return -EINVAL;
75	rv->in.family = AF_INET;
76	return 0;
77}
78
79static int
80parse_ipv6_val(const char *val, void *prm)
81{
82	union parse_val *rv;
83
84	rv = prm;
85	if (inet_pton(AF_INET6, val, &rv->in.addr6) != 1)
86		return -EINVAL;
87	rv->in.family = AF_INET6;
88	return 0;
89}
90
91static int
92parse_ip_val(const char *val, void *prm)
93{
94	if (parse_ipv6_val(val, prm) != 0 &&
95			parse_ipv4_val(val, prm) != 0)
96		return -EINVAL;
97	return 0;
98}
99
100#define PARSE_UINT8x16(s, v, l)	                          \
101do {                                                      \
102	char *end;                                        \
103	unsigned long t;                                  \
104	errno = 0;                                        \
105	t = strtoul((s), &end, 16);                       \
106	if (errno != 0 || end[0] != (l) || t > UINT8_MAX) \
107		return -EINVAL;                           \
108	(s) = end + 1;                                    \
109	(v) = t;                                          \
110} while (0)
111
112static int
113parse_mac_val(const char *val, void *prm)
114{
115	union parse_val *rv;
116	const char *s;
117
118	rv = prm;
119	s = val;
120
121	PARSE_UINT8x16(s, rv->mac.addr_bytes[0], ':');
122	PARSE_UINT8x16(s, rv->mac.addr_bytes[1], ':');
123	PARSE_UINT8x16(s, rv->mac.addr_bytes[2], ':');
124	PARSE_UINT8x16(s, rv->mac.addr_bytes[3], ':');
125	PARSE_UINT8x16(s, rv->mac.addr_bytes[4], ':');
126	PARSE_UINT8x16(s, rv->mac.addr_bytes[5], 0);
127	return 0;
128}
129
130static char *
131tldk_port_parse(ngx_conf_t *cf, struct tldk_port_conf *prt)
132{
133	uint32_t i, j;
134	ngx_str_t *v;
135
136	static const struct key_handler kh[] = {
137		{
138			.name = "port",
139			.func = parse_uint_val,
140		},
141		{
142			.name = "mtu",
143			.func = parse_uint_val,
144		},
145		{
146			.name = "rx_offload",
147			.func = parse_uint_val,
148		},
149		{
150			.name = "tx_offload",
151			.func = parse_uint_val,
152		},
153		{
154			.name = "ipv4",
155			.func = parse_ipv4_val,
156		},
157		{
158			.name = "ipv6",
159			.func = parse_ipv6_val,
160		},
161	};
162
163	union parse_val pvl[RTE_DIM(kh)];
164
165	memset(pvl, 0, sizeof(pvl));
166	pvl[1].u64 = ETHER_MAX_LEN - ETHER_CRC_LEN;
167
168	if (cf->args->nelts % 2 != 0)
169		return NGX_CONF_ERROR;
170
171	v = cf->args->elts;
172	for (i = 0; i != cf->args->nelts; i += 2) {
173
174		for (j = 0; j != RTE_DIM(kh); j++) {
175			if (ngx_strcmp(v[i].data, kh[j].name) == 0) {
176				 if (kh[j].func((const char *)v[i + 1].data,
177						pvl + j) < 0)
178					return NGX_CONF_ERROR;
179				else
180					break;
181			}
182		}
183
184		/* unknow key */
185		if (j == RTE_DIM(kh))
186			return NGX_CONF_ERROR;
187	}
188
189	memset(prt, 0, sizeof(*prt));
190
191	prt->id = pvl[0].u64;
192	prt->mtu = pvl[1].u64;
193	prt->rx_offload = pvl[2].u64;
194	prt->tx_offload = pvl[3].u64;
195	prt->ipv4 = pvl[4].in.addr4.s_addr;
196	prt->ipv6 = pvl[5].in.addr6;
197
198	return NGX_CONF_OK;
199}
200
201static char *
202tldk_dev_parse(ngx_conf_t *cf, struct tldk_dev_conf *dev,
203		tldk_conf_t *tcf)
204{
205	uint32_t i, j;
206	ngx_str_t *v;
207
208	static const struct key_handler kh[] = {
209		{
210			.name = "dev",
211			.func = parse_uint_val,
212		},
213		{
214			.name = "port",
215			.func = parse_uint_val,
216		},
217		{
218			.name = "queue",
219			.func = parse_uint_val,
220		},
221	};
222
223	union parse_val pvl[RTE_DIM(kh)];
224
225	memset(pvl, 0, sizeof(pvl));
226
227	if (cf->args->nelts % 2 != 0)
228		return NGX_CONF_ERROR;
229
230	v = cf->args->elts;
231	for (i = 0; i != cf->args->nelts; i += 2) {
232
233		for (j = 0; j != RTE_DIM(kh); j++) {
234			if (ngx_strcmp(v[i].data, kh[j].name) == 0) {
235				 if (kh[j].func((const char *)v[i + 1].data,
236						pvl + j) < 0)
237					return NGX_CONF_ERROR;
238				else
239					break;
240			}
241		}
242
243		/* unknow key */
244		if (j == RTE_DIM(kh))
245			return NGX_CONF_ERROR;
246	}
247
248	memset(dev, 0, sizeof(*dev));
249
250	dev->id = pvl[0].u64;
251	dev->port = pvl[1].u64;
252	dev->queue = pvl[2].u64;
253
254	return NGX_CONF_OK;
255}
256
257static char *
258tldk_dest_parse(ngx_conf_t *cf, struct tldk_dest_conf *dst)
259{
260	uint32_t i, j;
261	ngx_str_t *v;
262
263	static const struct key_handler kh[] = {
264		{
265			.name = "dev",
266			.func = parse_uint_val,
267		},
268		{
269			.name = "mtu",
270			.func = parse_uint_val,
271		},
272		{
273			.name = "masklen",
274			.func = parse_uint_val,
275		},
276		{
277			.name = "addr",
278			.func = parse_ip_val,
279		},
280		{
281			.name = "mac",
282			.func = parse_mac_val,
283		},
284	};
285
286	union parse_val pvl[RTE_DIM(kh)];
287
288	memset(pvl, 0, sizeof(pvl));
289	pvl[1].u64 = ETHER_MAX_LEN - ETHER_CRC_LEN;
290
291	if (cf->args->nelts % 2 != 1 || cf->args->nelts == 1)
292		return NGX_CONF_ERROR;
293
294	v = cf->args->elts;
295	for (i = 1; i != cf->args->nelts; i += 2) {
296
297		for (j = 0; j != RTE_DIM(kh); j++) {
298			if (ngx_strcmp(v[i].data, kh[j].name) == 0) {
299				 if (kh[j].func((const char *)v[i + 1].data,
300						pvl + j) < 0)
301					return NGX_CONF_ERROR;
302				else
303					break;
304			}
305		}
306
307		/* unknow key */
308		if (j == RTE_DIM(kh))
309			return NGX_CONF_ERROR;
310	}
311
312	memset(dst, 0, sizeof(*dst));
313
314	dst->dev = pvl[0].u64;
315	dst->mtu = pvl[1].u64;
316	dst->prfx = pvl[2].u64;
317
318	dst->family = pvl[3].in.family;
319	if (pvl[3].in.family == AF_INET)
320		dst->ipv4 = pvl[3].in.addr4;
321	else
322		dst->ipv6 = pvl[3].in.addr6;
323
324	memcpy(&dst->mac, &pvl[4].mac, sizeof(dst->mac));
325
326	return NGX_CONF_OK;
327}
328
329char *
330tldk_block_parse(ngx_conf_t *cf, ngx_command_t *dummy, void *conf)
331{
332	uint32_t i, len, n;
333	tldk_conf_t *tcf;
334	ngx_str_t *v;
335	char *rv, *s;
336	struct tldk_port_conf prt;
337
338	tcf = (tldk_conf_t *)((void **)conf)[0];
339	v = cf->args->elts;
340
341	if (ngx_strcmp(v[0].data, "eal_cmd") == 0) {
342
343		if (cf->args->nelts == 1 ||
344				cf->args->nelts > RTE_DIM(tcf->eal_argv))
345			return NGX_CONF_ERROR;
346
347		s = tcf->eal_cmd;
348		len = sizeof(tcf->eal_cmd);
349		for (i = 0; i != cf->args->nelts; i++) {
350			n = snprintf(s, len, "%s", v[i].data) + 1;
351			if (n > len)
352				return NGX_CONF_ERROR;
353			tcf->eal_argv[i] = s;
354			s += n;
355			len -= n;
356		}
357
358		tcf->eal_argc = i;
359		return NGX_CONF_OK;
360
361	} else if (ngx_strcmp(v[0].data, "port") == 0) {
362
363		rv = tldk_port_parse(cf, &prt);
364		if (rv == NGX_CONF_OK) {
365
366			/* too many ports */
367			if (tcf->nb_port >= RTE_DIM(tcf->port))
368				return NGX_CONF_ERROR;
369
370			/* copy stuff */
371			tcf->port[tcf->nb_port++] = prt;
372		}
373		return rv;
374	}
375
376	return NGX_CONF_ERROR;
377}
378
379char *
380tldk_ctx_parse(ngx_conf_t *cf, ngx_command_t *dummy, void *conf)
381{
382	char *rv;
383	ngx_str_t *v;
384	tldk_conf_t *tcf;
385	struct tldk_ctx_conf *tcx;
386	union parse_val pvl;
387
388	tcf = (tldk_conf_t *)((void **)conf)[0];
389	tcx = tcf->ctx + tcf->nb_ctx;
390	v = cf->args->elts;
391
392	if (ngx_strcmp(v[0].data, "worker") == 0) {
393		if (cf->args->nelts != 2 ||
394				parse_uint_val((const char *)v[1].data,
395					&pvl) < 0)
396			return NGX_CONF_ERROR;
397		tcx->worker = pvl.u64;
398	} else if (ngx_strcmp(v[0].data, "lcore") == 0) {
399		if (cf->args->nelts != 2 ||
400				parse_uint_val((const char *)v[1].data,
401					&pvl) < 0)
402			return NGX_CONF_ERROR;
403		tcx->lcore = pvl.u64;
404	} else if (ngx_strcmp(v[0].data, "mbufs") == 0) {
405		if (cf->args->nelts != 2 ||
406				parse_uint_val((const char *)v[1].data,
407					&pvl) < 0)
408			return NGX_CONF_ERROR;
409		tcx->nb_mbuf = pvl.u64;
410	} else if (ngx_strcmp(v[0].data, "streams") == 0) {
411		if (cf->args->nelts != 2 ||
412				parse_uint_val((const char *)v[1].data,
413					&pvl) < 0)
414			return NGX_CONF_ERROR;
415		tcx->nb_stream = pvl.u64;
416	} else if (ngx_strcmp(v[0].data, "rbufs") == 0) {
417		if (cf->args->nelts != 2 ||
418				parse_uint_val((const char *)v[1].data,
419					&pvl) < 0)
420			return NGX_CONF_ERROR;
421		tcx->nb_rbuf = pvl.u64;
422	} else if (ngx_strcmp(v[0].data, "sbufs") == 0) {
423		if (cf->args->nelts != 2 ||
424				parse_uint_val((const char *)v[1].data,
425					&pvl) < 0)
426			return NGX_CONF_ERROR;
427		tcx->nb_sbuf = pvl.u64;
428	} else if (ngx_strcmp(v[0].data, "be_in_worker") == 0) {
429		if (cf->args->nelts != 1)
430			return NGX_CONF_ERROR;
431		tcx->be_in_worker = 1;
432	} else if (ngx_strcmp(v[0].data, "tcp_timewait") == 0) {
433		if (cf->args->nelts != 2 ||
434				parse_uint_val((const char *)v[1].data,
435					&pvl) < 0)
436			return NGX_CONF_ERROR;
437		tcx->tcp_timewait = pvl.u64;
438	} else if (ngx_strcmp(v[0].data, "dev") == 0) {
439		if (tcx->nb_dev >= RTE_DIM(tcx->dev))
440			return NGX_CONF_ERROR;
441		rv = tldk_dev_parse(cf, tcx->dev + tcx->nb_dev, tcf);
442		if (rv != NGX_CONF_OK)
443			return rv;
444		tcx->nb_dev++;
445			return rv;
446	} else if (ngx_strcmp(v[0].data, "dest") == 0) {
447		if (tcx->nb_dest >= RTE_DIM(tcx->dest))
448			return NGX_CONF_ERROR;
449		rv = tldk_dest_parse(cf, tcx->dest + tcx->nb_dest);
450		if (rv != NGX_CONF_OK)
451			return rv;
452		tcx->nb_dest++;
453	}
454
455	return NGX_CONF_OK;
456}
457