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