diff --git a/examples/ipsec-secgw/ipsec.h b/examples/ipsec-secgw/ipsec.h
index 5988d59..3c77232 100644
--- a/examples/ipsec-secgw/ipsec.h
+++ b/examples/ipsec-secgw/ipsec.h
@@ -37,7 +37,6 @@
 
 #define DEFAULT_MAX_CATEGORIES	1
 
-#define IPSEC_SA_MAX_ENTRIES (128) /* must be power of 2, max 2 power 30 */
 #define INVALID_SPI (0)
 
 #define DISCARD	INVALID_SPI
diff --git a/examples/ipsec-secgw/parser.c b/examples/ipsec-secgw/parser.c
index fc8c238..67df170 100644
--- a/examples/ipsec-secgw/parser.c
+++ b/examples/ipsec-secgw/parser.c
@@ -642,6 +642,8 @@ parse_cfg_file(const char *cfg_filename)
 	cmdline_stdin_exit(cl);
 	fclose(f);
 
+	sa_sort_arr();
+
 	return 0;
 
 error_exit:
diff --git a/examples/ipsec-secgw/parser.h b/examples/ipsec-secgw/parser.h
index 6b8a100..1f8bd3e 100644
--- a/examples/ipsec-secgw/parser.h
+++ b/examples/ipsec-secgw/parser.h
@@ -75,6 +75,9 @@ parse_sp6_tokens(char **tokens, uint32_t n_tokens,
 	struct parse_status *status);
 
 void
+sa_sort_arr(void);
+
+void
 parse_sa_tokens(char **tokens, uint32_t n_tokens,
 	struct parse_status *status);
 
diff --git a/examples/ipsec-secgw/sa.c b/examples/ipsec-secgw/sa.c
index d10a6ec..b3b83e3 100644
--- a/examples/ipsec-secgw/sa.c
+++ b/examples/ipsec-secgw/sa.c
@@ -133,11 +133,15 @@ const struct supported_aead_algo aead_algos[] = {
 	}
 };
 
-static struct ipsec_sa sa_out[IPSEC_SA_MAX_ENTRIES];
+#define SA_INIT_NB	128
+
+static struct ipsec_sa *sa_out;
+static uint32_t sa_out_sz;
 static uint32_t nb_sa_out;
 static struct ipsec_sa_cnt sa_out_cnt;
 
-static struct ipsec_sa sa_in[IPSEC_SA_MAX_ENTRIES];
+static struct ipsec_sa *sa_in;
+static uint32_t sa_in_sz;
 static uint32_t nb_sa_in;
 static struct ipsec_sa_cnt sa_in_cnt;
 
@@ -224,6 +228,31 @@ parse_key_string(const char *key_str, uint8_t *key)
 	return nb_bytes;
 }
 
+static int
+extend_sa_arr(struct ipsec_sa **sa_tbl, uint32_t cur_cnt, uint32_t *cur_sz)
+{
+	if (*sa_tbl == NULL) {
+		*sa_tbl = calloc(SA_INIT_NB, sizeof(struct ipsec_sa));
+		if (*sa_tbl == NULL)
+			return -1;
+		*cur_sz = SA_INIT_NB;
+		return 0;
+	}
+
+	if (cur_cnt >= *cur_sz) {
+		*sa_tbl = realloc(*sa_tbl,
+			*cur_sz * sizeof(struct ipsec_sa) * 2);
+		if (*sa_tbl == NULL)
+			return -1;
+		/* clean reallocated extra space */
+		memset(&(*sa_tbl)[*cur_sz], 0,
+			*cur_sz * sizeof(struct ipsec_sa));
+		*cur_sz *= 2;
+	}
+
+	return 0;
+}
+
 void
 parse_sa_tokens(char **tokens, uint32_t n_tokens,
 	struct parse_status *status)
@@ -246,23 +275,15 @@ parse_sa_tokens(char **tokens, uint32_t n_tokens,
 	if (strcmp(tokens[0], "in") == 0) {
 		ri = &nb_sa_in;
 		sa_cnt = &sa_in_cnt;
-
-		APP_CHECK(*ri <= IPSEC_SA_MAX_ENTRIES - 1, status,
-			"too many sa rules, abort insertion\n");
-		if (status->status < 0)
+		if (extend_sa_arr(&sa_in, nb_sa_in, &sa_in_sz) < 0)
 			return;
-
 		rule = &sa_in[*ri];
 		rule->direction = RTE_SECURITY_IPSEC_SA_DIR_INGRESS;
 	} else {
 		ri = &nb_sa_out;
 		sa_cnt = &sa_out_cnt;
-
-		APP_CHECK(*ri <= IPSEC_SA_MAX_ENTRIES - 1, status,
-			"too many sa rules, abort insertion\n");
-		if (status->status < 0)
+		if (extend_sa_arr(&sa_out, nb_sa_out, &sa_out_sz) < 0)
 			return;
-
 		rule = &sa_out[*ri];
 		rule->direction = RTE_SECURITY_IPSEC_SA_DIR_EGRESS;
 	}
@@ -1311,13 +1332,24 @@ ipsec_satbl_init(struct sa_ctx *ctx, uint32_t nb_ent, int32_t socket)
 	return rc;
 }
 
+static int
+sa_cmp(const void *p, const void *q)
+{
+	uint32_t spi1 = ((const struct ipsec_sa *)p)->spi;
+	uint32_t spi2 = ((const struct ipsec_sa *)q)->spi;
+
+	return (int)(spi1 - spi2);
+}
+
 /*
  * Walk through all SA rules to find an SA with given SPI
  */
 int
 sa_spi_present(struct sa_ctx *sa_ctx, uint32_t spi, int inbound)
 {
-	uint32_t i, num;
+	uint32_t num;
+	struct ipsec_sa *sa;
+	struct ipsec_sa tmpl;
 	const struct ipsec_sa *sar;
 
 	sar = sa_ctx->sa;
@@ -1326,10 +1358,11 @@ sa_spi_present(struct sa_ctx *sa_ctx, uint32_t spi, int inbound)
 	else
 		num = nb_sa_out;
 
-	for (i = 0; i != num; i++) {
-		if (sar[i].spi == spi)
-			return i;
-	}
+	tmpl.spi = spi;
+
+	sa = bsearch(&tmpl, sar, num, sizeof(struct ipsec_sa), sa_cmp);
+	if (sa != NULL)
+		return RTE_PTR_DIFF(sa, sar) / sizeof(struct ipsec_sa);
 
 	return -ENOENT;
 }
@@ -1522,3 +1555,10 @@ sa_check_offloads(uint16_t port_id, uint64_t *rx_offloads,
 	}
 	return 0;
 }
+
+void
+sa_sort_arr(void)
+{
+	qsort(sa_in, nb_sa_in, sizeof(struct ipsec_sa), sa_cmp);
+	qsort(sa_out, nb_sa_out, sizeof(struct ipsec_sa), sa_cmp);
+}
