From df3e1d9489b094b49ba5ec2dc2a2720d247dc373 Mon Sep 17 00:00:00 2001 From: Vladimir Medvedkin Date: Fri, 31 Jan 2020 17:39:40 +0000 Subject: [PATCH] examples/ipsec-secgw: integrate inbound SAD 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 Acked-by: Konstantin Ananyev Acked-by: Akhil Goyal Acked-by: Anoob Joseph --- examples/ipsec-secgw/Makefile | 1 + examples/ipsec-secgw/ipsec-secgw.c | 4 +- examples/ipsec-secgw/ipsec.h | 3 +- examples/ipsec-secgw/meson.build | 2 +- examples/ipsec-secgw/sa.c | 182 ++++++++++++++++------------- examples/ipsec-secgw/sp4.c | 24 ++-- examples/ipsec-secgw/sp6.c | 24 ++-- 7 files changed, 139 insertions(+), 101 deletions(-) diff --git a/examples/ipsec-secgw/Makefile b/examples/ipsec-secgw/Makefile index a4977f61f8..ad83d79e90 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 3b5aaf6832..3e5f82eca2 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 9ddb5d91b2..5988d59984 100644 --- a/examples/ipsec-secgw/ipsec.h +++ b/examples/ipsec-secgw/ipsec.h @@ -38,7 +38,6 @@ #define DEFAULT_MAX_CATEGORIES 1 #define IPSEC_SA_MAX_ENTRIES (128) /* must be power of 2, max 2 power 30 */ -#define SPI2IDX(spi) (spi & (IPSEC_SA_MAX_ENTRIES - 1)) #define INVALID_SPI (0) #define DISCARD INVALID_SPI @@ -359,7 +358,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 9ece345cff..6bd5b78368 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 c75a5a15f5..a5b06847df 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,17 @@ 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++; rule->flags = IP4_TUNNEL; - else if (strcmp(tokens[ti], "ipv6-tunnel") == 0) + } else if (strcmp(tokens[ti], "ipv6-tunnel") == 0) { + sa_cnt->nb_v6++; rule->flags = IP6_TUNNEL; - else if (strcmp(tokens[ti], "transport") == 0) + } else if (strcmp(tokens[ti], "transport") == 0) { + sa_cnt->nb_v4++; + sa_cnt->nb_v6++; rule->flags = TRANSPORT; - else { + } else { APP_CHECK(0, status, "unrecognized " "input \"%s\"", tokens[ti]); return; @@ -781,19 +791,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; @@ -802,20 +814,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 = 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 = (struct sa_ctx *)mz->addr; + sa_ctx->xf = (struct ipsec_xf *)mz->addr; + sa_ctx->nb_sa = nb_sa; return sa_ctx; } @@ -958,7 +981,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", @@ -966,6 +989,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); @@ -1246,8 +1276,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; @@ -1257,7 +1286,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) { @@ -1280,7 +1309,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; @@ -1295,18 +1324,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) @@ -1335,16 +1362,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, @@ -1355,7 +1387,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, @@ -1364,7 +1396,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, @@ -1390,28 +1422,18 @@ 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_arr[], uint16_t nb_pkts) { - struct rte_esp_hdr *esp; + uint32_t i; struct ip *ip; uint32_t *src4_addr; uint8_t *src6_addr; - struct ipsec_sa *sa; void *result_sa; + struct ipsec_sa *sa; - *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_arr, nb_pkts); /* * Mark need for inline offload fallback on the LSB of SA pointer. @@ -1422,42 +1444,46 @@ 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 (sa_arr[i] == NULL) + continue; - 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) && + result_sa = sa = sa_arr[i]; + if (MBUF_NO_SEC_OFFLOAD(pkts[i]) && + sa->fallback_sessions > 0) { + uintptr_t intsa = (uintptr_t)sa; + intsa |= IPSEC_SA_OFFLOAD_FALLBACK_FLAG; + result_sa = (void *)intsa; + } + + ip = rte_pktmbuf_mtod(pkts[i], struct ip *); + 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_arr[i] = result_sa; + else + sa_arr[i] = NULL; + 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; + sa_arr[i] = result_sa; + else + sa_arr[i] = NULL; + break; + case TRANSPORT: + sa_arr[i] = 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 outbound_sa_lookup(struct sa_ctx *sa_ctx, uint32_t sa_idx[], void *sa[], uint16_t nb_pkts) diff --git a/examples/ipsec-secgw/sp4.c b/examples/ipsec-secgw/sp4.c index 3871c6cc10..1dcec5267b 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 d8be6b1bd2..b489e1581a 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.20.1