1/*
2 * Copyright (c) 2016-2017  Intel Corporation.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at:
6 *
7 *     http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16#include <stdlib.h>
17#include <stdio.h>
18#include <string.h>
19#include <sys/stat.h>
20#include <unistd.h>
21#include <fcntl.h>
22
23#include "netbe.h"
24#include "parse.h"
25
26#define DEF_LINE_NUM	0x400
27
28static const struct {
29	const char *name;
30	uint16_t op;
31} name2feop[] = {
32	{ .name = "rx", .op = RXONLY,},
33	{ .name = "tx", .op = TXONLY,},
34	{ .name = "echo", .op = ECHO,},
35	{ .name = "rxtx", .op = RXTX,},
36	{ .name = "fwd", .op = FWD,},
37};
38
39#define	OPT_SHORT_SBULK		'B'
40#define	OPT_LONG_SBULK		"sburst"
41
42#define	OPT_SHORT_CTXFLAGS	'C'
43#define	OPT_LONG_CTXFLAGS	"ctxflags"
44
45#define	OPT_SHORT_PROMISC	'P'
46#define	OPT_LONG_PROMISC	"promisc"
47
48#define	OPT_SHORT_MBUFNUM	'M'
49#define	OPT_LONG_MBUFNUM	"mbuf-num"
50
51#define	OPT_SHORT_RBUFS	'R'
52#define	OPT_LONG_RBUFS	"rbufs"
53
54#define	OPT_SHORT_SBUFS	'S'
55#define	OPT_LONG_SBUFS	"sbufs"
56
57#define	OPT_SHORT_ARP		'a'
58#define	OPT_LONG_ARP		"enable-arp"
59
60#define	OPT_SHORT_BECFG	'b'
61#define	OPT_LONG_BECFG	"becfg"
62
63#define	OPT_SHORT_TXCNT	'c'
64#define	OPT_LONG_TXCNT	"txcnt"
65
66#define	OPT_SHORT_FECFG	'f'
67#define	OPT_LONG_FECFG	"fecfg"
68
69#define	OPT_SHORT_STREAMS	's'
70#define	OPT_LONG_STREAMS	"streams"
71
72#define	OPT_SHORT_UDP	'U'
73#define	OPT_LONG_UDP	"udp"
74
75#define	OPT_SHORT_TCP	'T'
76#define	OPT_LONG_TCP	"tcp"
77
78#define	OPT_SHORT_LISTEN	'L'
79#define	OPT_LONG_LISTEN		"listen"
80
81#define OPT_SHORT_HASH         'H'
82#define OPT_LONG_HASH          "hash"
83
84#define OPT_SHORT_SEC_KEY         'K'
85#define OPT_LONG_SEC_KEY          "seckey"
86
87#define	OPT_SHORT_VERBOSE	'v'
88#define	OPT_LONG_VERBOSE	"verbose"
89
90#define	OPT_SHORT_WINDOW	'w'
91#define	OPT_LONG_WINDOW		"initial-window"
92
93#define	OPT_SHORT_TIMEWAIT	'W'
94#define	OPT_LONG_TIMEWAIT	"timewait"
95
96static const struct option long_opt[] = {
97	{OPT_LONG_ARP, 1, 0, OPT_SHORT_ARP},
98	{OPT_LONG_SBULK, 1, 0, OPT_SHORT_SBULK},
99	{OPT_LONG_CTXFLAGS, 1, 0, OPT_SHORT_CTXFLAGS},
100	{OPT_LONG_PROMISC, 0, 0, OPT_SHORT_PROMISC},
101	{OPT_LONG_MBUFNUM, 1, 0, OPT_SHORT_MBUFNUM},
102	{OPT_LONG_RBUFS, 1, 0, OPT_SHORT_RBUFS},
103	{OPT_LONG_SBUFS, 1, 0, OPT_SHORT_SBUFS},
104	{OPT_LONG_BECFG, 1, 0, OPT_SHORT_BECFG},
105	{OPT_LONG_FECFG, 1, 0, OPT_SHORT_FECFG},
106	{OPT_LONG_STREAMS, 1, 0, OPT_SHORT_STREAMS},
107	{OPT_LONG_UDP, 0, 0, OPT_SHORT_UDP},
108	{OPT_LONG_TCP, 0, 0, OPT_SHORT_TCP},
109	{OPT_LONG_HASH, 1, 0, OPT_SHORT_HASH},
110	{OPT_LONG_SEC_KEY, 1, 0, OPT_SHORT_SEC_KEY},
111	{OPT_LONG_LISTEN, 0, 0, OPT_SHORT_LISTEN},
112	{OPT_LONG_VERBOSE, 1, 0, OPT_SHORT_VERBOSE},
113	{OPT_LONG_WINDOW, 1, 0, OPT_SHORT_WINDOW},
114	{OPT_LONG_TIMEWAIT, 1, 0, OPT_SHORT_TIMEWAIT},
115	{OPT_LONG_TXCNT, 1, 0, OPT_SHORT_TXCNT},
116	{NULL, 0, 0, 0}
117};
118
119static int
120parse_uint_val(__rte_unused const char *key, const char *val, void *prm)
121{
122	union parse_val *rv;
123	unsigned long v;
124	char *end;
125
126	rv = prm;
127	errno = 0;
128	v = strtoul(val, &end, 0);
129	if (errno != 0 || end[0] != 0 || v > UINT32_MAX)
130		return -EINVAL;
131
132	rv->u64 = v;
133	return 0;
134}
135
136static int
137parse_ipv4_val(__rte_unused const char *key, const char *val, void *prm)
138{
139	union parse_val *rv;
140
141	rv = prm;
142	if (inet_pton(AF_INET, val, &rv->in.addr4) != 1)
143		return -EINVAL;
144	rv->in.family = AF_INET;
145	return 0;
146}
147
148static int
149parse_ipv6_val(__rte_unused const char *key, const char *val, void *prm)
150{
151	union parse_val *rv;
152
153	rv = prm;
154	if (inet_pton(AF_INET6, val, &rv->in.addr6) != 1)
155		return -EINVAL;
156	rv->in.family = AF_INET6;
157	return 0;
158}
159
160static int
161parse_ip_val(__rte_unused const char *key, const char *val, void *prm)
162{
163	if (parse_ipv6_val(key, val, prm) != 0 &&
164			parse_ipv4_val(key, val, prm) != 0)
165		return -EINVAL;
166	return 0;
167}
168
169#define PARSE_UINT8x16(s, v, l)	                          \
170do {                                                      \
171	char *end;                                        \
172	unsigned long t;                                  \
173	errno = 0;                                        \
174	t = strtoul((s), &end, 16);                       \
175	if (errno != 0 || end[0] != (l) || t > UINT8_MAX) \
176		return -EINVAL;                           \
177	(s) = end + 1;                                    \
178	(v) = t;                                          \
179} while (0)
180
181static int
182parse_mac_val(__rte_unused const char *key, const char *val, void *prm)
183{
184	union parse_val *rv;
185	const char *s;
186
187	rv = prm;
188	s = val;
189
190	PARSE_UINT8x16(s, rv->mac.addr_bytes[0], ':');
191	PARSE_UINT8x16(s, rv->mac.addr_bytes[1], ':');
192	PARSE_UINT8x16(s, rv->mac.addr_bytes[2], ':');
193	PARSE_UINT8x16(s, rv->mac.addr_bytes[3], ':');
194	PARSE_UINT8x16(s, rv->mac.addr_bytes[4], ':');
195	PARSE_UINT8x16(s, rv->mac.addr_bytes[5], 0);
196	return 0;
197}
198
199static int
200parse_feop_val(__rte_unused const char *key, const char *val, void *prm)
201{
202	uint32_t i;
203	union parse_val *rv;
204
205	rv = prm;
206	for (i = 0; i != RTE_DIM(name2feop); i++) {
207		if (strcmp(val, name2feop[i].name) == 0) {
208			rv->u64 = name2feop[i].op;
209			return 0;
210		}
211	}
212
213	return -EINVAL;
214}
215
216static int
217parse_lcore_list_val(__rte_unused const char *key, const char *val, void *prm)
218{
219	union parse_val *rv;
220	unsigned long a, b;
221	uint32_t i;
222	char *end;
223
224	rv = prm;
225
226	errno = 0;
227	a = strtoul(val, &end, 0);
228	if (errno != 0 || (end[0] != 0 && end[0] != '-') || a > UINT32_MAX)
229		return -EINVAL;
230
231	if (end[0] == '-') {
232		val = end + 1;
233		errno = 0;
234		b = strtoul(val, &end, 0);
235		if (errno != 0 || end[0] != 0 || b > UINT32_MAX)
236			return -EINVAL;
237	} else
238		b = a;
239
240	if (a <= b) {
241		for (i = a; i <= b; i++)
242			CPU_SET(i, &rv->cpuset);
243	} else {
244		RTE_LOG(ERR, USER1,
245			"%s: lcores not in ascending order\n", __func__);
246		return -EINVAL;
247	}
248
249	return 0;
250}
251
252static int
253parse_kvargs(const char *arg, const char *keys_man[], uint32_t nb_man,
254	const char *keys_opt[], uint32_t nb_opt,
255	const arg_handler_t hndl[], union parse_val val[])
256{
257	uint32_t j, k;
258	struct rte_kvargs *kvl;
259
260	kvl = rte_kvargs_parse(arg, NULL);
261	if (kvl == NULL) {
262		RTE_LOG(ERR, USER1,
263			"%s: invalid parameter: %s\n",
264			__func__, arg);
265		return -EINVAL;
266	}
267
268	for (j = 0; j != nb_man; j++) {
269		if (rte_kvargs_count(kvl, keys_man[j]) == 0) {
270			RTE_LOG(ERR, USER1,
271				"%s: %s missing mandatory key: %s\n",
272				__func__, arg, keys_man[j]);
273			rte_kvargs_free(kvl);
274			return -EINVAL;
275		}
276	}
277
278	for (j = 0; j != nb_man; j++) {
279		if (rte_kvargs_process(kvl, keys_man[j], hndl[j],
280				val + j) != 0) {
281			RTE_LOG(ERR, USER1,
282				"%s: %s invalid value for man key: %s\n",
283				__func__, arg, keys_man[j]);
284			rte_kvargs_free(kvl);
285			return -EINVAL;
286		}
287	}
288
289	for (j = 0; j != nb_opt; j++) {
290		k = j + nb_man;
291		if (rte_kvargs_process(kvl, keys_opt[j], hndl[k],
292				val + k) != 0) {
293			RTE_LOG(ERR, USER1,
294				"%s: %s invalid value for opt key: %s\n",
295				__func__, arg, keys_opt[j]);
296			rte_kvargs_free(kvl);
297			return -EINVAL;
298		}
299	}
300
301	rte_kvargs_free(kvl);
302	return 0;
303}
304
305int
306parse_netbe_arg(struct netbe_port *prt, const char *arg, rte_cpuset_t *pcpu)
307{
308	int32_t rc;
309	uint32_t i, j, nc;
310
311	static const char *keys_man[] = {
312		"port",
313		"lcore",
314	};
315
316	static const char *keys_opt[] = {
317		"mtu",
318		"rx_offload",
319		"tx_offload",
320		"ipv4",
321		"ipv6",
322	};
323
324	static const arg_handler_t hndl[] = {
325		parse_uint_val,
326		parse_lcore_list_val,
327		parse_uint_val,
328		parse_uint_val,
329		parse_uint_val,
330		parse_ipv4_val,
331		parse_ipv6_val,
332	};
333
334	union parse_val val[RTE_DIM(hndl)];
335
336	memset(val, 0, sizeof(val));
337	val[2].u64 = ETHER_MAX_LEN - ETHER_CRC_LEN;
338
339	rc = parse_kvargs(arg, keys_man, RTE_DIM(keys_man),
340		keys_opt, RTE_DIM(keys_opt), hndl, val);
341	if (rc != 0)
342		return rc;
343
344	prt->id = val[0].u64;
345
346	for (i = 0, nc = 0; i < RTE_MAX_LCORE; i++)
347		nc += CPU_ISSET(i, &val[1].cpuset);
348	prt->lcore_id = rte_zmalloc(NULL, nc * sizeof(prt->lcore_id[0]),
349		RTE_CACHE_LINE_SIZE);
350	prt->nb_lcore = nc;
351
352	for (i = 0, j = 0; i < RTE_MAX_LCORE; i++)
353		if (CPU_ISSET(i, &val[1].cpuset))
354			prt->lcore_id[j++] = i;
355	CPU_OR(pcpu, pcpu, &val[1].cpuset);
356
357	prt->mtu = val[2].u64;
358	prt->rx_offload = val[3].u64;
359	prt->tx_offload = val[4].u64;
360	prt->ipv4 = val[5].in.addr4.s_addr;
361	prt->ipv6 = val[6].in.addr6;
362
363	return 0;
364}
365
366static int
367check_netbe_dest(const struct netbe_dest *dst)
368{
369	if (dst->port >= RTE_MAX_ETHPORTS) {
370		RTE_LOG(ERR, USER1, "%s(line=%u) invalid port=%u",
371			__func__, dst->line, dst->port);
372		return -EINVAL;
373	} else if ((dst->family == AF_INET &&
374			dst->prfx > sizeof(struct in_addr) * CHAR_BIT) ||
375			(dst->family == AF_INET6 &&
376			dst->prfx > sizeof(struct in6_addr) * CHAR_BIT)) {
377		RTE_LOG(ERR, USER1, "%s(line=%u) invalid masklen=%u",
378			__func__, dst->line, dst->prfx);
379		return -EINVAL;
380	} else if (dst->mtu > ETHER_MAX_JUMBO_FRAME_LEN - ETHER_CRC_LEN) {
381		RTE_LOG(ERR, USER1, "%s(line=%u) invalid mtu=%u",
382			__func__, dst->line, dst->mtu);
383		return -EINVAL;
384	}
385	return 0;
386}
387
388static int
389parse_netbe_dest(struct netbe_dest *dst, const char *arg)
390{
391	int32_t rc;
392
393	static const char *keys_man[] = {
394		"port",
395		"addr",
396		"masklen",
397		"mac",
398	};
399
400	static const char *keys_opt[] = {
401		"mtu",
402	};
403
404	static const arg_handler_t hndl[] = {
405		parse_uint_val,
406		parse_ip_val,
407		parse_uint_val,
408		parse_mac_val,
409		parse_uint_val,
410	};
411
412	union parse_val val[RTE_DIM(hndl)];
413
414	/* set default values. */
415	memset(val, 0, sizeof(val));
416	val[4].u64 = ETHER_MAX_JUMBO_FRAME_LEN - ETHER_CRC_LEN;
417
418	rc = parse_kvargs(arg, keys_man, RTE_DIM(keys_man),
419		keys_opt, RTE_DIM(keys_opt), hndl, val);
420	if (rc != 0)
421		return rc;
422
423	dst->port = val[0].u64;
424	dst->family = val[1].in.family;
425	if (val[1].in.family == AF_INET)
426		dst->ipv4 = val[1].in.addr4;
427	else
428		dst->ipv6 = val[1].in.addr6;
429	dst->prfx = val[2].u64;
430	memcpy(&dst->mac, &val[3].mac, sizeof(dst->mac));
431	dst->mtu = val[4].u64;
432
433	return 0;
434}
435
436int
437netbe_parse_dest(const char *fname, struct netbe_dest_prm *prm)
438{
439	uint32_t i, ln, n, num;
440	int32_t rc;
441	size_t sz;
442	char *s;
443	FILE *f;
444	struct netbe_dest *dp;
445	char line[LINE_MAX];
446
447	f = fopen(fname, "r");
448	if (f == NULL) {
449		RTE_LOG(ERR, USER1, "%s failed to open file \"%s\"\n",
450			__func__, fname);
451		return -EINVAL;
452	}
453
454	n = 0;
455	num = 0;
456	dp = NULL;
457	rc = 0;
458	for (ln = 0; fgets(line, sizeof(line), f) != NULL; ln++) {
459
460		/* skip spaces at the start. */
461		for (s = line; isspace(s[0]); s++)
462			;
463
464		/* skip comment line. */
465		if (s[0] == '#' || s[0] == 0)
466			continue;
467
468		/* skip spaces at the end. */
469		for (i = strlen(s); i-- != 0 && isspace(s[i]); s[i] = 0)
470			;
471
472		if (n == num) {
473			num += DEF_LINE_NUM;
474			sz = sizeof(dp[0]) * num;
475			dp = realloc(dp, sizeof(dp[0]) * num);
476			if (dp == NULL) {
477				RTE_LOG(ERR, USER1,
478					"%s(%s) allocation of %zu bytes "
479					"failed\n",
480					__func__, fname, sz);
481				rc = -ENOMEM;
482				break;
483			}
484			memset(&dp[n], 0, sizeof(dp[0]) * (num - n));
485		}
486
487		dp[n].line = ln + 1;
488		rc = parse_netbe_dest(dp + n, s);
489		rc = (rc != 0) ? rc : check_netbe_dest(dp + n);
490		if (rc != 0) {
491			RTE_LOG(ERR, USER1, "%s(%s) failed to parse line %u\n",
492				__func__, fname, dp[n].line);
493			break;
494		}
495		n++;
496	}
497
498	fclose(f);
499
500	if (rc != 0) {
501		free(dp);
502		dp = NULL;
503		n = 0;
504	}
505
506	prm->dest = dp;
507	prm->nb_dest = n;
508	return rc;
509}
510
511static void
512pv2saddr(struct sockaddr_storage *ss, const union parse_val *pva,
513	const union parse_val *pvp)
514{
515	ss->ss_family = pva->in.family;
516	if (pva->in.family == AF_INET) {
517		struct sockaddr_in *si = (struct sockaddr_in *)ss;
518		si->sin_addr = pva->in.addr4;
519		si->sin_port = rte_cpu_to_be_16((uint16_t)pvp->u64);
520	} else {
521		struct sockaddr_in6 *si = (struct sockaddr_in6 *)ss;
522		si->sin6_addr = pva->in.addr6;
523		si->sin6_port = rte_cpu_to_be_16((uint16_t)pvp->u64);
524	}
525}
526
527static int
528parse_netfe_arg(struct netfe_stream_prm *sp, const char *arg)
529{
530	int32_t rc;
531
532	static const char *keys_man[] = {
533		"lcore",
534		"op",
535		"laddr",
536		"lport",
537		"raddr",
538		"rport",
539	};
540
541	static const char *keys_opt[] = {
542		"txlen",
543		"fwladdr",
544		"fwlport",
545		"fwraddr",
546		"fwrport",
547		"belcore",
548		"rxlen",
549	};
550
551	static const arg_handler_t hndl[] = {
552		parse_uint_val,
553		parse_feop_val,
554		parse_ip_val,
555		parse_uint_val,
556		parse_ip_val,
557		parse_uint_val,
558		parse_uint_val,
559		parse_ip_val,
560		parse_uint_val,
561		parse_ip_val,
562		parse_uint_val,
563		parse_uint_val,
564		parse_uint_val,
565	};
566
567	union parse_val val[RTE_DIM(hndl)];
568
569	memset(val, 0, sizeof(val));
570	val[11].u64 = LCORE_ID_ANY;
571	rc = parse_kvargs(arg, keys_man, RTE_DIM(keys_man),
572		keys_opt, RTE_DIM(keys_opt), hndl, val);
573	if (rc != 0)
574		return rc;
575	sp->lcore = val[0].u64;
576	sp->op = val[1].u64;
577	pv2saddr(&sp->sprm.local_addr, val + 2, val + 3);
578	pv2saddr(&sp->sprm.remote_addr, val + 4, val + 5);
579	sp->txlen = val[6].u64;
580	pv2saddr(&sp->fprm.local_addr, val + 7, val + 8);
581	pv2saddr(&sp->fprm.remote_addr, val + 9, val + 10);
582	sp->belcore = val[11].u64;
583	sp->rxlen = val[12].u64;
584
585	return 0;
586}
587
588static const char *
589format_feop(uint16_t op)
590{
591	uint32_t i;
592
593	for (i = 0; i != RTE_DIM(name2feop); i++) {
594		if (name2feop[i].op == op)
595			return name2feop[i].name;
596	}
597
598	return NULL;
599}
600
601static int
602is_addr_wc(const struct sockaddr_storage *sp)
603{
604	const struct sockaddr_in *i4;
605	const struct sockaddr_in6 *i6;
606
607	if (sp->ss_family == AF_INET) {
608		i4 = (const struct sockaddr_in *)sp;
609		return  (i4->sin_addr.s_addr == INADDR_ANY);
610	} else if (sp->ss_family == AF_INET6) {
611		i6 = (const struct sockaddr_in6 *)sp;
612		return (memcmp(&i6->sin6_addr, &in6addr_any,
613			sizeof(i6->sin6_addr)) == 0);
614	}
615	return 0;
616}
617
618static int
619check_netfe_arg(const struct netfe_stream_prm *sp)
620{
621	char buf[INET6_ADDRSTRLEN];
622
623	if (sp->sprm.local_addr.ss_family !=
624			sp->sprm.remote_addr.ss_family) {
625		RTE_LOG(ERR, USER1, "invalid arg at line %u: "
626			"laddr and raddr for different protocols\n",
627			sp->line);
628		return -EINVAL;
629	}
630
631	if (sp->op == TXONLY) {
632		if (sp->txlen > RTE_MBUF_DEFAULT_DATAROOM || sp->txlen == 0) {
633			RTE_LOG(ERR, USER1, "invalid arg at line %u: txlen=%u "
634				"exceeds allowed values: (0, %u]\n",
635				sp->line, sp->txlen, RTE_MBUF_DEFAULT_DATAROOM);
636			return -EINVAL;
637		} else if (is_addr_wc(&sp->sprm.remote_addr)) {
638			RTE_LOG(ERR, USER1, "invalid arg at line %u: "
639				"raddr=%s are not allowed for op=%s;\n",
640				sp->line,
641				format_addr(&sp->sprm.remote_addr,
642				buf, sizeof(buf)),
643				format_feop(sp->op));
644			return -EINVAL;
645		}
646	} else if (sp->op == FWD) {
647		if (sp->fprm.local_addr.ss_family !=
648				sp->fprm.remote_addr.ss_family) {
649			RTE_LOG(ERR, USER1, "invalid arg at line %u: "
650				"fwladdr and fwraddr for different protocols\n",
651				sp->line);
652			return -EINVAL;
653		} else if (is_addr_wc(&sp->fprm.remote_addr)) {
654			RTE_LOG(ERR, USER1, "invalid arg at line %u: "
655				"fwaddr=%s are not allowed for op=%s;\n",
656				sp->line,
657				format_addr(&sp->fprm.remote_addr,
658				buf, sizeof(buf)),
659				format_feop(sp->op));
660			return -EINVAL;
661		}
662	} else if (sp->op == RXTX) {
663		/* RXTX: Check tx pkt size */
664		if (sp->txlen == 0) {
665			RTE_LOG(ERR, USER1, "invalid arg at line %u: "
666				"txlen cannot be zero.\n", sp->line);
667			return -EINVAL;
668		}
669		if (sp->rxlen == 0) {
670			RTE_LOG(ERR, USER1, "invalid arg at line %u: "
671				"rxlen cannot be zero.\n", sp->line);
672			return -EINVAL;
673		}
674	}
675
676	return 0;
677}
678
679int
680netfe_parse_cfg(const char *fname, struct netfe_lcore_prm *lp)
681{
682	uint32_t i, ln, n, num;
683	int32_t rc;
684	size_t sz;
685	char *s;
686	FILE *f;
687	struct netfe_stream_prm *sp;
688	char line[LINE_MAX];
689
690	f = fopen(fname, "r");
691	if (f == NULL) {
692		RTE_LOG(ERR, USER1, "%s failed to open file \"%s\"\n",
693			__func__, fname);
694		return -EINVAL;
695	}
696
697	n = 0;
698	num = 0;
699	sp = NULL;
700	rc = 0;
701	for (ln = 0; fgets(line, sizeof(line), f) != NULL; ln++) {
702
703		/* skip spaces at the start. */
704		for (s = line; isspace(s[0]); s++)
705			;
706
707		/* skip comment line. */
708		if (s[0] == '#' || s[0] == 0)
709			continue;
710
711		/* skip spaces at the end. */
712		for (i = strlen(s); i-- != 0 && isspace(s[i]); s[i] = 0)
713			;
714
715		if (n == lp->max_streams) {
716			RTE_LOG(ERR, USER1,
717				"%s(%s) number of entries exceed max streams "
718				"value: %u\n",
719				__func__, fname, n);
720				rc = -EINVAL;
721				break;
722		}
723
724		if (n == num) {
725			num += DEF_LINE_NUM;
726			sz = sizeof(sp[0]) * num;
727			sp = realloc(sp, sizeof(sp[0]) * num);
728			if (sp == NULL) {
729				RTE_LOG(ERR, USER1,
730					"%s(%s) allocation of %zu bytes "
731					"failed\n",
732					__func__, fname, sz);
733				rc = -ENOMEM;
734				break;
735			}
736			memset(&sp[n], 0, sizeof(sp[0]) * (num - n));
737		}
738
739		sp[n].line = ln + 1;
740		rc = parse_netfe_arg(sp + n, s);
741		rc = (rc != 0) ? rc : check_netfe_arg(sp + n);
742		if (rc != 0) {
743			RTE_LOG(ERR, USER1, "%s(%s) failed to parse line %u\n",
744				__func__, fname, sp[n].line);
745			break;
746		}
747		n++;
748	}
749
750	fclose(f);
751
752	if (rc != 0) {
753		free(sp);
754		sp = NULL;
755		n = 0;
756	}
757
758	lp->stream = sp;
759	lp->nb_streams = n;
760	return rc;
761}
762
763static uint32_t
764parse_hash_alg(const char *val)
765{
766	if (strcmp(val, "jhash") == 0)
767		return TLE_JHASH;
768	else if (strcmp(val, "siphash") == 0)
769		return TLE_SIPHASH;
770	else
771		return TLE_HASH_NUM;
772}
773
774static int
775read_tx_content(const char *fname, struct tx_content *tx)
776{
777	int32_t fd, rc;
778	ssize_t sz;
779	struct stat st;
780
781	rc = stat(fname, &st);
782	if (rc != 0)
783		return -errno;
784
785	tx->data = rte_malloc(NULL, st.st_size, RTE_CACHE_LINE_SIZE);
786	if (tx->data == NULL) {
787		RTE_LOG(ERR, USER1, "%s(%s): failed to alloc %zu bytes;\n",
788			__func__, fname, st.st_size);
789		return -ENOMEM;
790	}
791
792	fd = open(fname, O_RDONLY);
793	sz = read(fd, tx->data, st.st_size);
794
795	RTE_LOG(NOTICE, USER1, "%s(%s): read %zd bytes from fd=%d;\n",
796		__func__, fname, sz, fd);
797
798	close(fd);
799
800	if (sz != st.st_size) {
801		rc = -errno;
802		sz = 0;
803		rte_free(tx->data);
804	}
805
806	tx->sz = sz;
807	return rc;
808}
809
810int
811parse_app_options(int argc, char **argv, struct netbe_cfg *cfg,
812	struct tle_ctx_param *ctx_prm,
813	char *fecfg_fname, char *becfg_fname)
814{
815	int32_t opt, opt_idx, rc;
816	uint64_t v;
817	uint32_t i, j, n, nc;
818	rte_cpuset_t cpuset;
819	uint32_t udp = 0, tcp = 0, listen = 0;
820
821	optind = 0;
822	optarg = NULL;
823	while ((opt = getopt_long(argc, argv, "aB:C:c:LPR:S:M:TUb:f:s:v:H:K:W:w:",
824			long_opt, &opt_idx)) != EOF) {
825		if (opt == OPT_SHORT_ARP) {
826			cfg->arp = 1;
827		} else if (opt == OPT_SHORT_SBULK) {
828			rc = parse_uint_val(NULL, optarg, &v);
829			if (rc < 0)
830				rte_exit(EXIT_FAILURE, "%s: invalid value: %s "
831					"for option: \'%c\'\n",
832					__func__, optarg, opt);
833			ctx_prm->send_bulk_size = v;
834		} else if (opt == OPT_SHORT_CTXFLAGS) {
835			rc = parse_uint_val(NULL, optarg, &v);
836			if (rc < 0)
837				rte_exit(EXIT_FAILURE, "%s: invalid value: %s "
838					"for option: \'%c\'\n",
839					__func__, optarg, opt);
840			ctx_prm->flags = v;
841		} else if (opt == OPT_SHORT_MBUFNUM) {
842			rc = parse_uint_val(NULL, optarg, &v);
843			if (rc < 0)
844				rte_exit(EXIT_FAILURE, "%s: invalid value: %s "
845					"for option: \'%c\'\n",
846					__func__, optarg, opt);
847			cfg->mpool_buf_num = v;
848		} else if (opt == OPT_SHORT_PROMISC) {
849			cfg->promisc = 1;
850		} else if (opt == OPT_SHORT_RBUFS) {
851			rc = parse_uint_val(NULL, optarg, &v);
852			if (rc < 0)
853				rte_exit(EXIT_FAILURE, "%s: invalid value: %s "
854					"for option: \'%c\'\n",
855					__func__, optarg, opt);
856			ctx_prm->max_stream_rbufs = v;
857		} else if (opt == OPT_SHORT_SBUFS) {
858			rc = parse_uint_val(NULL, optarg, &v);
859			if (rc < 0)
860				rte_exit(EXIT_FAILURE, "%s: invalid value: %s "
861					"for option: \'%c\'\n",
862					__func__, optarg, opt);
863			ctx_prm->max_stream_sbufs = v;
864		} else if (opt == OPT_SHORT_STREAMS) {
865			rc = parse_uint_val(NULL, optarg, &v);
866			if (rc < 0)
867				rte_exit(EXIT_FAILURE, "%s: invalid value: %s "
868					"for option: \'%c\'\n",
869					__func__, optarg, opt);
870			ctx_prm->max_streams = v;
871		} else if (opt == OPT_SHORT_VERBOSE) {
872			rc = parse_uint_val(NULL, optarg, &v);
873			if (rc < 0)
874				rte_exit(EXIT_FAILURE, "%s: invalid value: %s "
875					"for option: \'%c\'\n",
876					__func__, optarg, opt);
877			verbose = (v > VERBOSE_NUM) ? VERBOSE_NUM : v;
878		} else if (opt == OPT_SHORT_BECFG) {
879			snprintf(becfg_fname, PATH_MAX, "%s",
880				optarg);
881		} else if (opt == OPT_SHORT_FECFG) {
882			snprintf(fecfg_fname, PATH_MAX, "%s",
883				optarg);
884		} else if (opt == OPT_SHORT_UDP) {
885			udp = 1;
886			cfg->proto = TLE_PROTO_UDP;
887		} else if (opt == OPT_SHORT_TCP) {
888			tcp = 1;
889			cfg->proto = TLE_PROTO_TCP;
890		} else if (opt == OPT_SHORT_LISTEN) {
891			listen = 1;
892			cfg->server = 1;
893		} else if (opt == OPT_SHORT_HASH) {
894			ctx_prm->hash_alg = parse_hash_alg(optarg);
895			if (ctx_prm->hash_alg >= TLE_HASH_NUM) {
896				rte_exit(EXIT_FAILURE,
897					"%s: invalid hash algorithm %s "
898					"for option: \'%c\'\n",
899					__func__, optarg, opt);
900			}
901		} else if (opt == OPT_SHORT_SEC_KEY) {
902			n = strlen(optarg);
903			if (n != sizeof(ctx_prm->secret_key)) {
904				rte_exit(EXIT_FAILURE,
905					"%s: invalid length %s "
906					"for option \'%c\' "
907					"must be 16 characters long\n",
908					__func__, optarg, opt);
909			}
910			memcpy(&ctx_prm->secret_key, optarg,
911				sizeof(ctx_prm->secret_key));
912		} else if (opt == OPT_SHORT_WINDOW) {
913			rc = parse_uint_val(NULL, optarg, &v);
914			if (rc < 0)
915				rte_exit(EXIT_FAILURE, "%s: invalid value: %s "
916					"for option: \'%c\'\n",
917					__func__, optarg, opt);
918			ctx_prm->icw = v;
919		} else if (opt == OPT_SHORT_TIMEWAIT) {
920			rc = parse_uint_val(NULL, optarg, &v);
921			if (rc < 0)
922				rte_exit(EXIT_FAILURE, "%s: invalid value: %s "
923					"for option: \'%c\'\n",
924					__func__, optarg, opt);
925			ctx_prm->timewait = v;
926		} else if (opt == OPT_SHORT_TXCNT) {
927			rc = read_tx_content(optarg, &tx_content);
928			if (rc < 0)
929				rte_exit(EXIT_FAILURE,
930					"%s: failed to read tx contents "
931					"from \'%s\', error code: %d(%s)\n",
932					__func__, optarg, rc, strerror(-rc));
933		} else {
934			rte_exit(EXIT_FAILURE,
935				"%s: unknown option: \'%c\'\n",
936				__func__, opt);
937		}
938	}
939
940	if (!udp && !tcp)
941		rte_exit(EXIT_FAILURE, "%s: either UDP or TCP option has to be "
942			"provided\n", __func__);
943
944	if (udp && tcp)
945		rte_exit(EXIT_FAILURE, "%s: both UDP and TCP options are not "
946			"allowed\n", __func__);
947
948	if (udp && listen)
949		rte_exit(EXIT_FAILURE,
950			"%s: listen mode cannot be opened with UDP\n",
951			__func__);
952
953	if (udp && cfg->arp)
954		rte_exit(EXIT_FAILURE,
955			"%s: arp cannot be enabled with UDP\n",
956			__func__);
957
958	/* parse port params */
959	argc -= optind;
960	argv += optind;
961
962	/* allocate memory for number of ports defined */
963	n = (uint32_t)argc;
964	cfg->prt = rte_zmalloc(NULL, sizeof(struct netbe_port) * n,
965		RTE_CACHE_LINE_SIZE);
966	cfg->prt_num = n;
967
968	rc = 0;
969	for (i = 0; i != n; i++) {
970		rc = parse_netbe_arg(cfg->prt + i, argv[i], &cpuset);
971		if (rc != 0) {
972			RTE_LOG(ERR, USER1,
973				"%s: processing of \"%s\" failed with error "
974				"code: %d\n", __func__, argv[i], rc);
975			for (j = 0; j != i; j++)
976				rte_free(cfg->prt[j].lcore_id);
977			rte_free(cfg->prt);
978			return rc;
979		}
980	}
981
982	/* count the number of CPU defined in ports */
983	for (i = 0, nc = 0; i < RTE_MAX_LCORE; i++)
984		nc += CPU_ISSET(i, &cpuset);
985
986	/* allocate memory for number of CPU defined */
987	cfg->cpu = rte_zmalloc(NULL, sizeof(struct netbe_lcore) * nc,
988		RTE_CACHE_LINE_SIZE);
989
990	return 0;
991}
992