diff options
Diffstat (limited to 'examples/ipsec-secgw/sa.c')
-rw-r--r-- | examples/ipsec-secgw/sa.c | 446 |
1 files changed, 446 insertions, 0 deletions
diff --git a/examples/ipsec-secgw/sa.c b/examples/ipsec-secgw/sa.c new file mode 100644 index 00000000..b6260ede --- /dev/null +++ b/examples/ipsec-secgw/sa.c @@ -0,0 +1,446 @@ +/*- + * BSD LICENSE + * + * Copyright(c) 2016 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * Security Associations + */ +#include <sys/types.h> +#include <netinet/in.h> +#include <netinet/ip.h> + +#include <rte_memzone.h> +#include <rte_crypto.h> +#include <rte_cryptodev.h> +#include <rte_byteorder.h> +#include <rte_errno.h> + +#include "ipsec.h" +#include "esp.h" + +/* SAs EP0 Outbound */ +const struct ipsec_sa sa_ep0_out[] = { + { 5, 0, IPv4(172, 16, 1, 5), IPv4(172, 16, 2, 5), + NULL, NULL, + esp4_tunnel_outbound_pre_crypto, + esp4_tunnel_outbound_post_crypto, + RTE_CRYPTO_CIPHER_AES_CBC, RTE_CRYPTO_AUTH_SHA1_HMAC, + 12, 16, 16, + 0, 0 }, + { 6, 0, IPv4(172, 16, 1, 6), IPv4(172, 16, 2, 6), + NULL, NULL, + esp4_tunnel_outbound_pre_crypto, + esp4_tunnel_outbound_post_crypto, + RTE_CRYPTO_CIPHER_AES_CBC, RTE_CRYPTO_AUTH_SHA1_HMAC, + 12, 16, 16, + 0, 0 }, + { 7, 0, IPv4(172, 16, 1, 7), IPv4(172, 16, 2, 7), + NULL, NULL, + esp4_tunnel_outbound_pre_crypto, + esp4_tunnel_outbound_post_crypto, + RTE_CRYPTO_CIPHER_AES_CBC, RTE_CRYPTO_AUTH_SHA1_HMAC, + 12, 16, 16, + 0, 0 }, + { 8, 0, IPv4(172, 16, 1, 8), IPv4(172, 16, 2, 8), + NULL, NULL, + esp4_tunnel_outbound_pre_crypto, + esp4_tunnel_outbound_post_crypto, + RTE_CRYPTO_CIPHER_AES_CBC, RTE_CRYPTO_AUTH_SHA1_HMAC, + 12, 16, 16, + 0, 0 }, + { 9, 0, IPv4(172, 16, 1, 5), IPv4(172, 16, 2, 5), + NULL, NULL, + esp4_tunnel_outbound_pre_crypto, + esp4_tunnel_outbound_post_crypto, + RTE_CRYPTO_CIPHER_NULL, RTE_CRYPTO_AUTH_NULL, + 0, 0, 4, + 0, 0 }, +}; + +/* SAs EP0 Inbound */ +const struct ipsec_sa sa_ep0_in[] = { + { 5, 0, IPv4(172, 16, 2, 5), IPv4(172, 16, 1, 5), + NULL, NULL, + esp4_tunnel_inbound_pre_crypto, + esp4_tunnel_inbound_post_crypto, + RTE_CRYPTO_CIPHER_AES_CBC, RTE_CRYPTO_AUTH_SHA1_HMAC, + 12, 16, 16, + 0, 0 }, + { 6, 0, IPv4(172, 16, 2, 6), IPv4(172, 16, 1, 6), + NULL, NULL, + esp4_tunnel_inbound_pre_crypto, + esp4_tunnel_inbound_post_crypto, + RTE_CRYPTO_CIPHER_AES_CBC, RTE_CRYPTO_AUTH_SHA1_HMAC, + 12, 16, 16, + 0, 0 }, + { 7, 0, IPv4(172, 16, 2, 7), IPv4(172, 16, 1, 7), + NULL, NULL, + esp4_tunnel_inbound_pre_crypto, + esp4_tunnel_inbound_post_crypto, + RTE_CRYPTO_CIPHER_AES_CBC, RTE_CRYPTO_AUTH_SHA1_HMAC, + 12, 16, 16, + 0, 0 }, + { 8, 0, IPv4(172, 16, 2, 8), IPv4(172, 16, 1, 8), + NULL, NULL, + esp4_tunnel_inbound_pre_crypto, + esp4_tunnel_inbound_post_crypto, + RTE_CRYPTO_CIPHER_AES_CBC, RTE_CRYPTO_AUTH_SHA1_HMAC, + 12, 16, 16, + 0, 0 }, + { 9, 0, IPv4(172, 16, 2, 5), IPv4(172, 16, 1, 5), + NULL, NULL, + esp4_tunnel_inbound_pre_crypto, + esp4_tunnel_inbound_post_crypto, + RTE_CRYPTO_CIPHER_NULL, RTE_CRYPTO_AUTH_NULL, + 0, 0, 4, + 0, 0 }, +}; + +/* SAs EP1 Outbound */ +const struct ipsec_sa sa_ep1_out[] = { + { 5, 0, IPv4(172, 16, 2, 5), IPv4(172, 16, 1, 5), + NULL, NULL, + esp4_tunnel_outbound_pre_crypto, + esp4_tunnel_outbound_post_crypto, + RTE_CRYPTO_CIPHER_AES_CBC, RTE_CRYPTO_AUTH_SHA1_HMAC, + 12, 16, 16, + 0, 0 }, + { 6, 0, IPv4(172, 16, 2, 6), IPv4(172, 16, 1, 6), + NULL, NULL, + esp4_tunnel_outbound_pre_crypto, + esp4_tunnel_outbound_post_crypto, + RTE_CRYPTO_CIPHER_AES_CBC, RTE_CRYPTO_AUTH_SHA1_HMAC, + 12, 16, 16, + 0, 0 }, + { 7, 0, IPv4(172, 16, 2, 7), IPv4(172, 16, 1, 7), + NULL, NULL, + esp4_tunnel_outbound_pre_crypto, + esp4_tunnel_outbound_post_crypto, + RTE_CRYPTO_CIPHER_AES_CBC, RTE_CRYPTO_AUTH_SHA1_HMAC, + 12, 16, 16, + 0, 0 }, + { 8, 0, IPv4(172, 16, 2, 8), IPv4(172, 16, 1, 8), + NULL, NULL, + esp4_tunnel_outbound_pre_crypto, + esp4_tunnel_outbound_post_crypto, + RTE_CRYPTO_CIPHER_AES_CBC, RTE_CRYPTO_AUTH_SHA1_HMAC, + 12, 16, 16, + 0, 0 }, + { 9, 0, IPv4(172, 16, 2, 5), IPv4(172, 16, 1, 5), + NULL, NULL, + esp4_tunnel_outbound_pre_crypto, + esp4_tunnel_outbound_post_crypto, + RTE_CRYPTO_CIPHER_NULL, RTE_CRYPTO_AUTH_NULL, + 0, 0, 4, + 0, 0 }, +}; + +/* SAs EP1 Inbound */ +const struct ipsec_sa sa_ep1_in[] = { + { 5, 0, IPv4(172, 16, 1, 5), IPv4(172, 16, 2, 5), + NULL, NULL, + esp4_tunnel_inbound_pre_crypto, + esp4_tunnel_inbound_post_crypto, + RTE_CRYPTO_CIPHER_AES_CBC, RTE_CRYPTO_AUTH_SHA1_HMAC, + 12, 16, 16, + 0, 0 }, + { 6, 0, IPv4(172, 16, 1, 6), IPv4(172, 16, 2, 6), + NULL, NULL, + esp4_tunnel_inbound_pre_crypto, + esp4_tunnel_inbound_post_crypto, + RTE_CRYPTO_CIPHER_AES_CBC, RTE_CRYPTO_AUTH_SHA1_HMAC, + 12, 16, 16, + 0, 0 }, + { 7, 0, IPv4(172, 16, 1, 7), IPv4(172, 16, 2, 7), + NULL, NULL, + esp4_tunnel_inbound_pre_crypto, + esp4_tunnel_inbound_post_crypto, + RTE_CRYPTO_CIPHER_AES_CBC, RTE_CRYPTO_AUTH_SHA1_HMAC, + 12, 16, 16, + 0, 0 }, + { 8, 0, IPv4(172, 16, 1, 8), IPv4(172, 16, 2, 8), + NULL, NULL, + esp4_tunnel_inbound_pre_crypto, + esp4_tunnel_inbound_post_crypto, + RTE_CRYPTO_CIPHER_AES_CBC, RTE_CRYPTO_AUTH_SHA1_HMAC, + 12, 16, 16, + 0, 0 }, + { 9, 0, IPv4(172, 16, 1, 5), IPv4(172, 16, 2, 5), + NULL, NULL, + esp4_tunnel_inbound_pre_crypto, + esp4_tunnel_inbound_post_crypto, + RTE_CRYPTO_CIPHER_NULL, RTE_CRYPTO_AUTH_NULL, + 0, 0, 4, + 0, 0 }, +}; + +static uint8_t cipher_key[256] = "sixteenbytes key"; + +/* AES CBC xform */ +const struct rte_crypto_sym_xform aescbc_enc_xf = { + NULL, + RTE_CRYPTO_SYM_XFORM_CIPHER, + {.cipher = { RTE_CRYPTO_CIPHER_OP_ENCRYPT, RTE_CRYPTO_CIPHER_AES_CBC, + .key = { cipher_key, 16 } } + } +}; + +const struct rte_crypto_sym_xform aescbc_dec_xf = { + NULL, + RTE_CRYPTO_SYM_XFORM_CIPHER, + {.cipher = { RTE_CRYPTO_CIPHER_OP_DECRYPT, RTE_CRYPTO_CIPHER_AES_CBC, + .key = { cipher_key, 16 } } + } +}; + +static uint8_t auth_key[256] = "twentybytes hash key"; + +/* SHA1 HMAC xform */ +const struct rte_crypto_sym_xform sha1hmac_gen_xf = { + NULL, + RTE_CRYPTO_SYM_XFORM_AUTH, + {.auth = { RTE_CRYPTO_AUTH_OP_GENERATE, RTE_CRYPTO_AUTH_SHA1_HMAC, + .key = { auth_key, 20 }, 12, 0 } + } +}; + +const struct rte_crypto_sym_xform sha1hmac_verify_xf = { + NULL, + RTE_CRYPTO_SYM_XFORM_AUTH, + {.auth = { RTE_CRYPTO_AUTH_OP_VERIFY, RTE_CRYPTO_AUTH_SHA1_HMAC, + .key = { auth_key, 20 }, 12, 0 } + } +}; + +/* AES CBC xform */ +const struct rte_crypto_sym_xform null_cipher_xf = { + NULL, + RTE_CRYPTO_SYM_XFORM_CIPHER, + {.cipher = { .algo = RTE_CRYPTO_CIPHER_NULL } + } +}; + +const struct rte_crypto_sym_xform null_auth_xf = { + NULL, + RTE_CRYPTO_SYM_XFORM_AUTH, + {.auth = { .algo = RTE_CRYPTO_AUTH_NULL } + } +}; + +struct sa_ctx { + struct ipsec_sa sa[IPSEC_SA_MAX_ENTRIES]; + struct { + struct rte_crypto_sym_xform a; + struct rte_crypto_sym_xform b; + } xf[IPSEC_SA_MAX_ENTRIES]; +}; + +static struct sa_ctx * +sa_ipv4_create(const char *name, int socket_id) +{ + char s[PATH_MAX]; + struct sa_ctx *sa_ctx; + unsigned mz_size; + const struct rte_memzone *mz; + + snprintf(s, sizeof(s), "%s_%u", name, socket_id); + + /* Create SA array table */ + printf("Creating SA context with %u maximum entries\n", + IPSEC_SA_MAX_ENTRIES); + + mz_size = sizeof(struct sa_ctx); + 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"); + rte_errno = -ENOMEM; + return NULL; + } + + sa_ctx = (struct sa_ctx *)mz->addr; + + return sa_ctx; +} + +static int +sa_add_rules(struct sa_ctx *sa_ctx, const struct ipsec_sa entries[], + unsigned nb_entries, unsigned inbound) +{ + struct ipsec_sa *sa; + unsigned i, idx; + + for (i = 0; i < nb_entries; i++) { + idx = SPI2IDX(entries[i].spi); + sa = &sa_ctx->sa[idx]; + if (sa->spi != 0) { + printf("Index %u already in use by SPI %u\n", + idx, sa->spi); + return -EINVAL; + } + *sa = entries[i]; + sa->src = rte_cpu_to_be_32(sa->src); + sa->dst = rte_cpu_to_be_32(sa->dst); + if (inbound) { + if (sa->cipher_algo == RTE_CRYPTO_CIPHER_NULL) { + sa_ctx->xf[idx].a = null_auth_xf; + sa_ctx->xf[idx].b = null_cipher_xf; + } else { + sa_ctx->xf[idx].a = sha1hmac_verify_xf; + sa_ctx->xf[idx].b = aescbc_dec_xf; + } + } else { /* outbound */ + if (sa->cipher_algo == RTE_CRYPTO_CIPHER_NULL) { + sa_ctx->xf[idx].a = null_cipher_xf; + sa_ctx->xf[idx].b = null_auth_xf; + } else { + sa_ctx->xf[idx].a = aescbc_enc_xf; + sa_ctx->xf[idx].b = sha1hmac_gen_xf; + } + } + sa_ctx->xf[idx].a.next = &sa_ctx->xf[idx].b; + sa_ctx->xf[idx].b.next = NULL; + sa->xforms = &sa_ctx->xf[idx].a; + } + + return 0; +} + +static inline int +sa_out_add_rules(struct sa_ctx *sa_ctx, const struct ipsec_sa entries[], + unsigned nb_entries) +{ + return sa_add_rules(sa_ctx, entries, nb_entries, 0); +} + +static inline int +sa_in_add_rules(struct sa_ctx *sa_ctx, const struct ipsec_sa entries[], + unsigned nb_entries) +{ + return sa_add_rules(sa_ctx, entries, nb_entries, 1); +} + +void +sa_init(struct socket_ctx *ctx, int socket_id, unsigned ep) +{ + const struct ipsec_sa *sa_out_entries, *sa_in_entries; + unsigned nb_out_entries, nb_in_entries; + const char *name; + + if (ctx == NULL) + rte_exit(EXIT_FAILURE, "NULL context.\n"); + + if (ctx->sa_ipv4_in != NULL) + rte_exit(EXIT_FAILURE, "Inbound SA DB for socket %u already " + "initialized\n", socket_id); + + if (ctx->sa_ipv4_out != NULL) + rte_exit(EXIT_FAILURE, "Outbound SA DB for socket %u already " + "initialized\n", socket_id); + + if (ep == 0) { + sa_out_entries = sa_ep0_out; + nb_out_entries = RTE_DIM(sa_ep0_out); + sa_in_entries = sa_ep0_in; + nb_in_entries = RTE_DIM(sa_ep0_in); + } else if (ep == 1) { + sa_out_entries = sa_ep1_out; + nb_out_entries = RTE_DIM(sa_ep1_out); + sa_in_entries = sa_ep1_in; + nb_in_entries = RTE_DIM(sa_ep1_in); + } else + rte_exit(EXIT_FAILURE, "Invalid EP value %u. " + "Only 0 or 1 supported.\n", ep); + + name = "sa_ipv4_in"; + ctx->sa_ipv4_in = sa_ipv4_create(name, socket_id); + if (ctx->sa_ipv4_in == NULL) + rte_exit(EXIT_FAILURE, "Error [%d] creating SA context %s " + "in socket %d\n", rte_errno, name, socket_id); + + name = "sa_ipv4_out"; + ctx->sa_ipv4_out = sa_ipv4_create(name, socket_id); + if (ctx->sa_ipv4_out == NULL) + rte_exit(EXIT_FAILURE, "Error [%d] creating SA context %s " + "in socket %d\n", rte_errno, name, socket_id); + + sa_in_add_rules(ctx->sa_ipv4_in, sa_in_entries, nb_in_entries); + + sa_out_add_rules(ctx->sa_ipv4_out, sa_out_entries, nb_out_entries); +} + +int +inbound_sa_check(struct sa_ctx *sa_ctx, struct rte_mbuf *m, uint32_t sa_idx) +{ + struct ipsec_mbuf_metadata *priv; + + priv = RTE_PTR_ADD(m, sizeof(struct rte_mbuf)); + + return (sa_ctx->sa[sa_idx].spi == priv->sa->spi); +} + +void +inbound_sa_lookup(struct sa_ctx *sa_ctx, struct rte_mbuf *pkts[], + struct ipsec_sa *sa[], uint16_t nb_pkts) +{ + unsigned i; + uint32_t *src, spi; + + for (i = 0; i < nb_pkts; i++) { + spi = rte_pktmbuf_mtod_offset(pkts[i], struct esp_hdr *, + sizeof(struct ip))->spi; + + if (spi == INVALID_SPI) + continue; + + sa[i] = &sa_ctx->sa[SPI2IDX(spi)]; + if (spi != sa[i]->spi) { + sa[i] = NULL; + continue; + } + + src = rte_pktmbuf_mtod_offset(pkts[i], uint32_t *, + offsetof(struct ip, ip_src)); + if ((sa[i]->src != *src) || (sa[i]->dst != *(src + 1))) + sa[i] = NULL; + } +} + +void +outbound_sa_lookup(struct sa_ctx *sa_ctx, uint32_t sa_idx[], + struct ipsec_sa *sa[], uint16_t nb_pkts) +{ + unsigned i; + + for (i = 0; i < nb_pkts; i++) + sa[i] = &sa_ctx->sa[sa_idx[i]]; +} |