xref: /dpdk/examples/ipsec-secgw/parser.c (revision 3998e2a07220844d3f3c17f76a781ced3efe0de0)
1*3998e2a0SBruce Richardson /* SPDX-License-Identifier: BSD-3-Clause
2*3998e2a0SBruce Richardson  * Copyright(c) 2016 Intel Corporation
30d547ed0SFan Zhang  */
40d547ed0SFan Zhang #include <rte_common.h>
50d547ed0SFan Zhang #include <rte_crypto.h>
60d547ed0SFan Zhang 
70d547ed0SFan Zhang #include <cmdline_parse_string.h>
80d547ed0SFan Zhang #include <cmdline_parse_num.h>
90d547ed0SFan Zhang #include <cmdline_parse_ipaddr.h>
100d547ed0SFan Zhang #include <cmdline_socket.h>
110d547ed0SFan Zhang #include <cmdline.h>
120d547ed0SFan Zhang 
130d547ed0SFan Zhang #include "ipsec.h"
140d547ed0SFan Zhang #include "parser.h"
150d547ed0SFan Zhang 
160d547ed0SFan Zhang #define PARSE_DELIMITER		" \f\n\r\t\v"
170d547ed0SFan Zhang static int
180d547ed0SFan Zhang parse_tokenize_string(char *string, char *tokens[], uint32_t *n_tokens)
190d547ed0SFan Zhang {
200d547ed0SFan Zhang 	uint32_t i;
210d547ed0SFan Zhang 
220d547ed0SFan Zhang 	if ((string == NULL) ||
230d547ed0SFan Zhang 		(tokens == NULL) ||
240d547ed0SFan Zhang 		(*n_tokens < 1))
250d547ed0SFan Zhang 		return -EINVAL;
260d547ed0SFan Zhang 
270d547ed0SFan Zhang 	for (i = 0; i < *n_tokens; i++) {
280d547ed0SFan Zhang 		tokens[i] = strtok_r(string, PARSE_DELIMITER, &string);
290d547ed0SFan Zhang 		if (tokens[i] == NULL)
300d547ed0SFan Zhang 			break;
310d547ed0SFan Zhang 	}
320d547ed0SFan Zhang 
330d547ed0SFan Zhang 	if ((i == *n_tokens) &&
340d547ed0SFan Zhang 		(NULL != strtok_r(string, PARSE_DELIMITER, &string)))
350d547ed0SFan Zhang 		return -E2BIG;
360d547ed0SFan Zhang 
370d547ed0SFan Zhang 	*n_tokens = i;
380d547ed0SFan Zhang 	return 0;
390d547ed0SFan Zhang }
400d547ed0SFan Zhang 
410d547ed0SFan Zhang #define INADDRSZ 4
420d547ed0SFan Zhang #define IN6ADDRSZ 16
430d547ed0SFan Zhang 
440d547ed0SFan Zhang /* int
450d547ed0SFan Zhang  * inet_pton4(src, dst)
460d547ed0SFan Zhang  *      like inet_aton() but without all the hexadecimal and shorthand.
470d547ed0SFan Zhang  * return:
480d547ed0SFan Zhang  *      1 if `src' is a valid dotted quad, else 0.
490d547ed0SFan Zhang  * notice:
500d547ed0SFan Zhang  *      does not touch `dst' unless it's returning 1.
510d547ed0SFan Zhang  * author:
520d547ed0SFan Zhang  *      Paul Vixie, 1996.
530d547ed0SFan Zhang  */
540d547ed0SFan Zhang static int
550d547ed0SFan Zhang inet_pton4(const char *src, unsigned char *dst)
560d547ed0SFan Zhang {
570d547ed0SFan Zhang 	static const char digits[] = "0123456789";
580d547ed0SFan Zhang 	int saw_digit, octets, ch;
590d547ed0SFan Zhang 	unsigned char tmp[INADDRSZ], *tp;
600d547ed0SFan Zhang 
610d547ed0SFan Zhang 	saw_digit = 0;
620d547ed0SFan Zhang 	octets = 0;
630d547ed0SFan Zhang 	*(tp = tmp) = 0;
640d547ed0SFan Zhang 	while ((ch = *src++) != '\0') {
650d547ed0SFan Zhang 		const char *pch;
660d547ed0SFan Zhang 
670d547ed0SFan Zhang 		pch = strchr(digits, ch);
680d547ed0SFan Zhang 		if (pch != NULL) {
690d547ed0SFan Zhang 			unsigned int new = *tp * 10 + (pch - digits);
700d547ed0SFan Zhang 
710d547ed0SFan Zhang 			if (new > 255)
720d547ed0SFan Zhang 				return 0;
730d547ed0SFan Zhang 			if (!saw_digit) {
740d547ed0SFan Zhang 				if (++octets > 4)
750d547ed0SFan Zhang 					return 0;
760d547ed0SFan Zhang 				saw_digit = 1;
770d547ed0SFan Zhang 			}
780d547ed0SFan Zhang 			*tp = (unsigned char)new;
790d547ed0SFan Zhang 		} else if (ch == '.' && saw_digit) {
800d547ed0SFan Zhang 			if (octets == 4)
810d547ed0SFan Zhang 				return 0;
820d547ed0SFan Zhang 			*++tp = 0;
830d547ed0SFan Zhang 			saw_digit = 0;
840d547ed0SFan Zhang 		} else
850d547ed0SFan Zhang 			return 0;
860d547ed0SFan Zhang 	}
870d547ed0SFan Zhang 	if (octets < 4)
880d547ed0SFan Zhang 		return 0;
890d547ed0SFan Zhang 
900d547ed0SFan Zhang 	memcpy(dst, tmp, INADDRSZ);
910d547ed0SFan Zhang 	return 1;
920d547ed0SFan Zhang }
930d547ed0SFan Zhang 
940d547ed0SFan Zhang /* int
950d547ed0SFan Zhang  * inet_pton6(src, dst)
960d547ed0SFan Zhang  *      convert presentation level address to network order binary form.
970d547ed0SFan Zhang  * return:
980d547ed0SFan Zhang  *      1 if `src' is a valid [RFC1884 2.2] address, else 0.
990d547ed0SFan Zhang  * notice:
1000d547ed0SFan Zhang  *      (1) does not touch `dst' unless it's returning 1.
1010d547ed0SFan Zhang  *      (2) :: in a full address is silently ignored.
1020d547ed0SFan Zhang  * credit:
1030d547ed0SFan Zhang  *      inspired by Mark Andrews.
1040d547ed0SFan Zhang  * author:
1050d547ed0SFan Zhang  *      Paul Vixie, 1996.
1060d547ed0SFan Zhang  */
1070d547ed0SFan Zhang static int
1080d547ed0SFan Zhang inet_pton6(const char *src, unsigned char *dst)
1090d547ed0SFan Zhang {
1100d547ed0SFan Zhang 	static const char xdigits_l[] = "0123456789abcdef",
1110d547ed0SFan Zhang 		xdigits_u[] = "0123456789ABCDEF";
1120d547ed0SFan Zhang 	unsigned char tmp[IN6ADDRSZ], *tp = 0, *endp = 0, *colonp = 0;
1130d547ed0SFan Zhang 	const char *xdigits = 0, *curtok = 0;
1140d547ed0SFan Zhang 	int ch = 0, saw_xdigit = 0, count_xdigit = 0;
1150d547ed0SFan Zhang 	unsigned int val = 0;
1160d547ed0SFan Zhang 	unsigned dbloct_count = 0;
1170d547ed0SFan Zhang 
1180d547ed0SFan Zhang 	memset((tp = tmp), '\0', IN6ADDRSZ);
1190d547ed0SFan Zhang 	endp = tp + IN6ADDRSZ;
1200d547ed0SFan Zhang 	colonp = NULL;
1210d547ed0SFan Zhang 	/* Leading :: requires some special handling. */
1220d547ed0SFan Zhang 	if (*src == ':')
1230d547ed0SFan Zhang 		if (*++src != ':')
1240d547ed0SFan Zhang 			return 0;
1250d547ed0SFan Zhang 	curtok = src;
1260d547ed0SFan Zhang 	saw_xdigit = count_xdigit = 0;
1270d547ed0SFan Zhang 	val = 0;
1280d547ed0SFan Zhang 
1290d547ed0SFan Zhang 	while ((ch = *src++) != '\0') {
1300d547ed0SFan Zhang 		const char *pch;
1310d547ed0SFan Zhang 
1320d547ed0SFan Zhang 		pch = strchr((xdigits = xdigits_l), ch);
1330d547ed0SFan Zhang 		if (pch == NULL)
1340d547ed0SFan Zhang 			pch = strchr((xdigits = xdigits_u), ch);
1350d547ed0SFan Zhang 		if (pch != NULL) {
1360d547ed0SFan Zhang 			if (count_xdigit >= 4)
1370d547ed0SFan Zhang 				return 0;
1380d547ed0SFan Zhang 			val <<= 4;
1390d547ed0SFan Zhang 			val |= (pch - xdigits);
1400d547ed0SFan Zhang 			if (val > 0xffff)
1410d547ed0SFan Zhang 				return 0;
1420d547ed0SFan Zhang 			saw_xdigit = 1;
1430d547ed0SFan Zhang 			count_xdigit++;
1440d547ed0SFan Zhang 			continue;
1450d547ed0SFan Zhang 		}
1460d547ed0SFan Zhang 		if (ch == ':') {
1470d547ed0SFan Zhang 			curtok = src;
1480d547ed0SFan Zhang 			if (!saw_xdigit) {
1490d547ed0SFan Zhang 				if (colonp)
1500d547ed0SFan Zhang 					return 0;
1510d547ed0SFan Zhang 				colonp = tp;
1520d547ed0SFan Zhang 				continue;
1530d547ed0SFan Zhang 			} else if (*src == '\0') {
1540d547ed0SFan Zhang 				return 0;
1550d547ed0SFan Zhang 			}
1560d547ed0SFan Zhang 			if (tp + sizeof(int16_t) > endp)
1570d547ed0SFan Zhang 				return 0;
1580d547ed0SFan Zhang 			*tp++ = (unsigned char) ((val >> 8) & 0xff);
1590d547ed0SFan Zhang 			*tp++ = (unsigned char) (val & 0xff);
1600d547ed0SFan Zhang 			saw_xdigit = 0;
1610d547ed0SFan Zhang 			count_xdigit = 0;
1620d547ed0SFan Zhang 			val = 0;
1630d547ed0SFan Zhang 			dbloct_count++;
1640d547ed0SFan Zhang 			continue;
1650d547ed0SFan Zhang 		}
1660d547ed0SFan Zhang 		if (ch == '.' && ((tp + INADDRSZ) <= endp) &&
1670d547ed0SFan Zhang 		    inet_pton4(curtok, tp) > 0) {
1680d547ed0SFan Zhang 			tp += INADDRSZ;
1690d547ed0SFan Zhang 			saw_xdigit = 0;
1700d547ed0SFan Zhang 			dbloct_count += 2;
1710d547ed0SFan Zhang 			break;  /* '\0' was seen by inet_pton4(). */
1720d547ed0SFan Zhang 		}
1730d547ed0SFan Zhang 		return 0;
1740d547ed0SFan Zhang 	}
1750d547ed0SFan Zhang 	if (saw_xdigit) {
1760d547ed0SFan Zhang 		if (tp + sizeof(int16_t) > endp)
1770d547ed0SFan Zhang 			return 0;
1780d547ed0SFan Zhang 		*tp++ = (unsigned char) ((val >> 8) & 0xff);
1790d547ed0SFan Zhang 		*tp++ = (unsigned char) (val & 0xff);
1800d547ed0SFan Zhang 		dbloct_count++;
1810d547ed0SFan Zhang 	}
1820d547ed0SFan Zhang 	if (colonp != NULL) {
1830d547ed0SFan Zhang 		/* if we already have 8 double octets, having a colon
1840d547ed0SFan Zhang 		 * means error */
1850d547ed0SFan Zhang 		if (dbloct_count == 8)
1860d547ed0SFan Zhang 			return 0;
1870d547ed0SFan Zhang 
1880d547ed0SFan Zhang 		/*
1890d547ed0SFan Zhang 		 * Since some memmove()'s erroneously fail to handle
1900d547ed0SFan Zhang 		 * overlapping regions, we'll do the shift by hand.
1910d547ed0SFan Zhang 		 */
1920d547ed0SFan Zhang 		const int n = tp - colonp;
1930d547ed0SFan Zhang 		int i;
1940d547ed0SFan Zhang 
1950d547ed0SFan Zhang 		for (i = 1; i <= n; i++) {
1960d547ed0SFan Zhang 			endp[-i] = colonp[n - i];
1970d547ed0SFan Zhang 			colonp[n - i] = 0;
1980d547ed0SFan Zhang 		}
1990d547ed0SFan Zhang 		tp = endp;
2000d547ed0SFan Zhang 	}
2010d547ed0SFan Zhang 	if (tp != endp)
2020d547ed0SFan Zhang 		return 0;
2030d547ed0SFan Zhang 	memcpy(dst, tmp, IN6ADDRSZ);
2040d547ed0SFan Zhang 	return 1;
2050d547ed0SFan Zhang }
2060d547ed0SFan Zhang 
2070d547ed0SFan Zhang int
2080d547ed0SFan Zhang parse_ipv4_addr(const char *token, struct in_addr *ipv4, uint32_t *mask)
2090d547ed0SFan Zhang {
2100d547ed0SFan Zhang 	char ip_str[256] = {0};
2110d547ed0SFan Zhang 	char *pch;
2120d547ed0SFan Zhang 
2130d547ed0SFan Zhang 	pch = strchr(token, '/');
2140d547ed0SFan Zhang 	if (pch != NULL) {
2150d547ed0SFan Zhang 		strncpy(ip_str, token, pch - token);
2160d547ed0SFan Zhang 		pch += 1;
2170d547ed0SFan Zhang 		if (is_str_num(pch) != 0)
2180d547ed0SFan Zhang 			return -EINVAL;
2190d547ed0SFan Zhang 		if (mask)
2200d547ed0SFan Zhang 			*mask = atoi(pch);
2210d547ed0SFan Zhang 	} else {
22207b15619SFan Zhang 		strncpy(ip_str, token, sizeof(ip_str) - 1);
2230d547ed0SFan Zhang 		if (mask)
2240d547ed0SFan Zhang 			*mask = 0;
2250d547ed0SFan Zhang 	}
2260d547ed0SFan Zhang 
2270d547ed0SFan Zhang 	if (strlen(ip_str) >= INET_ADDRSTRLEN)
2280d547ed0SFan Zhang 		return -EINVAL;
2290d547ed0SFan Zhang 
2300d547ed0SFan Zhang 	if (inet_pton4(ip_str, (unsigned char *)ipv4) != 1)
2310d547ed0SFan Zhang 		return -EINVAL;
2320d547ed0SFan Zhang 
2330d547ed0SFan Zhang 	return 0;
2340d547ed0SFan Zhang }
2350d547ed0SFan Zhang 
2360d547ed0SFan Zhang int
2370d547ed0SFan Zhang parse_ipv6_addr(const char *token, struct in6_addr *ipv6, uint32_t *mask)
2380d547ed0SFan Zhang {
2390d547ed0SFan Zhang 	char ip_str[256] = {0};
2400d547ed0SFan Zhang 	char *pch;
2410d547ed0SFan Zhang 
2420d547ed0SFan Zhang 	pch = strchr(token, '/');
2430d547ed0SFan Zhang 	if (pch != NULL) {
2440d547ed0SFan Zhang 		strncpy(ip_str, token, pch - token);
2450d547ed0SFan Zhang 		pch += 1;
2460d547ed0SFan Zhang 		if (is_str_num(pch) != 0)
2470d547ed0SFan Zhang 			return -EINVAL;
2480d547ed0SFan Zhang 		if (mask)
2490d547ed0SFan Zhang 			*mask = atoi(pch);
2500d547ed0SFan Zhang 	} else {
25107b15619SFan Zhang 		strncpy(ip_str, token, sizeof(ip_str) - 1);
2520d547ed0SFan Zhang 		if (mask)
2530d547ed0SFan Zhang 			*mask = 0;
2540d547ed0SFan Zhang 	}
2550d547ed0SFan Zhang 
2560d547ed0SFan Zhang 	if (strlen(ip_str) >= INET6_ADDRSTRLEN)
2570d547ed0SFan Zhang 		return -EINVAL;
2580d547ed0SFan Zhang 
2590d547ed0SFan Zhang 	if (inet_pton6(ip_str, (unsigned char *)ipv6) != 1)
2600d547ed0SFan Zhang 		return -EINVAL;
2610d547ed0SFan Zhang 
2620d547ed0SFan Zhang 	return 0;
2630d547ed0SFan Zhang }
2640d547ed0SFan Zhang 
2650d547ed0SFan Zhang int
2660d547ed0SFan Zhang parse_range(const char *token, uint16_t *low, uint16_t *high)
2670d547ed0SFan Zhang {
2680d547ed0SFan Zhang 	char ch;
2690d547ed0SFan Zhang 	char num_str[20];
2700d547ed0SFan Zhang 	uint32_t pos;
2710d547ed0SFan Zhang 	int range_low = -1;
2720d547ed0SFan Zhang 	int range_high = -1;
2730d547ed0SFan Zhang 
2740d547ed0SFan Zhang 	if (!low || !high)
2750d547ed0SFan Zhang 		return -1;
2760d547ed0SFan Zhang 
2770d547ed0SFan Zhang 	memset(num_str, 0, 20);
2780d547ed0SFan Zhang 	pos = 0;
2790d547ed0SFan Zhang 
2800d547ed0SFan Zhang 	while ((ch = *token++) != '\0') {
2810d547ed0SFan Zhang 		if (isdigit(ch)) {
2820d547ed0SFan Zhang 			if (pos >= 19)
2830d547ed0SFan Zhang 				return -1;
2840d547ed0SFan Zhang 			num_str[pos++] = ch;
2850d547ed0SFan Zhang 		} else if (ch == ':') {
2860d547ed0SFan Zhang 			if (range_low != -1)
2870d547ed0SFan Zhang 				return -1;
2880d547ed0SFan Zhang 			range_low = atoi(num_str);
2890d547ed0SFan Zhang 			memset(num_str, 0, 20);
2900d547ed0SFan Zhang 			pos = 0;
2910d547ed0SFan Zhang 		}
2920d547ed0SFan Zhang 	}
2930d547ed0SFan Zhang 
2940d547ed0SFan Zhang 	if (strlen(num_str) == 0)
2950d547ed0SFan Zhang 		return -1;
2960d547ed0SFan Zhang 
2970d547ed0SFan Zhang 	range_high = atoi(num_str);
2980d547ed0SFan Zhang 
2990d547ed0SFan Zhang 	*low = (uint16_t)range_low;
3000d547ed0SFan Zhang 	*high = (uint16_t)range_high;
3010d547ed0SFan Zhang 
3020d547ed0SFan Zhang 	return 0;
3030d547ed0SFan Zhang }
3040d547ed0SFan Zhang 
3050d547ed0SFan Zhang /** sp add parse */
3060d547ed0SFan Zhang struct cfg_sp_add_cfg_item {
3070d547ed0SFan Zhang 	cmdline_fixed_string_t sp_keyword;
3080d547ed0SFan Zhang 	cmdline_multi_string_t multi_string;
3090d547ed0SFan Zhang };
3100d547ed0SFan Zhang 
3110d547ed0SFan Zhang static void
3120d547ed0SFan Zhang cfg_sp_add_cfg_item_parsed(void *parsed_result,
3130d547ed0SFan Zhang 	__rte_unused struct cmdline *cl, void *data)
3140d547ed0SFan Zhang {
3150d547ed0SFan Zhang 	struct cfg_sp_add_cfg_item *params = parsed_result;
3160d547ed0SFan Zhang 	char *tokens[32];
3170d547ed0SFan Zhang 	uint32_t n_tokens = RTE_DIM(tokens);
3180d547ed0SFan Zhang 	struct parse_status *status = (struct parse_status *)data;
3190d547ed0SFan Zhang 
3200d547ed0SFan Zhang 	APP_CHECK((parse_tokenize_string(params->multi_string, tokens,
3210d547ed0SFan Zhang 		&n_tokens) == 0), status, "too many arguments");
3220d547ed0SFan Zhang 
3230d547ed0SFan Zhang 	if (status->status < 0)
3240d547ed0SFan Zhang 		return;
3250d547ed0SFan Zhang 
3260d547ed0SFan Zhang 	if (strcmp(tokens[0], "ipv4") == 0) {
3270d547ed0SFan Zhang 		parse_sp4_tokens(tokens, n_tokens, status);
3280d547ed0SFan Zhang 		if (status->status < 0)
3290d547ed0SFan Zhang 			return;
3300d547ed0SFan Zhang 	} else if (strcmp(tokens[0], "ipv6") == 0) {
3310d547ed0SFan Zhang 		parse_sp6_tokens(tokens, n_tokens, status);
3320d547ed0SFan Zhang 		if (status->status < 0)
3330d547ed0SFan Zhang 			return;
3340d547ed0SFan Zhang 	} else {
3350d547ed0SFan Zhang 		APP_CHECK(0, status, "unrecognizable input %s\n",
3360d547ed0SFan Zhang 			tokens[0]);
3370d547ed0SFan Zhang 		return;
3380d547ed0SFan Zhang 	}
3390d547ed0SFan Zhang }
3400d547ed0SFan Zhang 
3410d547ed0SFan Zhang static cmdline_parse_token_string_t cfg_sp_add_sp_str =
3420d547ed0SFan Zhang 	TOKEN_STRING_INITIALIZER(struct cfg_sp_add_cfg_item,
3430d547ed0SFan Zhang 		sp_keyword, "sp");
3440d547ed0SFan Zhang 
3450d547ed0SFan Zhang static cmdline_parse_token_string_t cfg_sp_add_multi_str =
3460d547ed0SFan Zhang 	TOKEN_STRING_INITIALIZER(struct cfg_sp_add_cfg_item, multi_string,
3470d547ed0SFan Zhang 		TOKEN_STRING_MULTI);
3480d547ed0SFan Zhang 
3490d547ed0SFan Zhang cmdline_parse_inst_t cfg_sp_add_rule = {
3500d547ed0SFan Zhang 	.f = cfg_sp_add_cfg_item_parsed,
3510d547ed0SFan Zhang 	.data = NULL,
3520d547ed0SFan Zhang 	.help_str = "",
3530d547ed0SFan Zhang 	.tokens = {
3540d547ed0SFan Zhang 		(void *) &cfg_sp_add_sp_str,
3550d547ed0SFan Zhang 		(void *) &cfg_sp_add_multi_str,
3560d547ed0SFan Zhang 		NULL,
3570d547ed0SFan Zhang 	},
3580d547ed0SFan Zhang };
3590d547ed0SFan Zhang 
3600d547ed0SFan Zhang /* sa add parse */
3610d547ed0SFan Zhang struct cfg_sa_add_cfg_item {
3620d547ed0SFan Zhang 	cmdline_fixed_string_t sa_keyword;
3630d547ed0SFan Zhang 	cmdline_multi_string_t multi_string;
3640d547ed0SFan Zhang };
3650d547ed0SFan Zhang 
3660d547ed0SFan Zhang static void
3670d547ed0SFan Zhang cfg_sa_add_cfg_item_parsed(void *parsed_result,
3680d547ed0SFan Zhang 	__rte_unused struct cmdline *cl, void *data)
3690d547ed0SFan Zhang {
3700d547ed0SFan Zhang 	struct cfg_sa_add_cfg_item *params = parsed_result;
3710d547ed0SFan Zhang 	char *tokens[32];
3720d547ed0SFan Zhang 	uint32_t n_tokens = RTE_DIM(tokens);
3730d547ed0SFan Zhang 	struct parse_status *status = (struct parse_status *)data;
3740d547ed0SFan Zhang 
3750d547ed0SFan Zhang 	APP_CHECK(parse_tokenize_string(params->multi_string, tokens,
3760d547ed0SFan Zhang 		&n_tokens) == 0, status, "too many arguments\n");
3770d547ed0SFan Zhang 
3780d547ed0SFan Zhang 	parse_sa_tokens(tokens, n_tokens, status);
3790d547ed0SFan Zhang }
3800d547ed0SFan Zhang 
3810d547ed0SFan Zhang static cmdline_parse_token_string_t cfg_sa_add_sa_str =
3820d547ed0SFan Zhang 	TOKEN_STRING_INITIALIZER(struct cfg_sa_add_cfg_item,
3830d547ed0SFan Zhang 		sa_keyword, "sa");
3840d547ed0SFan Zhang 
3850d547ed0SFan Zhang static cmdline_parse_token_string_t cfg_sa_add_multi_str =
3860d547ed0SFan Zhang 	TOKEN_STRING_INITIALIZER(struct cfg_sa_add_cfg_item, multi_string,
3870d547ed0SFan Zhang 		TOKEN_STRING_MULTI);
3880d547ed0SFan Zhang 
3890d547ed0SFan Zhang cmdline_parse_inst_t cfg_sa_add_rule = {
3900d547ed0SFan Zhang 	.f = cfg_sa_add_cfg_item_parsed,
3910d547ed0SFan Zhang 	.data = NULL,
3920d547ed0SFan Zhang 	.help_str = "",
3930d547ed0SFan Zhang 	.tokens = {
3940d547ed0SFan Zhang 		(void *) &cfg_sa_add_sa_str,
3950d547ed0SFan Zhang 		(void *) &cfg_sa_add_multi_str,
3960d547ed0SFan Zhang 		NULL,
3970d547ed0SFan Zhang 	},
3980d547ed0SFan Zhang };
3990d547ed0SFan Zhang 
4000d547ed0SFan Zhang /* rt add parse */
4010d547ed0SFan Zhang struct cfg_rt_add_cfg_item {
4020d547ed0SFan Zhang 	cmdline_fixed_string_t rt_keyword;
4030d547ed0SFan Zhang 	cmdline_multi_string_t multi_string;
4040d547ed0SFan Zhang };
4050d547ed0SFan Zhang 
4060d547ed0SFan Zhang static void
4070d547ed0SFan Zhang cfg_rt_add_cfg_item_parsed(void *parsed_result,
4080d547ed0SFan Zhang 	__rte_unused struct cmdline *cl, void *data)
4090d547ed0SFan Zhang {
4100d547ed0SFan Zhang 	struct cfg_rt_add_cfg_item *params = parsed_result;
4110d547ed0SFan Zhang 	char *tokens[32];
4120d547ed0SFan Zhang 	uint32_t n_tokens = RTE_DIM(tokens);
4130d547ed0SFan Zhang 	struct parse_status *status = (struct parse_status *)data;
4140d547ed0SFan Zhang 
4150d547ed0SFan Zhang 	APP_CHECK(parse_tokenize_string(
4160d547ed0SFan Zhang 		params->multi_string, tokens, &n_tokens) == 0,
4170d547ed0SFan Zhang 		status, "too many arguments\n");
4180d547ed0SFan Zhang 	if (status->status < 0)
4190d547ed0SFan Zhang 		return;
4200d547ed0SFan Zhang 
4210d547ed0SFan Zhang 	parse_rt_tokens(tokens, n_tokens, status);
4220d547ed0SFan Zhang }
4230d547ed0SFan Zhang 
4240d547ed0SFan Zhang static cmdline_parse_token_string_t cfg_rt_add_rt_str =
4250d547ed0SFan Zhang 	TOKEN_STRING_INITIALIZER(struct cfg_rt_add_cfg_item,
4260d547ed0SFan Zhang 		rt_keyword, "rt");
4270d547ed0SFan Zhang 
4280d547ed0SFan Zhang static cmdline_parse_token_string_t cfg_rt_add_multi_str =
4290d547ed0SFan Zhang 	TOKEN_STRING_INITIALIZER(struct cfg_rt_add_cfg_item, multi_string,
4300d547ed0SFan Zhang 		TOKEN_STRING_MULTI);
4310d547ed0SFan Zhang 
4320d547ed0SFan Zhang cmdline_parse_inst_t cfg_rt_add_rule = {
4330d547ed0SFan Zhang 	.f = cfg_rt_add_cfg_item_parsed,
4340d547ed0SFan Zhang 	.data = NULL,
4350d547ed0SFan Zhang 	.help_str = "",
4360d547ed0SFan Zhang 	.tokens = {
4370d547ed0SFan Zhang 		(void *) &cfg_rt_add_rt_str,
4380d547ed0SFan Zhang 		(void *) &cfg_rt_add_multi_str,
4390d547ed0SFan Zhang 		NULL,
4400d547ed0SFan Zhang 	},
4410d547ed0SFan Zhang };
4420d547ed0SFan Zhang 
4430d547ed0SFan Zhang /** set of cfg items */
4440d547ed0SFan Zhang cmdline_parse_ctx_t ipsec_ctx[] = {
4450d547ed0SFan Zhang 	(cmdline_parse_inst_t *)&cfg_sp_add_rule,
4460d547ed0SFan Zhang 	(cmdline_parse_inst_t *)&cfg_sa_add_rule,
4470d547ed0SFan Zhang 	(cmdline_parse_inst_t *)&cfg_rt_add_rule,
4480d547ed0SFan Zhang 	NULL,
4490d547ed0SFan Zhang };
4500d547ed0SFan Zhang 
4510d547ed0SFan Zhang int
4520d547ed0SFan Zhang parse_cfg_file(const char *cfg_filename)
4530d547ed0SFan Zhang {
4540d547ed0SFan Zhang 	struct cmdline *cl = cmdline_stdin_new(ipsec_ctx, "");
4550d547ed0SFan Zhang 	FILE *f = fopen(cfg_filename, "r");
4560d547ed0SFan Zhang 	char str[1024] = {0}, *get_s = NULL;
4570d547ed0SFan Zhang 	uint32_t line_num = 0;
4580d547ed0SFan Zhang 	struct parse_status status = {0};
4590d547ed0SFan Zhang 
4600d547ed0SFan Zhang 	if (f == NULL) {
461a1469c31SFan Zhang 		rte_panic("Error: invalid file descriptor %s\n", cfg_filename);
4620d547ed0SFan Zhang 		goto error_exit;
4630d547ed0SFan Zhang 	}
4640d547ed0SFan Zhang 
4650d547ed0SFan Zhang 	if (cl == NULL) {
4660d547ed0SFan Zhang 		rte_panic("Error: cannot create cmdline instance\n");
4670d547ed0SFan Zhang 		goto error_exit;
4680d547ed0SFan Zhang 	}
4690d547ed0SFan Zhang 
4700d547ed0SFan Zhang 	cfg_sp_add_rule.data = &status;
4710d547ed0SFan Zhang 	cfg_sa_add_rule.data = &status;
4720d547ed0SFan Zhang 	cfg_rt_add_rule.data = &status;
4730d547ed0SFan Zhang 
4740d547ed0SFan Zhang 	do {
4750d547ed0SFan Zhang 		char oneline[1024];
4760d547ed0SFan Zhang 		char *pos;
477a1469c31SFan Zhang 		get_s = fgets(oneline, 1024, f);
478a1469c31SFan Zhang 
479a1469c31SFan Zhang 		if (!get_s)
480a1469c31SFan Zhang 			break;
4810d547ed0SFan Zhang 
4820d547ed0SFan Zhang 		line_num++;
4830d547ed0SFan Zhang 
4840d547ed0SFan Zhang 		if (strlen(oneline) > 1022) {
485a1469c31SFan Zhang 			rte_panic("%s:%u: error: "
486a1469c31SFan Zhang 				"the line contains more characters the parser can handle\n",
4870d547ed0SFan Zhang 				cfg_filename, line_num);
4880d547ed0SFan Zhang 			goto error_exit;
4890d547ed0SFan Zhang 		}
4900d547ed0SFan Zhang 
4910d547ed0SFan Zhang 		/* process comment char '#' */
4920d547ed0SFan Zhang 		if (oneline[0] == '#')
4930d547ed0SFan Zhang 			continue;
4940d547ed0SFan Zhang 
4950d547ed0SFan Zhang 		pos = strchr(oneline, '#');
4960d547ed0SFan Zhang 		if (pos != NULL)
4970d547ed0SFan Zhang 			*pos = '\0';
4980d547ed0SFan Zhang 
4990d547ed0SFan Zhang 		/* process line concatenator '\' */
5000d547ed0SFan Zhang 		pos = strchr(oneline, 92);
5010d547ed0SFan Zhang 		if (pos != NULL) {
5020d547ed0SFan Zhang 			if (pos != oneline+strlen(oneline) - 2) {
503a1469c31SFan Zhang 				rte_panic("%s:%u: error: "
504a1469c31SFan Zhang 					"no character should exist after '\\'\n",
5050d547ed0SFan Zhang 					cfg_filename, line_num);
5060d547ed0SFan Zhang 				goto error_exit;
5070d547ed0SFan Zhang 			}
5080d547ed0SFan Zhang 
5090d547ed0SFan Zhang 			*pos = '\0';
5100d547ed0SFan Zhang 
5110d547ed0SFan Zhang 			if (strlen(oneline) + strlen(str) > 1022) {
512a1469c31SFan Zhang 				rte_panic("%s:%u: error: "
513a1469c31SFan Zhang 					"the concatenated line contains more characters the parser can handle\n",
5140d547ed0SFan Zhang 					cfg_filename, line_num);
5150d547ed0SFan Zhang 				goto error_exit;
5160d547ed0SFan Zhang 			}
5170d547ed0SFan Zhang 
5180d547ed0SFan Zhang 			strncpy(str + strlen(str), oneline,
5190d547ed0SFan Zhang 				strlen(oneline));
5200d547ed0SFan Zhang 
5210d547ed0SFan Zhang 			continue;
5220d547ed0SFan Zhang 		}
5230d547ed0SFan Zhang 
5240d547ed0SFan Zhang 		/* copy the line to str and process */
5250d547ed0SFan Zhang 		if (strlen(oneline) + strlen(str) > 1022) {
526a1469c31SFan Zhang 			rte_panic("%s:%u: error: "
527a1469c31SFan Zhang 				"the line contains more characters the parser can handle\n",
5280d547ed0SFan Zhang 				cfg_filename, line_num);
5290d547ed0SFan Zhang 			goto error_exit;
5300d547ed0SFan Zhang 		}
5310d547ed0SFan Zhang 		strncpy(str + strlen(str), oneline,
5320d547ed0SFan Zhang 			strlen(oneline));
5330d547ed0SFan Zhang 
5340d547ed0SFan Zhang 		str[strlen(str)] = '\n';
5350d547ed0SFan Zhang 		if (cmdline_parse(cl, str) < 0) {
536a1469c31SFan Zhang 			rte_panic("%s:%u: error: parsing \"%s\" failed\n",
537a1469c31SFan Zhang 				cfg_filename, line_num, str);
5380d547ed0SFan Zhang 			goto error_exit;
5390d547ed0SFan Zhang 		}
5400d547ed0SFan Zhang 
5410d547ed0SFan Zhang 		if (status.status < 0) {
542a1469c31SFan Zhang 			rte_panic("%s:%u: error: %s", cfg_filename,
543a1469c31SFan Zhang 				line_num, status.parse_msg);
5440d547ed0SFan Zhang 			goto error_exit;
5450d547ed0SFan Zhang 		}
5460d547ed0SFan Zhang 
5470d547ed0SFan Zhang 		memset(str, 0, 1024);
548a1469c31SFan Zhang 	} while (1);
5490d547ed0SFan Zhang 
5500d547ed0SFan Zhang 	cmdline_stdin_exit(cl);
5510d547ed0SFan Zhang 	fclose(f);
5520d547ed0SFan Zhang 
5530d547ed0SFan Zhang 	return 0;
5540d547ed0SFan Zhang 
5550d547ed0SFan Zhang error_exit:
5560d547ed0SFan Zhang 	if (cl)
5570d547ed0SFan Zhang 		cmdline_stdin_exit(cl);
5580d547ed0SFan Zhang 	if (f)
5590d547ed0SFan Zhang 		fclose(f);
5600d547ed0SFan Zhang 
5610d547ed0SFan Zhang 	return -1;
5620d547ed0SFan Zhang }
563