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