ipsec: support SA telemetry

Add telemetry support for ipsec SAs.

Signed-off-by: Declan Doherty <declan.doherty@intel.com>
Signed-off-by: Radu Nicolau <radu.nicolau@intel.com>
Signed-off-by: Abhijit Sinha <abhijit.sinha@intel.com>
Signed-off-by: Daniel Martin Buckley <daniel.m.buckley@intel.com>
Acked-by: Fan Zhang <roy.fan.zhang@intel.com>
Acked-by: Konstantin Ananyev <konstantin.ananyev@intel.com>
Acked-by: Akhil Goyal <gakhil@marvell.com>
This commit is contained in:
Radu Nicolau 2021-10-14 17:03:26 +01:00 committed by Akhil Goyal
parent 64df4712ce
commit 68977baa75
10 changed files with 328 additions and 11 deletions

View File

@ -319,6 +319,14 @@ Supported features
AES_GMAC, HMAC-SHA1, NULL.
Telemetry support
------------------
Telemetry support implements SA details and IPsec packet add data counters
statistics. Per SA telemetry statistics can be enabled using
``rte_ipsec_telemetry_sa_add`` and disabled using
``rte_ipsec_telemetry_sa_del``. Note that these calls are not thread safe.
Limitations
-----------

View File

@ -156,6 +156,7 @@ New Features
* Added support for more AEAD algorithms AES_CCM, CHACHA20_POLY1305
and AES_GMAC.
* Added support for NAT-T / UDP encapsulated ESP.
* Added support for SA telemetry.
* **Added multi-process support for testpmd.**

View File

@ -15,7 +15,7 @@
#include "misc.h"
#include "pad.h"
typedef uint16_t (*esp_inb_process_t)(const struct rte_ipsec_sa *sa,
typedef uint16_t (*esp_inb_process_t)(struct rte_ipsec_sa *sa,
struct rte_mbuf *mb[], uint32_t sqn[], uint32_t dr[], uint16_t num,
uint8_t sqh_len);
@ -573,10 +573,10 @@ tun_process_step3(struct rte_mbuf *mb, uint64_t txof_msk, uint64_t txof_val)
* *process* function for tunnel packets
*/
static inline uint16_t
tun_process(const struct rte_ipsec_sa *sa, struct rte_mbuf *mb[],
tun_process(struct rte_ipsec_sa *sa, struct rte_mbuf *mb[],
uint32_t sqn[], uint32_t dr[], uint16_t num, uint8_t sqh_len)
{
uint32_t adj, i, k, tl;
uint32_t adj, i, k, tl, bytes;
uint32_t hl[num], to[num];
struct rte_esp_tail espt[num];
struct rte_mbuf *ml[num];
@ -598,6 +598,7 @@ tun_process(const struct rte_ipsec_sa *sa, struct rte_mbuf *mb[],
process_step1(mb[i], tlen, &ml[i], &espt[i], &hl[i], &to[i]);
k = 0;
bytes = 0;
for (i = 0; i != num; i++) {
adj = hl[i] + cofs;
@ -621,10 +622,13 @@ tun_process(const struct rte_ipsec_sa *sa, struct rte_mbuf *mb[],
tun_process_step3(mb[i], sa->tx_offload.msk,
sa->tx_offload.val);
k++;
bytes += mb[i]->pkt_len;
} else
dr[i - k] = i;
}
sa->statistics.count += k;
sa->statistics.bytes += bytes;
return k;
}
@ -632,11 +636,11 @@ tun_process(const struct rte_ipsec_sa *sa, struct rte_mbuf *mb[],
* *process* function for tunnel packets
*/
static inline uint16_t
trs_process(const struct rte_ipsec_sa *sa, struct rte_mbuf *mb[],
trs_process(struct rte_ipsec_sa *sa, struct rte_mbuf *mb[],
uint32_t sqn[], uint32_t dr[], uint16_t num, uint8_t sqh_len)
{
char *np;
uint32_t i, k, l2, tl;
uint32_t i, k, l2, tl, bytes;
uint32_t hl[num], to[num];
struct rte_esp_tail espt[num];
struct rte_mbuf *ml[num];
@ -656,6 +660,7 @@ trs_process(const struct rte_ipsec_sa *sa, struct rte_mbuf *mb[],
process_step1(mb[i], tlen, &ml[i], &espt[i], &hl[i], &to[i]);
k = 0;
bytes = 0;
for (i = 0; i != num; i++) {
tl = tlen + espt[i].pad_len;
@ -674,10 +679,13 @@ trs_process(const struct rte_ipsec_sa *sa, struct rte_mbuf *mb[],
/* update mbuf's metadata */
trs_process_step3(mb[i]);
k++;
bytes += mb[i]->pkt_len;
} else
dr[i - k] = i;
}
sa->statistics.count += k;
sa->statistics.bytes += bytes;
return k;
}

View File

@ -606,7 +606,7 @@ uint16_t
esp_outb_sqh_process(const struct rte_ipsec_session *ss, struct rte_mbuf *mb[],
uint16_t num)
{
uint32_t i, k, icv_len, *icv;
uint32_t i, k, icv_len, *icv, bytes;
struct rte_mbuf *ml;
struct rte_ipsec_sa *sa;
uint32_t dr[num];
@ -615,6 +615,7 @@ esp_outb_sqh_process(const struct rte_ipsec_session *ss, struct rte_mbuf *mb[],
k = 0;
icv_len = sa->icv_len;
bytes = 0;
for (i = 0; i != num; i++) {
if ((mb[i]->ol_flags & PKT_RX_SEC_OFFLOAD_FAILED) == 0) {
@ -625,10 +626,13 @@ esp_outb_sqh_process(const struct rte_ipsec_session *ss, struct rte_mbuf *mb[],
icv = rte_pktmbuf_mtod_offset(ml, void *,
ml->data_len - icv_len);
remove_sqh(icv, icv_len);
bytes += mb[i]->pkt_len;
k++;
} else
dr[i - k] = i;
}
sa->statistics.count += k;
sa->statistics.bytes += bytes;
/* handle unprocessed mbufs */
if (k != num) {
@ -648,16 +652,20 @@ static inline void
inline_outb_mbuf_prepare(const struct rte_ipsec_session *ss,
struct rte_mbuf *mb[], uint16_t num)
{
uint32_t i, ol_flags;
uint32_t i, ol_flags, bytes;
ol_flags = ss->security.ol_flags & RTE_SECURITY_TX_OLOAD_NEED_MDATA;
bytes = 0;
for (i = 0; i != num; i++) {
mb[i]->ol_flags |= PKT_TX_SEC_OFFLOAD;
bytes += mb[i]->pkt_len;
if (ol_flags != 0)
rte_security_set_pkt_metadata(ss->security.ctx,
ss->security.ses, mb[i], NULL);
}
ss->sa->statistics.count += num;
ss->sa->statistics.bytes += bytes;
}
/*

243
lib/ipsec/ipsec_telemetry.c Normal file
View File

@ -0,0 +1,243 @@
/* SPDX-License-Identifier: BSD-3-Clause
* Copyright(c) 2021 Intel Corporation
*/
#include <rte_ipsec.h>
#include <rte_telemetry.h>
#include <rte_malloc.h>
#include "sa.h"
struct ipsec_telemetry_entry {
LIST_ENTRY(ipsec_telemetry_entry) next;
const struct rte_ipsec_sa *sa;
};
static LIST_HEAD(ipsec_telemetry_head, ipsec_telemetry_entry)
ipsec_telemetry_list = LIST_HEAD_INITIALIZER();
static int
handle_telemetry_cmd_ipsec_sa_list(const char *cmd __rte_unused,
const char *params __rte_unused,
struct rte_tel_data *data)
{
struct ipsec_telemetry_entry *entry;
rte_tel_data_start_array(data, RTE_TEL_U64_VAL);
LIST_FOREACH(entry, &ipsec_telemetry_list, next) {
const struct rte_ipsec_sa *sa = entry->sa;
rte_tel_data_add_array_u64(data, rte_be_to_cpu_32(sa->spi));
}
return 0;
}
/**
* Handle IPsec SA statistics telemetry request
*
* Return dict of SA's with dict of key/value counters
*
* {
* "SA_SPI_XX": {"count": 0, "bytes": 0, "errors": 0},
* "SA_SPI_YY": {"count": 0, "bytes": 0, "errors": 0}
* }
*
*/
static int
handle_telemetry_cmd_ipsec_sa_stats(const char *cmd __rte_unused,
const char *params,
struct rte_tel_data *data)
{
struct ipsec_telemetry_entry *entry;
const struct rte_ipsec_sa *sa;
uint32_t sa_spi = 0;
if (params) {
sa_spi = rte_cpu_to_be_32((uint32_t)strtoul(params, NULL, 0));
if (sa_spi == 0)
return -EINVAL;
}
rte_tel_data_start_dict(data);
LIST_FOREACH(entry, &ipsec_telemetry_list, next) {
char sa_name[64];
sa = entry->sa;
static const char *name_pkt_cnt = "count";
static const char *name_byte_cnt = "bytes";
static const char *name_error_cnt = "errors";
struct rte_tel_data *sa_data;
/* If user provided SPI only get telemetry for that SA */
if (sa_spi && (sa_spi != sa->spi))
continue;
/* allocate telemetry data struct for SA telemetry */
sa_data = rte_tel_data_alloc();
if (!sa_data)
return -ENOMEM;
rte_tel_data_start_dict(sa_data);
/* add telemetry key/values pairs */
rte_tel_data_add_dict_u64(sa_data, name_pkt_cnt,
sa->statistics.count);
rte_tel_data_add_dict_u64(sa_data, name_byte_cnt,
sa->statistics.bytes -
(sa->statistics.count * sa->hdr_len));
rte_tel_data_add_dict_u64(sa_data, name_error_cnt,
sa->statistics.errors.count);
/* generate telemetry label */
snprintf(sa_name, sizeof(sa_name), "SA_SPI_%i",
rte_be_to_cpu_32(sa->spi));
/* add SA telemetry to dictionary container */
rte_tel_data_add_dict_container(data, sa_name, sa_data, 0);
}
return 0;
}
static int
handle_telemetry_cmd_ipsec_sa_details(const char *cmd __rte_unused,
const char *params,
struct rte_tel_data *data)
{
struct ipsec_telemetry_entry *entry;
const struct rte_ipsec_sa *sa;
uint32_t sa_spi = 0;
if (params)
sa_spi = rte_cpu_to_be_32((uint32_t)strtoul(params, NULL, 0));
/* valid SPI needed */
if (sa_spi == 0)
return -EINVAL;
rte_tel_data_start_dict(data);
LIST_FOREACH(entry, &ipsec_telemetry_list, next) {
uint64_t mode;
sa = entry->sa;
if (sa_spi != sa->spi)
continue;
/* add SA configuration key/values pairs */
rte_tel_data_add_dict_string(data, "Type",
(sa->type & RTE_IPSEC_SATP_PROTO_MASK) ==
RTE_IPSEC_SATP_PROTO_AH ? "AH" : "ESP");
rte_tel_data_add_dict_string(data, "Direction",
(sa->type & RTE_IPSEC_SATP_DIR_MASK) ==
RTE_IPSEC_SATP_DIR_IB ? "Inbound" : "Outbound");
mode = sa->type & RTE_IPSEC_SATP_MODE_MASK;
if (mode == RTE_IPSEC_SATP_MODE_TRANS) {
rte_tel_data_add_dict_string(data, "Mode", "Transport");
} else {
rte_tel_data_add_dict_string(data, "Mode", "Tunnel");
if ((sa->type & RTE_IPSEC_SATP_NATT_MASK) ==
RTE_IPSEC_SATP_NATT_ENABLE) {
if (sa->type & RTE_IPSEC_SATP_MODE_TUNLV4) {
rte_tel_data_add_dict_string(data,
"Tunnel-Type",
"IPv4-UDP");
} else if (sa->type &
RTE_IPSEC_SATP_MODE_TUNLV6) {
rte_tel_data_add_dict_string(data,
"Tunnel-Type",
"IPv4-UDP");
}
} else {
if (sa->type & RTE_IPSEC_SATP_MODE_TUNLV4) {
rte_tel_data_add_dict_string(data,
"Tunnel-Type",
"IPv4-UDP");
} else if (sa->type &
RTE_IPSEC_SATP_MODE_TUNLV6) {
rte_tel_data_add_dict_string(data,
"Tunnel-Type",
"IPv4-UDP");
}
}
}
rte_tel_data_add_dict_string(data,
"extended-sequence-number",
(sa->type & RTE_IPSEC_SATP_ESN_MASK) ==
RTE_IPSEC_SATP_ESN_ENABLE ?
"enabled" : "disabled");
if ((sa->type & RTE_IPSEC_SATP_DIR_MASK) ==
RTE_IPSEC_SATP_DIR_IB)
if (sa->sqn.inb.rsn[sa->sqn.inb.rdidx])
rte_tel_data_add_dict_u64(data,
"sequence-number",
sa->sqn.inb.rsn[sa->sqn.inb.rdidx]->sqn);
else
rte_tel_data_add_dict_u64(data,
"sequence-number", 0);
else
rte_tel_data_add_dict_u64(data, "sequence-number",
sa->sqn.outb);
rte_tel_data_add_dict_string(data,
"explicit-congestion-notification",
(sa->type & RTE_IPSEC_SATP_ECN_MASK) ==
RTE_IPSEC_SATP_ECN_ENABLE ?
"enabled" : "disabled");
rte_tel_data_add_dict_string(data,
"copy-DSCP",
(sa->type & RTE_IPSEC_SATP_DSCP_MASK) ==
RTE_IPSEC_SATP_DSCP_ENABLE ?
"enabled" : "disabled");
}
return 0;
}
int
rte_ipsec_telemetry_sa_add(const struct rte_ipsec_sa *sa)
{
struct ipsec_telemetry_entry *entry = rte_zmalloc(NULL,
sizeof(struct ipsec_telemetry_entry), 0);
if (entry == NULL)
return -ENOMEM;
entry->sa = sa;
LIST_INSERT_HEAD(&ipsec_telemetry_list, entry, next);
return 0;
}
void
rte_ipsec_telemetry_sa_del(const struct rte_ipsec_sa *sa)
{
struct ipsec_telemetry_entry *entry;
LIST_FOREACH(entry, &ipsec_telemetry_list, next) {
if (sa == entry->sa) {
LIST_REMOVE(entry, next);
rte_free(entry);
return;
}
}
}
RTE_INIT(rte_ipsec_telemetry_init)
{
rte_telemetry_register_cmd("/ipsec/sa/list",
handle_telemetry_cmd_ipsec_sa_list,
"Return list of IPsec SAs with telemetry enabled.");
rte_telemetry_register_cmd("/ipsec/sa/stats",
handle_telemetry_cmd_ipsec_sa_stats,
"Returns IPsec SA stastistics. Parameters: int sa_spi");
rte_telemetry_register_cmd("/ipsec/sa/details",
handle_telemetry_cmd_ipsec_sa_details,
"Returns IPsec SA configuration. Parameters: int sa_spi");
}

View File

@ -1,9 +1,11 @@
# SPDX-License-Identifier: BSD-3-Clause
# Copyright(c) 2018 Intel Corporation
sources = files('esp_inb.c', 'esp_outb.c', 'sa.c', 'ses.c', 'ipsec_sad.c')
sources = files('esp_inb.c', 'esp_outb.c',
'sa.c', 'ses.c', 'ipsec_sad.c',
'ipsec_telemetry.c')
headers = files('rte_ipsec.h', 'rte_ipsec_sa.h', 'rte_ipsec_sad.h')
indirect_headers += files('rte_ipsec_group.h')
deps += ['mbuf', 'net', 'cryptodev', 'security', 'hash']
deps += ['mbuf', 'net', 'cryptodev', 'security', 'hash', 'telemetry']

View File

@ -158,6 +158,29 @@ rte_ipsec_pkt_process(const struct rte_ipsec_session *ss, struct rte_mbuf *mb[],
return ss->pkt_func.process(ss, mb, num);
}
/**
* Enable per SA telemetry for a specific SA.
* Note that this function is not thread safe
* @param sa
* Pointer to the *rte_ipsec_sa* object that will have telemetry enabled.
* @return
* 0 on success, negative value otherwise.
*/
__rte_experimental
int
rte_ipsec_telemetry_sa_add(const struct rte_ipsec_sa *sa);
/**
* Disable per SA telemetry for a specific SA.
* Note that this function is not thread safe
* @param sa
* Pointer to the *rte_ipsec_sa* object that will have telemetry disabled.
*/
__rte_experimental
void
rte_ipsec_telemetry_sa_del(const struct rte_ipsec_sa *sa);
#include <rte_ipsec_group.h>
#ifdef __cplusplus

View File

@ -653,19 +653,25 @@ uint16_t
pkt_flag_process(const struct rte_ipsec_session *ss,
struct rte_mbuf *mb[], uint16_t num)
{
uint32_t i, k;
uint32_t i, k, bytes;
uint32_t dr[num];
RTE_SET_USED(ss);
k = 0;
bytes = 0;
for (i = 0; i != num; i++) {
if ((mb[i]->ol_flags & PKT_RX_SEC_OFFLOAD_FAILED) == 0)
if ((mb[i]->ol_flags & PKT_RX_SEC_OFFLOAD_FAILED) == 0) {
k++;
bytes += mb[i]->pkt_len;
}
else
dr[i - k] = i;
}
ss->sa->statistics.count += k;
ss->sa->statistics.bytes += bytes;
/* handle unprocessed mbufs */
if (k != num) {
rte_errno = EBADMSG;

View File

@ -132,6 +132,15 @@ struct rte_ipsec_sa {
struct replay_sqn *rsn[REPLAY_SQN_NUM];
} inb;
} sqn;
/* Statistics */
struct {
uint64_t count;
uint64_t bytes;
struct {
uint64_t count;
uint64_t authentication_failed;
} errors;
} statistics;
} __rte_cache_aligned;

View File

@ -19,3 +19,12 @@ DPDK_22 {
local: *;
};
EXPERIMENTAL {
global:
# added in 21.11
rte_ipsec_telemetry_sa_add;
rte_ipsec_telemetry_sa_del;
};