#include <sys/types.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include "ipsec.h"
#define SATP_OUT_IPV4(t) \
((((t) & RTE_IPSEC_SATP_MODE_MASK) == RTE_IPSEC_SATP_MODE_TRANS && \
(((t) & RTE_IPSEC_SATP_IPV_MASK) == RTE_IPSEC_SATP_IPV4)) || \
((t) & RTE_IPSEC_SATP_MODE_MASK) == RTE_IPSEC_SATP_MODE_TUNLV4)
static inline void
free_pkts(
struct rte_mbuf *mb[], uint32_t n)
{
uint32_t i;
for (i = 0; i != n; i++)
}
static inline void
{
uint32_t i;
for (i = 0; i != n; i++)
}
static inline void
enqueue_cop_bulk(
struct cdev_qp *cqp,
struct rte_crypto_op *cop[], uint32_t num)
{
uint32_t i, k, len, n;
len = cqp->len;
if (num >=
RTE_DIM(cqp->buf) * 3 / 4 && len == 0) {
cqp->in_flight += n;
free_cops(cop + n, num - n);
return;
}
k = 0;
do {
for (i = 0; i != n; i++)
cqp->buf[len + i] = cop[k + i];
len += n;
k += n;
cqp->buf, len);
cqp->in_flight += n;
free_cops(cqp->buf + n, len - n);
len = 0;
}
} while (k != num);
cqp->len = len;
}
static inline int
fill_ipsec_session(struct rte_ipsec_session *ss, struct ipsec_ctx *ctx,
struct ipsec_sa *sa)
{
int32_t rc;
if (sa->crypto_session == NULL) {
rc = create_session(ctx, sa);
if (rc != 0)
return rc;
}
ss->crypto.ses = sa->crypto_session;
} else {
if (sa->sec_session == NULL) {
rc = create_session(ctx, sa);
if (rc != 0)
return rc;
}
ss->security.ses = sa->sec_session;
ss->security.ctx = sa->security_ctx;
ss->security.ol_flags = sa->ol_flags;
}
rc = rte_ipsec_session_prepare(ss);
if (rc != 0)
memset(ss, 0, sizeof(*ss));
return rc;
}
static uint32_t
sa_group(
struct ipsec_sa *sa_ptr[],
struct rte_mbuf *pkts[],
struct rte_ipsec_group grp[], uint32_t num)
{
uint32_t i, n, spi;
void *sa;
void * const nosa = &spi;
sa = nosa;
for (i = 0, n = 0; i != num; i++) {
if (sa != sa_ptr[i]) {
grp[n].cnt = pkts + i - grp[n].m;
n += (sa != nosa);
grp[n].
id.ptr = sa_ptr[i];
grp[n].m = pkts + i;
sa = sa_ptr[i];
}
}
if (sa != nosa) {
grp[n].cnt = pkts + i - grp[n].m;
n++;
}
return n;
}
static inline void
copy_to_trf(
struct ipsec_traffic *trf, uint64_t satp,
struct rte_mbuf *mb[],
uint32_t num)
{
uint32_t j, ofs, s;
struct traffic_type *out;
if ((satp & RTE_IPSEC_SATP_DIR_MASK) == RTE_IPSEC_SATP_DIR_IB) {
if ((satp & RTE_IPSEC_SATP_IPV_MASK) == RTE_IPSEC_SATP_IPV4) {
out = &trf->ip4;
} else {
out = &trf->ip6;
ofs =
offsetof(
struct ip6_hdr, ip6_nxt);
}
} else if (SATP_OUT_IPV4(satp)) {
out = &trf->ip4;
} else {
out = &trf->ip6;
ofs =
offsetof(
struct ip6_hdr, ip6_nxt);
}
for (j = 0, s = out->num; j != num; j++) {
void *, ofs);
out->pkts[s + j] = mb[j];
}
out->num += num;
}
void
ipsec_process(struct ipsec_ctx *ctx, struct ipsec_traffic *trf)
{
uint64_t satp;
uint32_t i, j, k, n;
struct ipsec_sa *sa;
struct ipsec_mbuf_metadata *priv;
struct rte_ipsec_group *pg;
struct rte_ipsec_session *ips;
struct cdev_qp *cqp;
struct rte_ipsec_group grp[
RTE_DIM(trf->ipsec.pkts)];
n = sa_group(trf->ipsec.saptr, trf->ipsec.pkts, grp, trf->ipsec.num);
for (i = 0; i != n; i++) {
pg = grp + i;
sa = pg->id.ptr;
ips = &sa->ips;
if (sa == NULL || (ips->crypto.ses == NULL &&
fill_ipsec_session(ips, ctx, sa) != 0))
k = 0;
sa->type ==
satp = rte_ipsec_sa_type(ips->sa);
for (j = 0; j != pg->cnt; j++) {
priv = get_priv(pg->m[j]);
priv->sa = sa;
}
k = rte_ipsec_pkt_process(ips, pg->m, pg->cnt);
copy_to_trf(trf, satp, pg->m, k);
} else {
cqp = &ctx->tbl[sa->cdev_id_qp];
for (j = 0; j != pg->cnt; j++) {
priv = get_priv(pg->m[j]);
cop[j] = &priv->cop;
priv->sa = sa;
}
k = rte_ipsec_pkt_crypto_prepare(ips, pg->m, cop,
pg->cnt);
if (k != 0)
enqueue_cop_bulk(cqp, cop, k);
}
if (k != pg->cnt)
free_pkts(pg->m + k, pg->cnt - k);
}
}
static inline uint32_t
cqp_dequeue(
struct cdev_qp *cqp,
struct rte_crypto_op *cop[], uint32_t num)
{
uint32_t n;
if (cqp->in_flight == 0)
return 0;
RTE_ASSERT(cqp->in_flight >= n);
cqp->in_flight -= n;
return n;
}
static inline uint32_t
ctx_dequeue(
struct ipsec_ctx *ctx,
struct rte_crypto_op *cop[], uint32_t num)
{
uint32_t i, n;
n = 0;
for (i = ctx->last_qp; n != num && i != ctx->nb_qps; i++)
n += cqp_dequeue(ctx->tbl + i, cop + n, num - n);
for (i = 0; n != num && i != ctx->last_qp; i++)
n += cqp_dequeue(ctx->tbl + i, cop + n, num - n);
ctx->last_qp = i;
return n;
}
void
ipsec_cqp_process(struct ipsec_ctx *ctx, struct ipsec_traffic *trf)
{
uint64_t satp;
uint32_t i, k, n, ng;
struct rte_ipsec_session *ss;
struct traffic_type *out;
struct rte_ipsec_group *pg;
struct rte_ipsec_group grp[
RTE_DIM(trf->ipsec.pkts)];
trf->ip4.num = 0;
trf->ip6.num = 0;
out = &trf->ipsec;
n = ctx_dequeue(ctx, cop,
RTE_DIM(cop));
if (n == 0)
return;
(uintptr_t)cop, out->pkts, grp, n);
for (i = 0; i != ng; i++) {
pg = grp + i;
ss = pg->id.ptr;
satp = rte_ipsec_sa_type(ss->sa);
k = rte_ipsec_pkt_process(ss, pg->m, pg->cnt);
copy_to_trf(trf, satp, pg->m, k);
free_pkts(pg->m + k, pg->cnt - k);
n -= pg->cnt;
}
RTE_VERIFY(n == 0);
}