diff --git a/MAINTAINERS b/MAINTAINERS index b064e488d5..1dda19eba5 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1196,6 +1196,8 @@ F: lib/librte_ipsec/ M: Bernard Iremonger F: app/test/test_ipsec.c F: doc/guides/prog_guide/ipsec_lib.rst +M: Vladimir Medvedkin +F: app/test/test_ipsec_sad.c Flow Classify - EXPERIMENTAL M: Bernard Iremonger diff --git a/app/test/Makefile b/app/test/Makefile index df7f77f44d..e2832fb5b2 100644 --- a/app/test/Makefile +++ b/app/test/Makefile @@ -224,6 +224,7 @@ SRCS-$(CONFIG_RTE_LIBRTE_BPF) += test_bpf.c SRCS-$(CONFIG_RTE_LIBRTE_RCU) += test_rcu_qsbr.c test_rcu_qsbr_perf.c SRCS-$(CONFIG_RTE_LIBRTE_IPSEC) += test_ipsec.c +SRCS-$(CONFIG_RTE_LIBRTE_IPSEC) += test_ipsec_sad.c ifeq ($(CONFIG_RTE_LIBRTE_IPSEC),y) LDLIBS += -lrte_ipsec endif diff --git a/app/test/autotest_data.py b/app/test/autotest_data.py index 7405149bc8..a4f2882e3e 100644 --- a/app/test/autotest_data.py +++ b/app/test/autotest_data.py @@ -518,6 +518,12 @@ "Func": default_autotest, "Report": None, }, + { + "Name": "IPsec_SAD", + "Command": "ipsec_sad_autotest", + "Func": default_autotest, + "Report": None, + }, # #Please always keep all dump tests at the end and together! # diff --git a/app/test/meson.build b/app/test/meson.build index a88b0eba6c..d066e49aff 100644 --- a/app/test/meson.build +++ b/app/test/meson.build @@ -58,6 +58,7 @@ test_sources = files('commands.c', 'test_hash_readwrite_lf.c', 'test_interrupts.c', 'test_ipsec.c', + 'test_ipsec_sad.c', 'test_kni.c', 'test_kvargs.c', 'test_latencystats.c', diff --git a/app/test/test_ipsec_sad.c b/app/test/test_ipsec_sad.c new file mode 100644 index 0000000000..491164689e --- /dev/null +++ b/app/test/test_ipsec_sad.c @@ -0,0 +1,887 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2014 Intel Corporation + */ + +#include +#include +#include +#include + +#include +#include + +#include "test.h" +#include "test_xmmt_ops.h" + +typedef int32_t (*rte_ipsec_sad_test)(void); + +static int32_t test_create_invalid(void); +static int32_t test_find_existing(void); +static int32_t test_multiple_create(void); +static int32_t test_add_invalid(void); +static int32_t test_delete_invalid(void); +static int32_t test_lookup_invalid(void); +static int32_t test_lookup_basic(void); +static int32_t test_lookup_adv(void); +static int32_t test_lookup_order(void); + +#define MAX_SA 100000 +#define PASS 0 +#define SPI 0xdead /* spi to install */ +#define DIP 0xbeef /* dip to install */ +#define SIP 0xf00d /* sip to install */ +#define BAD 0xbad /* some random value not installed into the table */ + +/* + * Check that rte_ipsec_sad_create fails gracefully for incorrect user input + * arguments + */ +int32_t +test_create_invalid(void) +{ + struct rte_ipsec_sad *sad = NULL; + struct rte_ipsec_sad_conf config; + + config.max_sa[RTE_IPSEC_SAD_SPI_ONLY] = MAX_SA; + config.max_sa[RTE_IPSEC_SAD_SPI_DIP] = MAX_SA; + config.max_sa[RTE_IPSEC_SAD_SPI_DIP_SIP] = MAX_SA; + config.socket_id = SOCKET_ID_ANY; + config.flags = 0; + + /* name == NULL */ + sad = rte_ipsec_sad_create(NULL, &config); + RTE_TEST_ASSERT(sad == NULL, + "Call succeeded with invalid parameters\n"); + + /* max_sa for every type = 0 */ + config.max_sa[RTE_IPSEC_SAD_SPI_ONLY] = 0; + config.max_sa[RTE_IPSEC_SAD_SPI_DIP] = 0; + config.max_sa[RTE_IPSEC_SAD_SPI_DIP_SIP] = 0; + sad = rte_ipsec_sad_create(__func__, &config); + RTE_TEST_ASSERT(sad == NULL, + "Call succeeded with invalid parameters\n"); + config.max_sa[RTE_IPSEC_SAD_SPI_ONLY] = MAX_SA; + config.max_sa[RTE_IPSEC_SAD_SPI_DIP] = MAX_SA; + config.max_sa[RTE_IPSEC_SAD_SPI_DIP_SIP] = MAX_SA; + + /* socket_id < -1 is invalid */ + config.max_sa[RTE_IPSEC_SAD_SPI_ONLY] = MAX_SA; + config.socket_id = -2; + sad = rte_ipsec_sad_create(__func__, &config); + RTE_TEST_ASSERT(sad == NULL, + "Call succeeded with invalid parameters\n"); + config.socket_id = SOCKET_ID_ANY; + + return TEST_SUCCESS; +} + +/* + * Test rte_ipsec_sad_find_existing() + * Create SAD and try to find it by it's name + */ +int32_t +test_find_existing(void) +{ + const char *name1 = "sad_one"; + const char *name2 = "sad_two"; + struct rte_ipsec_sad *one, *two, *tmp; + struct rte_ipsec_sad_conf config; + + config.socket_id = SOCKET_ID_ANY; + config.max_sa[RTE_IPSEC_SAD_SPI_ONLY] = MAX_SA; + config.max_sa[RTE_IPSEC_SAD_SPI_DIP] = 0; + config.max_sa[RTE_IPSEC_SAD_SPI_DIP_SIP] = 0; + one = rte_ipsec_sad_create(name1, &config); + RTE_TEST_ASSERT_NOT_NULL(one, "Failed to create SAD\n"); + two = rte_ipsec_sad_create(name2, &config); + RTE_TEST_ASSERT_NOT_NULL(two, "Failed to create SAD\n"); + + /* Find non existing */ + tmp = rte_ipsec_sad_find_existing("sad_three"); + RTE_TEST_ASSERT(tmp == NULL, + "rte_ipsec_sad_find_existing returns invalid SAD\n"); + + tmp = rte_ipsec_sad_find_existing(name1); + RTE_TEST_ASSERT(tmp == one, + "rte_ipsec_sad_find_existing returns invalid SAD\n"); + + tmp = rte_ipsec_sad_find_existing(name2); + RTE_TEST_ASSERT(tmp == two, + "rte_ipsec_sad_find_existing returns invalid SAD\n"); + + rte_ipsec_sad_destroy(one); + rte_ipsec_sad_destroy(two); + return TEST_SUCCESS; +} + +/* + * Create ipsec sad then delete it 10 times + * Use a slightly different max_sa each time + */ +int32_t +test_multiple_create(void) +{ + int i; + struct rte_ipsec_sad *sad = NULL; + struct rte_ipsec_sad_conf config; + + config.socket_id = SOCKET_ID_ANY; + config.max_sa[RTE_IPSEC_SAD_SPI_DIP] = MAX_SA; + config.max_sa[RTE_IPSEC_SAD_SPI_DIP_SIP] = MAX_SA; + + for (i = 0; i < 10; i++) { + config.max_sa[RTE_IPSEC_SAD_SPI_ONLY] = MAX_SA - i; + sad = rte_ipsec_sad_create(__func__, &config); + RTE_TEST_ASSERT_NOT_NULL(sad, "Failed to create SAD\n"); + rte_ipsec_sad_destroy(sad); + } + return TEST_SUCCESS; +} + +static int32_t +__test_add_invalid(int ipv6, union rte_ipsec_sad_key *tuple) +{ + int status; + struct rte_ipsec_sad *sad = NULL; + struct rte_ipsec_sad_conf config; + uint64_t tmp; + void *sa = &tmp; + + /* sad == NULL*/ + status = rte_ipsec_sad_add(NULL, tuple, + RTE_IPSEC_SAD_SPI_DIP_SIP, sa); + RTE_TEST_ASSERT(status < 0, + "Call succeeded with invalid parameters\n"); + + config.max_sa[RTE_IPSEC_SAD_SPI_ONLY] = MAX_SA; + config.max_sa[RTE_IPSEC_SAD_SPI_DIP] = MAX_SA; + config.max_sa[RTE_IPSEC_SAD_SPI_DIP_SIP] = MAX_SA; + config.socket_id = SOCKET_ID_ANY; + config.flags = 0; + if (ipv6) + config.flags = RTE_IPSEC_SAD_FLAG_IPV6; + + sad = rte_ipsec_sad_create(__func__, &config); + RTE_TEST_ASSERT_NOT_NULL(sad, "Failed to create SAD\n"); + + /* key == NULL*/ + status = rte_ipsec_sad_add(sad, NULL, RTE_IPSEC_SAD_SPI_DIP_SIP, sa); + RTE_TEST_ASSERT(status < 0, + "Call succeeded with invalid parameters\n"); + + /* len is incorrect*/ + status = rte_ipsec_sad_add(sad, tuple, + RTE_IPSEC_SAD_SPI_DIP_SIP + 1, sa); + RTE_TEST_ASSERT(status < 0, + "Call succeeded with invalid parameters\n"); + + /* sa == NULL*/ + status = rte_ipsec_sad_add(sad, tuple, + RTE_IPSEC_SAD_SPI_DIP_SIP, NULL); + RTE_TEST_ASSERT(status < 0, + "Call succeeded with invalid parameters\n"); + + /* sa is not aligned*/ + status = rte_ipsec_sad_add(sad, tuple, + RTE_IPSEC_SAD_SPI_DIP_SIP, (void *)((uint8_t *)sa + 1)); + RTE_TEST_ASSERT(status < 0, + "Call succeeded with invalid parameters\n"); + + rte_ipsec_sad_destroy(sad); + + return TEST_SUCCESS; +} + +/* + * Check that rte_ipsec_sad_add fails gracefully + * for incorrect user input arguments + */ +int32_t +test_add_invalid(void) +{ + int status; + struct rte_ipsec_sadv4_key tuple_v4 = {10, 20, 30}; + struct rte_ipsec_sadv6_key tuple_v6 = {10, {20, }, {30, } }; + + status = __test_add_invalid(0, (union rte_ipsec_sad_key *)&tuple_v4); + if (status != TEST_SUCCESS) + return status; + + status = __test_add_invalid(1, (union rte_ipsec_sad_key *)&tuple_v6); + + return status; + +} + +static int32_t +__test_delete_invalid(int ipv6, union rte_ipsec_sad_key *tuple) +{ + int status; + struct rte_ipsec_sad *sad = NULL; + struct rte_ipsec_sad_conf config; + + /* sad == NULL*/ + status = rte_ipsec_sad_del(NULL, tuple, RTE_IPSEC_SAD_SPI_DIP_SIP); + RTE_TEST_ASSERT(status < 0, + "Call succeeded with invalid parameters\n"); + + config.max_sa[RTE_IPSEC_SAD_SPI_ONLY] = MAX_SA; + config.max_sa[RTE_IPSEC_SAD_SPI_DIP] = MAX_SA; + config.max_sa[RTE_IPSEC_SAD_SPI_DIP_SIP] = MAX_SA; + config.socket_id = SOCKET_ID_ANY; + config.flags = 0; + if (ipv6) + config.flags = RTE_IPSEC_SAD_FLAG_IPV6; + + sad = rte_ipsec_sad_create(__func__, &config); + RTE_TEST_ASSERT_NOT_NULL(sad, "Failed to create SAD\n"); + + /* key == NULL*/ + status = rte_ipsec_sad_del(sad, NULL, RTE_IPSEC_SAD_SPI_DIP_SIP); + RTE_TEST_ASSERT(status < 0, + "Call succeeded with invalid parameters\n"); + + /* len is incorrect */ + status = rte_ipsec_sad_del(sad, tuple, RTE_IPSEC_SAD_SPI_DIP_SIP + 1); + RTE_TEST_ASSERT(status < 0, + "Call succeeded with invalid parameters\n"); + + rte_ipsec_sad_destroy(sad); + + return TEST_SUCCESS; +} + +/* + * Check that rte_ipsec_sad_delete fails gracefully for incorrect user input + * arguments + */ +int32_t +test_delete_invalid(void) +{ + int status; + struct rte_ipsec_sadv4_key tuple_v4 = {SPI, DIP, SIP}; + struct rte_ipsec_sadv6_key tuple_v6 = {SPI, {0xbe, 0xef, }, + {0xf0, 0x0d, } }; + + status = __test_delete_invalid(0, (union rte_ipsec_sad_key *)&tuple_v4); + if (status != TEST_SUCCESS) + return status; + + status = __test_delete_invalid(1, (union rte_ipsec_sad_key *)&tuple_v6); + + return status; +} + +static int32_t +__test_lookup_invalid(int ipv6, union rte_ipsec_sad_key *tuple) +{ + int status; + struct rte_ipsec_sad *sad = NULL; + struct rte_ipsec_sad_conf config; + const union rte_ipsec_sad_key *key_arr[] = {tuple}; + void *sa[1]; + + status = rte_ipsec_sad_lookup(NULL, key_arr, sa, 1); + RTE_TEST_ASSERT(status < 0, + "Call succeeded with invalid parameters\n"); + + config.max_sa[RTE_IPSEC_SAD_SPI_ONLY] = MAX_SA; + config.max_sa[RTE_IPSEC_SAD_SPI_DIP] = MAX_SA; + config.max_sa[RTE_IPSEC_SAD_SPI_DIP_SIP] = MAX_SA; + config.socket_id = SOCKET_ID_ANY; + config.flags = 0; + if (ipv6) + config.flags = RTE_IPSEC_SAD_FLAG_IPV6; + + sad = rte_ipsec_sad_create(__func__, &config); + RTE_TEST_ASSERT_NOT_NULL(sad, "Failed to create SAD\n"); + + status = rte_ipsec_sad_lookup(sad, NULL, sa, 1); + RTE_TEST_ASSERT(status < 0, + "Call succeeded with invalid parameters\n"); + + status = rte_ipsec_sad_lookup(sad, key_arr, NULL, 1); + RTE_TEST_ASSERT(status < 0, + "Call succeeded with invalid parameters\n"); + + rte_ipsec_sad_destroy(sad); + + return TEST_SUCCESS; +} + +/* + * Check that rte_ipsec_sad_lookup fails gracefully for incorrect user input + * arguments + */ +int32_t +test_lookup_invalid(void) +{ + int status; + struct rte_ipsec_sadv4_key tuple_v4 = {10, 20, 30}; + struct rte_ipsec_sadv6_key tuple_v6 = {10, {20, }, {30, } }; + + status = __test_lookup_invalid(0, + (union rte_ipsec_sad_key *)&tuple_v4); + if (status != TEST_SUCCESS) + return status; + + status = __test_lookup_invalid(1, + (union rte_ipsec_sad_key *)&tuple_v6); + + return status; +} + +static int32_t +__test_lookup_basic(int ipv6, union rte_ipsec_sad_key *tuple, + union rte_ipsec_sad_key *tuple_1) +{ + int status; + struct rte_ipsec_sad *sad = NULL; + struct rte_ipsec_sad_conf config; + const union rte_ipsec_sad_key *key_arr[] = {tuple}; + + uint64_t tmp; + void *sa[1]; + + config.max_sa[RTE_IPSEC_SAD_SPI_ONLY] = MAX_SA; + config.max_sa[RTE_IPSEC_SAD_SPI_DIP] = MAX_SA; + config.max_sa[RTE_IPSEC_SAD_SPI_DIP_SIP] = MAX_SA; + config.socket_id = SOCKET_ID_ANY; + config.flags = 0; + if (ipv6) + config.flags = RTE_IPSEC_SAD_FLAG_IPV6; + + sad = rte_ipsec_sad_create(__func__, &config); + RTE_TEST_ASSERT_NOT_NULL(sad, "Failed to create SAD\n"); + + status = rte_ipsec_sad_lookup(sad, key_arr, sa, 1); + RTE_TEST_ASSERT((status == 0) && (sa[0] == NULL), + "Lookup returns an unexpected result\n"); + + sa[0] = &tmp; + status = rte_ipsec_sad_add(sad, tuple, RTE_IPSEC_SAD_SPI_ONLY, sa[0]); + RTE_TEST_ASSERT(status == 0, "Failed to add a rule\n"); + + status = rte_ipsec_sad_lookup(sad, key_arr, sa, 1); + RTE_TEST_ASSERT((status == 1) && (sa[0] == &tmp), + "Lookup returns an unexpected result\n"); + + key_arr[0] = tuple_1; + status = rte_ipsec_sad_lookup(sad, key_arr, sa, 1); + RTE_TEST_ASSERT((status == 1) && (sa[0] == &tmp), + "Lookup returns an unexpected result\n"); + key_arr[0] = tuple; + + status = rte_ipsec_sad_del(sad, tuple, RTE_IPSEC_SAD_SPI_ONLY); + RTE_TEST_ASSERT(status == 0, "Failed to delete a rule\n"); + + status = rte_ipsec_sad_lookup(sad, key_arr, sa, 1); + RTE_TEST_ASSERT((status == 0) && (sa[0] == NULL), + "Lookup returns an unexpected result\n"); + + rte_ipsec_sad_destroy(sad); + + return TEST_SUCCESS; +} + +/* + * Lookup missing key, then add it as RTE_IPSEC_SAD_SPI_ONLY, lookup it again, + * lookup different key with the same SPI, then delete it and repeat lookup + */ +int32_t +test_lookup_basic(void) +{ + int status; + struct rte_ipsec_sadv4_key tuple_v4 = {SPI, DIP, SIP}; + struct rte_ipsec_sadv4_key tuple_v4_1 = {SPI, BAD, BAD}; + struct rte_ipsec_sadv6_key tuple_v6 = {SPI, {0xbe, 0xef, }, + {0xf0, 0x0d, } }; + struct rte_ipsec_sadv6_key tuple_v6_1 = {SPI, {0x0b, 0xad, }, + {0x0b, 0xad, } }; + + status = __test_lookup_basic(0, (union rte_ipsec_sad_key *)&tuple_v4, + (union rte_ipsec_sad_key *)&tuple_v4_1); + if (status != TEST_SUCCESS) + return status; + + status = __test_lookup_basic(1, (union rte_ipsec_sad_key *)&tuple_v6, + (union rte_ipsec_sad_key *)&tuple_v6_1); + + return status; +} + +static int32_t +__test_lookup_adv(int ipv6, union rte_ipsec_sad_key *tuple, + const union rte_ipsec_sad_key **key_arr) +{ + int status; + struct rte_ipsec_sad *sad = NULL; + struct rte_ipsec_sad_conf config; + uint64_t tmp1, tmp2, tmp3; + void *install_sa; + void *sa[4]; + + config.max_sa[RTE_IPSEC_SAD_SPI_ONLY] = MAX_SA; + config.max_sa[RTE_IPSEC_SAD_SPI_DIP] = MAX_SA; + config.max_sa[RTE_IPSEC_SAD_SPI_DIP_SIP] = MAX_SA; + config.socket_id = SOCKET_ID_ANY; + config.flags = 0; + if (ipv6) + config.flags = RTE_IPSEC_SAD_FLAG_IPV6; + sad = rte_ipsec_sad_create(__func__, &config); + RTE_TEST_ASSERT_NOT_NULL(sad, "Failed to create SAD\n"); + + /* lookup with empty table */ + status = rte_ipsec_sad_lookup(sad, key_arr, sa, 4); + RTE_TEST_ASSERT(status == 0, "Lookup returns an unexpected result\n"); + RTE_TEST_ASSERT(sa[0] == NULL, + "Lookup returns an unexpected result\n"); + RTE_TEST_ASSERT(sa[1] == NULL, + "Lookup returns an unexpected result\n"); + RTE_TEST_ASSERT(sa[2] == NULL, + "Lookup returns an unexpected result\n"); + RTE_TEST_ASSERT(sa[3] == NULL, + "Lookup returns an unexpected result\n"); + + /* lookup with one RTE_IPSEC_SAD_SPI_ONLY rule */ + install_sa = &tmp1; + status = rte_ipsec_sad_add(sad, tuple, + RTE_IPSEC_SAD_SPI_ONLY, install_sa); + RTE_TEST_ASSERT(status == 0, "Failed to add a rule\n"); + + status = rte_ipsec_sad_lookup(sad, key_arr, sa, 4); + RTE_TEST_ASSERT(status == 3, "Lookup returns an unexpected result\n"); + RTE_TEST_ASSERT(sa[0] == &tmp1, + "Lookup returns an unexpected result\n"); + RTE_TEST_ASSERT(sa[1] == &tmp1, + "Lookup returns an unexpected result\n"); + RTE_TEST_ASSERT(sa[2] == &tmp1, + "Lookup returns an unexpected result\n"); + RTE_TEST_ASSERT(sa[3] == NULL, + "Lookup returns an unexpected result\n"); + + status = rte_ipsec_sad_del(sad, tuple, RTE_IPSEC_SAD_SPI_ONLY); + RTE_TEST_ASSERT(status == 0, "Failde to delete a rule\n"); + + /* lookup with one RTE_IPSEC_SAD_SPI_DIP rule */ + install_sa = &tmp2; + status = rte_ipsec_sad_add(sad, tuple, + RTE_IPSEC_SAD_SPI_DIP, install_sa); + RTE_TEST_ASSERT(status == 0, "failed to add a rule\n"); + + status = rte_ipsec_sad_lookup(sad, key_arr, sa, 4); + RTE_TEST_ASSERT(status == 2, "Lookup returns an unexpected result\n"); + RTE_TEST_ASSERT(sa[0] == &tmp2, + "Lookup returns an unexpected result\n"); + RTE_TEST_ASSERT(sa[1] == &tmp2, + "Lookup returns an unexpected result\n"); + RTE_TEST_ASSERT(sa[2] == NULL, + "Lookup returns an unexpected result\n"); + RTE_TEST_ASSERT(sa[3] == NULL, + "Lookup returns an unexpected result\n"); + + status = rte_ipsec_sad_del(sad, tuple, RTE_IPSEC_SAD_SPI_DIP); + RTE_TEST_ASSERT(status == 0, "Failed to delete a rule\n"); + + /* lookup with one RTE_IPSEC_SAD_SPI_DIP_SIP rule */ + install_sa = &tmp3; + status = rte_ipsec_sad_add(sad, tuple, + RTE_IPSEC_SAD_SPI_DIP_SIP, install_sa); + RTE_TEST_ASSERT(status == 0, "Failed to add a rule\n"); + + status = rte_ipsec_sad_lookup(sad, key_arr, sa, 4); + RTE_TEST_ASSERT(status == 1, "Lookup returns an unexpected result\n"); + RTE_TEST_ASSERT(sa[0] == &tmp3, + "Lookup returns an unexpected result\n"); + RTE_TEST_ASSERT(sa[1] == NULL, + "Lookup returns an unexpected result\n"); + RTE_TEST_ASSERT(sa[2] == NULL, + "Lookup returns an unexpected result\n"); + RTE_TEST_ASSERT(sa[3] == NULL, + "Lookup returns an unexpected result\n"); + + status = rte_ipsec_sad_del(sad, tuple, RTE_IPSEC_SAD_SPI_DIP_SIP); + RTE_TEST_ASSERT(status == 0, "Failed to delete a rule\n"); + + /* lookup with two RTE_IPSEC_SAD_ONLY and RTE_IPSEC_SAD_DIP rules */ + install_sa = &tmp1; + status = rte_ipsec_sad_add(sad, tuple, + RTE_IPSEC_SAD_SPI_ONLY, install_sa); + RTE_TEST_ASSERT(status == 0, "Failed to add a rule\n"); + install_sa = &tmp2; + status = rte_ipsec_sad_add(sad, tuple, + RTE_IPSEC_SAD_SPI_DIP, install_sa); + RTE_TEST_ASSERT(status == 0, "Failed to add a rule\n"); + + status = rte_ipsec_sad_lookup(sad, key_arr, sa, 4); + RTE_TEST_ASSERT(status == 3, "Lookup returns an unexpected result\n"); + RTE_TEST_ASSERT(sa[0] == &tmp2, + "Lookup returns an unexpected result\n"); + RTE_TEST_ASSERT(sa[1] == &tmp2, + "Lookup returns an unexpected result\n"); + RTE_TEST_ASSERT(sa[2] == &tmp1, + "Lookup returns an unexpected result\n"); + RTE_TEST_ASSERT(sa[3] == NULL, + "Lookup returns an unexpected result\n"); + + status = rte_ipsec_sad_del(sad, tuple, RTE_IPSEC_SAD_SPI_ONLY); + RTE_TEST_ASSERT(status == 0, "Failed to delete a rule\n"); + status = rte_ipsec_sad_del(sad, tuple, RTE_IPSEC_SAD_SPI_DIP); + RTE_TEST_ASSERT(status == 0, "Failed to delete a rule\n"); + + /* lookup with two RTE_IPSEC_SAD_ONLY and RTE_IPSEC_SAD_DIP_SIP rules */ + install_sa = &tmp1; + status = rte_ipsec_sad_add(sad, tuple, + RTE_IPSEC_SAD_SPI_ONLY, install_sa); + RTE_TEST_ASSERT(status == 0, "Failed to add a rule\n"); + install_sa = &tmp3; + status = rte_ipsec_sad_add(sad, tuple, + RTE_IPSEC_SAD_SPI_DIP_SIP, install_sa); + RTE_TEST_ASSERT(status == 0, "Failed to add a rule\n"); + + status = rte_ipsec_sad_lookup(sad, key_arr, sa, 4); + RTE_TEST_ASSERT(status == 3, "Lookup returns an unexpected result\n"); + RTE_TEST_ASSERT(sa[0] == &tmp3, + "Lookup returns an unexpected result\n"); + RTE_TEST_ASSERT(sa[1] == &tmp1, + "Lookup returns an unexpected result\n"); + RTE_TEST_ASSERT(sa[2] == &tmp1, + "Lookup returns an unexpected result\n"); + RTE_TEST_ASSERT(sa[3] == NULL, + "Lookup returns an unexpected result\n"); + + status = rte_ipsec_sad_del(sad, tuple, RTE_IPSEC_SAD_SPI_ONLY); + RTE_TEST_ASSERT(status == 0, "Failed to delete a rule\n"); + status = rte_ipsec_sad_del(sad, tuple, RTE_IPSEC_SAD_SPI_DIP_SIP); + RTE_TEST_ASSERT(status == 0, "Failed to delete a rule\n"); + + /* lookup with two RTE_IPSEC_SAD_DIP and RTE_IPSEC_SAD_DIP_SIP rules */ + install_sa = &tmp2; + status = rte_ipsec_sad_add(sad, tuple, + RTE_IPSEC_SAD_SPI_DIP, install_sa); + RTE_TEST_ASSERT(status == 0, "Failed to add a rule\n"); + install_sa = &tmp3; + status = rte_ipsec_sad_add(sad, tuple, + RTE_IPSEC_SAD_SPI_DIP_SIP, install_sa); + RTE_TEST_ASSERT(status == 0, "Failed to add a rule\n"); + + status = rte_ipsec_sad_lookup(sad, key_arr, sa, 4); + RTE_TEST_ASSERT(status == 2, "Lookup returns an unexpected result\n"); + RTE_TEST_ASSERT(sa[0] == &tmp3, + "Lookup returns an unexpected result\n"); + RTE_TEST_ASSERT(sa[1] == &tmp2, + "Lookup returns an unexpected result\n"); + RTE_TEST_ASSERT(sa[2] == NULL, + "Lookup returns an unexpected result\n"); + RTE_TEST_ASSERT(sa[3] == NULL, + "Lookup returns an unexpected result\n"); + + status = rte_ipsec_sad_del(sad, tuple, RTE_IPSEC_SAD_SPI_DIP); + RTE_TEST_ASSERT(status == 0, "Failed to delete a rule\n"); + status = rte_ipsec_sad_del(sad, tuple, RTE_IPSEC_SAD_SPI_DIP_SIP); + RTE_TEST_ASSERT(status == 0, "Failed to delete a rule\n"); + + /* + * lookup with three RTE_IPSEC_SAD_DIP, RTE_IPSEC_SAD_DIP and + * RTE_IPSEC_SAD_DIP_SIP rules + */ + install_sa = &tmp1; + status = rte_ipsec_sad_add(sad, tuple, + RTE_IPSEC_SAD_SPI_ONLY, install_sa); + RTE_TEST_ASSERT(status == 0, "Failed to add a rule\n"); + install_sa = &tmp2; + status = rte_ipsec_sad_add(sad, tuple, + RTE_IPSEC_SAD_SPI_DIP, install_sa); + RTE_TEST_ASSERT(status == 0, "Failed to add a rule\n"); + install_sa = &tmp3; + status = rte_ipsec_sad_add(sad, tuple, + RTE_IPSEC_SAD_SPI_DIP_SIP, install_sa); + RTE_TEST_ASSERT(status == 0, "Failed to add a rule\n"); + + status = rte_ipsec_sad_lookup(sad, key_arr, sa, 4); + RTE_TEST_ASSERT(status == 3, "Lookup returns an unexpected result\n"); + RTE_TEST_ASSERT(sa[0] == &tmp3, + "Lookup returns an unexpected result\n"); + RTE_TEST_ASSERT(sa[1] == &tmp2, + "Lookup returns an unexpected result\n"); + RTE_TEST_ASSERT(sa[2] == &tmp1, + "Lookup returns an unexpected result\n"); + RTE_TEST_ASSERT(sa[3] == NULL, + "Lookup returns an unexpected result\n"); + + status = rte_ipsec_sad_del(sad, tuple, RTE_IPSEC_SAD_SPI_ONLY); + RTE_TEST_ASSERT(status == 0, "Failed to delete a rule\n"); + status = rte_ipsec_sad_del(sad, tuple, RTE_IPSEC_SAD_SPI_DIP); + RTE_TEST_ASSERT(status == 0, "Failed to delete a rule\n"); + status = rte_ipsec_sad_del(sad, tuple, RTE_IPSEC_SAD_SPI_DIP_SIP); + RTE_TEST_ASSERT(status == 0, "Failed to delete a rule\n"); + + rte_ipsec_sad_destroy(sad); + + return TEST_SUCCESS; +} + +/* + * Lookup different keys in a table with: + * - RTE_IPSEC_SAD_SPI_ONLY + * - RTE_IPSEC_SAD_SPI_DIP + * - RTE_IPSEC_SAD_SPI_SIP + * - RTE_IPSEC_SAD_SPI_ONLY/RTE_IPSEC_SAD_SPI_DIP + * - RTE_IPSEC_SAD_SPI_ONLY/RTE_IPSEC_SAD_SPI_DIP_SIP + * - RTE_IPSEC_SAD_SPI_DIP/RTE_IPSEC_SAD_SPI_DIP_SIP + * - RTE_IPSEC_SAD_SPI_ONLY/RTE_IPSEC_SAD_SPI_DIP/RTE_IPSEC_SAD_SPI_DIP_SIP + * length of rule installed. + */ +int32_t +test_lookup_adv(void) +{ + int status; + /* key to install*/ + struct rte_ipsec_sadv4_key tuple_v4 = {SPI, DIP, SIP}; + struct rte_ipsec_sadv4_key tuple_v4_1 = {SPI, DIP, BAD}; + struct rte_ipsec_sadv4_key tuple_v4_2 = {SPI, BAD, SIP}; + struct rte_ipsec_sadv4_key tuple_v4_3 = {BAD, DIP, SIP}; + + /* key to install*/ + struct rte_ipsec_sadv6_key tuple_v6 = {SPI, {0xbe, 0xef, }, + {0xf0, 0x0d, } }; + struct rte_ipsec_sadv6_key tuple_v6_1 = {SPI, {0xbe, 0xef, }, + {0x0b, 0xad, } }; + struct rte_ipsec_sadv6_key tuple_v6_2 = {SPI, {0x0b, 0xad, }, + {0xf0, 0x0d, } }; + struct rte_ipsec_sadv6_key tuple_v6_3 = {BAD, {0xbe, 0xef, }, + {0xf0, 0x0d, } }; + + const union rte_ipsec_sad_key *key_arr[] = { + (union rte_ipsec_sad_key *)&tuple_v4, + (union rte_ipsec_sad_key *)&tuple_v4_1, + (union rte_ipsec_sad_key *)&tuple_v4_2, + (union rte_ipsec_sad_key *)&tuple_v4_3 + }; + + status = __test_lookup_adv(0, (union rte_ipsec_sad_key *)&tuple_v4, + key_arr); + if (status != TEST_SUCCESS) + return status; + key_arr[0] = (union rte_ipsec_sad_key *)&tuple_v6; + key_arr[1] = (union rte_ipsec_sad_key *)&tuple_v6_1; + key_arr[2] = (union rte_ipsec_sad_key *)&tuple_v6_2; + key_arr[3] = (union rte_ipsec_sad_key *)&tuple_v6_3; + status = __test_lookup_adv(1, (union rte_ipsec_sad_key *)&tuple_v6, + key_arr); + + return status; +} + + +static int32_t +__test_lookup_order(int ipv6, union rte_ipsec_sad_key *tuple, + union rte_ipsec_sad_key *tuple_1, union rte_ipsec_sad_key *tuple_2) +{ + int status; + struct rte_ipsec_sad *sad = NULL; + struct rte_ipsec_sad_conf config; + const union rte_ipsec_sad_key *key_arr[] = {tuple, tuple_1, tuple_2,}; + uint64_t tmp1, tmp2, tmp3; + void *install_sa; + void *sa[3]; + + config.max_sa[RTE_IPSEC_SAD_SPI_ONLY] = MAX_SA; + config.max_sa[RTE_IPSEC_SAD_SPI_DIP] = MAX_SA; + config.max_sa[RTE_IPSEC_SAD_SPI_DIP_SIP] = MAX_SA; + config.socket_id = SOCKET_ID_ANY; + config.flags = 0; + if (ipv6) + config.flags = RTE_IPSEC_SAD_FLAG_IPV6; + sad = rte_ipsec_sad_create(__func__, &config); + RTE_TEST_ASSERT_NOT_NULL(sad, "Failed to create SAD\n"); + + /* install RTE_IPSEC_SAD_SPI_ONLY */ + install_sa = &tmp1; + status = rte_ipsec_sad_add(sad, tuple, + RTE_IPSEC_SAD_SPI_ONLY, install_sa); + RTE_TEST_ASSERT(status == 0, "Failed to add a rule\n"); + + status = rte_ipsec_sad_lookup(sad, key_arr, sa, 3); + RTE_TEST_ASSERT(status == 3, "Lookup returns an unexpected result\n"); + RTE_TEST_ASSERT(sa[0] == &tmp1, + "Lookup returns an unexpected result\n"); + RTE_TEST_ASSERT(sa[1] == &tmp1, + "Lookup returns an unexpected result\n"); + RTE_TEST_ASSERT(sa[2] == &tmp1, + "Lookup returns an unexpected result\n"); + + /* add RTE_IPSEC_SAD_SPI_DIP */ + install_sa = &tmp2; + status = rte_ipsec_sad_add(sad, tuple, + RTE_IPSEC_SAD_SPI_DIP, install_sa); + RTE_TEST_ASSERT(status == 0, "Failed to add a rule\n"); + + status = rte_ipsec_sad_lookup(sad, key_arr, sa, 3); + RTE_TEST_ASSERT(status == 3, "Lookup returns an unexpected result\n"); + RTE_TEST_ASSERT(sa[0] == &tmp2, + "Lookup returns an unexpected result\n"); + RTE_TEST_ASSERT(sa[1] == &tmp2, + "Lookup returns an unexpected result\n"); + RTE_TEST_ASSERT(sa[2] == &tmp1, + "Lookup returns an unexpected result\n"); + + /* add RTE_IPSEC_SAD_SPI_DIP_SIP */ + install_sa = &tmp3; + status = rte_ipsec_sad_add(sad, tuple, + RTE_IPSEC_SAD_SPI_DIP_SIP, install_sa); + RTE_TEST_ASSERT(status == 0, "Failed to add a rule\n"); + + status = rte_ipsec_sad_lookup(sad, key_arr, sa, 3); + RTE_TEST_ASSERT(status == 3, "Lookup returns an unexpected result\n"); + RTE_TEST_ASSERT(sa[0] == &tmp3, + "Lookup returns an unexpected result\n"); + RTE_TEST_ASSERT(sa[1] == &tmp2, + "Lookup returns an unexpected result\n"); + RTE_TEST_ASSERT(sa[2] == &tmp1, + "Lookup returns an unexpected result\n"); + + /* delete RTE_IPSEC_SAD_SPI_ONLY */ + status = rte_ipsec_sad_del(sad, tuple, RTE_IPSEC_SAD_SPI_ONLY); + RTE_TEST_ASSERT(status == 0, "Failed to delete a rule\n"); + + status = rte_ipsec_sad_lookup(sad, key_arr, sa, 3); + RTE_TEST_ASSERT(status == 2, "Lookup returns an unexpected result\n"); + RTE_TEST_ASSERT(sa[0] == &tmp3, + "Lookup returns an unexpected result\n"); + RTE_TEST_ASSERT(sa[1] == &tmp2, + "Lookup returns an unexpected result\n"); + RTE_TEST_ASSERT(sa[2] == NULL, + "Lookup returns an unexpected result\n"); + + /* delete RTE_IPSEC_SAD_SPI_DIP */ + status = rte_ipsec_sad_del(sad, tuple, RTE_IPSEC_SAD_SPI_DIP); + RTE_TEST_ASSERT(status == 0, "Failed to delete a rule\n"); + + status = rte_ipsec_sad_lookup(sad, key_arr, sa, 3); + RTE_TEST_ASSERT(status == 1, "Lookup returns an unexpected result\n"); + RTE_TEST_ASSERT(sa[0] == &tmp3, + "Lookup returns an unexpected result\n"); + RTE_TEST_ASSERT(sa[1] == NULL, + "Lookup returns an unexpected result\n"); + RTE_TEST_ASSERT(sa[2] == NULL, + "Lookup returns an unexpected result\n"); + + /* delete RTE_IPSEC_SAD_SPI_DIP_SIP */ + status = rte_ipsec_sad_del(sad, tuple, RTE_IPSEC_SAD_SPI_DIP_SIP); + RTE_TEST_ASSERT(status == 0, "Failed to delete a rule\n"); + + status = rte_ipsec_sad_lookup(sad, key_arr, sa, 3); + RTE_TEST_ASSERT(status == 0, "Lookup returns an unexpected result\n"); + RTE_TEST_ASSERT(sa[0] == NULL, + "Lookup returns an unexpected result\n"); + RTE_TEST_ASSERT(sa[1] == NULL, + "Lookup returns an unexpected result\n"); + RTE_TEST_ASSERT(sa[2] == NULL, + "Lookup returns an unexpected result\n"); + + /* add RTE_IPSEC_SAD_SPI_DIP_SIP */ + install_sa = &tmp3; + status = rte_ipsec_sad_add(sad, tuple, + RTE_IPSEC_SAD_SPI_DIP_SIP, install_sa); + RTE_TEST_ASSERT(status == 0, "Failed to add a rule\n"); + + status = rte_ipsec_sad_lookup(sad, key_arr, sa, 3); + RTE_TEST_ASSERT(status == 1, "Lookup returns an unexpected result\n"); + RTE_TEST_ASSERT(sa[0] == &tmp3, + "Lookup returns an unexpected result\n"); + RTE_TEST_ASSERT(sa[1] == NULL, + "Lookup returns an unexpected result\n"); + RTE_TEST_ASSERT(sa[2] == NULL, + "Lookup returns an unexpected result\n"); + + /* add RTE_IPSEC_SAD_SPI_DIP */ + install_sa = &tmp2; + status = rte_ipsec_sad_add(sad, tuple, + RTE_IPSEC_SAD_SPI_DIP, install_sa); + RTE_TEST_ASSERT(status == 0, "Failed to add a rule\n"); + + status = rte_ipsec_sad_lookup(sad, key_arr, sa, 3); + RTE_TEST_ASSERT(status == 2, "Lookup returns an unexpected result\n"); + RTE_TEST_ASSERT(sa[0] == &tmp3, + "Lookup returns an unexpected result\n"); + RTE_TEST_ASSERT(sa[1] == &tmp2, + "Lookup returns an unexpected result\n"); + RTE_TEST_ASSERT(sa[2] == NULL, + "Lookup returns an unexpected result\n"); + + /* add RTE_IPSEC_SAD_SPI_ONLY */ + install_sa = &tmp1; + status = rte_ipsec_sad_add(sad, tuple, + RTE_IPSEC_SAD_SPI_ONLY, install_sa); + RTE_TEST_ASSERT(status == 0, "Failed to add a rule\n"); + + status = rte_ipsec_sad_lookup(sad, key_arr, sa, 3); + RTE_TEST_ASSERT(status == 3, "Lookup returns an unexpected result\n"); + RTE_TEST_ASSERT(sa[0] == &tmp3, + "Lookup returns an unexpected result\n"); + RTE_TEST_ASSERT(sa[1] == &tmp2, + "Lookup returns an unexpected result\n"); + RTE_TEST_ASSERT(sa[2] == &tmp1, + "Lookup returns an unexpected result\n"); + + rte_ipsec_sad_destroy(sad); + return TEST_SUCCESS; +} + +/* + * Check an order of add and delete + */ +int32_t +test_lookup_order(void) +{ + int status; + /* key to install*/ + struct rte_ipsec_sadv4_key tuple_v4 = {SPI, DIP, SIP}; + struct rte_ipsec_sadv4_key tuple_v4_1 = {SPI, DIP, BAD}; + struct rte_ipsec_sadv4_key tuple_v4_2 = {SPI, BAD, SIP}; + /* key to install*/ + struct rte_ipsec_sadv6_key tuple_v6 = {SPI, {0xbe, 0xef, }, + {0xf0, 0x0d, } }; + struct rte_ipsec_sadv6_key tuple_v6_1 = {SPI, {0xbe, 0xef, }, + {0x0b, 0xad, } }; + struct rte_ipsec_sadv6_key tuple_v6_2 = {SPI, {0x0b, 0xad, }, + {0xf0, 0x0d, } }; + + status = __test_lookup_order(0, (union rte_ipsec_sad_key *)&tuple_v4, + (union rte_ipsec_sad_key *)&tuple_v4_1, + (union rte_ipsec_sad_key *)&tuple_v4_2); + if (status != TEST_SUCCESS) + return status; + + status = __test_lookup_order(1, (union rte_ipsec_sad_key *)&tuple_v6, + (union rte_ipsec_sad_key *)&tuple_v6_1, + (union rte_ipsec_sad_key *)&tuple_v6_2); + return status; +} + +static struct unit_test_suite ipsec_sad_tests = { + .suite_name = "ipsec sad autotest", + .setup = NULL, + .teardown = NULL, + .unit_test_cases = { + TEST_CASE(test_create_invalid), + TEST_CASE(test_find_existing), + TEST_CASE(test_multiple_create), + TEST_CASE(test_add_invalid), + TEST_CASE(test_delete_invalid), + TEST_CASE(test_lookup_invalid), + TEST_CASE(test_lookup_basic), + TEST_CASE(test_lookup_adv), + TEST_CASE(test_lookup_order), + TEST_CASES_END() + } +}; + +static int +test_ipsec_sad(void) +{ + return unit_test_suite_runner(&ipsec_sad_tests); +} + +REGISTER_TEST_COMMAND(ipsec_sad_autotest, test_ipsec_sad);