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:
parent
64df4712ce
commit
68977baa75
@ -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
|
||||
-----------
|
||||
|
||||
|
@ -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.**
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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
243
lib/ipsec/ipsec_telemetry.c
Normal 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");
|
||||
}
|
@ -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']
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
||||
|
@ -19,3 +19,12 @@ DPDK_22 {
|
||||
|
||||
local: *;
|
||||
};
|
||||
|
||||
EXPERIMENTAL {
|
||||
global:
|
||||
|
||||
# added in 21.11
|
||||
rte_ipsec_telemetry_sa_add;
|
||||
rte_ipsec_telemetry_sa_del;
|
||||
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user