diff options
Diffstat (limited to 'examples/ipsec-secgw/ipsec.c')
-rw-r--r-- | examples/ipsec-secgw/ipsec.c | 249 |
1 files changed, 187 insertions, 62 deletions
diff --git a/examples/ipsec-secgw/ipsec.c b/examples/ipsec-secgw/ipsec.c index 70ed2272..5fb5bc16 100644 --- a/examples/ipsec-secgw/ipsec.c +++ b/examples/ipsec-secgw/ipsec.c @@ -1,34 +1,5 @@ -/*- - * BSD LICENSE - * - * Copyright(c) 2016-2017 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. +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2016-2017 Intel Corporation */ #include <sys/types.h> #include <netinet/in.h> @@ -46,6 +17,27 @@ #include "ipsec.h" #include "esp.h" +static inline void +set_ipsec_conf(struct ipsec_sa *sa, struct rte_security_ipsec_xform *ipsec) +{ + if (ipsec->mode == RTE_SECURITY_IPSEC_SA_MODE_TUNNEL) { + struct rte_security_ipsec_tunnel_param *tunnel = + &ipsec->tunnel; + if (sa->flags == IP4_TUNNEL) { + tunnel->type = + RTE_SECURITY_IPSEC_TUNNEL_IPV4; + tunnel->ipv4.ttl = IPDEFTTL; + + memcpy((uint8_t *)&tunnel->ipv4.src_ip, + (uint8_t *)&sa->src.ip.ip4, 4); + + memcpy((uint8_t *)&tunnel->ipv4.dst_ip, + (uint8_t *)&sa->dst.ip.ip4, 4); + } + /* TODO support for Transport and IPV6 tunnel */ + } +} + static inline int create_session(struct ipsec_ctx *ipsec_ctx, struct ipsec_sa *sa) { @@ -95,7 +87,8 @@ create_session(struct ipsec_ctx *ipsec_ctx, struct ipsec_sa *sa) RTE_SECURITY_IPSEC_SA_MODE_TUNNEL : RTE_SECURITY_IPSEC_SA_MODE_TRANSPORT, } }, - .crypto_xform = sa->xforms + .crypto_xform = sa->xforms, + .userdata = NULL, }; @@ -104,23 +97,8 @@ create_session(struct ipsec_ctx *ipsec_ctx, struct ipsec_sa *sa) rte_cryptodev_get_sec_ctx( ipsec_ctx->tbl[cdev_id_qp].id); - if (sess_conf.ipsec.mode == - RTE_SECURITY_IPSEC_SA_MODE_TUNNEL) { - struct rte_security_ipsec_tunnel_param *tunnel = - &sess_conf.ipsec.tunnel; - if (sa->flags == IP4_TUNNEL) { - tunnel->type = - RTE_SECURITY_IPSEC_TUNNEL_IPV4; - tunnel->ipv4.ttl = IPDEFTTL; - - memcpy((uint8_t *)&tunnel->ipv4.src_ip, - (uint8_t *)&sa->src.ip.ip4, 4); - - memcpy((uint8_t *)&tunnel->ipv4.dst_ip, - (uint8_t *)&sa->dst.ip.ip4, 4); - } - /* TODO support for Transport and IPV6 tunnel */ - } + /* Set IPsec parameters in conf */ + set_ipsec_conf(sa, &(sess_conf.ipsec)); sa->sec_session = rte_security_session_create(ctx, &sess_conf, ipsec_ctx->session_pool); @@ -135,6 +113,7 @@ create_session(struct ipsec_ctx *ipsec_ctx, struct ipsec_sa *sa) rte_eth_dev_get_sec_ctx( sa->portid); const struct rte_security_capability *sec_cap; + int ret = 0; sa->sec_session = rte_security_session_create(ctx, &sess_conf, ipsec_ctx->session_pool); @@ -187,7 +166,7 @@ create_session(struct ipsec_ctx *ipsec_ctx, struct ipsec_sa *sa) sa->pattern[2].type = RTE_FLOW_ITEM_TYPE_ESP; sa->pattern[2].spec = &sa->esp_spec; sa->pattern[2].mask = &rte_flow_item_esp_mask; - sa->esp_spec.hdr.spi = sa->spi; + sa->esp_spec.hdr.spi = rte_cpu_to_be_32(sa->spi); sa->pattern[3].type = RTE_FLOW_ITEM_TYPE_END; @@ -198,14 +177,143 @@ create_session(struct ipsec_ctx *ipsec_ctx, struct ipsec_sa *sa) sa->attr.egress = (sa->direction == RTE_SECURITY_IPSEC_SA_DIR_EGRESS); + sa->attr.ingress = (sa->direction == + RTE_SECURITY_IPSEC_SA_DIR_INGRESS); + if (sa->attr.ingress) { + uint8_t rss_key[40]; + struct rte_eth_rss_conf rss_conf = { + .rss_key = rss_key, + .rss_key_len = 40, + }; + struct rte_eth_dev *eth_dev; + union { + struct rte_flow_action_rss rss; + struct { + const struct rte_eth_rss_conf *rss_conf; + uint16_t num; + uint16_t queue[RTE_MAX_QUEUES_PER_PORT]; + } local; + } action_rss; + unsigned int i; + unsigned int j; + + sa->action[2].type = RTE_FLOW_ACTION_TYPE_END; + /* Try RSS. */ + sa->action[1].type = RTE_FLOW_ACTION_TYPE_RSS; + sa->action[1].conf = &action_rss; + eth_dev = ctx->device; + rte_eth_dev_rss_hash_conf_get(sa->portid, + &rss_conf); + for (i = 0, j = 0; + i < eth_dev->data->nb_rx_queues; ++i) + if (eth_dev->data->rx_queues[i]) + action_rss.local.queue[j++] = i; + action_rss.local.num = j; + action_rss.local.rss_conf = &rss_conf; + ret = rte_flow_validate(sa->portid, &sa->attr, + sa->pattern, sa->action, + &err); + if (!ret) + goto flow_create; + /* Try Queue. */ + sa->action[1].type = RTE_FLOW_ACTION_TYPE_QUEUE; + sa->action[1].conf = + &(struct rte_flow_action_queue){ + .index = 0, + }; + ret = rte_flow_validate(sa->portid, &sa->attr, + sa->pattern, sa->action, + &err); + /* Try End. */ + sa->action[1].type = RTE_FLOW_ACTION_TYPE_END; + sa->action[1].conf = NULL; + ret = rte_flow_validate(sa->portid, &sa->attr, + sa->pattern, sa->action, + &err); + if (ret) + goto flow_create_failure; + } else if (sa->attr.egress && + (sa->ol_flags & + RTE_SECURITY_TX_HW_TRAILER_OFFLOAD)) { + sa->action[1].type = + RTE_FLOW_ACTION_TYPE_PASSTHRU; + sa->action[2].type = + RTE_FLOW_ACTION_TYPE_END; + } +flow_create: sa->flow = rte_flow_create(sa->portid, &sa->attr, sa->pattern, sa->action, &err); if (sa->flow == NULL) { +flow_create_failure: RTE_LOG(ERR, IPSEC, "Failed to create ipsec flow msg: %s\n", err.message); return -1; } + } else if (sa->type == + RTE_SECURITY_ACTION_TYPE_INLINE_PROTOCOL) { + struct rte_security_ctx *ctx = + (struct rte_security_ctx *) + rte_eth_dev_get_sec_ctx(sa->portid); + const struct rte_security_capability *sec_cap; + + if (ctx == NULL) { + RTE_LOG(ERR, IPSEC, + "Ethernet device doesn't have security features registered\n"); + return -1; + } + + /* Set IPsec parameters in conf */ + set_ipsec_conf(sa, &(sess_conf.ipsec)); + + /* Save SA as userdata for the security session. When + * the packet is received, this userdata will be + * retrieved using the metadata from the packet. + * + * This is required only for inbound SAs. + */ + + if (sa->direction == RTE_SECURITY_IPSEC_SA_DIR_INGRESS) + sess_conf.userdata = (void *) sa; + + sa->sec_session = rte_security_session_create(ctx, + &sess_conf, ipsec_ctx->session_pool); + if (sa->sec_session == NULL) { + RTE_LOG(ERR, IPSEC, + "SEC Session init failed: err: %d\n", ret); + return -1; + } + + sec_cap = rte_security_capabilities_get(ctx); + + if (sec_cap == NULL) { + RTE_LOG(ERR, IPSEC, + "No capabilities registered\n"); + return -1; + } + + /* iterate until ESP tunnel*/ + while (sec_cap->action != + RTE_SECURITY_ACTION_TYPE_NONE) { + + if (sec_cap->action == sa->type && + sec_cap->protocol == + RTE_SECURITY_PROTOCOL_IPSEC && + sec_cap->ipsec.mode == + RTE_SECURITY_IPSEC_SA_MODE_TUNNEL && + sec_cap->ipsec.direction == sa->direction) + break; + sec_cap++; + } + + if (sec_cap->action == RTE_SECURITY_ACTION_TYPE_NONE) { + RTE_LOG(ERR, IPSEC, + "No suitable security capability found\n"); + return -1; + } + + sa->ol_flags = sec_cap->ol_flags; + sa->security_ctx = ctx; } } else { sa->crypto_session = rte_cryptodev_sym_session_create( @@ -266,7 +374,6 @@ ipsec_enqueue(ipsec_xform_fn xform_func, struct ipsec_ctx *ipsec_ctx, struct ipsec_mbuf_metadata *priv; struct rte_crypto_sym_op *sym_cop; struct ipsec_sa *sa; - struct cdev_qp *cqp; for (i = 0; i < nb_pkts; i++) { if (unlikely(sas[i] == NULL)) { @@ -323,7 +430,18 @@ ipsec_enqueue(ipsec_xform_fn xform_func, struct ipsec_ctx *ipsec_ctx, } break; case RTE_SECURITY_ACTION_TYPE_INLINE_PROTOCOL: - break; + if ((unlikely(sa->sec_session == NULL)) && + create_session(ipsec_ctx, sa)) { + rte_pktmbuf_free(pkts[i]); + continue; + } + + ipsec_ctx->ol_pkts[ipsec_ctx->ol_pkts_cnt++] = pkts[i]; + if (sa->ol_flags & RTE_SECURITY_TX_OLOAD_NEED_MDATA) + rte_security_set_pkt_metadata( + sa->security_ctx, + sa->sec_session, pkts[i], NULL); + continue; case RTE_SECURITY_ACTION_TYPE_INLINE_CRYPTO: priv->cop.type = RTE_CRYPTO_OP_TYPE_SYMMETRIC; priv->cop.status = RTE_CRYPTO_OP_STATUS_NOT_PROCESSED; @@ -345,8 +463,7 @@ ipsec_enqueue(ipsec_xform_fn xform_func, struct ipsec_ctx *ipsec_ctx, continue; } - cqp = &ipsec_ctx->tbl[sa->cdev_id_qp]; - cqp->ol_pkts[cqp->ol_pkts_cnt++] = pkts[i]; + ipsec_ctx->ol_pkts[ipsec_ctx->ol_pkts_cnt++] = pkts[i]; if (sa->ol_flags & RTE_SECURITY_TX_OLOAD_NEED_MDATA) rte_security_set_pkt_metadata( sa->security_ctx, @@ -369,15 +486,12 @@ ipsec_dequeue(ipsec_xform_fn xform_func, struct ipsec_ctx *ipsec_ctx, struct ipsec_sa *sa; struct rte_mbuf *pkt; - for (i = 0; i < ipsec_ctx->nb_qps && nb_pkts < max_pkts; i++) { + for (i = 0; i < ipsec_ctx->nb_qps && nb_pkts < max_pkts;) { struct cdev_qp *cqp; + cqp = &ipsec_ctx->tbl[ipsec_ctx->last_qp]; - cqp = &ipsec_ctx->tbl[ipsec_ctx->last_qp++]; - if (ipsec_ctx->last_qp == ipsec_ctx->nb_qps) - ipsec_ctx->last_qp %= ipsec_ctx->nb_qps; - - while (cqp->ol_pkts_cnt > 0 && nb_pkts < max_pkts) { - pkt = cqp->ol_pkts[--cqp->ol_pkts_cnt]; + while (ipsec_ctx->ol_pkts_cnt > 0 && nb_pkts < max_pkts) { + pkt = ipsec_ctx->ol_pkts[--ipsec_ctx->ol_pkts_cnt]; rte_prefetch0(pkt); priv = get_priv(pkt); sa = priv->sa; @@ -389,8 +503,13 @@ ipsec_dequeue(ipsec_xform_fn xform_func, struct ipsec_ctx *ipsec_ctx, pkts[nb_pkts++] = pkt; } - if (cqp->in_flight == 0) + if (cqp->in_flight == 0) { + ipsec_ctx->last_qp++; + if (ipsec_ctx->last_qp == ipsec_ctx->nb_qps) + ipsec_ctx->last_qp %= ipsec_ctx->nb_qps; + i++; continue; + } nb_cops = rte_cryptodev_dequeue_burst(cqp->id, cqp->qp, cops, max_pkts - nb_pkts); @@ -414,6 +533,12 @@ ipsec_dequeue(ipsec_xform_fn xform_func, struct ipsec_ctx *ipsec_ctx, } } pkts[nb_pkts++] = pkt; + if (cqp->in_flight < max_pkts) { + ipsec_ctx->last_qp++; + if (ipsec_ctx->last_qp == ipsec_ctx->nb_qps) + ipsec_ctx->last_qp %= ipsec_ctx->nb_qps; + i++; + } } } |