From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from dpdk.org (dpdk.org [92.243.14.124]) by inbox.dpdk.org (Postfix) with ESMTP id 29199A0510; Wed, 18 Dec 2019 17:01:06 +0100 (CET) Received: from [92.243.14.124] (localhost [127.0.0.1]) by dpdk.org (Postfix) with ESMTP id 7DDD51BF71; Wed, 18 Dec 2019 17:00:34 +0100 (CET) Received: from mga04.intel.com (mga04.intel.com [192.55.52.120]) by dpdk.org (Postfix) with ESMTP id CDE7E5681 for ; Wed, 18 Dec 2019 17:00:30 +0100 (CET) X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from fmsmga003.fm.intel.com ([10.253.24.29]) by fmsmga104.fm.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 18 Dec 2019 08:00:30 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.69,330,1571727600"; d="scan'208";a="266922960" Received: from silpixa00400072.ir.intel.com ([10.237.222.213]) by FMSMGA003.fm.intel.com with ESMTP; 18 Dec 2019 08:00:29 -0800 From: Vladimir Medvedkin To: dev@dpdk.org Cc: konstantin.ananyev@intel.com, akhil.goyal@nxp.com Date: Wed, 18 Dec 2019 16:00:21 +0000 Message-Id: <4f2553a3a2f24442574dc61b8f780c6c10cde83a.1576684589.git.vladimir.medvedkin@intel.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: References: In-Reply-To: References: Subject: [dpdk-dev] [PATCH v2 3/5] examples/ipsec-secgw: integrate inbound SAD X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Sender: "dev" Integrate ipsec SAD support into secgw app: 1. Use SAD library for inbound SA lookup 2. Changes in struct sa_ctx: - sa array allocates dynamically depending on number of configured sa - All SA's are kept one by one without using SPI2IDX 3. SP's userdata now contain index of SA in sa_ctx instead of SPI 4. Get rid of SPI2IDX macro Signed-off-by: Vladimir Medvedkin --- examples/ipsec-secgw/Makefile | 1 + examples/ipsec-secgw/ipsec-secgw.c | 4 +- examples/ipsec-secgw/ipsec.h | 2 +- examples/ipsec-secgw/meson.build | 2 +- examples/ipsec-secgw/sa.c | 160 +++++++++++++++++-------------------- examples/ipsec-secgw/sp4.c | 24 +++--- examples/ipsec-secgw/sp6.c | 24 +++--- 7 files changed, 110 insertions(+), 107 deletions(-) diff --git a/examples/ipsec-secgw/Makefile b/examples/ipsec-secgw/Makefile index 851123b..8734b15 100644 --- a/examples/ipsec-secgw/Makefile +++ b/examples/ipsec-secgw/Makefile @@ -12,6 +12,7 @@ SRCS-y += esp.c SRCS-y += sp4.c SRCS-y += sp6.c SRCS-y += sa.c +SRCS-y += sad.c SRCS-y += rt.c SRCS-y += ipsec_process.c SRCS-y += ipsec-secgw.c diff --git a/examples/ipsec-secgw/ipsec-secgw.c b/examples/ipsec-secgw/ipsec-secgw.c index 3b5aaf6..3e5f82e 100644 --- a/examples/ipsec-secgw/ipsec-secgw.c +++ b/examples/ipsec-secgw/ipsec-secgw.c @@ -601,7 +601,7 @@ inbound_sp_sa(struct sp_ctx *sp, struct sa_ctx *sa, struct traffic_type *ip, continue; } - sa_idx = SPI2IDX(res); + sa_idx = res - 1; if (!inbound_sa_check(sa, m, sa_idx)) { rte_pktmbuf_free(m); continue; @@ -688,7 +688,7 @@ outbound_sp(struct sp_ctx *sp, struct traffic_type *ip, j = 0; for (i = 0; i < ip->num; i++) { m = ip->pkts[i]; - sa_idx = SPI2IDX(ip->res[i]); + sa_idx = ip->res[i] - 1; if (ip->res[i] == DISCARD) rte_pktmbuf_free(m); else if (ip->res[i] == BYPASS) diff --git a/examples/ipsec-secgw/ipsec.h b/examples/ipsec-secgw/ipsec.h index 132286c..f731bf8 100644 --- a/examples/ipsec-secgw/ipsec.h +++ b/examples/ipsec-secgw/ipsec.h @@ -363,7 +363,7 @@ sp6_spi_present(uint32_t spi, int inbound, struct ip_addr ip_addr[2], * or -ENOENT otherwise. */ int -sa_spi_present(uint32_t spi, int inbound); +sa_spi_present(struct sa_ctx *sa_ctx, uint32_t spi, int inbound); void sa_init(struct socket_ctx *ctx, int32_t socket_id); diff --git a/examples/ipsec-secgw/meson.build b/examples/ipsec-secgw/meson.build index 9ece345..6bd5b78 100644 --- a/examples/ipsec-secgw/meson.build +++ b/examples/ipsec-secgw/meson.build @@ -10,5 +10,5 @@ deps += ['security', 'lpm', 'acl', 'hash', 'ip_frag', 'ipsec'] allow_experimental_apis = true sources = files( 'esp.c', 'ipsec.c', 'ipsec_process.c', 'ipsec-secgw.c', - 'parser.c', 'rt.c', 'sa.c', 'sp4.c', 'sp6.c' + 'parser.c', 'rt.c', 'sa.c', 'sad.c', 'sp4.c', 'sp6.c' ) diff --git a/examples/ipsec-secgw/sa.c b/examples/ipsec-secgw/sa.c index 7f046e3..8cc7b17 100644 --- a/examples/ipsec-secgw/sa.c +++ b/examples/ipsec-secgw/sa.c @@ -24,6 +24,7 @@ #include "ipsec.h" #include "esp.h" #include "parser.h" +#include "sad.h" #define IPDEFTTL 64 @@ -134,9 +135,11 @@ const struct supported_aead_algo aead_algos[] = { static struct ipsec_sa sa_out[IPSEC_SA_MAX_ENTRIES]; 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 uint32_t nb_sa_in; +static struct ipsec_sa_cnt sa_in_cnt; static const struct supported_cipher_algo * find_match_cipher_algo(const char *cipher_keyword) @@ -229,6 +232,7 @@ parse_sa_tokens(char **tokens, uint32_t n_tokens, struct rte_ipsec_session *ips; uint32_t ti; /*token index*/ uint32_t *ri /*rule index*/; + struct ipsec_sa_cnt *sa_cnt; uint32_t cipher_algo_p = 0; uint32_t auth_algo_p = 0; uint32_t aead_algo_p = 0; @@ -241,6 +245,7 @@ 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"); @@ -251,6 +256,7 @@ parse_sa_tokens(char **tokens, uint32_t n_tokens, 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"); @@ -280,13 +286,16 @@ parse_sa_tokens(char **tokens, uint32_t n_tokens, if (status->status < 0) return; - if (strcmp(tokens[ti], "ipv4-tunnel") == 0) + if (strcmp(tokens[ti], "ipv4-tunnel") == 0) { + sa_cnt->nb_v4_tun++; rule->flags = IP4_TUNNEL; - else if (strcmp(tokens[ti], "ipv6-tunnel") == 0) + } else if (strcmp(tokens[ti], "ipv6-tunnel") == 0) { + sa_cnt->nb_v6_tun++; rule->flags = IP6_TUNNEL; - else if (strcmp(tokens[ti], "transport") == 0) + } else if (strcmp(tokens[ti], "transport") == 0) { + sa_cnt->nb_trn++; rule->flags = TRANSPORT; - else { + } else { APP_CHECK(0, status, "unrecognized " "input \"%s\"", tokens[ti]); return; @@ -772,19 +781,21 @@ print_one_sa_rule(const struct ipsec_sa *sa, int inbound) printf("\n"); } +struct ipsec_xf { + struct rte_crypto_sym_xform a; + struct rte_crypto_sym_xform b; +}; + struct sa_ctx { void *satbl; /* pointer to array of rte_ipsec_sa objects*/ - struct ipsec_sa sa[IPSEC_SA_MAX_ENTRIES]; - union { - struct { - struct rte_crypto_sym_xform a; - struct rte_crypto_sym_xform b; - }; - } xf[IPSEC_SA_MAX_ENTRIES]; + struct ipsec_sad sad; + struct ipsec_xf *xf; + uint32_t nb_sa; + struct ipsec_sa sa[]; }; static struct sa_ctx * -sa_create(const char *name, int32_t socket_id) +sa_create(const char *name, int32_t socket_id, uint32_t nb_sa) { char s[PATH_MAX]; struct sa_ctx *sa_ctx; @@ -793,20 +804,31 @@ sa_create(const char *name, int32_t socket_id) snprintf(s, sizeof(s), "%s_%u", name, socket_id); - /* Create SA array table */ + /* Create SA context */ printf("Creating SA context with %u maximum entries on socket %d\n", - IPSEC_SA_MAX_ENTRIES, socket_id); + nb_sa, socket_id); - mz_size = sizeof(struct sa_ctx); + mz_size = sizeof(struct ipsec_xf) * nb_sa; mz = rte_memzone_reserve(s, mz_size, socket_id, RTE_MEMZONE_1GB | RTE_MEMZONE_SIZE_HINT_ONLY); if (mz == NULL) { - printf("Failed to allocate SA DB memory\n"); + printf("Failed to allocate SA XFORM memory\n"); rte_errno = ENOMEM; return NULL; } - sa_ctx = (struct sa_ctx *)mz->addr; + sa_ctx = rte_malloc(NULL, sizeof(struct sa_ctx) + + sizeof(struct ipsec_sa) * nb_sa, RTE_CACHE_LINE_SIZE); + + if (sa_ctx == NULL) { + printf("Failed to allocate SA CTX memory\n"); + rte_errno = ENOMEM; + rte_memzone_free(mz); + return NULL; + } + + sa_ctx->xf = (struct ipsec_xf *)mz->addr; + sa_ctx->nb_sa = nb_sa; return sa_ctx; } @@ -949,7 +971,7 @@ sa_add_rules(struct sa_ctx *sa_ctx, const struct ipsec_sa entries[], aad_length = (app_sa_prm.enable_esn != 0) ? sizeof(uint32_t) : 0; for (i = 0; i < nb_entries; i++) { - idx = SPI2IDX(entries[i].spi); + idx = i; sa = &sa_ctx->sa[idx]; if (sa->spi != 0) { printf("Index %u already in use by SPI %u\n", @@ -957,6 +979,13 @@ sa_add_rules(struct sa_ctx *sa_ctx, const struct ipsec_sa entries[], return -EINVAL; } *sa = entries[i]; + + if (inbound) { + rc = ipsec_sad_add(&sa_ctx->sad, sa); + if (rc != 0) + return rc; + } + sa->seq = 0; ips = ipsec_get_primary_session(sa); @@ -1237,8 +1266,7 @@ ipsec_sa_init(struct ipsec_sa *lsa, struct rte_ipsec_sa *sa, uint32_t sa_size) * one per session. */ static int -ipsec_satbl_init(struct sa_ctx *ctx, const struct ipsec_sa *ent, - uint32_t nb_ent, int32_t socket) +ipsec_satbl_init(struct sa_ctx *ctx, uint32_t nb_ent, int32_t socket) { int32_t rc, sz; uint32_t i, idx; @@ -1248,7 +1276,7 @@ ipsec_satbl_init(struct sa_ctx *ctx, const struct ipsec_sa *ent, struct rte_ipsec_sa_prm prm; /* determine SA size */ - idx = SPI2IDX(ent[0].spi); + idx = 0; fill_ipsec_sa_prm(&prm, ctx->sa + idx, NULL, NULL); sz = rte_ipsec_sa_size(&prm); if (sz < 0) { @@ -1271,7 +1299,7 @@ ipsec_satbl_init(struct sa_ctx *ctx, const struct ipsec_sa *ent, rc = 0; for (i = 0; i != nb_ent && rc == 0; i++) { - idx = SPI2IDX(ent[i].spi); + idx = i; sa = (struct rte_ipsec_sa *)((uintptr_t)ctx->satbl + sz * i); lsa = ctx->sa + idx; @@ -1286,18 +1314,16 @@ ipsec_satbl_init(struct sa_ctx *ctx, const struct ipsec_sa *ent, * Walk through all SA rules to find an SA with given SPI */ int -sa_spi_present(uint32_t spi, int inbound) +sa_spi_present(struct sa_ctx *sa_ctx, uint32_t spi, int inbound) { uint32_t i, num; const struct ipsec_sa *sar; - if (inbound != 0) { - sar = sa_in; + sar = sa_ctx->sa; + if (inbound != 0) num = nb_sa_in; - } else { - sar = sa_out; + else num = nb_sa_out; - } for (i = 0; i != num; i++) { if (sar[i].spi == spi) @@ -1326,16 +1352,21 @@ sa_init(struct socket_ctx *ctx, int32_t socket_id) if (nb_sa_in > 0) { name = "sa_in"; - ctx->sa_in = sa_create(name, socket_id); + ctx->sa_in = sa_create(name, socket_id, nb_sa_in); if (ctx->sa_in == NULL) rte_exit(EXIT_FAILURE, "Error [%d] creating SA " "context %s in socket %d\n", rte_errno, name, socket_id); + rc = ipsec_sad_create(name, &ctx->sa_in->sad, socket_id, + &sa_in_cnt); + if (rc != 0) + rte_exit(EXIT_FAILURE, "failed to init SAD\n"); + sa_in_add_rules(ctx->sa_in, sa_in, nb_sa_in, ctx); if (app_sa_prm.enable != 0) { - rc = ipsec_satbl_init(ctx->sa_in, sa_in, nb_sa_in, + rc = ipsec_satbl_init(ctx->sa_in, nb_sa_in, socket_id); if (rc != 0) rte_exit(EXIT_FAILURE, @@ -1346,7 +1377,7 @@ sa_init(struct socket_ctx *ctx, int32_t socket_id) if (nb_sa_out > 0) { name = "sa_out"; - ctx->sa_out = sa_create(name, socket_id); + ctx->sa_out = sa_create(name, socket_id, nb_sa_out); if (ctx->sa_out == NULL) rte_exit(EXIT_FAILURE, "Error [%d] creating SA " "context %s in socket %d\n", rte_errno, @@ -1355,7 +1386,7 @@ sa_init(struct socket_ctx *ctx, int32_t socket_id) sa_out_add_rules(ctx->sa_out, sa_out, nb_sa_out, ctx); if (app_sa_prm.enable != 0) { - rc = ipsec_satbl_init(ctx->sa_out, sa_out, nb_sa_out, + rc = ipsec_satbl_init(ctx->sa_out, nb_sa_out, socket_id); if (rc != 0) rte_exit(EXIT_FAILURE, @@ -1381,28 +1412,13 @@ inbound_sa_check(struct sa_ctx *sa_ctx, struct rte_mbuf *m, uint32_t sa_idx) return 0; } -static inline void -single_inbound_lookup(struct ipsec_sa *sadb, struct rte_mbuf *pkt, - void **sa_ret) +void +inbound_sa_lookup(struct sa_ctx *sa_ctx, struct rte_mbuf *pkts[], + void *sa[], uint16_t nb_pkts) { - struct rte_esp_hdr *esp; - struct ip *ip; - uint32_t *src4_addr; - uint8_t *src6_addr; - struct ipsec_sa *sa; - void *result_sa; + uint32_t i; - *sa_ret = NULL; - - ip = rte_pktmbuf_mtod(pkt, struct ip *); - esp = rte_pktmbuf_mtod_offset(pkt, struct rte_esp_hdr *, pkt->l3_len); - - if (esp->spi == INVALID_SPI) - return; - - result_sa = sa = &sadb[SPI2IDX(rte_be_to_cpu_32(esp->spi))]; - if (rte_be_to_cpu_32(esp->spi) != sa->spi) - return; + sad_lookup(&sa_ctx->sad, pkts, sa, nb_pkts); /* * Mark need for inline offload fallback on the LSB of SA pointer. @@ -1413,40 +1429,14 @@ single_inbound_lookup(struct ipsec_sa *sadb, struct rte_mbuf *pkt, * pointer to prevent from unintentional use. Use ipsec_mask_saptr * to get valid struct pointer. */ - if (MBUF_NO_SEC_OFFLOAD(pkt) && sa->fallback_sessions > 0) { - uintptr_t intsa = (uintptr_t)sa; - intsa |= IPSEC_SA_OFFLOAD_FALLBACK_FLAG; - result_sa = (void *)intsa; + for (i = 0; i < nb_pkts; i++) { + if (MBUF_NO_SEC_OFFLOAD(pkts[i]) && (sa[i] != NULL) && + ((struct ipsec_sa *)sa[i])->fallback_sessions > 0) { + uintptr_t intsa = (uintptr_t)sa[i]; + intsa |= IPSEC_SA_OFFLOAD_FALLBACK_FLAG; + sa[i] = (void *)intsa; + } } - - switch (WITHOUT_TRANSPORT_VERSION(sa->flags)) { - case IP4_TUNNEL: - src4_addr = RTE_PTR_ADD(ip, offsetof(struct ip, ip_src)); - if ((ip->ip_v == IPVERSION) && - (sa->src.ip.ip4 == *src4_addr) && - (sa->dst.ip.ip4 == *(src4_addr + 1))) - *sa_ret = result_sa; - break; - case IP6_TUNNEL: - src6_addr = RTE_PTR_ADD(ip, offsetof(struct ip6_hdr, ip6_src)); - if ((ip->ip_v == IP6_VERSION) && - !memcmp(&sa->src.ip.ip6.ip6, src6_addr, 16) && - !memcmp(&sa->dst.ip.ip6.ip6, src6_addr + 16, 16)) - *sa_ret = result_sa; - break; - case TRANSPORT: - *sa_ret = result_sa; - } -} - -void -inbound_sa_lookup(struct sa_ctx *sa_ctx, struct rte_mbuf *pkts[], - void *sa[], uint16_t nb_pkts) -{ - uint32_t i; - - for (i = 0; i < nb_pkts; i++) - single_inbound_lookup(sa_ctx->sa, pkts[i], &sa[i]); } void diff --git a/examples/ipsec-secgw/sp4.c b/examples/ipsec-secgw/sp4.c index 3871c6c..1dcec52 100644 --- a/examples/ipsec-secgw/sp4.c +++ b/examples/ipsec-secgw/sp4.c @@ -493,10 +493,11 @@ acl4_init(const char *name, int32_t socketid, const struct acl4_rules *rules, * check that for each rule it's SPI has a correspondent entry in SAD */ static int -check_spi_value(int inbound) +check_spi_value(struct sa_ctx *sa_ctx, int inbound) { uint32_t i, num, spi; - const struct acl4_rules *acr; + int32_t spi_idx; + struct acl4_rules *acr; if (inbound != 0) { acr = acl4_rules_in; @@ -508,11 +509,16 @@ check_spi_value(int inbound) for (i = 0; i != num; i++) { spi = acr[i].data.userdata; - if (spi != DISCARD && spi != BYPASS && - sa_spi_present(spi, inbound) < 0) { - RTE_LOG(ERR, IPSEC, "SPI %u is not present in SAD\n", - spi); - return -ENOENT; + if (spi != DISCARD && spi != BYPASS) { + spi_idx = sa_spi_present(sa_ctx, spi, inbound); + if (spi_idx < 0) { + RTE_LOG(ERR, IPSEC, + "SPI %u is not present in SAD\n", + spi); + return -ENOENT; + } + /* Update userdata with spi index */ + acr[i].data.userdata = spi_idx + 1; } } @@ -535,11 +541,11 @@ sp4_init(struct socket_ctx *ctx, int32_t socket_id) rte_exit(EXIT_FAILURE, "Outbound SP DB for socket %u already " "initialized\n", socket_id); - if (check_spi_value(1) < 0) + if (check_spi_value(ctx->sa_in, 1) < 0) rte_exit(EXIT_FAILURE, "Inbound IPv4 SP DB has unmatched in SAD SPIs\n"); - if (check_spi_value(0) < 0) + if (check_spi_value(ctx->sa_out, 0) < 0) rte_exit(EXIT_FAILURE, "Outbound IPv4 SP DB has unmatched in SAD SPIs\n"); diff --git a/examples/ipsec-secgw/sp6.c b/examples/ipsec-secgw/sp6.c index d8be6b1..b489e15 100644 --- a/examples/ipsec-secgw/sp6.c +++ b/examples/ipsec-secgw/sp6.c @@ -625,10 +625,11 @@ acl6_init(const char *name, int32_t socketid, const struct acl6_rules *rules, * check that for each rule it's SPI has a correspondent entry in SAD */ static int -check_spi_value(int inbound) +check_spi_value(struct sa_ctx *sa_ctx, int inbound) { uint32_t i, num, spi; - const struct acl6_rules *acr; + int32_t spi_idx; + struct acl6_rules *acr; if (inbound != 0) { acr = acl6_rules_in; @@ -640,11 +641,16 @@ check_spi_value(int inbound) for (i = 0; i != num; i++) { spi = acr[i].data.userdata; - if (spi != DISCARD && spi != BYPASS && - sa_spi_present(spi, inbound) < 0) { - RTE_LOG(ERR, IPSEC, "SPI %u is not present in SAD\n", - spi); - return -ENOENT; + if (spi != DISCARD && spi != BYPASS) { + spi_idx = sa_spi_present(sa_ctx, spi, inbound); + if (spi_idx < 0) { + RTE_LOG(ERR, IPSEC, + "SPI %u is not present in SAD\n", + spi); + return -ENOENT; + } + /* Update userdata with spi index */ + acr[i].data.userdata = spi_idx + 1; } } @@ -667,11 +673,11 @@ sp6_init(struct socket_ctx *ctx, int32_t socket_id) rte_exit(EXIT_FAILURE, "Outbound IPv6 SP DB for socket %u " "already initialized\n", socket_id); - if (check_spi_value(1) < 0) + if (check_spi_value(ctx->sa_in, 1) < 0) rte_exit(EXIT_FAILURE, "Inbound IPv6 SP DB has unmatched in SAD SPIs\n"); - if (check_spi_value(0) < 0) + if (check_spi_value(ctx->sa_out, 0) < 0) rte_exit(EXIT_FAILURE, "Outbound IPv6 SP DB has unmatched in SAD SPIs\n"); -- 2.7.4