summaryrefslogtreecommitdiffstats
path: root/examples
diff options
context:
space:
mode:
Diffstat (limited to 'examples')
-rw-r--r--examples/Makefile1
-rw-r--r--examples/fips_validation/Makefile75
-rw-r--r--examples/fips_validation/fips_validation.c595
-rw-r--r--examples/fips_validation/fips_validation.h233
-rw-r--r--examples/fips_validation/fips_validation_aes.c188
-rw-r--r--examples/fips_validation/fips_validation_ccm.c272
-rw-r--r--examples/fips_validation/fips_validation_cmac.c116
-rw-r--r--examples/fips_validation/fips_validation_gcm.c125
-rw-r--r--examples/fips_validation/fips_validation_hmac.c105
-rw-r--r--examples/fips_validation/fips_validation_tdes.c264
-rw-r--r--examples/fips_validation/main.c1225
-rw-r--r--examples/fips_validation/meson.build20
-rw-r--r--examples/flow_filtering/flow_blocks.c21
-rw-r--r--examples/flow_filtering/main.c3
-rw-r--r--examples/ip_pipeline/cli.c980
-rw-r--r--examples/ip_pipeline/pipeline.c88
-rw-r--r--examples/ip_pipeline/pipeline.h63
-rw-r--r--examples/ip_pipeline/thread.c710
-rw-r--r--examples/multi_process/client_server_mp/mp_server/main.c15
-rw-r--r--examples/vm_power_manager/power_manager.c16
20 files changed, 4732 insertions, 383 deletions
diff --git a/examples/Makefile b/examples/Makefile
index 356fcb1c..33fe0e58 100644
--- a/examples/Makefile
+++ b/examples/Makefile
@@ -17,6 +17,7 @@ DIRS-$(CONFIG_RTE_LIBRTE_DISTRIBUTOR) += distributor
DIRS-y += ethtool
DIRS-y += exception_path
DIRS-$(CONFIG_RTE_LIBRTE_EFD) += server_node_efd
+DIRS-$(CONFIG_RTE_LIBRTE_CRYPTODEV) += fips_validation
DIRS-$(CONFIG_RTE_LIBRTE_FLOW_CLASSIFY) += flow_classify
DIRS-y += flow_filtering
DIRS-y += helloworld
diff --git a/examples/fips_validation/Makefile b/examples/fips_validation/Makefile
new file mode 100644
index 00000000..7b1fe34a
--- /dev/null
+++ b/examples/fips_validation/Makefile
@@ -0,0 +1,75 @@
+# SPDX-License-Identifier: BSD-3-Clause
+# Copyright(c) 2018 Intel Corporation
+
+# binary name
+APP = fips_validation
+
+# all source are stored in SRCS-y
+SRCS-y := fips_validation.c
+SRCS-y += fips_validation_aes.c
+SRCS-y += fips_validation_hmac.c
+SRCS-y += fips_validation_tdes.c
+SRCS-y += fips_validation_gcm.c
+SRCS-y += fips_validation_cmac.c
+SRCS-y += fips_validation_ccm.c
+SRCS-y += main.c
+
+# Build using pkg-config variables if possible
+$(shell pkg-config --exists libdpdk)
+ifeq ($(.SHELLSTATUS),0)
+
+all: shared
+.PHONY: shared static
+shared: build/$(APP)-shared
+ ln -sf $(APP)-shared build/$(APP)
+static: build/$(APP)-static
+ ln -sf $(APP)-static build/$(APP)
+
+PC_FILE := $(shell pkg-config --path libdpdk)
+CFLAGS += -O3 $(shell pkg-config --cflags libdpdk)
+LDFLAGS_SHARED = $(shell pkg-config --libs libdpdk)
+LDFLAGS_STATIC = -Wl,-Bstatic $(shell pkg-config --static --libs libdpdk)
+
+build/$(APP)-shared: $(SRCS-y) Makefile $(PC_FILE) | build
+ $(CC) $(CFLAGS) $(SRCS-y) -o $@ $(LDFLAGS) $(LDFLAGS_SHARED)
+
+build/$(APP)-static: $(SRCS-y) Makefile $(PC_FILE) | build
+ $(CC) $(CFLAGS) $(SRCS-y) -o $@ $(LDFLAGS) $(LDFLAGS_STATIC)
+
+build:
+ @mkdir -p $@
+
+.PHONY: clean
+clean:
+ rm -f build/$(APP) build/$(APP)-static build/$(APP)-shared
+ rmdir --ignore-fail-on-non-empty build
+
+else
+
+ifeq ($(RTE_SDK),)
+$(error "Please define RTE_SDK environment variable")
+endif
+
+# Default target, can be overridden by command line or environment
+RTE_TARGET ?= x86_64-native-linuxapp-gcc
+
+INC += $(sort $(wildcard *.h))
+
+include $(RTE_SDK)/mk/rte.vars.mk
+
+CFLAGS += $(WERROR_FLAGS)
+
+# workaround for a gcc bug with noreturn attribute
+# http://gcc.gnu.org/bugzilla/show_bug.cgi?id=12603
+ifeq ($(CONFIG_RTE_TOOLCHAIN_GCC),y)
+CFLAGS_main.o += -Wno-return-type
+endif
+
+CFLAGS += -DALLOW_EXPERIMENTAL_API
+CFLAGS += -I$(SRCDIR)
+CFLAGS += -O3
+CFLAGS += $(WERROR_FLAGS)
+
+include $(RTE_SDK)/mk/rte.extapp.mk
+
+endif
diff --git a/examples/fips_validation/fips_validation.c b/examples/fips_validation/fips_validation.c
new file mode 100644
index 00000000..a835cc3f
--- /dev/null
+++ b/examples/fips_validation/fips_validation.c
@@ -0,0 +1,595 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018 Intel Corporation
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#include <rte_string_fns.h>
+#include <rte_cryptodev.h>
+#include <rte_malloc.h>
+
+#include "fips_validation.h"
+
+#define skip_white_spaces(pos) \
+({ \
+ __typeof__(pos) _p = (pos); \
+ for ( ; isspace(*_p); _p++) \
+ ; \
+ _p; \
+})
+
+static int
+get_file_line(void)
+{
+ FILE *fp = info.fp_rd;
+ char *line = info.one_line_text;
+ int ret;
+ uint32_t loc = 0;
+
+ memset(line, 0, MAX_LINE_CHAR);
+ while ((ret = fgetc(fp)) != EOF) {
+ char c = (char)ret;
+
+ if (loc >= MAX_LINE_CHAR - 1)
+ return -ENOMEM;
+ if (c == '\n')
+ break;
+ line[loc++] = c;
+ }
+
+ if (ret == EOF)
+ return -EOF;
+
+ return 0;
+}
+
+int
+fips_test_fetch_one_block(void)
+{
+ size_t size;
+ int ret = 0;
+ uint32_t i;
+
+ for (i = 0; i < info.nb_vec_lines; i++) {
+ free(info.vec[i]);
+ info.vec[i] = NULL;
+ }
+
+ i = 0;
+ do {
+ if (i >= MAX_LINE_PER_VECTOR) {
+ ret = -ENOMEM;
+ goto error_exit;
+ }
+
+ ret = get_file_line();
+ size = strlen(info.one_line_text);
+ if (size == 0)
+ break;
+
+ info.vec[i] = calloc(1, size + 5);
+ if (info.vec[i] == NULL)
+ goto error_exit;
+
+ strlcpy(info.vec[i], info.one_line_text, size + 1);
+ i++;
+ } while (ret == 0);
+
+ info.nb_vec_lines = i;
+
+ return ret;
+
+error_exit:
+ for (i = 0; i < MAX_LINE_PER_VECTOR; i++)
+ if (info.vec[i] != NULL) {
+ free(info.vec[i]);
+ info.vec[i] = NULL;
+ }
+
+ info.nb_vec_lines = 0;
+
+ return -ENOMEM;
+}
+
+static int
+fips_test_parse_header(void)
+{
+ uint32_t i;
+ char *tmp;
+ int ret;
+ time_t t = time(NULL);
+ struct tm *tm_now = localtime(&t);
+
+ ret = fips_test_fetch_one_block();
+ if (ret < 0)
+ return ret;
+
+ for (i = 0; i < info.nb_vec_lines; i++) {
+ if (strstr(info.vec[i], "AESVS")) {
+ info.algo = FIPS_TEST_ALGO_AES;
+ ret = parse_test_aes_init();
+ if (ret < 0)
+ return ret;
+ } else if (strstr(info.vec[i], "GCM")) {
+ info.algo = FIPS_TEST_ALGO_AES_GCM;
+ ret = parse_test_gcm_init();
+ if (ret < 0)
+ return ret;
+ } else if (strstr(info.vec[i], "CMAC")) {
+ info.algo = FIPS_TEST_ALGO_AES_CMAC;
+ ret = parse_test_cmac_init();
+ if (ret < 0)
+ return 0;
+ } else if (strstr(info.vec[i], "CCM")) {
+ info.algo = FIPS_TEST_ALGO_AES_CCM;
+ ret = parse_test_ccm_init();
+ if (ret < 0)
+ return 0;
+ } else if (strstr(info.vec[i], "HMAC")) {
+ info.algo = FIPS_TEST_ALGO_HMAC;
+ ret = parse_test_hmac_init();
+ if (ret < 0)
+ return ret;
+ } else if (strstr(info.vec[i], "TDES")) {
+ info.algo = FIPS_TEST_ALGO_TDES;
+ ret = parse_test_tdes_init();
+ if (ret < 0)
+ return 0;
+ }
+
+ tmp = strstr(info.vec[i], "# Config info for ");
+ if (tmp != NULL) {
+ fprintf(info.fp_wr, "%s%s\n", "# Config info for DPDK Cryptodev ",
+ info.device_name);
+ continue;
+ }
+
+ tmp = strstr(info.vec[i], "# HMAC information for ");
+ if (tmp != NULL) {
+ fprintf(info.fp_wr, "%s%s\n", "# HMAC information for "
+ "DPDK Cryptodev ",
+ info.device_name);
+ continue;
+ }
+
+ tmp = strstr(info.vec[i], "# Config Info for : ");
+ if (tmp != NULL) {
+
+ fprintf(info.fp_wr, "%s%s\n", "# Config Info for DPDK Cryptodev : ",
+ info.device_name);
+ continue;
+ }
+
+ tmp = strstr(info.vec[i], "# information for ");
+ if (tmp != NULL) {
+
+ char tmp_output[128] = {0};
+
+ strlcpy(tmp_output, info.vec[i], tmp - info.vec[i] + 1);
+
+ fprintf(info.fp_wr, "%s%s%s\n", tmp_output,
+ "information for DPDK Cryptodev ",
+ info.device_name);
+ continue;
+ }
+
+ tmp = strstr(info.vec[i], " test information for ");
+ if (tmp != NULL) {
+ char tmp_output[128] = {0};
+
+ strlcpy(tmp_output, info.vec[i], tmp - info.vec[i] + 1);
+
+ fprintf(info.fp_wr, "%s%s%s\n", tmp_output,
+ "test information for DPDK Cryptodev ",
+ info.device_name);
+ continue;
+ }
+
+ if (i == info.nb_vec_lines - 1) {
+ /** update the time as current time, write to file */
+ fprintf(info.fp_wr, "%s%s\n", "# Generated on ",
+ asctime(tm_now));
+ continue;
+ }
+
+ /* to this point, no field need to update,
+ * only copy to rsp file
+ */
+ fprintf(info.fp_wr, "%s\n", info.vec[i]);
+ }
+
+ return 0;
+}
+
+static int
+parse_file_type(const char *path)
+{
+ const char *tmp = path + strlen(path) - 3;
+
+ if (strstr(tmp, REQ_FILE_PERFIX))
+ info.file_type = FIPS_TYPE_REQ;
+ else if (strstr(tmp, RSP_FILE_PERFIX))
+ info.file_type = FIPS_TYPE_RSP;
+ else if (strstr(path, FAX_FILE_PERFIX))
+ info.file_type = FIPS_TYPE_FAX;
+ else
+ return -EINVAL;
+
+ return 0;
+}
+
+int
+fips_test_init(const char *req_file_path, const char *rsp_file_path,
+ const char *device_name)
+{
+ if (strcmp(req_file_path, rsp_file_path) == 0) {
+ RTE_LOG(ERR, USER1, "File paths cannot be the same\n");
+ return -EINVAL;
+ }
+
+ fips_test_clear();
+
+ info.algo = FIPS_TEST_ALGO_MAX;
+ if (parse_file_type(req_file_path) < 0) {
+ RTE_LOG(ERR, USER1, "File %s type not supported\n",
+ req_file_path);
+ return -EINVAL;
+ }
+
+ info.fp_rd = fopen(req_file_path, "r");
+ if (!info.fp_rd) {
+ RTE_LOG(ERR, USER1, "Cannot open file %s\n", req_file_path);
+ return -EINVAL;
+ }
+
+ info.fp_wr = fopen(rsp_file_path, "w");
+ if (!info.fp_wr) {
+ RTE_LOG(ERR, USER1, "Cannot open file %s\n", rsp_file_path);
+ return -EINVAL;
+ }
+
+ info.one_line_text = calloc(1, MAX_LINE_CHAR);
+ if (!info.one_line_text) {
+ RTE_LOG(ERR, USER1, "Insufficient memory\n");
+ return -ENOMEM;
+ }
+
+ strlcpy(info.device_name, device_name, sizeof(info.device_name));
+
+ if (fips_test_parse_header() < 0) {
+ RTE_LOG(ERR, USER1, "Failed parsing header\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+void
+fips_test_clear(void)
+{
+ if (info.fp_rd)
+ fclose(info.fp_rd);
+ if (info.fp_wr)
+ fclose(info.fp_wr);
+ if (info.one_line_text)
+ free(info.one_line_text);
+ if (info.nb_vec_lines) {
+ uint32_t i;
+
+ for (i = 0; i < info.nb_vec_lines; i++)
+ free(info.vec[i]);
+ }
+
+ memset(&info, 0, sizeof(info));
+}
+
+int
+fips_test_parse_one_case(void)
+{
+ uint32_t i, j = 0;
+ uint32_t is_interim = 0;
+ int ret;
+
+ if (info.interim_callbacks) {
+ for (i = 0; i < info.nb_vec_lines; i++) {
+ for (j = 0; info.interim_callbacks[j].key != NULL; j++)
+ if (strstr(info.vec[i],
+ info.interim_callbacks[j].key)) {
+ is_interim = 1;
+
+ ret = info.interim_callbacks[j].cb(
+ info.interim_callbacks[j].key,
+ info.vec[i],
+ info.interim_callbacks[j].val);
+ if (ret < 0)
+ return ret;
+ }
+ }
+ }
+
+ if (is_interim) {
+ for (i = 0; i < info.nb_vec_lines; i++)
+ fprintf(info.fp_wr, "%s\n", info.vec[i]);
+ fprintf(info.fp_wr, "\n");
+ return 1;
+ }
+
+ for (i = 0; i < info.nb_vec_lines; i++) {
+ for (j = 0; info.callbacks[j].key != NULL; j++)
+ if (strstr(info.vec[i], info.callbacks[j].key)) {
+ ret = info.callbacks[j].cb(
+ info.callbacks[j].key,
+ info.vec[i], info.callbacks[j].val);
+ if (ret < 0)
+ return ret;
+ break;
+ }
+ }
+
+ return 0;
+}
+
+void
+fips_test_write_one_case(void)
+{
+ uint32_t i;
+
+ for (i = 0; i < info.nb_vec_lines; i++)
+ fprintf(info.fp_wr, "%s\n", info.vec[i]);
+}
+
+static int
+parser_read_uint64_hex(uint64_t *value, const char *p)
+{
+ char *next;
+ uint64_t val;
+
+ p = skip_white_spaces(p);
+
+ val = strtoul(p, &next, 16);
+ if (p == next)
+ return -EINVAL;
+
+ p = skip_white_spaces(next);
+ if (*p != '\0')
+ return -EINVAL;
+
+ *value = val;
+ return 0;
+}
+
+int
+parser_read_uint8_hex(uint8_t *value, const char *p)
+{
+ uint64_t val = 0;
+ int ret = parser_read_uint64_hex(&val, p);
+
+ if (ret < 0)
+ return ret;
+
+ if (val > UINT8_MAX)
+ return -ERANGE;
+
+ *value = val;
+ return 0;
+}
+
+int
+parse_uint8_known_len_hex_str(const char *key, char *src, struct fips_val *val)
+{
+ struct fips_val tmp_val = {0};
+ uint32_t len = val->len;
+ int ret;
+
+ if (len == 0) {
+ if (val->val != NULL) {
+ rte_free(val->val);
+ val->val = NULL;
+ }
+
+ return 0;
+ }
+
+ ret = parse_uint8_hex_str(key, src, &tmp_val);
+ if (ret < 0)
+ return ret;
+
+ if (tmp_val.len == val->len) {
+ val->val = tmp_val.val;
+ return 0;
+ }
+
+ if (tmp_val.len < val->len) {
+ rte_free(tmp_val.val);
+ return -EINVAL;
+ }
+
+ val->val = rte_zmalloc(NULL, val->len, 0);
+ if (!val->val) {
+ rte_free(tmp_val.val);
+ memset(val, 0, sizeof(*val));
+ return -ENOMEM;
+ }
+
+ memcpy(val->val, tmp_val.val, val->len);
+ rte_free(tmp_val.val);
+
+ return 0;
+}
+
+int
+parse_uint8_hex_str(const char *key, char *src, struct fips_val *val)
+{
+ uint32_t len, j;
+
+ src += strlen(key);
+
+ len = strlen(src) / 2;
+
+ if (val->val) {
+ rte_free(val->val);
+ val->val = NULL;
+ }
+
+ val->val = rte_zmalloc(NULL, len, 0);
+ if (!val->val)
+ return -ENOMEM;
+
+ for (j = 0; j < len; j++) {
+ char byte[3] = {src[j * 2], src[j * 2 + 1], '\0'};
+
+ if (parser_read_uint8_hex(&val->val[j], byte) < 0) {
+ rte_free(val->val);
+ memset(val, 0, sizeof(*val));
+ return -EINVAL;
+ }
+ }
+
+ val->len = len;
+
+ return 0;
+}
+
+int
+parser_read_uint32_val(const char *key, char *src, struct fips_val *val)
+{
+ char *data = src + strlen(key);
+ size_t data_len = strlen(data);
+ int ret;
+
+ if (data[data_len - 1] == ']') {
+ char *tmp_data = calloc(1, data_len + 1);
+
+ if (tmp_data == NULL)
+ return -ENOMEM;
+
+ strlcpy(tmp_data, data, data_len);
+
+ ret = parser_read_uint32(&val->len, tmp_data);
+
+ free(tmp_data);
+ } else
+ ret = parser_read_uint32(&val->len, data);
+
+ return ret;
+}
+
+int
+parser_read_uint32_bit_val(const char *key, char *src, struct fips_val *val)
+{
+ int ret;
+
+ ret = parser_read_uint32_val(key, src, val);
+
+ if (ret < 0)
+ return ret;
+
+ val->len /= 8;
+
+ return 0;
+}
+
+int
+writeback_hex_str(const char *key, char *dst, struct fips_val *val)
+{
+ char *str = dst;
+ uint32_t len;
+
+ str += strlen(key);
+
+ for (len = 0; len < val->len; len++)
+ snprintf(str + len * 2, 255, "%02x", val->val[len]);
+
+ return 0;
+}
+
+static int
+parser_read_uint64(uint64_t *value, const char *p)
+{
+ char *next;
+ uint64_t val;
+
+ p = skip_white_spaces(p);
+ if (!isdigit(*p))
+ return -EINVAL;
+
+ val = strtoul(p, &next, 10);
+ if (p == next)
+ return -EINVAL;
+
+ p = next;
+ switch (*p) {
+ case 'T':
+ val *= 1024ULL;
+ /* fall through */
+ case 'G':
+ val *= 1024ULL;
+ /* fall through */
+ case 'M':
+ val *= 1024ULL;
+ /* fall through */
+ case 'k':
+ case 'K':
+ val *= 1024ULL;
+ p++;
+ break;
+ }
+
+ p = skip_white_spaces(p);
+ if (*p != '\0')
+ return -EINVAL;
+
+ *value = val;
+ return 0;
+}
+
+int
+parser_read_uint32(uint32_t *value, char *p)
+{
+ uint64_t val = 0;
+ int ret = parser_read_uint64(&val, p);
+
+ if (ret < 0)
+ return ret;
+
+ if (val > UINT32_MAX)
+ return -EINVAL;
+
+ *value = val;
+ return 0;
+}
+
+void
+parse_write_hex_str(struct fips_val *src)
+{
+ writeback_hex_str("", info.one_line_text, src);
+
+ fprintf(info.fp_wr, "%s\n", info.one_line_text);
+}
+
+int
+update_info_vec(uint32_t count)
+{
+ const struct fips_test_callback *cb;
+ uint32_t i, j;
+
+ if (!info.writeback_callbacks)
+ return -1;
+
+ cb = &info.writeback_callbacks[0];
+
+ snprintf(info.vec[0], strlen(info.vec[0]) + 4, "%s%u", cb->key, count);
+
+ for (i = 1; i < info.nb_vec_lines; i++) {
+ for (j = 1; info.writeback_callbacks[j].key != NULL; j++) {
+ cb = &info.writeback_callbacks[j];
+ if (strstr(info.vec[i], cb->key)) {
+ cb->cb(cb->key, info.vec[i], cb->val);
+ break;
+ }
+ }
+ }
+
+ return 0;
+}
diff --git a/examples/fips_validation/fips_validation.h b/examples/fips_validation/fips_validation.h
new file mode 100644
index 00000000..3e291bc3
--- /dev/null
+++ b/examples/fips_validation/fips_validation.h
@@ -0,0 +1,233 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018 Intel Corporation
+ */
+
+#ifndef _FIPS_VALIDATION_H_
+#define _FIPS_VALIDATION_H_
+
+#define FIPS_PARSE_ERR(fmt, args) \
+ RTE_LOG(ERR, USER1, "FIPS parse error" ## fmt ## "\n", ## args)
+
+#define ERR_MSG_SIZE 128
+#define MAX_CASE_LINE 15
+#define MAX_LINE_CHAR 204800 /*< max number of characters per line */
+#define MAX_NB_TESTS 10240
+#define MAX_BUF_SIZE 2048
+#define MAX_STRING_SIZE 64
+
+#define POSITIVE_TEST 0
+#define NEGATIVE_TEST -1
+
+#define REQ_FILE_PERFIX "req"
+#define RSP_FILE_PERFIX "rsp"
+#define FAX_FILE_PERFIX "fax"
+
+enum fips_test_algorithms {
+ FIPS_TEST_ALGO_AES = 0,
+ FIPS_TEST_ALGO_AES_GCM,
+ FIPS_TEST_ALGO_AES_CMAC,
+ FIPS_TEST_ALGO_AES_CCM,
+ FIPS_TEST_ALGO_HMAC,
+ FIPS_TEST_ALGO_TDES,
+ FIPS_TEST_ALGO_MAX
+};
+
+enum file_types {
+ FIPS_TYPE_REQ = 1,
+ FIPS_TYPE_FAX,
+ FIPS_TYPE_RSP
+};
+
+enum fips_test_op {
+ FIPS_TEST_ENC_AUTH_GEN = 1,
+ FIPS_TEST_DEC_AUTH_VERIF,
+};
+
+#define MAX_LINE_PER_VECTOR 16
+
+struct fips_val {
+ uint8_t *val;
+ uint32_t len;
+};
+
+struct fips_test_vector {
+ union {
+ struct {
+ struct fips_val key;
+ struct fips_val digest;
+ struct fips_val auth_aad;
+ struct fips_val aad;
+ } cipher_auth;
+ struct {
+ struct fips_val key;
+ struct fips_val digest;
+ struct fips_val aad;
+ } aead;
+ };
+
+ struct fips_val pt;
+ struct fips_val ct;
+ struct fips_val iv;
+
+ enum rte_crypto_op_status status;
+};
+
+typedef int (*post_prcess_t)(struct fips_val *val);
+
+typedef int (*parse_callback_t)(const char *key, char *text,
+ struct fips_val *val);
+
+struct fips_test_callback {
+ const char *key;
+ parse_callback_t cb;
+ struct fips_val *val;
+};
+
+enum fips_aesavs_test_types {
+ AESAVS_TYPE_GFXBOX = 1,
+ AESAVS_TYPE_KEYSBOX,
+ AESAVS_TYPE_VARKEY,
+ AESAVS_TYPE_VARTXT,
+ AESAVS_TYPE_MMT,
+ AESAVS_TYPE_MCT,
+};
+
+enum fips_tdes_test_types {
+ TDES_INVERSE_PERMUTATION = 0,
+ TDES_PERMUTATION,
+ TDES_SUBSTITUTION_TABLE,
+ TDES_VARIABLE_KEY,
+ TDES_VARIABLE_TEXT,
+ TDES_KAT,
+ TDES_MCT, /* Monte Carlo (Modes) Test */
+ TDES_MMT /* Multi block Message Test */
+};
+
+enum fips_ccm_test_types {
+ CCM_VADT = 1, /* Variable Associated Data Test */
+ CCM_VPT, /* Variable Payload Test */
+ CCM_VNT, /* Variable Nonce Test */
+ CCM_VTT, /* Variable Tag Test */
+ CCM_DVPT, /* Decryption-Verification Process Test */
+};
+
+struct aesavs_interim_data {
+ enum fips_aesavs_test_types test_type;
+ uint32_t cipher_algo;
+ uint32_t key_len;
+};
+
+struct hmac_interim_data {
+ enum rte_crypto_auth_algorithm algo;
+};
+
+struct tdes_interim_data {
+ enum fips_tdes_test_types test_type;
+ uint32_t nb_keys;
+};
+
+struct ccm_interim_data {
+ enum fips_ccm_test_types test_type;
+ uint32_t aad_len;
+ uint32_t pt_len;
+ uint32_t digest_len;
+ uint32_t key_len;
+ uint32_t iv_len;
+};
+
+struct fips_test_interim_info {
+ FILE *fp_rd;
+ FILE *fp_wr;
+ enum file_types file_type;
+ enum fips_test_algorithms algo;
+ char *one_line_text;
+ char *vec[MAX_LINE_PER_VECTOR];
+ uint32_t nb_vec_lines;
+ char device_name[MAX_STRING_SIZE];
+
+ union {
+ struct aesavs_interim_data aes_data;
+ struct hmac_interim_data hmac_data;
+ struct tdes_interim_data tdes_data;
+ struct ccm_interim_data ccm_data;
+
+ } interim_info;
+
+ enum fips_test_op op;
+
+ const struct fips_test_callback *callbacks;
+ const struct fips_test_callback *interim_callbacks;
+ const struct fips_test_callback *writeback_callbacks;
+
+ post_prcess_t parse_writeback;
+ post_prcess_t kat_check;
+};
+
+extern struct fips_test_vector vec;
+extern struct fips_test_interim_info info;
+
+int
+fips_test_init(const char *req_file_path, const char *rsp_file_path,
+ const char *device_name);
+
+void
+fips_test_clear(void);
+
+int
+fips_test_fetch_one_block(void);
+
+int
+fips_test_parse_one_case(void);
+
+void
+fips_test_write_one_case(void);
+
+int
+parse_test_aes_init(void);
+
+int
+parse_test_tdes_init(void);
+
+int
+parse_test_hmac_init(void);
+
+int
+parse_test_gcm_init(void);
+
+int
+parse_test_cmac_init(void);
+
+int
+parse_test_ccm_init(void);
+
+int
+parser_read_uint8_hex(uint8_t *value, const char *p);
+
+int
+parse_uint8_hex_str(const char *key, char *src, struct fips_val *val);
+
+int
+parse_uint8_known_len_hex_str(const char *key, char *src, struct fips_val *val);
+
+int
+parser_read_uint32_val(const char *key, char *src, struct fips_val *val);
+
+int
+parser_read_uint32_bit_val(const char *key, char *src, struct fips_val *val);
+
+int
+parser_read_uint32(uint32_t *value, char *p);
+
+int
+parser_read_uint32_val(const char *key, char *src, struct fips_val *val);
+
+int
+writeback_hex_str(const char *key, char *dst, struct fips_val *val);
+
+void
+parse_write_hex_str(struct fips_val *src);
+
+int
+update_info_vec(uint32_t count);
+
+#endif
diff --git a/examples/fips_validation/fips_validation_aes.c b/examples/fips_validation/fips_validation_aes.c
new file mode 100644
index 00000000..8cbc158e
--- /dev/null
+++ b/examples/fips_validation/fips_validation_aes.c
@@ -0,0 +1,188 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018 Intel Corporation
+ */
+
+#include <string.h>
+#include <time.h>
+#include <stdio.h>
+
+#include <rte_cryptodev.h>
+
+#include "fips_validation.h"
+
+#define MODE_STR "AESVS"
+#define ALGO_STR "test data for "
+#define OP_STR "State"
+#define KEY_SIZE_STR "Key Length : "
+
+
+#define COUNT_STR "COUNT = "
+#define KEY_STR "KEY = "
+#define IV_STR "IV = "
+#define PT_STR "PLAINTEXT = "
+#define CT_STR "CIPHERTEXT = "
+
+#define OP_ENC_STR "ENCRYPT"
+#define OP_DEC_STR "DECRYPT"
+
+struct {
+ uint32_t type;
+ const char *desc;
+} aes_test_types[] = {
+ {AESAVS_TYPE_GFXBOX, "GFSbox"},
+ {AESAVS_TYPE_KEYSBOX, "KeySbox"},
+ {AESAVS_TYPE_VARKEY, "VarKey"},
+ {AESAVS_TYPE_VARTXT, "VarTxt"},
+ {TDES_VARIABLE_TEXT, "VARIABLE PLAINTEXT/CIPHERTEXT"},
+ {TDES_VARIABLE_TEXT, "KAT"},
+ {AESAVS_TYPE_MMT, "MMT"},
+ {AESAVS_TYPE_MCT, "MCT"},
+};
+
+struct aes_test_algo {
+ const char *name;
+ enum rte_crypto_cipher_algorithm algo;
+} const algo_con[] = {
+ {"CBC", RTE_CRYPTO_CIPHER_AES_CBC},
+};
+
+static int
+parse_interim_enc_dec(const char *key,
+ __attribute__((__unused__)) char *text,
+ __attribute__((__unused__)) struct fips_val *val)
+{
+ if (strcmp(key, OP_ENC_STR) == 0)
+ info.op = FIPS_TEST_ENC_AUTH_GEN;
+ else if (strcmp(key, OP_DEC_STR) == 0)
+ info.op = FIPS_TEST_DEC_AUTH_VERIF;
+ else
+ return -1;
+
+ return 0;
+}
+
+struct fips_test_callback aes_tests_interim[] = {
+ {OP_ENC_STR, parse_interim_enc_dec, NULL},
+ {OP_DEC_STR, parse_interim_enc_dec, NULL},
+ {NULL, NULL, NULL} /**< end pointer */
+};
+
+struct fips_test_callback aes_tests_vectors[] = {
+ {KEY_STR, parse_uint8_hex_str, &vec.cipher_auth.key},
+ {IV_STR, parse_uint8_hex_str, &vec.iv},
+ {PT_STR, parse_uint8_hex_str, &vec.pt},
+ {CT_STR, parse_uint8_hex_str, &vec.ct},
+ {NULL, NULL, NULL} /**< end pointer */
+};
+
+struct fips_test_callback aes_tests_interim_vectors[] = {
+ {OP_ENC_STR, parse_interim_enc_dec, NULL},
+ {OP_DEC_STR, parse_interim_enc_dec, NULL},
+ {NULL, NULL, NULL} /**< end pointer */
+};
+
+struct fips_test_callback aes_writeback_callbacks[] = {
+ /** First element is used to pass COUNT string */
+ {COUNT_STR, NULL, NULL},
+ {IV_STR, writeback_hex_str, &vec.iv},
+ {KEY_STR, writeback_hex_str, &vec.cipher_auth.key},
+ {PT_STR, writeback_hex_str, &vec.pt},
+ {CT_STR, writeback_hex_str, &vec.ct},
+ {NULL, NULL, NULL} /**< end pointer */
+};
+
+static int
+parse_test_aes_writeback(struct fips_val *val)
+{
+ if (info.op == FIPS_TEST_ENC_AUTH_GEN)
+ fprintf(info.fp_wr, "%s", CT_STR);
+ else
+ fprintf(info.fp_wr, "%s", PT_STR);
+
+ parse_write_hex_str(val);
+
+ return 0;
+}
+
+static int
+rsp_test_aes_check(struct fips_val *val)
+{
+ struct fips_val *data;
+
+ if (info.op == FIPS_TEST_ENC_AUTH_GEN)
+ data = &vec.ct;
+ else
+ data = &vec.pt;
+
+ if (memcmp(val->val, data->val, val->len) == 0)
+ fprintf(info.fp_wr, "Success\n");
+ else
+ fprintf(info.fp_wr, "Failed\n");
+
+ return 0;
+}
+
+int
+parse_test_aes_init(void)
+{
+ char *tmp;
+ uint32_t i, j;
+
+ for (i = 0; i < info.nb_vec_lines; i++) {
+ char *line = info.vec[i];
+
+ tmp = strstr(line, MODE_STR);
+ if (tmp) {
+ for (j = 0; j < RTE_DIM(aes_test_types); j++)
+ if (strstr(line, aes_test_types[j].desc)) {
+ info.interim_info.aes_data.test_type =
+ aes_test_types[j].type;
+ break;
+ }
+
+ if (j >= RTE_DIM(aes_test_types))
+ return -EINVAL;
+
+ tmp = strstr(line, ALGO_STR);
+ if (!tmp)
+ return -EINVAL;
+
+ tmp += strlen(ALGO_STR);
+ for (j = 0; j < RTE_DIM(algo_con); j++)
+ if (strcmp(algo_con[j].name, tmp) == 0) {
+ info.interim_info.aes_data.cipher_algo =
+ (uint32_t)algo_con[j].algo;
+ break;
+ }
+ if (j >= RTE_DIM(algo_con))
+ return -EINVAL;
+
+ continue;
+ }
+
+ tmp = strstr(line, OP_STR);
+ if (tmp)
+ continue;
+
+ tmp = strstr(line, KEY_SIZE_STR);
+ if (tmp) {
+ tmp += strlen(KEY_SIZE_STR);
+ if (parser_read_uint32
+ (&info.interim_info.aes_data.key_len,
+ tmp) < 0)
+ return -EINVAL;
+
+ info.interim_info.aes_data.key_len /= 8;
+
+ continue;
+ }
+ }
+
+ info.parse_writeback = parse_test_aes_writeback;
+ info.callbacks = aes_tests_vectors;
+ info.interim_callbacks = aes_tests_interim_vectors;
+ info.writeback_callbacks = aes_writeback_callbacks;
+ info.kat_check = rsp_test_aes_check;
+
+ return 0;
+}
diff --git a/examples/fips_validation/fips_validation_ccm.c b/examples/fips_validation/fips_validation_ccm.c
new file mode 100644
index 00000000..632999c1
--- /dev/null
+++ b/examples/fips_validation/fips_validation_ccm.c
@@ -0,0 +1,272 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018 Intel Corporation
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#include <rte_string_fns.h>
+#include <rte_cryptodev.h>
+#include <rte_malloc.h>
+
+#include "fips_validation.h"
+
+#define DVPT_STR "CCM-DVPT"
+#define VADT_STR "CCM-VADT"
+#define VPT_STR "CCM-VPT"
+#define VNT_STR "CCM-VNT"
+#define VTT_STR "CCM-VTT"
+
+#define PARAM_PREFIX "["
+#define ALEN_PREFIX "Alen = "
+#define PLEN_PREFIX "Plen = "
+#define IVLEN_PREFIX "Nlen = "
+#define DIGESTL_PREFIX "Tlen = "
+
+#define COUNT_STR "Count = "
+#define KEY_STR "Key = "
+#define IV_STR "Nonce = "
+#define PT_STR "Payload = "
+#define CT_STR "CT = "
+#define AAD_STR "Adata = "
+#define POS_NEG_STR "Result = "
+
+#define POS_KEYWORD "Pass"
+#define NEG_KEYWORD "Fail"
+
+static int
+parser_dvpt_interim(const char *key, char *src, struct fips_val *val)
+{
+ char *tmp, c, value[10];
+ char num_pattern[] = "0123456789";
+ int i = 0;
+
+ memset(value, 0, 10);
+
+ tmp = strstr(src, key);
+ if (!tmp)
+ return -1;
+
+ tmp += strlen(key);
+
+ c = tmp[0];
+
+ while (strchr(num_pattern, c) && i < 10) {
+ value[i++] = c;
+ c = tmp[i];
+ }
+
+ return parser_read_uint32_val("", value, val);
+}
+
+static int
+parse_dvpt_ct_hex_str(const char *key, char *src, struct fips_val *val)
+{
+ int ret;
+
+ val->len = vec.pt.len;
+
+ ret = parse_uint8_known_len_hex_str(key, src, val);
+ if (ret < 0)
+ return ret;
+
+ src += strlen(key) + val->len * 2;
+
+ ret = parse_uint8_known_len_hex_str("", src, &vec.aead.digest);
+ if (ret < 0) {
+ rte_free(val->val);
+ memset(val, 0, sizeof(*val));
+ return ret;
+ }
+
+ return 0;
+}
+
+static int
+parse_uint8_ccm_aad_str(const char *key, char *src, struct fips_val *val)
+{
+ uint32_t len = val->len, j;
+
+ src += strlen(key);
+
+ /* CCM aad requires 18 bytes padding before the real content */
+ val->val = rte_zmalloc(NULL, len + 18, 0);
+ if (!val->val)
+ return -1;
+
+ for (j = 0; j < len; j++) {
+ char byte[3] = {src[j * 2], src[j * 2 + 1], '\0'};
+
+ if (parser_read_uint8_hex(&val->val[j + 18], byte) < 0) {
+ rte_free(val->val);
+ memset(val, 0, sizeof(*val));
+ return -EINVAL;
+ }
+ }
+
+ return 0;
+}
+
+struct fips_test_callback ccm_vnt_vec[] = {
+ {IV_STR, parse_uint8_known_len_hex_str, &vec.iv},
+ {AAD_STR, parse_uint8_ccm_aad_str, &vec.aead.aad},
+ {PT_STR, parse_uint8_known_len_hex_str, &vec.pt},
+ {NULL, NULL, NULL} /**< end pointer */
+};
+
+struct fips_test_callback ccm_vnt_interim_vec[] = {
+ {ALEN_PREFIX, parser_read_uint32_val, &vec.aead.aad},
+ {PLEN_PREFIX, parser_read_uint32_val, &vec.pt},
+ {DIGESTL_PREFIX, parser_read_uint32_val, &vec.aead.digest},
+ {IVLEN_PREFIX, parser_read_uint32_val, &vec.iv},
+ {KEY_STR, parse_uint8_hex_str, &vec.aead.key},
+ {NULL, NULL, NULL} /**< end pointer */
+};
+
+struct fips_test_callback ccm_vtt_vec[] = {
+ {AAD_STR, parse_uint8_ccm_aad_str, &vec.aead.aad},
+ {PT_STR, parse_uint8_known_len_hex_str, &vec.pt},
+ {NULL, NULL, NULL} /**< end pointer */
+};
+
+struct fips_test_callback ccm_vtt_interim_vec[] = {
+ {ALEN_PREFIX, parser_read_uint32_val, &vec.aead.aad},
+ {PLEN_PREFIX, parser_read_uint32_val, &vec.pt},
+ {IVLEN_PREFIX, parser_read_uint32_val, &vec.iv},
+ {DIGESTL_PREFIX, parser_read_uint32_val, &vec.aead.digest},
+ {KEY_STR, parse_uint8_hex_str, &vec.aead.key},
+ {IV_STR, parse_uint8_known_len_hex_str, &vec.iv},
+ {NULL, NULL, NULL} /**< end pointer */
+};
+
+struct fips_test_callback ccm_vadt_vec[] = {
+ {AAD_STR, parse_uint8_ccm_aad_str, &vec.aead.aad},
+ {PT_STR, parse_uint8_known_len_hex_str, &vec.pt},
+ {NULL, NULL, NULL} /**< end pointer */
+};
+
+struct fips_test_callback ccm_vadt_interim_vec[] = {
+ {PLEN_PREFIX, parser_read_uint32_val, &vec.pt},
+ {IVLEN_PREFIX, parser_read_uint32_val, &vec.iv},
+ {ALEN_PREFIX, parser_read_uint32_val, &vec.aead.aad},
+ {DIGESTL_PREFIX, parser_read_uint32_val, &vec.aead.digest},
+ {KEY_STR, parse_uint8_hex_str, &vec.aead.key},
+ {IV_STR, parse_uint8_known_len_hex_str, &vec.iv},
+ {NULL, NULL, NULL} /**< end pointer */
+};
+
+struct fips_test_callback ccm_vpt_vec[] = {
+ {AAD_STR, parse_uint8_ccm_aad_str, &vec.aead.aad},
+ {PT_STR, parse_uint8_known_len_hex_str, &vec.pt},
+ {NULL, NULL, NULL} /**< end pointer */
+};
+
+struct fips_test_callback ccm_vpt_interim_vec[] = {
+ {ALEN_PREFIX, parser_read_uint32_val, &vec.aead.aad},
+ {IVLEN_PREFIX, parser_read_uint32_val, &vec.iv},
+ {DIGESTL_PREFIX, parser_read_uint32_val, &vec.aead.digest},
+ {PLEN_PREFIX, parser_read_uint32_val, &vec.pt},
+ {KEY_STR, parse_uint8_hex_str, &vec.aead.key},
+ {IV_STR, parse_uint8_known_len_hex_str, &vec.iv},
+ {NULL, NULL, NULL} /**< end pointer */
+};
+
+struct fips_test_callback ccm_dvpt_vec[] = {
+ {IV_STR, parse_uint8_known_len_hex_str, &vec.iv},
+ {AAD_STR, parse_uint8_ccm_aad_str, &vec.aead.aad},
+ {CT_STR, parse_dvpt_ct_hex_str, &vec.ct},
+ {NULL, NULL, NULL} /**< end pointer */
+};
+
+struct fips_test_callback ccm_dvpt_interim_vec[] = {
+ {ALEN_PREFIX, parser_dvpt_interim, &vec.aead.aad},
+ {PLEN_PREFIX, parser_dvpt_interim, &vec.pt},
+ {IVLEN_PREFIX, parser_dvpt_interim, &vec.iv},
+ {DIGESTL_PREFIX, parser_dvpt_interim, &vec.aead.digest},
+ {KEY_STR, parse_uint8_hex_str, &vec.aead.key},
+ {NULL, NULL, NULL} /**< end pointer */
+};
+
+struct ccm_test_types {
+ const char *str;
+ uint32_t type;
+ const struct fips_test_callback *cb;
+ const struct fips_test_callback *cb_interim;
+ enum fips_test_op op;
+} ctt[] = {
+ {DVPT_STR, CCM_DVPT, ccm_dvpt_vec, ccm_dvpt_interim_vec,
+ FIPS_TEST_DEC_AUTH_VERIF},
+ {VPT_STR, CCM_VPT, ccm_vpt_vec, ccm_vpt_interim_vec,
+ FIPS_TEST_ENC_AUTH_GEN},
+ {VADT_STR, CCM_VADT, ccm_vadt_vec, ccm_vadt_interim_vec,
+ FIPS_TEST_ENC_AUTH_GEN},
+ {VNT_STR, CCM_VNT, ccm_vnt_vec, ccm_vnt_interim_vec,
+ FIPS_TEST_ENC_AUTH_GEN},
+ {VTT_STR, CCM_VTT, ccm_vtt_vec, ccm_vtt_interim_vec,
+ FIPS_TEST_ENC_AUTH_GEN},
+};
+
+static int
+parse_test_ccm_writeback(struct fips_val *val)
+{
+ struct fips_val tmp_val;
+
+ switch (info.interim_info.ccm_data.test_type) {
+ case CCM_DVPT:
+ fprintf(info.fp_wr, "%s", POS_NEG_STR);
+ if (vec.status == RTE_CRYPTO_OP_STATUS_SUCCESS) {
+ fprintf(info.fp_wr, "%s\n", POS_KEYWORD);
+ fprintf(info.fp_wr, "%s", PT_STR);
+
+ tmp_val.val = val->val;
+ tmp_val.len = vec.pt.len;
+
+ if (tmp_val.len == 0)
+ fprintf(info.fp_wr, "00\n");
+ else
+ parse_write_hex_str(&tmp_val);
+ } else
+ fprintf(info.fp_wr, "%s\n", NEG_KEYWORD);
+
+ break;
+
+ case CCM_VADT:
+ case CCM_VNT:
+ case CCM_VPT:
+ case CCM_VTT:
+ fprintf(info.fp_wr, "%s", CT_STR);
+
+ parse_write_hex_str(val);
+
+ break;
+
+ }
+
+ return 0;
+}
+
+int
+parse_test_ccm_init(void)
+{
+
+ uint32_t i;
+
+ for (i = 0; i < info.nb_vec_lines; i++) {
+ char *line = info.vec[i];
+ uint32_t j;
+
+ for (j = 0; j < RTE_DIM(ctt); j++)
+ if (strstr(line, ctt[j].str)) {
+ info.interim_info.ccm_data.test_type =
+ ctt[j].type;
+ info.callbacks = ctt[j].cb;
+ info.interim_callbacks = ctt[j].cb_interim;
+ info.op = ctt[j].op;
+ break;
+ }
+ }
+
+ info.parse_writeback = parse_test_ccm_writeback;
+
+ return 0;
+}
diff --git a/examples/fips_validation/fips_validation_cmac.c b/examples/fips_validation/fips_validation_cmac.c
new file mode 100644
index 00000000..54c951ef
--- /dev/null
+++ b/examples/fips_validation/fips_validation_cmac.c
@@ -0,0 +1,116 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018 Intel Corporation
+ */
+
+#include <string.h>
+#include <time.h>
+#include <stdio.h>
+#include <rte_string_fns.h>
+
+#include <rte_cryptodev.h>
+
+#include "fips_validation.h"
+
+#define NEW_LINE_STR "#"
+#define OP_STR "CMAC"
+
+#define ALGO_STR "Alg = "
+#define MODE_STR "Mode = "
+
+#define COUNT_STR "Count = "
+#define KLEN_STR "Klen = "
+#define PTLEN_STR "Mlen = "
+#define TAGLEN_STR "Tlen = "
+#define KEY_STR "Key = "
+#define PT_STR "Msg = "
+#define TAG_STR "Mac = "
+
+#define GEN_STR "Generate"
+#define VERIF_STR "Verify"
+
+#define POS_NEG_STR "Result = "
+#define PASS_STR "P"
+#define FAIL_STR "F"
+
+struct hash_algo_conversion {
+ const char *str;
+ enum fips_test_algorithms algo;
+} cmac_algo[] = {
+ {"AES", FIPS_TEST_ALGO_AES_CMAC},
+};
+
+static int
+parse_test_cmac_writeback(struct fips_val *val)
+{
+ if (info.op == FIPS_TEST_ENC_AUTH_GEN) {
+ struct fips_val tmp_val = {val->val + vec.pt.len,
+ vec.cipher_auth.digest.len};
+
+ fprintf(info.fp_wr, "%s", TAG_STR);
+ parse_write_hex_str(&tmp_val);
+ } else {
+ fprintf(info.fp_wr, "%s", POS_NEG_STR);
+
+ if (vec.status == RTE_CRYPTO_OP_STATUS_SUCCESS)
+ fprintf(info.fp_wr, "%s\n", PASS_STR);
+ else if (vec.status == RTE_CRYPTO_OP_STATUS_AUTH_FAILED)
+ fprintf(info.fp_wr, "%s\n", FAIL_STR);
+ else
+ fprintf(info.fp_wr, "Error\n");
+ }
+
+ return 0;
+}
+
+struct fips_test_callback cmac_tests_vectors[] = {
+ {KLEN_STR, parser_read_uint32_val, &vec.cipher_auth.key},
+ {PTLEN_STR, parser_read_uint32_val, &vec.pt},
+ {TAGLEN_STR, parser_read_uint32_val, &vec.cipher_auth.digest},
+ {KEY_STR, parse_uint8_hex_str, &vec.cipher_auth.key},
+ {PT_STR, parse_uint8_known_len_hex_str, &vec.pt},
+ {TAG_STR, parse_uint8_known_len_hex_str,
+ &vec.cipher_auth.digest},
+ {NULL, NULL, NULL} /**< end pointer */
+};
+
+int
+parse_test_cmac_init(void)
+{
+ char *tmp;
+ uint32_t i, j;
+
+ for (i = 0; i < info.nb_vec_lines; i++) {
+ char *line = info.vec[i];
+
+ tmp = strstr(line, ALGO_STR);
+ if (!tmp)
+ continue;
+
+ for (j = 0; j < RTE_DIM(cmac_algo); j++) {
+ if (!strstr(line, cmac_algo[j].str))
+ continue;
+
+ info.algo = cmac_algo[j].algo;
+ break;
+ }
+
+ if (j == RTE_DIM(cmac_algo))
+ return -EINVAL;
+
+ tmp = strstr(line, MODE_STR);
+ if (!tmp)
+ return -1;
+
+ if (strstr(tmp, GEN_STR))
+ info.op = FIPS_TEST_ENC_AUTH_GEN;
+ else if (strstr(tmp, VERIF_STR))
+ info.op = FIPS_TEST_DEC_AUTH_VERIF;
+ else
+ return -EINVAL;
+ }
+
+ info.parse_writeback = parse_test_cmac_writeback;
+ info.callbacks = cmac_tests_vectors;
+
+ return 0;
+}
diff --git a/examples/fips_validation/fips_validation_gcm.c b/examples/fips_validation/fips_validation_gcm.c
new file mode 100644
index 00000000..0509b101
--- /dev/null
+++ b/examples/fips_validation/fips_validation_gcm.c
@@ -0,0 +1,125 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018 Intel Corporation
+ */
+
+#include <string.h>
+#include <time.h>
+#include <stdio.h>
+
+#include <rte_cryptodev.h>
+
+#include "fips_validation.h"
+
+#define NEW_LINE_STR "#"
+#define OP_STR "GCM "
+
+#define PARAM_PREFIX "["
+#define KEYLEN_STR "Keylen = "
+#define IVLEN_STR "IVlen = "
+#define PTLEN_STR "PTlen = "
+#define AADLEN_STR "AADlen = "
+#define TAGLEN_STR "Taglen = "
+
+#define COUNT_STR "Count = "
+#define KEY_STR "Key = "
+#define IV_STR "IV = "
+#define PT_STR "PT = "
+#define CT_STR "CT = "
+#define TAG_STR "Tag = "
+#define AAD_STR "AAD = "
+
+#define OP_ENC_STR "Encrypt"
+#define OP_DEC_STR "Decrypt"
+
+#define NEG_TEST_STR "FAIL"
+
+struct fips_test_callback gcm_dec_vectors[] = {
+ {KEY_STR, parse_uint8_known_len_hex_str, &vec.cipher_auth.key},
+ {IV_STR, parse_uint8_known_len_hex_str, &vec.iv},
+ {CT_STR, parse_uint8_known_len_hex_str, &vec.ct},
+ {AAD_STR, parse_uint8_known_len_hex_str, &vec.cipher_auth.aad},
+ {TAG_STR, parse_uint8_known_len_hex_str,
+ &vec.cipher_auth.digest},
+ {NULL, NULL, NULL} /**< end pointer */
+};
+struct fips_test_callback gcm_interim_vectors[] = {
+ {KEYLEN_STR, parser_read_uint32_bit_val, &vec.cipher_auth.key},
+ {IVLEN_STR, parser_read_uint32_bit_val, &vec.iv},
+ {PTLEN_STR, parser_read_uint32_bit_val, &vec.pt},
+ {AADLEN_STR, parser_read_uint32_bit_val, &vec.cipher_auth.aad},
+ {TAGLEN_STR, parser_read_uint32_bit_val,
+ &vec.cipher_auth.digest},
+ {NULL, NULL, NULL} /**< end pointer */
+};
+
+struct fips_test_callback gcm_enc_vectors[] = {
+ {KEY_STR, parse_uint8_known_len_hex_str, &vec.cipher_auth.key},
+ {IV_STR, parse_uint8_known_len_hex_str, &vec.iv},
+ {PT_STR, parse_uint8_known_len_hex_str, &vec.pt},
+ {AAD_STR, parse_uint8_known_len_hex_str, &vec.cipher_auth.aad},
+ {NULL, NULL, NULL} /**< end pointer */
+};
+
+static int
+parse_test_gcm_writeback(struct fips_val *val)
+{
+ struct fips_val tmp_val;
+
+ if (info.op == FIPS_TEST_ENC_AUTH_GEN) {
+ fprintf(info.fp_wr, "%s", CT_STR);
+
+ tmp_val.val = val->val;
+ tmp_val.len = vec.pt.len;
+
+ parse_write_hex_str(&tmp_val);
+
+ fprintf(info.fp_wr, "%s", TAG_STR);
+
+ tmp_val.val = val->val + vec.pt.len;
+ tmp_val.len = val->len - vec.pt.len;
+
+ parse_write_hex_str(&tmp_val);
+ } else {
+ if (vec.status == RTE_CRYPTO_OP_STATUS_SUCCESS) {
+ fprintf(info.fp_wr, "%s", PT_STR);
+
+ tmp_val.val = val->val;
+ tmp_val.len = vec.pt.len;
+
+ parse_write_hex_str(&tmp_val);
+ } else
+ fprintf(info.fp_wr, "%s\n", NEG_TEST_STR);
+ }
+
+ return 0;
+}
+
+int
+parse_test_gcm_init(void)
+{
+ char *tmp;
+ uint32_t i;
+
+
+ for (i = 0; i < info.nb_vec_lines; i++) {
+ char *line = info.vec[i];
+
+
+ tmp = strstr(line, OP_STR);
+ if (tmp) {
+ if (strstr(line, OP_ENC_STR)) {
+ info.op = FIPS_TEST_ENC_AUTH_GEN;
+ info.callbacks = gcm_enc_vectors;
+ } else if (strstr(line, OP_DEC_STR)) {
+ info.op = FIPS_TEST_DEC_AUTH_VERIF;
+ info.callbacks = gcm_dec_vectors;
+ } else
+ return -EINVAL;
+ }
+ }
+
+ info.interim_callbacks = gcm_interim_vectors;
+ info.parse_writeback = parse_test_gcm_writeback;
+
+ return 0;
+}
diff --git a/examples/fips_validation/fips_validation_hmac.c b/examples/fips_validation/fips_validation_hmac.c
new file mode 100644
index 00000000..97ac7186
--- /dev/null
+++ b/examples/fips_validation/fips_validation_hmac.c
@@ -0,0 +1,105 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018 Intel Corporation
+ */
+
+#include <string.h>
+#include <time.h>
+#include <stdio.h>
+
+#include <rte_cryptodev.h>
+
+#include "fips_validation.h"
+
+#define ALGO_PREFIX "[L="
+#define KEYLEN_STR "Klen = "
+#define TAGLEN_STR "Tlen = "
+
+#define COUNT_STR "Count = "
+#define KEY_STR "Key = "
+#define PT_STR "Msg = "
+#define TAG_STR "Mac = "
+
+struct hash_size_conversion {
+ const char *str;
+ enum rte_crypto_auth_algorithm algo;
+} hsc[] = {
+ {"20", RTE_CRYPTO_AUTH_SHA1_HMAC},
+ {"28", RTE_CRYPTO_AUTH_SHA224_HMAC},
+ {"32", RTE_CRYPTO_AUTH_SHA256_HMAC},
+ {"48", RTE_CRYPTO_AUTH_SHA384_HMAC},
+ {"64", RTE_CRYPTO_AUTH_SHA512_HMAC},
+};
+
+static int
+parse_interim_algo(__attribute__((__unused__)) const char *key,
+ char *text,
+ __attribute__((__unused__)) struct fips_val *val)
+{
+
+ uint32_t i;
+
+ for (i = 0; i < RTE_DIM(hsc); i++) {
+ if (strstr(text, hsc[i].str)) {
+ info.interim_info.hmac_data.algo = hsc[i].algo;
+ break;
+ }
+ }
+
+ if (i == RTE_DIM(hsc))
+ return -1;
+
+ return 0;
+}
+
+struct fips_test_callback hmac_tests_vectors[] = {
+ {KEYLEN_STR, parser_read_uint32_val, &vec.cipher_auth.key},
+ {TAGLEN_STR, parser_read_uint32_val, &vec.cipher_auth.digest},
+ {KEY_STR, parse_uint8_hex_str, &vec.cipher_auth.key},
+ {PT_STR, parse_uint8_hex_str, &vec.pt},
+ {TAG_STR, parse_uint8_hex_str, &vec.cipher_auth.digest},
+ {NULL, NULL, NULL} /**< end pointer */
+};
+
+struct fips_test_callback hmac_tests_interim_vectors[] = {
+ {ALGO_PREFIX, parse_interim_algo, NULL},
+ {NULL, NULL, NULL} /**< end pointer */
+};
+
+static int
+parse_test_hmac_writeback(struct fips_val *val)
+{
+ struct fips_val val_local;
+
+ fprintf(info.fp_wr, "%s", TAG_STR);
+
+ val_local.val = val->val + vec.pt.len;
+ val_local.len = vec.cipher_auth.digest.len;
+
+ parse_write_hex_str(&val_local);
+ return 0;
+}
+
+static int
+rsp_test_hmac_check(struct fips_val *val)
+{
+ if (memcmp(val->val + vec.pt.len, vec.cipher_auth.digest.val,
+ vec.cipher_auth.digest.len) == 0)
+ fprintf(info.fp_wr, "Success\n");
+ else
+ fprintf(info.fp_wr, "Failed\n");
+
+ return 0;
+}
+
+int
+parse_test_hmac_init(void)
+{
+ info.op = FIPS_TEST_ENC_AUTH_GEN;
+ info.parse_writeback = parse_test_hmac_writeback;
+ info.callbacks = hmac_tests_vectors;
+ info.interim_callbacks = hmac_tests_interim_vectors;
+ info.writeback_callbacks = NULL;
+ info.kat_check = rsp_test_hmac_check;
+
+ return 0;
+}
diff --git a/examples/fips_validation/fips_validation_tdes.c b/examples/fips_validation/fips_validation_tdes.c
new file mode 100644
index 00000000..5064ff3b
--- /dev/null
+++ b/examples/fips_validation/fips_validation_tdes.c
@@ -0,0 +1,264 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018 Intel Corporation
+ */
+
+#include <string.h>
+#include <stdio.h>
+
+#include <rte_malloc.h>
+#include <rte_cryptodev.h>
+
+#include "fips_validation.h"
+
+#define NEW_LINE_STR "#"
+#define TEST_TYPE_KEY " for CBC"
+#define TEST_CBCI_KEY " for CBCI"
+
+#define ENC_STR "[ENCRYPT]"
+#define DEC_STR "[DECRYPT]"
+
+#define COUNT_STR "COUNT = "
+#define KEY1_STR "KEY1 = "
+#define KEY2_STR "KEY2 = "
+#define KEY3_STR "KEY3 = "
+
+#define KEYS_STR "KEYs = "
+#define IV_STR "IV = "
+#define PT_STR "PLAINTEXT = "
+#define CT_STR "CIPHERTEXT = "
+#define NK_STR "NumKeys = "
+
+#define SET_STR " = "
+
+#define PLAIN_TEXT 0
+#define CIPHER_TEXT 1
+#define KEY_TEXT 2
+#define IV_TEXT 3
+
+#define DEVICE_STR "# Config Info for : "
+
+struct {
+ uint32_t type;
+ const char *desc;
+} test_types[] = {
+ {TDES_INVERSE_PERMUTATION, "INVERSE PERMUTATION"},
+ {TDES_PERMUTATION, "PERMUTATION OPERATION"},
+ {TDES_SUBSTITUTION_TABLE, "SUBSTITUTION TABLE"},
+ {TDES_VARIABLE_KEY, "VARIABLE KEY"},
+ {TDES_VARIABLE_TEXT, "VARIABLE PLAINTEXT/CIPHERTEXT"},
+ {TDES_VARIABLE_TEXT, "KAT"},
+ {TDES_MCT, "Monte Carlo (Modes) Test"},
+ {TDES_MMT, "Multi block Message Test"},
+};
+
+static int
+writeback_tdes_hex_str(const char *key, char *dst, struct fips_val *val);
+
+static int
+parse_tdes_uint8_hex_str(const char *key, char *src, struct fips_val *val);
+
+static int
+parse_tdes_interim(const char *key,
+ __attribute__((__unused__)) char *text,
+ struct fips_val *val);
+
+struct fips_test_callback tdes_tests_vectors[] = {
+ {KEYS_STR, parse_tdes_uint8_hex_str, &vec.cipher_auth.key},
+ {KEY1_STR, parse_tdes_uint8_hex_str, &vec.cipher_auth.key},
+ {KEY2_STR, parse_tdes_uint8_hex_str, &vec.cipher_auth.key},
+ {KEY3_STR, parse_tdes_uint8_hex_str, &vec.cipher_auth.key},
+ {IV_STR, parse_uint8_hex_str, &vec.iv},
+ {PT_STR, parse_uint8_hex_str, &vec.pt},
+ {CT_STR, parse_uint8_hex_str, &vec.ct},
+ {NULL, NULL, NULL} /**< end pointer */
+};
+
+struct fips_test_callback tdes_tests_interim_vectors[] = {
+ {ENC_STR, parse_tdes_interim, NULL},
+ {DEC_STR, parse_tdes_interim, NULL},
+ {NULL, NULL, NULL} /**< end pointer */
+};
+
+struct fips_test_callback tdes_writeback_callbacks[] = {
+ /** First element is used to pass COUNT string */
+ {COUNT_STR, NULL, NULL},
+ {IV_STR, writeback_hex_str, &vec.iv},
+ {KEY1_STR, writeback_tdes_hex_str, &vec.cipher_auth.key},
+ {KEY2_STR, writeback_tdes_hex_str, &vec.cipher_auth.key},
+ {KEY3_STR, writeback_tdes_hex_str, &vec.cipher_auth.key},
+ {KEYS_STR, writeback_tdes_hex_str, &vec.cipher_auth.key},
+ {PT_STR, writeback_hex_str, &vec.pt},
+ {CT_STR, writeback_hex_str, &vec.ct},
+ {NULL, NULL, NULL} /**< end pointer */
+};
+
+static int
+parse_tdes_interim(const char *key,
+ __attribute__((__unused__)) char *text,
+ __attribute__((__unused__)) struct fips_val *val)
+{
+ if (strstr(key, ENC_STR))
+ info.op = FIPS_TEST_ENC_AUTH_GEN;
+ else if (strstr(key, DEC_STR))
+ info.op = FIPS_TEST_DEC_AUTH_VERIF;
+ else if (strstr(NK_STR, "NumKeys = 1"))
+ info.interim_info.tdes_data.nb_keys = 1;
+ else if (strstr(NK_STR, "NumKeys = 2"))
+ info.interim_info.tdes_data.nb_keys = 2;
+ else if (strstr(NK_STR, "NumKeys = 3"))
+ info.interim_info.tdes_data.nb_keys = 3;
+ else
+ return -EINVAL;
+
+ return 0;
+}
+
+static int
+parse_tdes_uint8_hex_str(const char *key, char *src, struct fips_val *val)
+{
+ uint8_t tmp_key[24] = {0};
+ uint32_t len, i;
+
+ src += strlen(key);
+
+ len = strlen(src) / 2;
+
+ if (val->val) {
+ memcpy(tmp_key, val->val, val->len);
+ rte_free(val->val);
+ }
+
+ val->val = rte_zmalloc(NULL, 24, 0);
+ if (!val->val)
+ return -1;
+
+ memcpy(val->val, tmp_key, 24);
+
+ if (strstr(key, KEYS_STR)) {
+ for (i = 0; i < len; i++) {
+ char byte[3] = {src[i * 2], src[i * 2 + 1], '\0'};
+
+ if (parser_read_uint8_hex(&val->val[i], byte) < 0)
+ goto error_exit;
+ }
+
+ memcpy(val->val + 8, val->val, 8);
+ memcpy(val->val + 16, val->val, 8);
+
+ } else if (strstr(key, KEY1_STR)) {
+ for (i = 0; i < len; i++) {
+ char byte[3] = {src[i * 2], src[i * 2 + 1], '\0'};
+
+ if (parser_read_uint8_hex(&val->val[i], byte) < 0)
+ goto error_exit;
+ }
+
+ if (info.interim_info.tdes_data.nb_keys == 2)
+ memcpy(val->val + 16, val->val, 8);
+
+ } else if (strstr(key, KEY2_STR)) {
+ for (i = 0; i < len; i++) {
+ char byte[3] = {src[i * 2], src[i * 2 + 1], '\0'};
+
+ if (parser_read_uint8_hex(&val->val[i + 8], byte) < 0)
+ goto error_exit;
+ }
+
+ } else if (strstr(key, KEY3_STR)) {
+ for (i = 0; i < len; i++) {
+ char byte[3] = {src[i * 2], src[i * 2 + 1], '\0'};
+
+ if (parser_read_uint8_hex(&val->val[i + 16], byte) < 0)
+ goto error_exit;
+ }
+ } else
+ return -EINVAL;
+
+ val->len = 24;
+
+ return 0;
+
+error_exit:
+ rte_free(val->val);
+ memset(val, 0, sizeof(*val));
+ return -EINVAL;
+}
+
+static int
+parse_test_tdes_writeback(struct fips_val *val)
+{
+
+ if (info.op == FIPS_TEST_ENC_AUTH_GEN)
+ fprintf(info.fp_wr, "%s", CT_STR);
+ else
+ fprintf(info.fp_wr, "%s", PT_STR);
+
+ parse_write_hex_str(val);
+
+ return 0;
+
+}
+
+static int
+writeback_tdes_hex_str(const char *key, char *dst, struct fips_val *val)
+{
+ struct fips_val tmp_val;
+
+ tmp_val.len = 8;
+
+ if (strstr(key, KEY1_STR))
+ tmp_val.val = val->val;
+ else if (strstr(key, KEY2_STR))
+ tmp_val.val = val->val + 8;
+ else if (strstr(key, KEY3_STR))
+ tmp_val.val = val->val + 16;
+
+ return writeback_hex_str(key, dst, &tmp_val);
+}
+
+static int
+rsp_test_tdes_check(struct fips_val *val)
+{
+ struct fips_val *data;
+
+ if (info.op == FIPS_TEST_ENC_AUTH_GEN)
+ data = &vec.ct;
+ else
+ data = &vec.pt;
+
+ if (memcmp(val->val, data->val, val->len) == 0)
+ fprintf(info.fp_wr, "Success\n");
+ else
+ fprintf(info.fp_wr, "Failed\n");
+
+ return 0;
+}
+
+int
+parse_test_tdes_init(void)
+{
+ uint32_t i;
+
+ for (i = 0; i < info.nb_vec_lines; i++) {
+ char *line = info.vec[i];
+ uint32_t j;
+
+ if (strstr(line, TEST_CBCI_KEY))
+ return -EPERM;
+
+ for (j = 0; j < RTE_DIM(test_types); j++)
+ if (strstr(line, test_types[j].desc)) {
+ info.interim_info.tdes_data.test_type =
+ test_types[j].type;
+ break;
+ }
+ }
+
+ info.parse_writeback = parse_test_tdes_writeback;
+ info.callbacks = tdes_tests_vectors;
+ info.interim_callbacks = tdes_tests_interim_vectors;
+ info.writeback_callbacks = tdes_writeback_callbacks;
+ info.kat_check = rsp_test_tdes_check;
+
+ return 0;
+}
diff --git a/examples/fips_validation/main.c b/examples/fips_validation/main.c
new file mode 100644
index 00000000..85f54cbf
--- /dev/null
+++ b/examples/fips_validation/main.c
@@ -0,0 +1,1225 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018 Intel Corporation
+ */
+
+#include <sys/stat.h>
+#include <getopt.h>
+#include <dirent.h>
+
+#include <rte_cryptodev.h>
+#include <rte_cryptodev_pmd.h>
+#include <rte_mempool.h>
+#include <rte_mbuf.h>
+#include <rte_string_fns.h>
+
+#include "fips_validation.h"
+
+#define REQ_FILE_PATH_KEYWORD "req-file"
+#define RSP_FILE_PATH_KEYWORD "rsp-file"
+#define FOLDER_KEYWORD "path-is-folder"
+#define CRYPTODEV_KEYWORD "cryptodev"
+#define CRYPTODEV_ID_KEYWORD "cryptodev-id"
+
+struct fips_test_vector vec;
+struct fips_test_interim_info info;
+
+struct cryptodev_fips_validate_env {
+ const char *req_path;
+ const char *rsp_path;
+ uint32_t is_path_folder;
+ uint32_t dev_id;
+ struct rte_mempool *mpool;
+ struct rte_mempool *op_pool;
+ struct rte_mbuf *mbuf;
+ struct rte_crypto_op *op;
+ struct rte_cryptodev_sym_session *sess;
+} env;
+
+static int
+cryptodev_fips_validate_app_int(void)
+{
+ struct rte_cryptodev_config conf = {rte_socket_id(), 1};
+ struct rte_cryptodev_qp_conf qp_conf = {128};
+ int ret;
+
+ ret = rte_cryptodev_configure(env.dev_id, &conf);
+ if (ret < 0)
+ return ret;
+
+ env.mpool = rte_pktmbuf_pool_create("FIPS_MEMPOOL", 128, 0, 0,
+ UINT16_MAX, rte_socket_id());
+ if (!env.mpool)
+ return ret;
+
+ ret = rte_cryptodev_queue_pair_setup(env.dev_id, 0, &qp_conf,
+ rte_socket_id(), env.mpool);
+ if (ret < 0)
+ return ret;
+
+ ret = -ENOMEM;
+
+ env.op_pool = rte_crypto_op_pool_create(
+ "FIPS_OP_POOL",
+ RTE_CRYPTO_OP_TYPE_SYMMETRIC,
+ 1, 0,
+ 16,
+ rte_socket_id());
+ if (!env.op_pool)
+ goto error_exit;
+
+ env.mbuf = rte_pktmbuf_alloc(env.mpool);
+ if (!env.mbuf)
+ goto error_exit;
+
+ env.op = rte_crypto_op_alloc(env.op_pool, RTE_CRYPTO_OP_TYPE_SYMMETRIC);
+ if (!env.op)
+ goto error_exit;
+
+ return 0;
+
+error_exit:
+ rte_mempool_free(env.mpool);
+ if (env.op_pool)
+ rte_mempool_free(env.op_pool);
+
+ return ret;
+}
+
+static void
+cryptodev_fips_validate_app_uninit(void)
+{
+ rte_pktmbuf_free(env.mbuf);
+ rte_crypto_op_free(env.op);
+ rte_cryptodev_sym_session_clear(env.dev_id, env.sess);
+ rte_cryptodev_sym_session_free(env.sess);
+ rte_mempool_free(env.mpool);
+ rte_mempool_free(env.op_pool);
+}
+
+static int
+fips_test_one_file(void);
+
+static int
+parse_cryptodev_arg(char *arg)
+{
+ int id = rte_cryptodev_get_dev_id(arg);
+
+ if (id < 0) {
+ RTE_LOG(ERR, USER1, "Error %i: invalid cryptodev name %s\n",
+ id, arg);
+ return id;
+ }
+
+ env.dev_id = (uint32_t)id;
+
+ return 0;
+}
+
+static int
+parse_cryptodev_id_arg(char *arg)
+{
+ uint32_t cryptodev_id;
+
+ if (parser_read_uint32(&cryptodev_id, arg) < 0) {
+ RTE_LOG(ERR, USER1, "Error %i: invalid cryptodev id %s\n",
+ -EINVAL, arg);
+ return -1;
+ }
+
+
+ if (!rte_cryptodev_pmd_is_valid_dev(cryptodev_id)) {
+ RTE_LOG(ERR, USER1, "Error %i: invalid cryptodev id %s\n",
+ cryptodev_id, arg);
+ return -1;
+ }
+
+ env.dev_id = (uint32_t)cryptodev_id;
+
+ return 0;
+}
+
+static void
+cryptodev_fips_validate_usage(const char *prgname)
+{
+ printf("%s [EAL options] --\n"
+ " --%s: REQUEST-FILE-PATH\n"
+ " --%s: RESPONSE-FILE-PATH\n"
+ " --%s: indicating both paths are folders\n"
+ " --%s: CRYPTODEV-NAME\n"
+ " --%s: CRYPTODEV-ID-NAME\n",
+ prgname, REQ_FILE_PATH_KEYWORD, RSP_FILE_PATH_KEYWORD,
+ FOLDER_KEYWORD, CRYPTODEV_KEYWORD, CRYPTODEV_ID_KEYWORD);
+}
+
+static int
+cryptodev_fips_validate_parse_args(int argc, char **argv)
+{
+ int opt, ret;
+ char *prgname = argv[0];
+ char **argvopt;
+ int option_index;
+ struct option lgopts[] = {
+ {REQ_FILE_PATH_KEYWORD, required_argument, 0, 0},
+ {RSP_FILE_PATH_KEYWORD, required_argument, 0, 0},
+ {FOLDER_KEYWORD, no_argument, 0, 0},
+ {CRYPTODEV_KEYWORD, required_argument, 0, 0},
+ {CRYPTODEV_ID_KEYWORD, required_argument, 0, 0},
+ {NULL, 0, 0, 0}
+ };
+
+ argvopt = argv;
+
+ while ((opt = getopt_long(argc, argvopt, "s:",
+ lgopts, &option_index)) != EOF) {
+
+ switch (opt) {
+ case 0:
+ if (strcmp(lgopts[option_index].name,
+ REQ_FILE_PATH_KEYWORD) == 0)
+ env.req_path = optarg;
+ else if (strcmp(lgopts[option_index].name,
+ RSP_FILE_PATH_KEYWORD) == 0)
+ env.rsp_path = optarg;
+ else if (strcmp(lgopts[option_index].name,
+ FOLDER_KEYWORD) == 0)
+ env.is_path_folder = 1;
+ else if (strcmp(lgopts[option_index].name,
+ CRYPTODEV_KEYWORD) == 0) {
+ ret = parse_cryptodev_arg(optarg);
+ if (ret < 0) {
+ cryptodev_fips_validate_usage(prgname);
+ return -EINVAL;
+ }
+ } else if (strcmp(lgopts[option_index].name,
+ CRYPTODEV_ID_KEYWORD) == 0) {
+ ret = parse_cryptodev_id_arg(optarg);
+ if (ret < 0) {
+ cryptodev_fips_validate_usage(prgname);
+ return -EINVAL;
+ }
+ } else {
+ cryptodev_fips_validate_usage(prgname);
+ return -EINVAL;
+ }
+ break;
+ default:
+ return -1;
+ }
+ }
+
+ if (env.req_path == NULL || env.rsp_path == NULL ||
+ env.dev_id == UINT32_MAX) {
+ cryptodev_fips_validate_usage(prgname);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+int
+main(int argc, char *argv[])
+{
+ int ret;
+
+ ret = rte_eal_init(argc, argv);
+ if (ret < 0) {
+ RTE_LOG(ERR, USER1, "Error %i: Failed init\n", ret);
+ return -1;
+ }
+
+ argc -= ret;
+ argv += ret;
+
+ ret = cryptodev_fips_validate_parse_args(argc, argv);
+ if (ret < 0)
+ rte_exit(EXIT_FAILURE, "Failed to parse arguments!\n");
+
+ ret = cryptodev_fips_validate_app_int();
+ if (ret < 0) {
+ RTE_LOG(ERR, USER1, "Error %i: Failed init\n", ret);
+ return -1;
+ }
+
+ if (!env.is_path_folder) {
+ printf("Processing file %s... ", env.req_path);
+
+ ret = fips_test_init(env.req_path, env.rsp_path,
+ rte_cryptodev_name_get(env.dev_id));
+ if (ret < 0) {
+ RTE_LOG(ERR, USER1, "Error %i: Failed test %s\n",
+ ret, env.req_path);
+ goto exit;
+ }
+
+
+ ret = fips_test_one_file();
+ if (ret < 0) {
+ RTE_LOG(ERR, USER1, "Error %i: Failed test %s\n",
+ ret, env.req_path);
+ goto exit;
+ }
+
+ printf("Done\n");
+
+ } else {
+ struct dirent *dir;
+ DIR *d_req, *d_rsp;
+ char req_path[1024];
+ char rsp_path[1024];
+
+ d_req = opendir(env.req_path);
+ if (!d_req) {
+ RTE_LOG(ERR, USER1, "Error %i: Path %s not exist\n",
+ -EINVAL, env.req_path);
+ goto exit;
+ }
+
+ d_rsp = opendir(env.rsp_path);
+ if (!d_rsp) {
+ ret = mkdir(env.rsp_path, 0700);
+ if (ret == 0)
+ d_rsp = opendir(env.rsp_path);
+ else {
+ RTE_LOG(ERR, USER1, "Error %i: Invalid %s\n",
+ -EINVAL, env.rsp_path);
+ goto exit;
+ }
+ }
+ closedir(d_rsp);
+
+ while ((dir = readdir(d_req)) != NULL) {
+ if (strstr(dir->d_name, "req") == NULL)
+ continue;
+
+ snprintf(req_path, 1023, "%s/%s", env.req_path,
+ dir->d_name);
+ snprintf(rsp_path, 1023, "%s/%s", env.rsp_path,
+ dir->d_name);
+ strlcpy(strstr(rsp_path, "req"), "rsp", 4);
+
+ printf("Processing file %s... ", req_path);
+
+ ret = fips_test_init(req_path, rsp_path,
+ rte_cryptodev_name_get(env.dev_id));
+ if (ret < 0) {
+ RTE_LOG(ERR, USER1, "Error %i: Failed test %s\n",
+ ret, req_path);
+ break;
+ }
+
+ ret = fips_test_one_file();
+ if (ret < 0) {
+ RTE_LOG(ERR, USER1, "Error %i: Failed test %s\n",
+ ret, req_path);
+ break;
+ }
+
+ printf("Done\n");
+ }
+
+ closedir(d_req);
+ }
+
+
+exit:
+ fips_test_clear();
+ cryptodev_fips_validate_app_uninit();
+
+ return ret;
+
+}
+
+#define IV_OFF (sizeof(struct rte_crypto_op) + sizeof(struct rte_crypto_sym_op))
+#define CRYPTODEV_FIPS_MAX_RETRIES 16
+
+typedef int (*fips_test_one_case_t)(void);
+typedef int (*fips_prepare_op_t)(void);
+typedef int (*fips_prepare_xform_t)(struct rte_crypto_sym_xform *);
+
+struct fips_test_ops {
+ fips_prepare_xform_t prepare_xform;
+ fips_prepare_op_t prepare_op;
+ fips_test_one_case_t test;
+} test_ops;
+
+static int
+prepare_cipher_op(void)
+{
+ struct rte_crypto_sym_op *sym = env.op->sym;
+ uint8_t *iv = rte_crypto_op_ctod_offset(env.op, uint8_t *, IV_OFF);
+
+ __rte_crypto_op_reset(env.op, RTE_CRYPTO_OP_TYPE_SYMMETRIC);
+ rte_pktmbuf_reset(env.mbuf);
+
+ sym->m_src = env.mbuf;
+ sym->cipher.data.offset = 0;
+
+ memcpy(iv, vec.iv.val, vec.iv.len);
+
+ if (info.op == FIPS_TEST_ENC_AUTH_GEN) {
+ uint8_t *pt;
+
+ if (vec.pt.len > RTE_MBUF_MAX_NB_SEGS) {
+ RTE_LOG(ERR, USER1, "PT len %u\n", vec.pt.len);
+ return -EPERM;
+ }
+
+ pt = (uint8_t *)rte_pktmbuf_append(env.mbuf, vec.pt.len);
+
+ if (!pt) {
+ RTE_LOG(ERR, USER1, "Error %i: MBUF too small\n",
+ -ENOMEM);
+ return -ENOMEM;
+ }
+
+ memcpy(pt, vec.pt.val, vec.pt.len);
+ sym->cipher.data.length = vec.pt.len;
+
+ } else {
+ uint8_t *ct;
+
+ if (vec.ct.len > RTE_MBUF_MAX_NB_SEGS) {
+ RTE_LOG(ERR, USER1, "CT len %u\n", vec.ct.len);
+ return -EPERM;
+ }
+
+ ct = (uint8_t *)rte_pktmbuf_append(env.mbuf, vec.ct.len);
+
+ if (!ct) {
+ RTE_LOG(ERR, USER1, "Error %i: MBUF too small\n",
+ -ENOMEM);
+ return -ENOMEM;
+ }
+
+ memcpy(ct, vec.ct.val, vec.ct.len);
+ sym->cipher.data.length = vec.ct.len;
+ }
+
+ rte_crypto_op_attach_sym_session(env.op, env.sess);
+
+ return 0;
+}
+
+static int
+prepare_auth_op(void)
+{
+ struct rte_crypto_sym_op *sym = env.op->sym;
+
+ __rte_crypto_op_reset(env.op, RTE_CRYPTO_OP_TYPE_SYMMETRIC);
+ rte_pktmbuf_reset(env.mbuf);
+
+ sym->m_src = env.mbuf;
+ sym->auth.data.offset = 0;
+
+ if (info.op == FIPS_TEST_ENC_AUTH_GEN) {
+ uint8_t *pt;
+
+ if (vec.pt.len > RTE_MBUF_MAX_NB_SEGS) {
+ RTE_LOG(ERR, USER1, "PT len %u\n", vec.pt.len);
+ return -EPERM;
+ }
+
+ pt = (uint8_t *)rte_pktmbuf_append(env.mbuf, vec.pt.len +
+ vec.cipher_auth.digest.len);
+
+ if (!pt) {
+ RTE_LOG(ERR, USER1, "Error %i: MBUF too small\n",
+ -ENOMEM);
+ return -ENOMEM;
+ }
+
+ memcpy(pt, vec.pt.val, vec.pt.len);
+ sym->auth.data.length = vec.pt.len;
+ sym->auth.digest.data = pt + vec.pt.len;
+ sym->auth.digest.phys_addr = rte_pktmbuf_mtophys_offset(
+ env.mbuf, vec.pt.len);
+
+ } else {
+ uint8_t *ct;
+
+ if (vec.ct.len > RTE_MBUF_MAX_NB_SEGS) {
+ RTE_LOG(ERR, USER1, "CT len %u\n", vec.ct.len);
+ return -EPERM;
+ }
+
+ ct = (uint8_t *)rte_pktmbuf_append(env.mbuf,
+ vec.ct.len + vec.cipher_auth.digest.len);
+
+ if (!ct) {
+ RTE_LOG(ERR, USER1, "Error %i: MBUF too small\n",
+ -ENOMEM);
+ return -ENOMEM;
+ }
+
+ memcpy(ct, vec.ct.val, vec.ct.len);
+ sym->auth.data.length = vec.ct.len;
+ sym->auth.digest.data = vec.cipher_auth.digest.val;
+ sym->auth.digest.phys_addr = rte_malloc_virt2iova(
+ sym->auth.digest.data);
+ }
+
+ rte_crypto_op_attach_sym_session(env.op, env.sess);
+
+ return 0;
+}
+
+static int
+prepare_aead_op(void)
+{
+ struct rte_crypto_sym_op *sym = env.op->sym;
+ uint8_t *iv = rte_crypto_op_ctod_offset(env.op, uint8_t *, IV_OFF);
+
+ __rte_crypto_op_reset(env.op, RTE_CRYPTO_OP_TYPE_SYMMETRIC);
+ rte_pktmbuf_reset(env.mbuf);
+
+ if (info.algo == FIPS_TEST_ALGO_AES_CCM)
+ memcpy(iv + 1, vec.iv.val, vec.iv.len);
+ else
+ memcpy(iv, vec.iv.val, vec.iv.len);
+
+ sym->m_src = env.mbuf;
+ sym->aead.data.offset = 0;
+ sym->aead.aad.data = vec.aead.aad.val;
+ sym->aead.aad.phys_addr = rte_malloc_virt2iova(sym->aead.aad.data);
+
+ if (info.op == FIPS_TEST_ENC_AUTH_GEN) {
+ uint8_t *pt;
+
+ if (vec.pt.len > RTE_MBUF_MAX_NB_SEGS) {
+ RTE_LOG(ERR, USER1, "PT len %u\n", vec.pt.len);
+ return -EPERM;
+ }
+
+ pt = (uint8_t *)rte_pktmbuf_append(env.mbuf,
+ vec.pt.len + vec.aead.digest.len);
+
+ if (!pt) {
+ RTE_LOG(ERR, USER1, "Error %i: MBUF too small\n",
+ -ENOMEM);
+ return -ENOMEM;
+ }
+
+ memcpy(pt, vec.pt.val, vec.pt.len);
+ sym->aead.data.length = vec.pt.len;
+ sym->aead.digest.data = pt + vec.pt.len;
+ sym->aead.digest.phys_addr = rte_pktmbuf_mtophys_offset(
+ env.mbuf, vec.pt.len);
+ } else {
+ uint8_t *ct;
+
+ if (vec.ct.len > RTE_MBUF_MAX_NB_SEGS) {
+ RTE_LOG(ERR, USER1, "CT len %u\n", vec.ct.len);
+ return -EPERM;
+ }
+
+ ct = (uint8_t *)rte_pktmbuf_append(env.mbuf, vec.ct.len);
+
+ if (!ct) {
+ RTE_LOG(ERR, USER1, "Error %i: MBUF too small\n",
+ -ENOMEM);
+ return -ENOMEM;
+ }
+
+ memcpy(ct, vec.ct.val, vec.ct.len);
+ sym->aead.data.length = vec.ct.len;
+ sym->aead.digest.data = vec.aead.digest.val;
+ sym->aead.digest.phys_addr = rte_malloc_virt2iova(
+ sym->aead.digest.data);
+ }
+
+ rte_crypto_op_attach_sym_session(env.op, env.sess);
+
+ return 0;
+}
+
+static int
+prepare_aes_xform(struct rte_crypto_sym_xform *xform)
+{
+ const struct rte_cryptodev_symmetric_capability *cap;
+ struct rte_cryptodev_sym_capability_idx cap_idx;
+ struct rte_crypto_cipher_xform *cipher_xform = &xform->cipher;
+
+ xform->type = RTE_CRYPTO_SYM_XFORM_CIPHER;
+
+ cipher_xform->algo = RTE_CRYPTO_CIPHER_AES_CBC;
+ cipher_xform->op = (info.op == FIPS_TEST_ENC_AUTH_GEN) ?
+ RTE_CRYPTO_CIPHER_OP_ENCRYPT :
+ RTE_CRYPTO_CIPHER_OP_DECRYPT;
+ cipher_xform->key.data = vec.cipher_auth.key.val;
+ cipher_xform->key.length = vec.cipher_auth.key.len;
+ cipher_xform->iv.length = vec.iv.len;
+ cipher_xform->iv.offset = IV_OFF;
+
+ cap_idx.algo.cipher = RTE_CRYPTO_CIPHER_AES_CBC;
+ cap_idx.type = RTE_CRYPTO_SYM_XFORM_CIPHER;
+
+ cap = rte_cryptodev_sym_capability_get(env.dev_id, &cap_idx);
+ if (!cap) {
+ RTE_LOG(ERR, USER1, "Failed to get capability for cdev %u\n",
+ env.dev_id);
+ return -EINVAL;
+ }
+
+ if (rte_cryptodev_sym_capability_check_cipher(cap,
+ cipher_xform->key.length,
+ cipher_xform->iv.length) != 0) {
+ RTE_LOG(ERR, USER1, "PMD %s key length %u IV length %u\n",
+ info.device_name, cipher_xform->key.length,
+ cipher_xform->iv.length);
+ return -EPERM;
+ }
+
+ return 0;
+}
+
+static int
+prepare_tdes_xform(struct rte_crypto_sym_xform *xform)
+{
+ const struct rte_cryptodev_symmetric_capability *cap;
+ struct rte_cryptodev_sym_capability_idx cap_idx;
+ struct rte_crypto_cipher_xform *cipher_xform = &xform->cipher;
+
+ xform->type = RTE_CRYPTO_SYM_XFORM_CIPHER;
+
+ cipher_xform->algo = RTE_CRYPTO_CIPHER_3DES_CBC;
+ cipher_xform->op = (info.op == FIPS_TEST_ENC_AUTH_GEN) ?
+ RTE_CRYPTO_CIPHER_OP_ENCRYPT :
+ RTE_CRYPTO_CIPHER_OP_DECRYPT;
+ cipher_xform->key.data = vec.cipher_auth.key.val;
+ cipher_xform->key.length = vec.cipher_auth.key.len;
+ cipher_xform->iv.length = vec.iv.len;
+ cipher_xform->iv.offset = IV_OFF;
+
+ cap_idx.algo.cipher = RTE_CRYPTO_CIPHER_3DES_CBC;
+ cap_idx.type = RTE_CRYPTO_SYM_XFORM_CIPHER;
+
+ cap = rte_cryptodev_sym_capability_get(env.dev_id, &cap_idx);
+ if (!cap) {
+ RTE_LOG(ERR, USER1, "Failed to get capability for cdev %u\n",
+ env.dev_id);
+ return -EINVAL;
+ }
+
+ if (rte_cryptodev_sym_capability_check_cipher(cap,
+ cipher_xform->key.length,
+ cipher_xform->iv.length) != 0) {
+ RTE_LOG(ERR, USER1, "PMD %s key length %u IV length %u\n",
+ info.device_name, cipher_xform->key.length,
+ cipher_xform->iv.length);
+ return -EPERM;
+ }
+
+ return 0;
+}
+
+static int
+prepare_hmac_xform(struct rte_crypto_sym_xform *xform)
+{
+ const struct rte_cryptodev_symmetric_capability *cap;
+ struct rte_cryptodev_sym_capability_idx cap_idx;
+ struct rte_crypto_auth_xform *auth_xform = &xform->auth;
+
+ xform->type = RTE_CRYPTO_SYM_XFORM_AUTH;
+
+ auth_xform->algo = info.interim_info.hmac_data.algo;
+ auth_xform->op = RTE_CRYPTO_AUTH_OP_GENERATE;
+ auth_xform->digest_length = vec.cipher_auth.digest.len;
+ auth_xform->key.data = vec.cipher_auth.key.val;
+ auth_xform->key.length = vec.cipher_auth.key.len;
+
+ cap_idx.algo.auth = auth_xform->algo;
+ cap_idx.type = RTE_CRYPTO_SYM_XFORM_AUTH;
+
+ cap = rte_cryptodev_sym_capability_get(env.dev_id, &cap_idx);
+ if (!cap) {
+ RTE_LOG(ERR, USER1, "Failed to get capability for cdev %u\n",
+ env.dev_id);
+ return -EINVAL;
+ }
+
+ if (rte_cryptodev_sym_capability_check_auth(cap,
+ auth_xform->key.length,
+ auth_xform->digest_length, 0) != 0) {
+ RTE_LOG(ERR, USER1, "PMD %s key length %u IV length %u\n",
+ info.device_name, auth_xform->key.length,
+ auth_xform->digest_length);
+ return -EPERM;
+ }
+
+ return 0;
+}
+
+static int
+prepare_gcm_xform(struct rte_crypto_sym_xform *xform)
+{
+ const struct rte_cryptodev_symmetric_capability *cap;
+ struct rte_cryptodev_sym_capability_idx cap_idx;
+ struct rte_crypto_aead_xform *aead_xform = &xform->aead;
+
+ xform->type = RTE_CRYPTO_SYM_XFORM_AEAD;
+
+ aead_xform->algo = RTE_CRYPTO_AEAD_AES_GCM;
+ aead_xform->aad_length = vec.aead.aad.len;
+ aead_xform->digest_length = vec.aead.digest.len;
+ aead_xform->iv.offset = IV_OFF;
+ aead_xform->iv.length = vec.iv.len;
+ aead_xform->key.data = vec.aead.key.val;
+ aead_xform->key.length = vec.aead.key.len;
+ aead_xform->op = (info.op == FIPS_TEST_ENC_AUTH_GEN) ?
+ RTE_CRYPTO_AEAD_OP_ENCRYPT :
+ RTE_CRYPTO_AEAD_OP_DECRYPT;
+
+ cap_idx.algo.aead = aead_xform->algo;
+ cap_idx.type = RTE_CRYPTO_SYM_XFORM_AEAD;
+
+ cap = rte_cryptodev_sym_capability_get(env.dev_id, &cap_idx);
+ if (!cap) {
+ RTE_LOG(ERR, USER1, "Failed to get capability for cdev %u\n",
+ env.dev_id);
+ return -EINVAL;
+ }
+
+ if (rte_cryptodev_sym_capability_check_aead(cap,
+ aead_xform->key.length,
+ aead_xform->digest_length, aead_xform->aad_length,
+ aead_xform->iv.length) != 0) {
+ RTE_LOG(ERR, USER1,
+ "PMD %s key_len %u tag_len %u aad_len %u iv_len %u\n",
+ info.device_name, aead_xform->key.length,
+ aead_xform->digest_length,
+ aead_xform->aad_length,
+ aead_xform->iv.length);
+ return -EPERM;
+ }
+
+ return 0;
+}
+
+static int
+prepare_cmac_xform(struct rte_crypto_sym_xform *xform)
+{
+ const struct rte_cryptodev_symmetric_capability *cap;
+ struct rte_cryptodev_sym_capability_idx cap_idx;
+ struct rte_crypto_auth_xform *auth_xform = &xform->auth;
+
+ xform->type = RTE_CRYPTO_SYM_XFORM_AUTH;
+
+ auth_xform->algo = RTE_CRYPTO_AUTH_AES_CMAC;
+ auth_xform->op = (info.op == FIPS_TEST_ENC_AUTH_GEN) ?
+ RTE_CRYPTO_AUTH_OP_GENERATE : RTE_CRYPTO_AUTH_OP_VERIFY;
+ auth_xform->digest_length = vec.cipher_auth.digest.len;
+ auth_xform->key.data = vec.cipher_auth.key.val;
+ auth_xform->key.length = vec.cipher_auth.key.len;
+
+ cap_idx.algo.auth = auth_xform->algo;
+ cap_idx.type = RTE_CRYPTO_SYM_XFORM_AUTH;
+
+ cap = rte_cryptodev_sym_capability_get(env.dev_id, &cap_idx);
+ if (!cap) {
+ RTE_LOG(ERR, USER1, "Failed to get capability for cdev %u\n",
+ env.dev_id);
+ return -EINVAL;
+ }
+
+ if (rte_cryptodev_sym_capability_check_auth(cap,
+ auth_xform->key.length,
+ auth_xform->digest_length, 0) != 0) {
+ RTE_LOG(ERR, USER1, "PMD %s key length %u IV length %u\n",
+ info.device_name, auth_xform->key.length,
+ auth_xform->digest_length);
+ return -EPERM;
+ }
+
+ return 0;
+}
+
+static int
+prepare_ccm_xform(struct rte_crypto_sym_xform *xform)
+{
+ const struct rte_cryptodev_symmetric_capability *cap;
+ struct rte_cryptodev_sym_capability_idx cap_idx;
+ struct rte_crypto_aead_xform *aead_xform = &xform->aead;
+
+ xform->type = RTE_CRYPTO_SYM_XFORM_AEAD;
+
+ aead_xform->algo = RTE_CRYPTO_AEAD_AES_CCM;
+ aead_xform->aad_length = vec.aead.aad.len;
+ aead_xform->digest_length = vec.aead.digest.len;
+ aead_xform->iv.offset = IV_OFF;
+ aead_xform->iv.length = vec.iv.len;
+ aead_xform->key.data = vec.aead.key.val;
+ aead_xform->key.length = vec.aead.key.len;
+ aead_xform->op = (info.op == FIPS_TEST_ENC_AUTH_GEN) ?
+ RTE_CRYPTO_AEAD_OP_ENCRYPT :
+ RTE_CRYPTO_AEAD_OP_DECRYPT;
+
+ cap_idx.algo.aead = aead_xform->algo;
+ cap_idx.type = RTE_CRYPTO_SYM_XFORM_AEAD;
+
+ cap = rte_cryptodev_sym_capability_get(env.dev_id, &cap_idx);
+ if (!cap) {
+ RTE_LOG(ERR, USER1, "Failed to get capability for cdev %u\n",
+ env.dev_id);
+ return -EINVAL;
+ }
+
+ if (rte_cryptodev_sym_capability_check_aead(cap,
+ aead_xform->key.length,
+ aead_xform->digest_length, aead_xform->aad_length,
+ aead_xform->iv.length) != 0) {
+ RTE_LOG(ERR, USER1,
+ "PMD %s key_len %u tag_len %u aad_len %u iv_len %u\n",
+ info.device_name, aead_xform->key.length,
+ aead_xform->digest_length,
+ aead_xform->aad_length,
+ aead_xform->iv.length);
+ return -EPERM;
+ }
+
+ return 0;
+}
+
+static void
+get_writeback_data(struct fips_val *val)
+{
+ val->val = rte_pktmbuf_mtod(env.mbuf, uint8_t *);
+ val->len = rte_pktmbuf_pkt_len(env.mbuf);
+}
+
+static int
+fips_run_test(void)
+{
+ struct rte_crypto_sym_xform xform = {0};
+ uint16_t n_deqd;
+ int ret;
+
+ ret = test_ops.prepare_xform(&xform);
+ if (ret < 0)
+ return ret;
+
+ env.sess = rte_cryptodev_sym_session_create(env.mpool);
+ if (!env.sess)
+ return -ENOMEM;
+
+ ret = rte_cryptodev_sym_session_init(env.dev_id,
+ env.sess, &xform, env.mpool);
+ if (ret < 0) {
+ RTE_LOG(ERR, USER1, "Error %i: Init session\n",
+ ret);
+ return ret;
+ }
+
+ ret = test_ops.prepare_op();
+ if (ret < 0) {
+ RTE_LOG(ERR, USER1, "Error %i: Prepare op\n",
+ ret);
+ return ret;
+ }
+
+ if (rte_cryptodev_enqueue_burst(env.dev_id, 0, &env.op, 1) < 1) {
+ RTE_LOG(ERR, USER1, "Error: Failed enqueue\n");
+ return ret;
+ }
+
+ do {
+ struct rte_crypto_op *deqd_op;
+
+ n_deqd = rte_cryptodev_dequeue_burst(env.dev_id, 0, &deqd_op,
+ 1);
+ } while (n_deqd == 0);
+
+ vec.status = env.op->status;
+
+ rte_cryptodev_sym_session_clear(env.dev_id, env.sess);
+ rte_cryptodev_sym_session_free(env.sess);
+ env.sess = NULL;
+
+ return ret;
+}
+
+static int
+fips_generic_test(void)
+{
+ struct fips_val val;
+ int ret;
+
+ fips_test_write_one_case();
+
+ ret = fips_run_test();
+ if (ret < 0) {
+ if (ret == -EPERM) {
+ fprintf(info.fp_wr, "Bypass\n\n");
+ return 0;
+ }
+
+ return ret;
+ }
+
+ get_writeback_data(&val);
+
+ switch (info.file_type) {
+ case FIPS_TYPE_REQ:
+ case FIPS_TYPE_RSP:
+ if (info.parse_writeback == NULL)
+ return -EPERM;
+ ret = info.parse_writeback(&val);
+ if (ret < 0)
+ return ret;
+ break;
+ case FIPS_TYPE_FAX:
+ if (info.kat_check == NULL)
+ return -EPERM;
+ ret = info.kat_check(&val);
+ if (ret < 0)
+ return ret;
+ break;
+ }
+
+ fprintf(info.fp_wr, "\n");
+
+ return 0;
+}
+
+static int
+fips_mct_tdes_test(void)
+{
+#define TDES_BLOCK_SIZE 8
+#define TDES_EXTERN_ITER 400
+#define TDES_INTERN_ITER 10000
+ struct fips_val val, val_key;
+ uint8_t prev_out[TDES_BLOCK_SIZE];
+ uint8_t prev_prev_out[TDES_BLOCK_SIZE];
+ uint8_t prev_in[TDES_BLOCK_SIZE];
+ uint32_t i, j, k;
+ int ret;
+
+ for (i = 0; i < TDES_EXTERN_ITER; i++) {
+ if (i != 0)
+ update_info_vec(i);
+
+ fips_test_write_one_case();
+
+ for (j = 0; j < TDES_INTERN_ITER; j++) {
+ ret = fips_run_test();
+ if (ret < 0) {
+ if (ret == -EPERM) {
+ fprintf(info.fp_wr, "Bypass\n");
+ return 0;
+ }
+
+ return ret;
+ }
+
+ get_writeback_data(&val);
+
+ if (info.op == FIPS_TEST_DEC_AUTH_VERIF)
+ memcpy(prev_in, vec.ct.val, TDES_BLOCK_SIZE);
+
+ if (j == 0) {
+ memcpy(prev_out, val.val, TDES_BLOCK_SIZE);
+
+ if (info.op == FIPS_TEST_ENC_AUTH_GEN) {
+ memcpy(vec.pt.val, vec.iv.val,
+ TDES_BLOCK_SIZE);
+ memcpy(vec.iv.val, val.val,
+ TDES_BLOCK_SIZE);
+ } else {
+ memcpy(vec.iv.val, vec.ct.val,
+ TDES_BLOCK_SIZE);
+ memcpy(vec.ct.val, val.val,
+ TDES_BLOCK_SIZE);
+ }
+ continue;
+ }
+
+ if (info.op == FIPS_TEST_ENC_AUTH_GEN) {
+ memcpy(vec.iv.val, val.val, TDES_BLOCK_SIZE);
+ memcpy(vec.pt.val, prev_out, TDES_BLOCK_SIZE);
+ } else {
+ memcpy(vec.iv.val, vec.ct.val, TDES_BLOCK_SIZE);
+ memcpy(vec.ct.val, val.val, TDES_BLOCK_SIZE);
+ }
+
+ if (j == TDES_INTERN_ITER - 1)
+ continue;
+
+ memcpy(prev_out, val.val, TDES_BLOCK_SIZE);
+
+ if (j == TDES_INTERN_ITER - 3)
+ memcpy(prev_prev_out, val.val, TDES_BLOCK_SIZE);
+ }
+
+ info.parse_writeback(&val);
+ fprintf(info.fp_wr, "\n");
+
+ if (i == TDES_EXTERN_ITER - 1)
+ continue;
+
+ /** update key */
+ memcpy(&val_key, &vec.cipher_auth.key, sizeof(val_key));
+
+ if (info.interim_info.tdes_data.nb_keys == 0) {
+ if (memcmp(val_key.val, val_key.val + 8, 8) == 0)
+ info.interim_info.tdes_data.nb_keys = 1;
+ else if (memcmp(val_key.val, val_key.val + 16, 8) == 0)
+ info.interim_info.tdes_data.nb_keys = 2;
+ else
+ info.interim_info.tdes_data.nb_keys = 3;
+
+ }
+
+ for (k = 0; k < TDES_BLOCK_SIZE; k++) {
+
+ switch (info.interim_info.tdes_data.nb_keys) {
+ case 3:
+ val_key.val[k] ^= val.val[k];
+ val_key.val[k + 8] ^= prev_out[k];
+ val_key.val[k + 16] ^= prev_prev_out[k];
+ break;
+ case 2:
+ val_key.val[k] ^= val.val[k];
+ val_key.val[k + 8] ^= prev_out[k];
+ val_key.val[k + 16] ^= val.val[k];
+ break;
+ default: /* case 1 */
+ val_key.val[k] ^= val.val[k];
+ val_key.val[k + 8] ^= val.val[k];
+ val_key.val[k + 16] ^= val.val[k];
+ break;
+ }
+
+ }
+
+ for (k = 0; k < 24; k++)
+ val_key.val[k] = (__builtin_popcount(val_key.val[k]) &
+ 0x1) ?
+ val_key.val[k] : (val_key.val[k] ^ 0x1);
+
+ if (info.op == FIPS_TEST_ENC_AUTH_GEN) {
+ memcpy(vec.iv.val, val.val, TDES_BLOCK_SIZE);
+ memcpy(vec.pt.val, prev_out, TDES_BLOCK_SIZE);
+ } else {
+ memcpy(vec.iv.val, prev_out, TDES_BLOCK_SIZE);
+ memcpy(vec.ct.val, val.val, TDES_BLOCK_SIZE);
+ }
+ }
+
+ return 0;
+}
+
+static int
+fips_mct_aes_test(void)
+{
+#define AES_BLOCK_SIZE 16
+#define AES_EXTERN_ITER 100
+#define AES_INTERN_ITER 1000
+ struct fips_val val, val_key;
+ uint8_t prev_out[AES_BLOCK_SIZE] = {0};
+ uint8_t prev_in[AES_BLOCK_SIZE] = {0};
+ uint32_t i, j, k;
+ int ret;
+
+ for (i = 0; i < AES_EXTERN_ITER; i++) {
+ if (i != 0)
+ update_info_vec(i);
+
+ fips_test_write_one_case();
+
+ for (j = 0; j < AES_INTERN_ITER; j++) {
+ ret = fips_run_test();
+ if (ret < 0) {
+ if (ret == -EPERM) {
+ fprintf(info.fp_wr, "Bypass\n");
+ return 0;
+ }
+
+ return ret;
+ }
+
+ get_writeback_data(&val);
+
+ if (info.op == FIPS_TEST_DEC_AUTH_VERIF)
+ memcpy(prev_in, vec.ct.val, AES_BLOCK_SIZE);
+
+ if (j == 0) {
+ memcpy(prev_out, val.val, AES_BLOCK_SIZE);
+
+ if (info.op == FIPS_TEST_ENC_AUTH_GEN) {
+ memcpy(vec.pt.val, vec.iv.val,
+ AES_BLOCK_SIZE);
+ memcpy(vec.iv.val, val.val,
+ AES_BLOCK_SIZE);
+ } else {
+ memcpy(vec.ct.val, vec.iv.val,
+ AES_BLOCK_SIZE);
+ memcpy(vec.iv.val, prev_in,
+ AES_BLOCK_SIZE);
+ }
+ continue;
+ }
+
+ if (info.op == FIPS_TEST_ENC_AUTH_GEN) {
+ memcpy(vec.iv.val, val.val, AES_BLOCK_SIZE);
+ memcpy(vec.pt.val, prev_out, AES_BLOCK_SIZE);
+ } else {
+ memcpy(vec.iv.val, prev_in, AES_BLOCK_SIZE);
+ memcpy(vec.ct.val, prev_out, AES_BLOCK_SIZE);
+ }
+
+ if (j == AES_INTERN_ITER - 1)
+ continue;
+
+ memcpy(prev_out, val.val, AES_BLOCK_SIZE);
+ }
+
+ info.parse_writeback(&val);
+ fprintf(info.fp_wr, "\n");
+
+ if (i == AES_EXTERN_ITER - 1)
+ continue;
+
+ /** update key */
+ memcpy(&val_key, &vec.cipher_auth.key, sizeof(val_key));
+ for (k = 0; k < vec.cipher_auth.key.len; k++) {
+ switch (vec.cipher_auth.key.len) {
+ case 16:
+ val_key.val[k] ^= val.val[k];
+ break;
+ case 24:
+ if (k < 8)
+ val_key.val[k] ^= prev_out[k + 8];
+ else
+ val_key.val[k] ^= val.val[k - 8];
+ break;
+ case 32:
+ if (k < 16)
+ val_key.val[k] ^= prev_out[k];
+ else
+ val_key.val[k] ^= val.val[k - 16];
+ break;
+ default:
+ return -1;
+ }
+ }
+
+ if (info.op == FIPS_TEST_DEC_AUTH_VERIF)
+ memcpy(vec.iv.val, val.val, AES_BLOCK_SIZE);
+ }
+
+ return 0;
+}
+
+static int
+init_test_ops(void)
+{
+ switch (info.algo) {
+ case FIPS_TEST_ALGO_AES:
+ test_ops.prepare_op = prepare_cipher_op;
+ test_ops.prepare_xform = prepare_aes_xform;
+ if (info.interim_info.aes_data.test_type == AESAVS_TYPE_MCT)
+ test_ops.test = fips_mct_aes_test;
+ else
+ test_ops.test = fips_generic_test;
+ break;
+ case FIPS_TEST_ALGO_HMAC:
+ test_ops.prepare_op = prepare_auth_op;
+ test_ops.prepare_xform = prepare_hmac_xform;
+ test_ops.test = fips_generic_test;
+ break;
+ case FIPS_TEST_ALGO_TDES:
+ test_ops.prepare_op = prepare_cipher_op;
+ test_ops.prepare_xform = prepare_tdes_xform;
+ if (info.interim_info.tdes_data.test_type == TDES_MCT)
+ test_ops.test = fips_mct_tdes_test;
+ else
+ test_ops.test = fips_generic_test;
+ break;
+ case FIPS_TEST_ALGO_AES_GCM:
+ test_ops.prepare_op = prepare_aead_op;
+ test_ops.prepare_xform = prepare_gcm_xform;
+ test_ops.test = fips_generic_test;
+ break;
+ case FIPS_TEST_ALGO_AES_CMAC:
+ test_ops.prepare_op = prepare_auth_op;
+ test_ops.prepare_xform = prepare_cmac_xform;
+ test_ops.test = fips_generic_test;
+ break;
+ case FIPS_TEST_ALGO_AES_CCM:
+ test_ops.prepare_op = prepare_aead_op;
+ test_ops.prepare_xform = prepare_ccm_xform;
+ test_ops.test = fips_generic_test;
+ break;
+ default:
+ return -1;
+ }
+
+ return 0;
+}
+
+static void
+print_test_block(void)
+{
+ uint32_t i;
+
+ for (i = 0; i < info.nb_vec_lines; i++)
+ printf("%s\n", info.vec[i]);
+
+ printf("\n");
+}
+
+static int
+fips_test_one_file(void)
+{
+ int fetch_ret = 0, ret;
+
+
+ ret = init_test_ops();
+ if (ret < 0) {
+ RTE_LOG(ERR, USER1, "Error %i: Init test op\n", ret);
+ return ret;
+ }
+
+ while (ret >= 0 && fetch_ret == 0) {
+ fetch_ret = fips_test_fetch_one_block();
+ if (fetch_ret < 0) {
+ RTE_LOG(ERR, USER1, "Error %i: Fetch block\n",
+ fetch_ret);
+ ret = fetch_ret;
+ goto error_one_case;
+ }
+
+ if (info.nb_vec_lines == 0) {
+ if (fetch_ret == -EOF)
+ break;
+
+ fprintf(info.fp_wr, "\n");
+ continue;
+ }
+
+ ret = fips_test_parse_one_case();
+ switch (ret) {
+ case 0:
+ ret = test_ops.test();
+ if (ret == 0)
+ break;
+ RTE_LOG(ERR, USER1, "Error %i: test block\n",
+ ret);
+ goto error_one_case;
+ case 1:
+ break;
+ default:
+ RTE_LOG(ERR, USER1, "Error %i: Parse block\n",
+ ret);
+ goto error_one_case;
+ }
+
+ continue;
+error_one_case:
+ print_test_block();
+ }
+
+ fips_test_clear();
+
+ return ret;
+
+}
diff --git a/examples/fips_validation/meson.build b/examples/fips_validation/meson.build
new file mode 100644
index 00000000..498c9ba9
--- /dev/null
+++ b/examples/fips_validation/meson.build
@@ -0,0 +1,20 @@
+# SPDX-License-Identifier: BSD-3-Clause
+# Copyright(c) 2018 Intel Corporation
+
+# meson file, for building this example as part of a main DPDK build.
+#
+# To build this example as a standalone application with an already-installed
+# DPDK instance, use 'make'
+
+deps += ['cryptodev']
+allow_experimental_apis = true
+sources = files(
+ 'fips_validation_aes.c',
+ 'fips_validation.c',
+ 'fips_validation_hmac.c',
+ 'fips_validation_tdes.c',
+ 'fips_validation_gcm.c',
+ 'fips_validation_cmac.c',
+ 'fips_validation_ccm.c',
+ 'main.c'
+)
diff --git a/examples/flow_filtering/flow_blocks.c b/examples/flow_filtering/flow_blocks.c
index 4da45928..bae71169 100644
--- a/examples/flow_filtering/flow_blocks.c
+++ b/examples/flow_filtering/flow_blocks.c
@@ -46,8 +46,6 @@ generate_ipv4_flow(uint16_t port_id, uint16_t rx_q,
struct rte_flow_action_queue queue = { .index = rx_q };
struct rte_flow_item_eth eth_spec;
struct rte_flow_item_eth eth_mask;
- struct rte_flow_item_vlan vlan_spec;
- struct rte_flow_item_vlan vlan_mask;
struct rte_flow_item_ipv4 ip_spec;
struct rte_flow_item_ipv4 ip_mask;
int res;
@@ -85,17 +83,6 @@ generate_ipv4_flow(uint16_t port_id, uint16_t rx_q,
pattern[0].mask = &eth_mask;
/*
- * setting the second level of the pattern (vlan).
- * since in this example we just want to get the
- * ipv4 we also set this level to allow all.
- */
- memset(&vlan_spec, 0, sizeof(struct rte_flow_item_vlan));
- memset(&vlan_mask, 0, sizeof(struct rte_flow_item_vlan));
- pattern[1].type = RTE_FLOW_ITEM_TYPE_VLAN;
- pattern[1].spec = &vlan_spec;
- pattern[1].mask = &vlan_mask;
-
- /*
* setting the third level of the pattern (ip).
* in this example this is the level we care about
* so we set it according to the parameters.
@@ -106,12 +93,12 @@ generate_ipv4_flow(uint16_t port_id, uint16_t rx_q,
ip_mask.hdr.dst_addr = dest_mask;
ip_spec.hdr.src_addr = htonl(src_ip);
ip_mask.hdr.src_addr = src_mask;
- pattern[2].type = RTE_FLOW_ITEM_TYPE_IPV4;
- pattern[2].spec = &ip_spec;
- pattern[2].mask = &ip_mask;
+ pattern[1].type = RTE_FLOW_ITEM_TYPE_IPV4;
+ pattern[1].spec = &ip_spec;
+ pattern[1].mask = &ip_mask;
/* the final level must be always type end */
- pattern[3].type = RTE_FLOW_ITEM_TYPE_END;
+ pattern[2].type = RTE_FLOW_ITEM_TYPE_END;
res = rte_flow_validate(port_id, &attr, pattern, action, error);
if (!res)
diff --git a/examples/flow_filtering/main.c b/examples/flow_filtering/main.c
index a73d120e..27e287ae 100644
--- a/examples/flow_filtering/main.c
+++ b/examples/flow_filtering/main.c
@@ -136,6 +136,8 @@ init_port(void)
struct rte_eth_rxconf rxq_conf;
struct rte_eth_dev_info dev_info;
+ rte_eth_dev_info_get(port_id, &dev_info);
+ port_conf.txmode.offloads &= dev_info.rx_offload_capa;
printf(":: initializing port: %d\n", port_id);
ret = rte_eth_dev_configure(port_id,
nr_queues, nr_queues, &port_conf);
@@ -145,7 +147,6 @@ init_port(void)
ret, port_id);
}
- rte_eth_dev_info_get(port_id, &dev_info);
rxq_conf = dev_info.default_rxconf;
rxq_conf.offloads = port_conf.rxmode.offloads;
/* only set Rx queues: something we care only so far */
diff --git a/examples/ip_pipeline/cli.c b/examples/ip_pipeline/cli.c
index d1e55407..3de62068 100644
--- a/examples/ip_pipeline/cli.c
+++ b/examples/ip_pipeline/cli.c
@@ -4321,7 +4321,6 @@ cmd_pipeline_table_rule_add(char **tokens,
struct table_rule_match m;
struct table_rule_action a;
char *pipeline_name;
- void *data;
uint32_t table_id, t0, n_tokens_parsed;
int status;
@@ -4379,8 +4378,7 @@ cmd_pipeline_table_rule_add(char **tokens,
return;
}
- status = pipeline_table_rule_add(pipeline_name, table_id,
- &m, &a, &data);
+ status = pipeline_table_rule_add(pipeline_name, table_id, &m, &a);
if (status) {
snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
return;
@@ -4409,7 +4407,6 @@ cmd_pipeline_table_rule_add_default(char **tokens,
size_t out_size)
{
struct table_rule_action action;
- void *data;
char *pipeline_name;
uint32_t table_id;
int status;
@@ -4515,8 +4512,7 @@ cmd_pipeline_table_rule_add_default(char **tokens,
status = pipeline_table_rule_add_default(pipeline_name,
table_id,
- &action,
- &data);
+ &action);
if (status) {
snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
return;
@@ -4525,7 +4521,7 @@ cmd_pipeline_table_rule_add_default(char **tokens,
static const char cmd_pipeline_table_rule_add_bulk_help[] =
-"pipeline <pipeline_name> table <table_id> rule add bulk <file_name> <n_rules>\n"
+"pipeline <pipeline_name> table <table_id> rule add bulk <file_name>\n"
"\n"
" File <file_name>:\n"
" - line format: match <match> action <action>\n";
@@ -4533,8 +4529,7 @@ static const char cmd_pipeline_table_rule_add_bulk_help[] =
static int
cli_rule_file_process(const char *file_name,
size_t line_len_max,
- struct table_rule_match *m,
- struct table_rule_action *a,
+ struct table_rule_list **rule_list,
uint32_t *n_rules,
uint32_t *line_number,
char *out,
@@ -4546,14 +4541,12 @@ cmd_pipeline_table_rule_add_bulk(char **tokens,
char *out,
size_t out_size)
{
- struct table_rule_match *match;
- struct table_rule_action *action;
- void **data;
+ struct table_rule_list *list = NULL;
char *pipeline_name, *file_name;
- uint32_t table_id, n_rules, n_rules_parsed, line_number;
+ uint32_t table_id, n_rules, n_rules_added, n_rules_not_added, line_number;
int status;
- if (n_tokens != 9) {
+ if (n_tokens != 8) {
snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
return;
}
@@ -4587,68 +4580,33 @@ cmd_pipeline_table_rule_add_bulk(char **tokens,
file_name = tokens[7];
- if ((parser_read_uint32(&n_rules, tokens[8]) != 0) ||
- (n_rules == 0)) {
- snprintf(out, out_size, MSG_ARG_INVALID, "n_rules");
- return;
- }
-
- /* Memory allocation. */
- match = calloc(n_rules, sizeof(struct table_rule_match));
- action = calloc(n_rules, sizeof(struct table_rule_action));
- data = calloc(n_rules, sizeof(void *));
- if ((match == NULL) || (action == NULL) || (data == NULL)) {
- snprintf(out, out_size, MSG_OUT_OF_MEMORY);
- free(data);
- free(action);
- free(match);
- return;
- }
-
- /* Load rule file */
- n_rules_parsed = n_rules;
+ /* Load rules from file. */
status = cli_rule_file_process(file_name,
1024,
- match,
- action,
- &n_rules_parsed,
+ &list,
+ &n_rules,
&line_number,
out,
out_size);
if (status) {
snprintf(out, out_size, MSG_FILE_ERR, file_name, line_number);
- free(data);
- free(action);
- free(match);
- return;
- }
- if (n_rules_parsed != n_rules) {
- snprintf(out, out_size, MSG_FILE_NOT_ENOUGH, file_name);
- free(data);
- free(action);
- free(match);
return;
}
/* Rule bulk add */
status = pipeline_table_rule_add_bulk(pipeline_name,
table_id,
- match,
- action,
- data,
- &n_rules);
+ list,
+ &n_rules_added,
+ &n_rules_not_added);
if (status) {
snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
- free(data);
- free(action);
- free(match);
return;
}
- /* Memory free */
- free(data);
- free(action);
- free(match);
+ snprintf(out, out_size, "Added %u rules out of %u.\n",
+ n_rules_added,
+ n_rules);
}
@@ -4781,19 +4739,530 @@ cmd_pipeline_table_rule_delete_default(char **tokens,
}
}
+static void
+ether_addr_show(FILE *f, struct ether_addr *addr)
+{
+ fprintf(f, "%02x:%02x:%02x:%02x:%02x:%02x",
+ (uint32_t)addr->addr_bytes[0], (uint32_t)addr->addr_bytes[1],
+ (uint32_t)addr->addr_bytes[2], (uint32_t)addr->addr_bytes[3],
+ (uint32_t)addr->addr_bytes[4], (uint32_t)addr->addr_bytes[5]);
+}
+
+static void
+ipv4_addr_show(FILE *f, uint32_t addr)
+{
+ fprintf(f, "%u.%u.%u.%u",
+ addr >> 24,
+ (addr >> 16) & 0xFF,
+ (addr >> 8) & 0xFF,
+ addr & 0xFF);
+}
+
+static void
+ipv6_addr_show(FILE *f, uint8_t *addr)
+{
+ fprintf(f, "%02x%02x:%02x%02x:%02x%02x:%02x%02x:"
+ "%02x%02x:%02x%02x:%02x%02x:%02x%02x:",
+ (uint32_t)addr[0], (uint32_t)addr[1],
+ (uint32_t)addr[2], (uint32_t)addr[3],
+ (uint32_t)addr[4], (uint32_t)addr[5],
+ (uint32_t)addr[6], (uint32_t)addr[7],
+ (uint32_t)addr[8], (uint32_t)addr[9],
+ (uint32_t)addr[10], (uint32_t)addr[11],
+ (uint32_t)addr[12], (uint32_t)addr[13],
+ (uint32_t)addr[14], (uint32_t)addr[15]);
+}
+
+static const char *
+policer_action_string(enum rte_table_action_policer action) {
+ switch (action) {
+ case RTE_TABLE_ACTION_POLICER_COLOR_GREEN: return "G";
+ case RTE_TABLE_ACTION_POLICER_COLOR_YELLOW: return "Y";
+ case RTE_TABLE_ACTION_POLICER_COLOR_RED: return "R";
+ case RTE_TABLE_ACTION_POLICER_DROP: return "D";
+ default: return "?";
+ }
+}
+
+static int
+table_rule_show(const char *pipeline_name,
+ uint32_t table_id,
+ const char *file_name)
+{
+ struct pipeline *p;
+ struct table *table;
+ struct table_rule *rule;
+ FILE *f = NULL;
+ uint32_t i;
+
+ /* Check input params. */
+ if ((pipeline_name == NULL) ||
+ (file_name == NULL))
+ return -1;
+
+ p = pipeline_find(pipeline_name);
+ if ((p == NULL) ||
+ (table_id >= p->n_tables))
+ return -1;
+
+ table = &p->table[table_id];
+
+ /* Open file. */
+ f = fopen(file_name, "w");
+ if (f == NULL)
+ return -1;
+
+ /* Write table rules to file. */
+ TAILQ_FOREACH(rule, &table->rules, node) {
+ struct table_rule_match *m = &rule->match;
+ struct table_rule_action *a = &rule->action;
+
+ fprintf(f, "match ");
+ switch (m->match_type) {
+ case TABLE_ACL:
+ fprintf(f, "acl priority %u ",
+ m->match.acl.priority);
+
+ fprintf(f, m->match.acl.ip_version ? "ipv4 " : "ipv6 ");
+
+ if (m->match.acl.ip_version)
+ ipv4_addr_show(f, m->match.acl.ipv4.sa);
+ else
+ ipv6_addr_show(f, m->match.acl.ipv6.sa);
+
+ fprintf(f, "%u", m->match.acl.sa_depth);
+
+ if (m->match.acl.ip_version)
+ ipv4_addr_show(f, m->match.acl.ipv4.da);
+ else
+ ipv6_addr_show(f, m->match.acl.ipv6.da);
+
+ fprintf(f, "%u", m->match.acl.da_depth);
+
+ fprintf(f, "%u %u %u %u %u ",
+ (uint32_t)m->match.acl.sp0,
+ (uint32_t)m->match.acl.sp1,
+ (uint32_t)m->match.acl.dp0,
+ (uint32_t)m->match.acl.dp1,
+ (uint32_t)m->match.acl.proto);
+ break;
+
+ case TABLE_ARRAY:
+ fprintf(f, "array %u ",
+ m->match.array.pos);
+ break;
+
+ case TABLE_HASH:
+ fprintf(f, "hash raw ");
+ for (i = 0; i < table->params.match.hash.key_size; i++)
+ fprintf(f, "%02x", m->match.hash.key[i]);
+ fprintf(f, " ");
+ break;
+
+ case TABLE_LPM:
+ fprintf(f, "lpm ");
+
+ fprintf(f, m->match.lpm.ip_version ? "ipv4 " : "ipv6 ");
+
+ if (m->match.acl.ip_version)
+ ipv4_addr_show(f, m->match.lpm.ipv4);
+ else
+ ipv6_addr_show(f, m->match.lpm.ipv6);
+
+ fprintf(f, "%u ",
+ (uint32_t)m->match.lpm.depth);
+ break;
+
+ default:
+ fprintf(f, "unknown ");
+ }
+
+ fprintf(f, "action ");
+ if (a->action_mask & (1LLU << RTE_TABLE_ACTION_FWD)) {
+ fprintf(f, "fwd ");
+ switch (a->fwd.action) {
+ case RTE_PIPELINE_ACTION_DROP:
+ fprintf(f, "drop ");
+ break;
+
+ case RTE_PIPELINE_ACTION_PORT:
+ fprintf(f, "port %u ", a->fwd.id);
+ break;
+
+ case RTE_PIPELINE_ACTION_PORT_META:
+ fprintf(f, "meta ");
+ break;
+
+ case RTE_PIPELINE_ACTION_TABLE:
+ default:
+ fprintf(f, "table %u ", a->fwd.id);
+ }
+ }
+
+ if (a->action_mask & (1LLU << RTE_TABLE_ACTION_LB)) {
+ fprintf(f, "balance ");
+ for (i = 0; i < RTE_DIM(a->lb.out); i++)
+ fprintf(f, "%u ", a->lb.out[i]);
+ }
+
+ if (a->action_mask & (1LLU << RTE_TABLE_ACTION_MTR)) {
+ fprintf(f, "mtr ");
+ for (i = 0; i < RTE_TABLE_ACTION_TC_MAX; i++)
+ if (a->mtr.tc_mask & (1 << i)) {
+ struct rte_table_action_mtr_tc_params *p =
+ &a->mtr.mtr[i];
+ enum rte_table_action_policer ga =
+ p->policer[e_RTE_METER_GREEN];
+ enum rte_table_action_policer ya =
+ p->policer[e_RTE_METER_YELLOW];
+ enum rte_table_action_policer ra =
+ p->policer[e_RTE_METER_RED];
+
+ fprintf(f, "tc%u meter %u policer g %s y %s r %s ",
+ i,
+ a->mtr.mtr[i].meter_profile_id,
+ policer_action_string(ga),
+ policer_action_string(ya),
+ policer_action_string(ra));
+ }
+ }
+
+ if (a->action_mask & (1LLU << RTE_TABLE_ACTION_TM))
+ fprintf(f, "tm subport %u pipe %u ",
+ a->tm.subport_id,
+ a->tm.pipe_id);
+
+ if (a->action_mask & (1LLU << RTE_TABLE_ACTION_ENCAP)) {
+ fprintf(f, "encap ");
+ switch (a->encap.type) {
+ case RTE_TABLE_ACTION_ENCAP_ETHER:
+ fprintf(f, "ether ");
+ ether_addr_show(f, &a->encap.ether.ether.da);
+ fprintf(f, " ");
+ ether_addr_show(f, &a->encap.ether.ether.sa);
+ fprintf(f, " ");
+ break;
+
+ case RTE_TABLE_ACTION_ENCAP_VLAN:
+ fprintf(f, "vlan ");
+ ether_addr_show(f, &a->encap.vlan.ether.da);
+ fprintf(f, " ");
+ ether_addr_show(f, &a->encap.vlan.ether.sa);
+ fprintf(f, " pcp %u dei %u vid %u ",
+ a->encap.vlan.vlan.pcp,
+ a->encap.vlan.vlan.dei,
+ a->encap.vlan.vlan.vid);
+ break;
+
+ case RTE_TABLE_ACTION_ENCAP_QINQ:
+ fprintf(f, "qinq ");
+ ether_addr_show(f, &a->encap.qinq.ether.da);
+ fprintf(f, " ");
+ ether_addr_show(f, &a->encap.qinq.ether.sa);
+ fprintf(f, " pcp %u dei %u vid %u pcp %u dei %u vid %u ",
+ a->encap.qinq.svlan.pcp,
+ a->encap.qinq.svlan.dei,
+ a->encap.qinq.svlan.vid,
+ a->encap.qinq.cvlan.pcp,
+ a->encap.qinq.cvlan.dei,
+ a->encap.qinq.cvlan.vid);
+ break;
+
+ case RTE_TABLE_ACTION_ENCAP_MPLS:
+ fprintf(f, "mpls %s ", (a->encap.mpls.unicast) ?
+ "unicast " : "multicast ");
+ ether_addr_show(f, &a->encap.mpls.ether.da);
+ fprintf(f, " ");
+ ether_addr_show(f, &a->encap.mpls.ether.sa);
+ fprintf(f, " ");
+ for (i = 0; i < a->encap.mpls.mpls_count; i++) {
+ struct rte_table_action_mpls_hdr *l =
+ &a->encap.mpls.mpls[i];
+
+ fprintf(f, "label%u %u %u %u ",
+ i,
+ l->label,
+ l->tc,
+ l->ttl);
+ }
+ break;
+
+ case RTE_TABLE_ACTION_ENCAP_PPPOE:
+ fprintf(f, "pppoe ");
+ ether_addr_show(f, &a->encap.pppoe.ether.da);
+ fprintf(f, " ");
+ ether_addr_show(f, &a->encap.pppoe.ether.sa);
+ fprintf(f, " %u ", a->encap.pppoe.pppoe.session_id);
+ break;
+
+ case RTE_TABLE_ACTION_ENCAP_VXLAN:
+ fprintf(f, "vxlan ether ");
+ ether_addr_show(f, &a->encap.vxlan.ether.da);
+ fprintf(f, " ");
+ ether_addr_show(f, &a->encap.vxlan.ether.sa);
+ if (table->ap->params.encap.vxlan.vlan)
+ fprintf(f, " vlan pcp %u dei %u vid %u ",
+ a->encap.vxlan.vlan.pcp,
+ a->encap.vxlan.vlan.dei,
+ a->encap.vxlan.vlan.vid);
+ if (table->ap->params.encap.vxlan.ip_version) {
+ fprintf(f, " ipv4 ");
+ ipv4_addr_show(f, a->encap.vxlan.ipv4.sa);
+ fprintf(f, " ");
+ ipv4_addr_show(f, a->encap.vxlan.ipv4.da);
+ fprintf(f, " %u %u ",
+ (uint32_t)a->encap.vxlan.ipv4.dscp,
+ (uint32_t)a->encap.vxlan.ipv4.ttl);
+ } else {
+ fprintf(f, " ipv6 ");
+ ipv6_addr_show(f, a->encap.vxlan.ipv6.sa);
+ fprintf(f, " ");
+ ipv6_addr_show(f, a->encap.vxlan.ipv6.da);
+ fprintf(f, " %u %u %u ",
+ a->encap.vxlan.ipv6.flow_label,
+ (uint32_t)a->encap.vxlan.ipv6.dscp,
+ (uint32_t)a->encap.vxlan.ipv6.hop_limit);
+ fprintf(f, " udp %u %u vxlan %u ",
+ a->encap.vxlan.udp.sp,
+ a->encap.vxlan.udp.dp,
+ a->encap.vxlan.vxlan.vni);
+ }
+ break;
+
+ default:
+ fprintf(f, "unknown ");
+ }
+ }
+
+ if (a->action_mask & (1LLU << RTE_TABLE_ACTION_NAT)) {
+ fprintf(f, "nat %s ", (a->nat.ip_version) ? "ipv4 " : "ipv6 ");
+ if (a->nat.ip_version)
+ ipv4_addr_show(f, a->nat.addr.ipv4);
+ else
+ ipv6_addr_show(f, a->nat.addr.ipv6);
+ fprintf(f, " %u ", (uint32_t)(a->nat.port));
+ }
+
+ if (a->action_mask & (1LLU << RTE_TABLE_ACTION_TTL))
+ fprintf(f, "ttl %s ", (a->ttl.decrement) ? "dec" : "keep");
+
+ if (a->action_mask & (1LLU << RTE_TABLE_ACTION_STATS))
+ fprintf(f, "stats ");
+
+ if (a->action_mask & (1LLU << RTE_TABLE_ACTION_TIME))
+ fprintf(f, "time ");
+
+ if (a->action_mask & (1LLU << RTE_TABLE_ACTION_SYM_CRYPTO))
+ fprintf(f, "sym_crypto ");
+
+ if (a->action_mask & (1LLU << RTE_TABLE_ACTION_TAG))
+ fprintf(f, "tag %u ", a->tag.tag);
+
+ if (a->action_mask & (1LLU << RTE_TABLE_ACTION_DECAP))
+ fprintf(f, "decap %u ", a->decap.n);
+
+ /* end */
+ fprintf(f, "\n");
+ }
+
+ /* Write table default rule to file. */
+ if (table->rule_default) {
+ struct table_rule_action *a = &table->rule_default->action;
+
+ fprintf(f, "# match default action fwd ");
+
+ switch (a->fwd.action) {
+ case RTE_PIPELINE_ACTION_DROP:
+ fprintf(f, "drop ");
+ break;
+
+ case RTE_PIPELINE_ACTION_PORT:
+ fprintf(f, "port %u ", a->fwd.id);
+ break;
+
+ case RTE_PIPELINE_ACTION_PORT_META:
+ fprintf(f, "meta ");
+ break;
+
+ case RTE_PIPELINE_ACTION_TABLE:
+ default:
+ fprintf(f, "table %u ", a->fwd.id);
+ }
+ } else
+ fprintf(f, "# match default action fwd drop ");
+
+ fprintf(f, "\n");
+
+ /* Close file. */
+ fclose(f);
+
+ return 0;
+}
+
+static const char cmd_pipeline_table_rule_show_help[] =
+"pipeline <pipeline_name> table <table_id> rule show\n"
+" file <file_name>\n";
+
+static void
+cmd_pipeline_table_rule_show(char **tokens,
+ uint32_t n_tokens,
+ char *out,
+ size_t out_size)
+{
+ char *file_name = NULL, *pipeline_name;
+ uint32_t table_id;
+ int status;
+
+ if (n_tokens != 8) {
+ snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
+ return;
+ }
+
+ pipeline_name = tokens[1];
+
+ if (strcmp(tokens[2], "table") != 0) {
+ snprintf(out, out_size, MSG_ARG_NOT_FOUND, "table");
+ return;
+ }
+
+ if (parser_read_uint32(&table_id, tokens[3]) != 0) {
+ snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
+ return;
+ }
+
+ if (strcmp(tokens[4], "rule") != 0) {
+ snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rule");
+ return;
+ }
+
+ if (strcmp(tokens[5], "show") != 0) {
+ snprintf(out, out_size, MSG_ARG_NOT_FOUND, "show");
+ return;
+ }
+
+ if (strcmp(tokens[6], "file") != 0) {
+ snprintf(out, out_size, MSG_ARG_NOT_FOUND, "file");
+ return;
+ }
+
+ file_name = tokens[7];
+
+ status = table_rule_show(pipeline_name, table_id, file_name);
+ if (status) {
+ snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
+ return;
+ }
+}
static const char cmd_pipeline_table_rule_stats_read_help[] =
-"pipeline <pipeline_name> table <table_id> rule read stats [clear]\n";
+"pipeline <pipeline_name> table <table_id> rule read stats [clear]\n"
+" match <match>\n";
static void
cmd_pipeline_table_rule_stats_read(char **tokens,
- uint32_t n_tokens __rte_unused,
+ uint32_t n_tokens,
char *out,
size_t out_size)
{
- snprintf(out, out_size, MSG_CMD_UNIMPLEM, tokens[0]);
-}
+ struct table_rule_match m;
+ struct rte_table_action_stats_counters stats;
+ char *pipeline_name;
+ uint32_t table_id, n_tokens_parsed;
+ int clear = 0, status;
+
+ if (n_tokens < 7) {
+ snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
+ return;
+ }
+
+ pipeline_name = tokens[1];
+
+ if (strcmp(tokens[2], "table") != 0) {
+ snprintf(out, out_size, MSG_ARG_NOT_FOUND, "table");
+ return;
+ }
+
+ if (parser_read_uint32(&table_id, tokens[3]) != 0) {
+ snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
+ return;
+ }
+
+ if (strcmp(tokens[4], "rule") != 0) {
+ snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rule");
+ return;
+ }
+
+ if (strcmp(tokens[5], "read") != 0) {
+ snprintf(out, out_size, MSG_ARG_NOT_FOUND, "read");
+ return;
+ }
+
+ if (strcmp(tokens[6], "stats") != 0) {
+ snprintf(out, out_size, MSG_ARG_NOT_FOUND, "stats");
+ return;
+ }
+
+ n_tokens -= 7;
+ tokens += 7;
+
+ /* clear */
+ if (n_tokens && (strcmp(tokens[0], "clear") == 0)) {
+ clear = 1;
+
+ n_tokens--;
+ tokens++;
+ }
+
+ /* match */
+ if ((n_tokens == 0) || strcmp(tokens[0], "match")) {
+ snprintf(out, out_size, MSG_ARG_NOT_FOUND, "match");
+ return;
+ }
+
+ n_tokens_parsed = parse_match(tokens,
+ n_tokens,
+ out,
+ out_size,
+ &m);
+ if (n_tokens_parsed == 0)
+ return;
+ n_tokens -= n_tokens_parsed;
+ tokens += n_tokens_parsed;
+
+ /* end */
+ if (n_tokens) {
+ snprintf(out, out_size, MSG_ARG_INVALID, tokens[0]);
+ return;
+ }
+
+ /* Read table rule stats. */
+ status = pipeline_table_rule_stats_read(pipeline_name,
+ table_id,
+ &m,
+ &stats,
+ clear);
+ if (status) {
+ snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
+ return;
+ }
+ /* Print stats. */
+ if (stats.n_packets_valid && stats.n_bytes_valid)
+ snprintf(out, out_size, "Packets: %" PRIu64 "; Bytes: %" PRIu64 "\n",
+ stats.n_packets,
+ stats.n_bytes);
+
+ if (stats.n_packets_valid && !stats.n_bytes_valid)
+ snprintf(out, out_size, "Packets: %" PRIu64 "; Bytes: N/A\n",
+ stats.n_packets);
+
+ if (!stats.n_packets_valid && stats.n_bytes_valid)
+ snprintf(out, out_size, "Packets: N/A; Bytes: %" PRIu64 "\n",
+ stats.n_bytes);
+
+ if (!stats.n_packets_valid && !stats.n_bytes_valid)
+ snprintf(out, out_size, "Packets: N/A ; Bytes: N/A\n");
+}
static const char cmd_pipeline_table_meter_profile_add_help[] =
"pipeline <pipeline_name> table <table_id> meter profile <meter_profile_id>\n"
@@ -5010,15 +5479,98 @@ cmd_pipeline_table_meter_profile_delete(char **tokens,
static const char cmd_pipeline_table_rule_meter_read_help[] =
-"pipeline <pipeline_name> table <table_id> rule read meter [clear]\n";
+"pipeline <pipeline_name> table <table_id> rule read meter [clear]\n"
+" match <match>\n";
static void
cmd_pipeline_table_rule_meter_read(char **tokens,
- uint32_t n_tokens __rte_unused,
+ uint32_t n_tokens,
char *out,
size_t out_size)
{
- snprintf(out, out_size, MSG_CMD_UNIMPLEM, tokens[0]);
+ struct table_rule_match m;
+ struct rte_table_action_mtr_counters stats;
+ char *pipeline_name;
+ uint32_t table_id, n_tokens_parsed;
+ int clear = 0, status;
+
+ if (n_tokens < 7) {
+ snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
+ return;
+ }
+
+ pipeline_name = tokens[1];
+
+ if (strcmp(tokens[2], "table") != 0) {
+ snprintf(out, out_size, MSG_ARG_NOT_FOUND, "table");
+ return;
+ }
+
+ if (parser_read_uint32(&table_id, tokens[3]) != 0) {
+ snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
+ return;
+ }
+
+ if (strcmp(tokens[4], "rule") != 0) {
+ snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rule");
+ return;
+ }
+
+ if (strcmp(tokens[5], "read") != 0) {
+ snprintf(out, out_size, MSG_ARG_NOT_FOUND, "read");
+ return;
+ }
+
+ if (strcmp(tokens[6], "meter") != 0) {
+ snprintf(out, out_size, MSG_ARG_NOT_FOUND, "meter");
+ return;
+ }
+
+ n_tokens -= 7;
+ tokens += 7;
+
+ /* clear */
+ if (n_tokens && (strcmp(tokens[0], "clear") == 0)) {
+ clear = 1;
+
+ n_tokens--;
+ tokens++;
+ }
+
+ /* match */
+ if ((n_tokens == 0) || strcmp(tokens[0], "match")) {
+ snprintf(out, out_size, MSG_ARG_NOT_FOUND, "match");
+ return;
+ }
+
+ n_tokens_parsed = parse_match(tokens,
+ n_tokens,
+ out,
+ out_size,
+ &m);
+ if (n_tokens_parsed == 0)
+ return;
+ n_tokens -= n_tokens_parsed;
+ tokens += n_tokens_parsed;
+
+ /* end */
+ if (n_tokens) {
+ snprintf(out, out_size, MSG_ARG_INVALID, tokens[0]);
+ return;
+ }
+
+ /* Read table rule meter stats. */
+ status = pipeline_table_rule_mtr_read(pipeline_name,
+ table_id,
+ &m,
+ &stats,
+ clear);
+ if (status) {
+ snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
+ return;
+ }
+
+ /* Print stats. */
}
@@ -5173,17 +5725,188 @@ cmd_pipeline_table_dscp(char **tokens,
static const char cmd_pipeline_table_rule_ttl_read_help[] =
-"pipeline <pipeline_name> table <table_id> rule read ttl [clear]\n";
+"pipeline <pipeline_name> table <table_id> rule read ttl [clear]\n"
+" match <match>\n";
static void
cmd_pipeline_table_rule_ttl_read(char **tokens,
- uint32_t n_tokens __rte_unused,
+ uint32_t n_tokens,
char *out,
size_t out_size)
{
- snprintf(out, out_size, MSG_CMD_UNIMPLEM, tokens[0]);
+ struct table_rule_match m;
+ struct rte_table_action_ttl_counters stats;
+ char *pipeline_name;
+ uint32_t table_id, n_tokens_parsed;
+ int clear = 0, status;
+
+ if (n_tokens < 7) {
+ snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
+ return;
+ }
+
+ pipeline_name = tokens[1];
+
+ if (strcmp(tokens[2], "table") != 0) {
+ snprintf(out, out_size, MSG_ARG_NOT_FOUND, "table");
+ return;
+ }
+
+ if (parser_read_uint32(&table_id, tokens[3]) != 0) {
+ snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
+ return;
+ }
+
+ if (strcmp(tokens[4], "rule") != 0) {
+ snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rule");
+ return;
+ }
+
+ if (strcmp(tokens[5], "read") != 0) {
+ snprintf(out, out_size, MSG_ARG_NOT_FOUND, "read");
+ return;
+ }
+
+ if (strcmp(tokens[6], "ttl") != 0) {
+ snprintf(out, out_size, MSG_ARG_NOT_FOUND, "ttl");
+ return;
+ }
+
+ n_tokens -= 7;
+ tokens += 7;
+
+ /* clear */
+ if (n_tokens && (strcmp(tokens[0], "clear") == 0)) {
+ clear = 1;
+
+ n_tokens--;
+ tokens++;
+ }
+
+ /* match */
+ if ((n_tokens == 0) || strcmp(tokens[0], "match")) {
+ snprintf(out, out_size, MSG_ARG_NOT_FOUND, "match");
+ return;
+ }
+
+ n_tokens_parsed = parse_match(tokens,
+ n_tokens,
+ out,
+ out_size,
+ &m);
+ if (n_tokens_parsed == 0)
+ return;
+ n_tokens -= n_tokens_parsed;
+ tokens += n_tokens_parsed;
+
+ /* end */
+ if (n_tokens) {
+ snprintf(out, out_size, MSG_ARG_INVALID, tokens[0]);
+ return;
+ }
+
+ /* Read table rule TTL stats. */
+ status = pipeline_table_rule_ttl_read(pipeline_name,
+ table_id,
+ &m,
+ &stats,
+ clear);
+ if (status) {
+ snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
+ return;
+ }
+
+ /* Print stats. */
+ snprintf(out, out_size, "Packets: %" PRIu64 "\n",
+ stats.n_packets);
}
+static const char cmd_pipeline_table_rule_time_read_help[] =
+"pipeline <pipeline_name> table <table_id> rule read time\n"
+" match <match>\n";
+
+static void
+cmd_pipeline_table_rule_time_read(char **tokens,
+ uint32_t n_tokens,
+ char *out,
+ size_t out_size)
+{
+ struct table_rule_match m;
+ char *pipeline_name;
+ uint64_t timestamp;
+ uint32_t table_id, n_tokens_parsed;
+ int status;
+
+ if (n_tokens < 7) {
+ snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
+ return;
+ }
+
+ pipeline_name = tokens[1];
+
+ if (strcmp(tokens[2], "table") != 0) {
+ snprintf(out, out_size, MSG_ARG_NOT_FOUND, "table");
+ return;
+ }
+
+ if (parser_read_uint32(&table_id, tokens[3]) != 0) {
+ snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
+ return;
+ }
+
+ if (strcmp(tokens[4], "rule") != 0) {
+ snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rule");
+ return;
+ }
+
+ if (strcmp(tokens[5], "read") != 0) {
+ snprintf(out, out_size, MSG_ARG_NOT_FOUND, "read");
+ return;
+ }
+
+ if (strcmp(tokens[6], "time") != 0) {
+ snprintf(out, out_size, MSG_ARG_NOT_FOUND, "time");
+ return;
+ }
+
+ n_tokens -= 7;
+ tokens += 7;
+
+ /* match */
+ if ((n_tokens == 0) || strcmp(tokens[0], "match")) {
+ snprintf(out, out_size, MSG_ARG_NOT_FOUND, "match");
+ return;
+ }
+
+ n_tokens_parsed = parse_match(tokens,
+ n_tokens,
+ out,
+ out_size,
+ &m);
+ if (n_tokens_parsed == 0)
+ return;
+ n_tokens -= n_tokens_parsed;
+ tokens += n_tokens_parsed;
+
+ /* end */
+ if (n_tokens) {
+ snprintf(out, out_size, MSG_ARG_INVALID, tokens[0]);
+ return;
+ }
+
+ /* Read table rule timestamp. */
+ status = pipeline_table_rule_time_read(pipeline_name,
+ table_id,
+ &m,
+ &timestamp);
+ if (status) {
+ snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
+ return;
+ }
+
+ /* Print stats. */
+ snprintf(out, out_size, "Packets: %" PRIu64 "\n", timestamp);
+}
static const char cmd_thread_pipeline_enable_help[] =
"thread <thread_id> pipeline <pipeline_name> enable\n";
@@ -5308,12 +6031,14 @@ cmd_help(char **tokens, uint32_t n_tokens, char *out, size_t out_size)
"\tpipeline table rule add bulk\n"
"\tpipeline table rule delete\n"
"\tpipeline table rule delete default\n"
+ "\tpipeline table rule show\n"
"\tpipeline table rule stats read\n"
"\tpipeline table meter profile add\n"
"\tpipeline table meter profile delete\n"
"\tpipeline table rule meter read\n"
"\tpipeline table dscp\n"
"\tpipeline table rule ttl read\n"
+ "\tpipeline table rule time read\n"
"\tthread pipeline enable\n"
"\tthread pipeline disable\n\n");
return;
@@ -5521,6 +6246,14 @@ cmd_help(char **tokens, uint32_t n_tokens, char *out, size_t out_size)
return;
}
+ if ((n_tokens == 4) &&
+ (strcmp(tokens[2], "rule") == 0) &&
+ (strcmp(tokens[3], "show") == 0)) {
+ snprintf(out, out_size, "\n%s\n",
+ cmd_pipeline_table_rule_show_help);
+ return;
+ }
+
if ((n_tokens == 5) &&
(strcmp(tokens[2], "rule") == 0) &&
(strcmp(tokens[3], "stats") == 0) &&
@@ -5565,6 +6298,15 @@ cmd_help(char **tokens, uint32_t n_tokens, char *out, size_t out_size)
cmd_pipeline_table_rule_ttl_read_help);
return;
}
+
+ if ((n_tokens == 5) &&
+ (strcmp(tokens[2], "rule") == 0) &&
+ (strcmp(tokens[3], "time") == 0) &&
+ (strcmp(tokens[4], "read") == 0)) {
+ snprintf(out, out_size, "\n%s\n",
+ cmd_pipeline_table_rule_time_read_help);
+ return;
+ }
}
if ((n_tokens == 3) &&
@@ -5816,6 +6558,15 @@ cli_process(char *in, char *out, size_t out_size)
return;
}
+ if ((n_tokens >= 6) &&
+ (strcmp(tokens[2], "table") == 0) &&
+ (strcmp(tokens[4], "rule") == 0) &&
+ (strcmp(tokens[5], "show") == 0)) {
+ cmd_pipeline_table_rule_show(tokens, n_tokens,
+ out, out_size);
+ return;
+ }
+
if ((n_tokens >= 7) &&
(strcmp(tokens[2], "table") == 0) &&
(strcmp(tokens[4], "rule") == 0) &&
@@ -5873,6 +6624,16 @@ cli_process(char *in, char *out, size_t out_size)
out, out_size);
return;
}
+
+ if ((n_tokens >= 7) &&
+ (strcmp(tokens[2], "table") == 0) &&
+ (strcmp(tokens[4], "rule") == 0) &&
+ (strcmp(tokens[5], "read") == 0) &&
+ (strcmp(tokens[6], "time") == 0)) {
+ cmd_pipeline_table_rule_time_read(tokens, n_tokens,
+ out, out_size);
+ return;
+ }
}
if (strcmp(tokens[0], "thread") == 0) {
@@ -5952,44 +6713,56 @@ cli_script_process(const char *file_name,
static int
cli_rule_file_process(const char *file_name,
size_t line_len_max,
- struct table_rule_match *m,
- struct table_rule_action *a,
+ struct table_rule_list **rule_list,
uint32_t *n_rules,
uint32_t *line_number,
char *out,
size_t out_size)
{
- FILE *f = NULL;
+ struct table_rule_list *list = NULL;
char *line = NULL;
- uint32_t rule_id, line_id;
+ FILE *f = NULL;
+ uint32_t rule_id = 0, line_id = 0;
int status = 0;
/* Check input arguments */
if ((file_name == NULL) ||
(strlen(file_name) == 0) ||
- (line_len_max == 0)) {
- *line_number = 0;
- return -EINVAL;
+ (line_len_max == 0) ||
+ (rule_list == NULL) ||
+ (n_rules == NULL) ||
+ (line_number == NULL) ||
+ (out == NULL)) {
+ status = -EINVAL;
+ goto cli_rule_file_process_free;
}
/* Memory allocation */
+ list = malloc(sizeof(struct table_rule_list));
+ if (list == NULL) {
+ status = -ENOMEM;
+ goto cli_rule_file_process_free;
+ }
+
+ TAILQ_INIT(list);
+
line = malloc(line_len_max + 1);
if (line == NULL) {
- *line_number = 0;
- return -ENOMEM;
+ status = -ENOMEM;
+ goto cli_rule_file_process_free;
}
/* Open file */
f = fopen(file_name, "r");
if (f == NULL) {
- *line_number = 0;
- free(line);
- return -EIO;
+ status = -EIO;
+ goto cli_rule_file_process_free;
}
/* Read file */
- for (line_id = 1, rule_id = 0; rule_id < *n_rules; line_id++) {
+ for (line_id = 1, rule_id = 0; ; line_id++) {
char *tokens[CMD_MAX_TOKENS];
+ struct table_rule *rule = NULL;
uint32_t n_tokens, n_tokens_parsed, t0;
/* Read next line from file. */
@@ -6005,7 +6778,7 @@ cli_rule_file_process(const char *file_name,
status = parse_tokenize_string(line, tokens, &n_tokens);
if (status) {
status = -EINVAL;
- break;
+ goto cli_rule_file_process_free;
}
/* Empty line. */
@@ -6013,15 +6786,24 @@ cli_rule_file_process(const char *file_name,
continue;
t0 = 0;
+ /* Rule alloc and insert. */
+ rule = calloc(1, sizeof(struct table_rule));
+ if (rule == NULL) {
+ status = -ENOMEM;
+ goto cli_rule_file_process_free;
+ }
+
+ TAILQ_INSERT_TAIL(list, rule, node);
+
/* Rule match. */
n_tokens_parsed = parse_match(tokens + t0,
n_tokens - t0,
out,
out_size,
- &m[rule_id]);
+ &rule->match);
if (n_tokens_parsed == 0) {
status = -EINVAL;
- break;
+ goto cli_rule_file_process_free;
}
t0 += n_tokens_parsed;
@@ -6030,17 +6812,17 @@ cli_rule_file_process(const char *file_name,
n_tokens - t0,
out,
out_size,
- &a[rule_id]);
+ &rule->action);
if (n_tokens_parsed == 0) {
status = -EINVAL;
- break;
+ goto cli_rule_file_process_free;
}
t0 += n_tokens_parsed;
/* Line completed. */
if (t0 < n_tokens) {
status = -EINVAL;
- break;
+ goto cli_rule_file_process_free;
}
/* Increment rule count */
@@ -6053,7 +6835,31 @@ cli_rule_file_process(const char *file_name,
/* Memory free */
free(line);
+ *rule_list = list;
*n_rules = rule_id;
*line_number = line_id;
+ return 0;
+
+cli_rule_file_process_free:
+ *rule_list = NULL;
+ *n_rules = rule_id;
+ *line_number = line_id;
+
+ for ( ; ; ) {
+ struct table_rule *rule;
+
+ rule = TAILQ_FIRST(list);
+ if (rule == NULL)
+ break;
+
+ TAILQ_REMOVE(list, rule, node);
+ free(rule);
+ }
+
+ if (f)
+ fclose(f);
+ free(line);
+ free(list);
+
return status;
}
diff --git a/examples/ip_pipeline/pipeline.c b/examples/ip_pipeline/pipeline.c
index b23d6c09..78d590d7 100644
--- a/examples/ip_pipeline/pipeline.c
+++ b/examples/ip_pipeline/pipeline.c
@@ -1041,7 +1041,95 @@ pipeline_table_create(const char *pipeline_name,
memcpy(&table->params, params, sizeof(*params));
table->ap = ap;
table->a = action;
+ TAILQ_INIT(&table->rules);
+ table->rule_default = NULL;
+
pipeline->n_tables++;
return 0;
}
+
+struct table_rule *
+table_rule_find(struct table *table,
+ struct table_rule_match *match)
+{
+ struct table_rule *rule;
+
+ TAILQ_FOREACH(rule, &table->rules, node)
+ if (memcmp(&rule->match, match, sizeof(*match)) == 0)
+ return rule;
+
+ return NULL;
+}
+
+void
+table_rule_add(struct table *table,
+ struct table_rule *new_rule)
+{
+ struct table_rule *existing_rule;
+
+ existing_rule = table_rule_find(table, &new_rule->match);
+ if (existing_rule == NULL)
+ TAILQ_INSERT_TAIL(&table->rules, new_rule, node);
+ else {
+ TAILQ_INSERT_AFTER(&table->rules, existing_rule, new_rule, node);
+ TAILQ_REMOVE(&table->rules, existing_rule, node);
+ free(existing_rule);
+ }
+}
+
+void
+table_rule_add_bulk(struct table *table,
+ struct table_rule_list *list,
+ uint32_t n_rules)
+{
+ uint32_t i;
+
+ for (i = 0; i < n_rules; i++) {
+ struct table_rule *existing_rule, *new_rule;
+
+ new_rule = TAILQ_FIRST(list);
+ if (new_rule == NULL)
+ break;
+
+ TAILQ_REMOVE(list, new_rule, node);
+
+ existing_rule = table_rule_find(table, &new_rule->match);
+ if (existing_rule == NULL)
+ TAILQ_INSERT_TAIL(&table->rules, new_rule, node);
+ else {
+ TAILQ_INSERT_AFTER(&table->rules, existing_rule, new_rule, node);
+ TAILQ_REMOVE(&table->rules, existing_rule, node);
+ free(existing_rule);
+ }
+ }
+}
+
+void
+table_rule_delete(struct table *table,
+ struct table_rule_match *match)
+{
+ struct table_rule *rule;
+
+ rule = table_rule_find(table, match);
+ if (rule == NULL)
+ return;
+
+ TAILQ_REMOVE(&table->rules, rule, node);
+ free(rule);
+}
+
+void
+table_rule_default_add(struct table *table,
+ struct table_rule *rule)
+{
+ free(table->rule_default);
+ table->rule_default = rule;
+}
+
+void
+table_rule_default_delete(struct table *table)
+{
+ free(table->rule_default);
+ table->rule_default = NULL;
+}
diff --git a/examples/ip_pipeline/pipeline.h b/examples/ip_pipeline/pipeline.h
index e5b1d5d0..278775c2 100644
--- a/examples/ip_pipeline/pipeline.h
+++ b/examples/ip_pipeline/pipeline.h
@@ -143,6 +143,10 @@ struct table_params {
const char *action_profile_name;
};
+struct table_rule;
+
+TAILQ_HEAD(table_rule_list, table_rule);
+
struct port_in {
struct port_in_params params;
struct port_in_action_profile *ap;
@@ -153,6 +157,8 @@ struct table {
struct table_params params;
struct table_action_profile *ap;
struct rte_table_action *a;
+ struct table_rule_list rules;
+ struct table_rule *rule_default;
};
struct pipeline {
@@ -286,6 +292,13 @@ struct table_rule_action {
struct rte_table_action_decap_params decap;
};
+struct table_rule {
+ TAILQ_ENTRY(table_rule) node;
+ struct table_rule_match match;
+ struct table_rule_action action;
+ void *data;
+};
+
int
pipeline_port_in_stats_read(const char *pipeline_name,
uint32_t port_id,
@@ -316,22 +329,19 @@ int
pipeline_table_rule_add(const char *pipeline_name,
uint32_t table_id,
struct table_rule_match *match,
- struct table_rule_action *action,
- void **data);
+ struct table_rule_action *action);
int
pipeline_table_rule_add_bulk(const char *pipeline_name,
uint32_t table_id,
- struct table_rule_match *match,
- struct table_rule_action *action,
- void **data,
- uint32_t *n_rules);
+ struct table_rule_list *list,
+ uint32_t *n_rules_added,
+ uint32_t *n_rules_not_added);
int
pipeline_table_rule_add_default(const char *pipeline_name,
uint32_t table_id,
- struct table_rule_action *action,
- void **data);
+ struct table_rule_action *action);
int
pipeline_table_rule_delete(const char *pipeline_name,
@@ -345,7 +355,7 @@ pipeline_table_rule_delete_default(const char *pipeline_name,
int
pipeline_table_rule_stats_read(const char *pipeline_name,
uint32_t table_id,
- void *data,
+ struct table_rule_match *match,
struct rte_table_action_stats_counters *stats,
int clear);
@@ -363,8 +373,7 @@ pipeline_table_mtr_profile_delete(const char *pipeline_name,
int
pipeline_table_rule_mtr_read(const char *pipeline_name,
uint32_t table_id,
- void *data,
- uint32_t tc_mask,
+ struct table_rule_match *match,
struct rte_table_action_mtr_counters *stats,
int clear);
@@ -377,8 +386,38 @@ pipeline_table_dscp_table_update(const char *pipeline_name,
int
pipeline_table_rule_ttl_read(const char *pipeline_name,
uint32_t table_id,
- void *data,
+ struct table_rule_match *match,
struct rte_table_action_ttl_counters *stats,
int clear);
+int
+pipeline_table_rule_time_read(const char *pipeline_name,
+ uint32_t table_id,
+ struct table_rule_match *match,
+ uint64_t *timestamp);
+
+struct table_rule *
+table_rule_find(struct table *table,
+ struct table_rule_match *match);
+
+void
+table_rule_add(struct table *table,
+ struct table_rule *rule);
+
+void
+table_rule_add_bulk(struct table *table,
+ struct table_rule_list *list,
+ uint32_t n_rules);
+
+void
+table_rule_delete(struct table *table,
+ struct table_rule_match *match);
+
+void
+table_rule_default_add(struct table *table,
+ struct table_rule *rule);
+
+void
+table_rule_default_delete(struct table *table);
+
#endif /* _INCLUDE_PIPELINE_H_ */
diff --git a/examples/ip_pipeline/thread.c b/examples/ip_pipeline/thread.c
index 4bd971fd..272fbbee 100644
--- a/examples/ip_pipeline/thread.c
+++ b/examples/ip_pipeline/thread.c
@@ -584,6 +584,7 @@ enum pipeline_req_type {
PIPELINE_REQ_TABLE_RULE_MTR_READ,
PIPELINE_REQ_TABLE_DSCP_TABLE_UPDATE,
PIPELINE_REQ_TABLE_RULE_TTL_READ,
+ PIPELINE_REQ_TABLE_RULE_TIME_READ,
PIPELINE_REQ_MAX
};
@@ -609,10 +610,7 @@ struct pipeline_msg_req_table_rule_add_default {
};
struct pipeline_msg_req_table_rule_add_bulk {
- struct table_rule_match *match;
- struct table_rule_action *action;
- void **data;
- uint32_t n_rules;
+ struct table_rule_list *list;
int bulk;
};
@@ -650,6 +648,10 @@ struct pipeline_msg_req_table_rule_ttl_read {
int clear;
};
+struct pipeline_msg_req_table_rule_time_read {
+ void *data;
+};
+
struct pipeline_msg_req {
enum pipeline_req_type type;
uint32_t id; /* Port IN, port OUT or table ID */
@@ -669,6 +671,7 @@ struct pipeline_msg_req {
struct pipeline_msg_req_table_rule_mtr_read table_rule_mtr_read;
struct pipeline_msg_req_table_dscp_table_update table_dscp_table_update;
struct pipeline_msg_req_table_rule_ttl_read table_rule_ttl_read;
+ struct pipeline_msg_req_table_rule_time_read table_rule_time_read;
};
};
@@ -708,6 +711,10 @@ struct pipeline_msg_rsp_table_rule_ttl_read {
struct rte_table_action_ttl_counters stats;
};
+struct pipeline_msg_rsp_table_rule_time_read {
+ uint64_t timestamp;
+};
+
struct pipeline_msg_rsp {
int status;
@@ -722,6 +729,7 @@ struct pipeline_msg_rsp {
struct pipeline_msg_rsp_table_rule_stats_read table_rule_stats_read;
struct pipeline_msg_rsp_table_rule_mtr_read table_rule_mtr_read;
struct pipeline_msg_rsp_table_rule_ttl_read table_rule_ttl_read;
+ struct pipeline_msg_rsp_table_rule_time_read table_rule_time_read;
};
};
@@ -812,7 +820,7 @@ pipeline_port_in_stats_read(const char *pipeline_name,
/* Read response */
status = rsp->status;
- if (status)
+ if (status == 0)
memcpy(stats, &rsp->port_in_stats_read.stats, sizeof(*stats));
/* Free response */
@@ -960,7 +968,7 @@ pipeline_port_out_stats_read(const char *pipeline_name,
/* Read response */
status = rsp->status;
- if (status)
+ if (status == 0)
memcpy(stats, &rsp->port_out_stats_read.stats, sizeof(*stats));
/* Free response */
@@ -1016,7 +1024,7 @@ pipeline_table_stats_read(const char *pipeline_name,
/* Read response */
status = rsp->status;
- if (status)
+ if (status == 0)
memcpy(stats, &rsp->table_stats_read.stats, sizeof(*stats));
/* Free response */
@@ -1206,23 +1214,145 @@ action_convert(struct rte_table_action *a,
struct table_rule_action *action,
struct rte_pipeline_table_entry *data);
+struct table_ll {
+ struct rte_pipeline *p;
+ int table_id;
+ struct rte_table_action *a;
+ int bulk_supported;
+};
+
+static int
+table_rule_add_bulk_ll(struct table_ll *table,
+ struct table_rule_list *list,
+ uint32_t *n_rules)
+{
+ union table_rule_match_low_level *match_ll = NULL;
+ uint8_t *action_ll = NULL;
+ void **match_ll_ptr = NULL;
+ struct rte_pipeline_table_entry **action_ll_ptr = NULL;
+ struct rte_pipeline_table_entry **entries_ptr = NULL;
+ int *found = NULL;
+ struct table_rule *rule;
+ uint32_t n, i;
+ int status = 0;
+
+ n = 0;
+ TAILQ_FOREACH(rule, list, node)
+ n++;
+
+ /* Memory allocation */
+ match_ll = calloc(n, sizeof(union table_rule_match_low_level));
+ action_ll = calloc(n, TABLE_RULE_ACTION_SIZE_MAX);
+
+ match_ll_ptr = calloc(n, sizeof(void *));
+ action_ll_ptr = calloc(n, sizeof(struct rte_pipeline_table_entry *));
+
+ entries_ptr = calloc(n, sizeof(struct rte_pipeline_table_entry *));
+ found = calloc(n, sizeof(int));
+
+ if (match_ll == NULL ||
+ action_ll == NULL ||
+ match_ll_ptr == NULL ||
+ action_ll_ptr == NULL ||
+ entries_ptr == NULL ||
+ found == NULL) {
+ status = -ENOMEM;
+ goto table_rule_add_bulk_ll_free;
+ }
+
+ /* Init */
+ for (i = 0; i < n; i++) {
+ match_ll_ptr[i] = (void *)&match_ll[i];
+ action_ll_ptr[i] = (struct rte_pipeline_table_entry *)
+ &action_ll[i * TABLE_RULE_ACTION_SIZE_MAX];
+ }
+
+ /* Rule (match, action) conversion */
+ i = 0;
+ TAILQ_FOREACH(rule, list, node) {
+ status = match_convert(&rule->match, match_ll_ptr[i], 1);
+ if (status)
+ goto table_rule_add_bulk_ll_free;
+
+ status = action_convert(table->a, &rule->action, action_ll_ptr[i]);
+ if (status)
+ goto table_rule_add_bulk_ll_free;
+
+ i++;
+ }
+
+ /* Add rule (match, action) to table */
+ if (table->bulk_supported) {
+ status = rte_pipeline_table_entry_add_bulk(table->p,
+ table->table_id,
+ match_ll_ptr,
+ action_ll_ptr,
+ n,
+ found,
+ entries_ptr);
+ if (status)
+ goto table_rule_add_bulk_ll_free;
+ } else
+ for (i = 0; i < n; i++) {
+ status = rte_pipeline_table_entry_add(table->p,
+ table->table_id,
+ match_ll_ptr[i],
+ action_ll_ptr[i],
+ &found[i],
+ &entries_ptr[i]);
+ if (status) {
+ if (i == 0)
+ goto table_rule_add_bulk_ll_free;
+
+ /* No roll-back. */
+ status = 0;
+ n = i;
+ break;
+ }
+ }
+
+ /* Write back to the rule list. */
+ i = 0;
+ TAILQ_FOREACH(rule, list, node) {
+ if (i >= n)
+ break;
+
+ rule->data = entries_ptr[i];
+
+ i++;
+ }
+
+ *n_rules = n;
+
+ /* Free */
+table_rule_add_bulk_ll_free:
+ free(found);
+ free(entries_ptr);
+ free(action_ll_ptr);
+ free(match_ll_ptr);
+ free(action_ll);
+ free(match_ll);
+
+ return status;
+}
+
int
pipeline_table_rule_add(const char *pipeline_name,
uint32_t table_id,
struct table_rule_match *match,
- struct table_rule_action *action,
- void **data)
+ struct table_rule_action *action)
{
struct pipeline *p;
+ struct table *table;
struct pipeline_msg_req *req;
struct pipeline_msg_rsp *rsp;
+ struct table_rule *rule;
int status;
/* Check input params */
if ((pipeline_name == NULL) ||
(match == NULL) ||
- (action == NULL) ||
- (data == NULL))
+ (action == NULL))
return -1;
p = pipeline_find(pipeline_name);
@@ -1232,16 +1362,26 @@ pipeline_table_rule_add(const char *pipeline_name,
action_check(action, p, table_id))
return -1;
+ table = &p->table[table_id];
+
+ rule = calloc(1, sizeof(struct table_rule));
+ if (rule == NULL)
+ return -1;
+
+ memcpy(&rule->match, match, sizeof(*match));
+ memcpy(&rule->action, action, sizeof(*action));
+
if (!pipeline_is_running(p)) {
- struct rte_table_action *a = p->table[table_id].a;
union table_rule_match_low_level match_ll;
struct rte_pipeline_table_entry *data_in, *data_out;
int key_found;
uint8_t *buffer;
buffer = calloc(TABLE_RULE_ACTION_SIZE_MAX, sizeof(uint8_t));
- if (buffer == NULL)
+ if (buffer == NULL) {
+ free(rule);
return -1;
+ }
/* Table match-action rule conversion */
data_in = (struct rte_pipeline_table_entry *)buffer;
@@ -1249,12 +1389,14 @@ pipeline_table_rule_add(const char *pipeline_name,
status = match_convert(match, &match_ll, 1);
if (status) {
free(buffer);
+ free(rule);
return -1;
}
- status = action_convert(a, action, data_in);
+ status = action_convert(table->a, action, data_in);
if (status) {
free(buffer);
+ free(rule);
return -1;
}
@@ -1267,11 +1409,13 @@ pipeline_table_rule_add(const char *pipeline_name,
&data_out);
if (status) {
free(buffer);
+ free(rule);
return -1;
}
/* Write Response */
- *data = data_out;
+ rule->data = data_out;
+ table_rule_add(table, rule);
free(buffer);
return 0;
@@ -1279,8 +1423,10 @@ pipeline_table_rule_add(const char *pipeline_name,
/* Allocate request */
req = pipeline_msg_alloc();
- if (req == NULL)
+ if (req == NULL) {
+ free(rule);
return -1;
+ }
/* Write request */
req->type = PIPELINE_REQ_TABLE_RULE_ADD;
@@ -1290,13 +1436,18 @@ pipeline_table_rule_add(const char *pipeline_name,
/* Send request and wait for response */
rsp = pipeline_msg_send_recv(p, req);
- if (rsp == NULL)
+ if (rsp == NULL) {
+ free(rule);
return -1;
+ }
/* Read response */
status = rsp->status;
- if (status == 0)
- *data = rsp->table_rule_add.data;
+ if (status == 0) {
+ rule->data = rsp->table_rule_add.data;
+ table_rule_add(table, rule);
+ } else
+ free(rule);
/* Free response */
pipeline_msg_free(rsp);
@@ -1307,18 +1458,18 @@ pipeline_table_rule_add(const char *pipeline_name,
int
pipeline_table_rule_add_default(const char *pipeline_name,
uint32_t table_id,
- struct table_rule_action *action,
- void **data)
+ struct table_rule_action *action)
{
struct pipeline *p;
+ struct table *table;
struct pipeline_msg_req *req;
struct pipeline_msg_rsp *rsp;
+ struct table_rule *rule;
int status;
/* Check input params */
if ((pipeline_name == NULL) ||
- (action == NULL) ||
- (data == NULL))
+ (action == NULL))
return -1;
p = pipeline_find(pipeline_name);
@@ -1327,13 +1478,23 @@ pipeline_table_rule_add_default(const char *pipeline_name,
action_default_check(action, p, table_id))
return -1;
+ table = &p->table[table_id];
+
+ rule = calloc(1, sizeof(struct table_rule));
+ if (rule == NULL)
+ return -1;
+
+ memcpy(&rule->action, action, sizeof(*action));
+
if (!pipeline_is_running(p)) {
struct rte_pipeline_table_entry *data_in, *data_out;
uint8_t *buffer;
buffer = calloc(TABLE_RULE_ACTION_SIZE_MAX, sizeof(uint8_t));
- if (buffer == NULL)
+ if (buffer == NULL) {
+ free(rule);
return -1;
+ }
/* Apply actions */
data_in = (struct rte_pipeline_table_entry *)buffer;
@@ -1351,11 +1512,13 @@ pipeline_table_rule_add_default(const char *pipeline_name,
&data_out);
if (status) {
free(buffer);
+ free(rule);
return -1;
}
/* Write Response */
- *data = data_out;
+ rule->data = data_out;
+ table_rule_default_add(table, rule);
free(buffer);
return 0;
@@ -1363,8 +1526,10 @@ pipeline_table_rule_add_default(const char *pipeline_name,
/* Allocate request */
req = pipeline_msg_alloc();
- if (req == NULL)
+ if (req == NULL) {
+ free(rule);
return -1;
+ }
/* Write request */
req->type = PIPELINE_REQ_TABLE_RULE_ADD_DEFAULT;
@@ -1373,13 +1538,18 @@ pipeline_table_rule_add_default(const char *pipeline_name,
/* Send request and wait for response */
rsp = pipeline_msg_send_recv(p, req);
- if (rsp == NULL)
+ if (rsp == NULL) {
+ free(rule);
return -1;
+ }
/* Read response */
status = rsp->status;
- if (status == 0)
- *data = rsp->table_rule_add_default.data;
+ if (status == 0) {
+ rule->data = rsp->table_rule_add_default.data;
+ table_rule_default_add(table, rule);
+ } else
+ free(rule);
/* Free response */
pipeline_msg_free(rsp);
@@ -1387,156 +1557,119 @@ pipeline_table_rule_add_default(const char *pipeline_name,
return status;
}
+static uint32_t
+table_rule_list_free(struct table_rule_list *list)
+{
+ uint32_t n = 0;
+
+ if (!list)
+ return 0;
+
+ for ( ; ; ) {
+ struct table_rule *rule;
+
+ rule = TAILQ_FIRST(list);
+ if (rule == NULL)
+ break;
+
+ TAILQ_REMOVE(list, rule, node);
+ free(rule);
+ n++;
+ }
+
+ free(list);
+ return n;
+}
+
int
pipeline_table_rule_add_bulk(const char *pipeline_name,
uint32_t table_id,
- struct table_rule_match *match,
- struct table_rule_action *action,
- void **data,
- uint32_t *n_rules)
+ struct table_rule_list *list,
+ uint32_t *n_rules_added,
+ uint32_t *n_rules_not_added)
{
struct pipeline *p;
+ struct table *table;
struct pipeline_msg_req *req;
struct pipeline_msg_rsp *rsp;
- uint32_t i;
- int status;
+ struct table_rule *rule;
+ int status = 0;
/* Check input params */
if ((pipeline_name == NULL) ||
- (match == NULL) ||
- (action == NULL) ||
- (data == NULL) ||
- (n_rules == NULL) ||
- (*n_rules == 0))
- return -1;
+ (list == NULL) ||
+ TAILQ_EMPTY(list) ||
+ (n_rules_added == NULL) ||
+ (n_rules_not_added == NULL)) {
+ table_rule_list_free(list);
+ return -EINVAL;
+ }
p = pipeline_find(pipeline_name);
if ((p == NULL) ||
- (table_id >= p->n_tables))
- return -1;
-
- for (i = 0; i < *n_rules; i++)
- if (match_check(match, p, table_id) ||
- action_check(action, p, table_id))
- return -1;
-
- if (!pipeline_is_running(p)) {
- struct rte_table_action *a = p->table[table_id].a;
- union table_rule_match_low_level *match_ll;
- uint8_t *action_ll;
- void **match_ll_ptr;
- struct rte_pipeline_table_entry **action_ll_ptr;
- struct rte_pipeline_table_entry **entries_ptr =
- (struct rte_pipeline_table_entry **)data;
- uint32_t bulk =
- (p->table[table_id].params.match_type == TABLE_ACL) ? 1 : 0;
- int *found;
-
- /* Memory allocation */
- match_ll = calloc(*n_rules, sizeof(union table_rule_match_low_level));
- action_ll = calloc(*n_rules, TABLE_RULE_ACTION_SIZE_MAX);
- match_ll_ptr = calloc(*n_rules, sizeof(void *));
- action_ll_ptr =
- calloc(*n_rules, sizeof(struct rte_pipeline_table_entry *));
- found = calloc(*n_rules, sizeof(int));
-
- if (match_ll == NULL ||
- action_ll == NULL ||
- match_ll_ptr == NULL ||
- action_ll_ptr == NULL ||
- found == NULL)
- goto fail;
-
- for (i = 0; i < *n_rules; i++) {
- match_ll_ptr[i] = (void *)&match_ll[i];
- action_ll_ptr[i] =
- (struct rte_pipeline_table_entry *)&action_ll[i * TABLE_RULE_ACTION_SIZE_MAX];
- }
+ (table_id >= p->n_tables)) {
+ table_rule_list_free(list);
+ return -EINVAL;
+ }
- /* Rule match conversion */
- for (i = 0; i < *n_rules; i++) {
- status = match_convert(&match[i], match_ll_ptr[i], 1);
- if (status)
- goto fail;
- }
+ table = &p->table[table_id];
- /* Rule action conversion */
- for (i = 0; i < *n_rules; i++) {
- status = action_convert(a, &action[i], action_ll_ptr[i]);
- if (status)
- goto fail;
+ TAILQ_FOREACH(rule, list, node)
+ if (match_check(&rule->match, p, table_id) ||
+ action_check(&rule->action, p, table_id)) {
+ table_rule_list_free(list);
+ return -EINVAL;
}
- /* Add rule (match, action) to table */
- if (bulk) {
- status = rte_pipeline_table_entry_add_bulk(p->p,
- table_id,
- match_ll_ptr,
- action_ll_ptr,
- *n_rules,
- found,
- entries_ptr);
- if (status)
- *n_rules = 0;
- } else {
- for (i = 0; i < *n_rules; i++) {
- status = rte_pipeline_table_entry_add(p->p,
- table_id,
- match_ll_ptr[i],
- action_ll_ptr[i],
- &found[i],
- &entries_ptr[i]);
- if (status) {
- *n_rules = i;
- break;
- }
- }
+ if (!pipeline_is_running(p)) {
+ struct table_ll table_ll = {
+ .p = p->p,
+ .table_id = table_id,
+ .a = table->a,
+ .bulk_supported = table->params.match_type == TABLE_ACL,
+ };
+
+ status = table_rule_add_bulk_ll(&table_ll, list, n_rules_added);
+ if (status) {
+ table_rule_list_free(list);
+ return status;
}
- /* Free */
- free(found);
- free(action_ll_ptr);
- free(match_ll_ptr);
- free(action_ll);
- free(match_ll);
-
- return status;
-
-fail:
- free(found);
- free(action_ll_ptr);
- free(match_ll_ptr);
- free(action_ll);
- free(match_ll);
-
- *n_rules = 0;
- return -1;
+ table_rule_add_bulk(table, list, *n_rules_added);
+ *n_rules_not_added = table_rule_list_free(list);
+ return 0;
}
/* Allocate request */
req = pipeline_msg_alloc();
- if (req == NULL)
- return -1;
+ if (req == NULL) {
+ table_rule_list_free(list);
+ return -ENOMEM;
+ }
/* Write request */
req->type = PIPELINE_REQ_TABLE_RULE_ADD_BULK;
req->id = table_id;
- req->table_rule_add_bulk.match = match;
- req->table_rule_add_bulk.action = action;
- req->table_rule_add_bulk.data = data;
- req->table_rule_add_bulk.n_rules = *n_rules;
- req->table_rule_add_bulk.bulk =
- (p->table[table_id].params.match_type == TABLE_ACL) ? 1 : 0;
+ req->table_rule_add_bulk.list = list;
+ req->table_rule_add_bulk.bulk = table->params.match_type == TABLE_ACL;
/* Send request and wait for response */
rsp = pipeline_msg_send_recv(p, req);
- if (rsp == NULL)
- return -1;
+ if (rsp == NULL) {
+ table_rule_list_free(list);
+ return -ENOMEM;
+ }
/* Read response */
status = rsp->status;
- if (status == 0)
- *n_rules = rsp->table_rule_add_bulk.n_rules;
+ if (status == 0) {
+ *n_rules_added = rsp->table_rule_add_bulk.n_rules;
+
+ table_rule_add_bulk(table, list, *n_rules_added);
+ *n_rules_not_added = table_rule_list_free(list);
+ } else
+ table_rule_list_free(list);
+
/* Free response */
pipeline_msg_free(rsp);
@@ -1550,6 +1683,7 @@ pipeline_table_rule_delete(const char *pipeline_name,
struct table_rule_match *match)
{
struct pipeline *p;
+ struct table *table;
struct pipeline_msg_req *req;
struct pipeline_msg_rsp *rsp;
int status;
@@ -1565,6 +1699,8 @@ pipeline_table_rule_delete(const char *pipeline_name,
match_check(match, p, table_id))
return -1;
+ table = &p->table[table_id];
+
if (!pipeline_is_running(p)) {
union table_rule_match_low_level match_ll;
int key_found;
@@ -1579,6 +1715,9 @@ pipeline_table_rule_delete(const char *pipeline_name,
&key_found,
NULL);
+ if (status == 0)
+ table_rule_delete(table, match);
+
return status;
}
@@ -1599,6 +1738,8 @@ pipeline_table_rule_delete(const char *pipeline_name,
/* Read response */
status = rsp->status;
+ if (status == 0)
+ table_rule_delete(table, match);
/* Free response */
pipeline_msg_free(rsp);
@@ -1611,6 +1752,7 @@ pipeline_table_rule_delete_default(const char *pipeline_name,
uint32_t table_id)
{
struct pipeline *p;
+ struct table *table;
struct pipeline_msg_req *req;
struct pipeline_msg_rsp *rsp;
int status;
@@ -1624,11 +1766,16 @@ pipeline_table_rule_delete_default(const char *pipeline_name,
(table_id >= p->n_tables))
return -1;
+ table = &p->table[table_id];
+
if (!pipeline_is_running(p)) {
status = rte_pipeline_table_default_entry_delete(p->p,
table_id,
NULL);
+ if (status == 0)
+ table_rule_default_delete(table);
+
return status;
}
@@ -1648,6 +1795,8 @@ pipeline_table_rule_delete_default(const char *pipeline_name,
/* Read response */
status = rsp->status;
+ if (status == 0)
+ table_rule_default_delete(table);
/* Free response */
pipeline_msg_free(rsp);
@@ -1658,31 +1807,37 @@ pipeline_table_rule_delete_default(const char *pipeline_name,
int
pipeline_table_rule_stats_read(const char *pipeline_name,
uint32_t table_id,
- void *data,
+ struct table_rule_match *match,
struct rte_table_action_stats_counters *stats,
int clear)
{
struct pipeline *p;
+ struct table *table;
struct pipeline_msg_req *req;
struct pipeline_msg_rsp *rsp;
+ struct table_rule *rule;
int status;
/* Check input params */
if ((pipeline_name == NULL) ||
- (data == NULL) ||
+ (match == NULL) ||
(stats == NULL))
return -1;
p = pipeline_find(pipeline_name);
if ((p == NULL) ||
- (table_id >= p->n_tables))
+ (table_id >= p->n_tables) ||
+ match_check(match, p, table_id))
return -1;
- if (!pipeline_is_running(p)) {
- struct rte_table_action *a = p->table[table_id].a;
+ table = &p->table[table_id];
+ rule = table_rule_find(table, match);
+ if (rule == NULL)
+ return -1;
- status = rte_table_action_stats_read(a,
- data,
+ if (!pipeline_is_running(p)) {
+ status = rte_table_action_stats_read(table->a,
+ rule->data,
stats,
clear);
@@ -1697,7 +1852,7 @@ pipeline_table_rule_stats_read(const char *pipeline_name,
/* Write request */
req->type = PIPELINE_REQ_TABLE_RULE_STATS_READ;
req->id = table_id;
- req->table_rule_stats_read.data = data;
+ req->table_rule_stats_read.data = rule->data;
req->table_rule_stats_read.clear = clear;
/* Send request and wait for response */
@@ -1707,7 +1862,7 @@ pipeline_table_rule_stats_read(const char *pipeline_name,
/* Read response */
status = rsp->status;
- if (status)
+ if (status == 0)
memcpy(stats, &rsp->table_rule_stats_read.stats, sizeof(*stats));
/* Free response */
@@ -1827,32 +1982,40 @@ pipeline_table_mtr_profile_delete(const char *pipeline_name,
int
pipeline_table_rule_mtr_read(const char *pipeline_name,
uint32_t table_id,
- void *data,
- uint32_t tc_mask,
+ struct table_rule_match *match,
struct rte_table_action_mtr_counters *stats,
int clear)
{
struct pipeline *p;
+ struct table *table;
struct pipeline_msg_req *req;
struct pipeline_msg_rsp *rsp;
+ struct table_rule *rule;
+ uint32_t tc_mask;
int status;
/* Check input params */
if ((pipeline_name == NULL) ||
- (data == NULL) ||
+ (match == NULL) ||
(stats == NULL))
return -1;
p = pipeline_find(pipeline_name);
if ((p == NULL) ||
- (table_id >= p->n_tables))
+ (table_id >= p->n_tables) ||
+ match_check(match, p, table_id))
return -1;
- if (!pipeline_is_running(p)) {
- struct rte_table_action *a = p->table[table_id].a;
+ table = &p->table[table_id];
+ tc_mask = (1 << table->ap->params.mtr.n_tc) - 1;
+
+ rule = table_rule_find(table, match);
+ if (rule == NULL)
+ return -1;
- status = rte_table_action_meter_read(a,
- data,
+ if (!pipeline_is_running(p)) {
+ status = rte_table_action_meter_read(table->a,
+ rule->data,
tc_mask,
stats,
clear);
@@ -1868,7 +2031,7 @@ pipeline_table_rule_mtr_read(const char *pipeline_name,
/* Write request */
req->type = PIPELINE_REQ_TABLE_RULE_MTR_READ;
req->id = table_id;
- req->table_rule_mtr_read.data = data;
+ req->table_rule_mtr_read.data = rule->data;
req->table_rule_mtr_read.tc_mask = tc_mask;
req->table_rule_mtr_read.clear = clear;
@@ -1879,7 +2042,7 @@ pipeline_table_rule_mtr_read(const char *pipeline_name,
/* Read response */
status = rsp->status;
- if (status)
+ if (status == 0)
memcpy(stats, &rsp->table_rule_mtr_read.stats, sizeof(*stats));
/* Free response */
@@ -1948,31 +2111,40 @@ pipeline_table_dscp_table_update(const char *pipeline_name,
int
pipeline_table_rule_ttl_read(const char *pipeline_name,
uint32_t table_id,
- void *data,
+ struct table_rule_match *match,
struct rte_table_action_ttl_counters *stats,
int clear)
{
struct pipeline *p;
+ struct table *table;
struct pipeline_msg_req *req;
struct pipeline_msg_rsp *rsp;
+ struct table_rule *rule;
int status;
/* Check input params */
if ((pipeline_name == NULL) ||
- (data == NULL) ||
+ (match == NULL) ||
(stats == NULL))
return -1;
p = pipeline_find(pipeline_name);
if ((p == NULL) ||
- (table_id >= p->n_tables))
+ (table_id >= p->n_tables) ||
+ match_check(match, p, table_id))
return -1;
- if (!pipeline_is_running(p)) {
- struct rte_table_action *a = p->table[table_id].a;
+ table = &p->table[table_id];
+ if (!table->ap->params.ttl.n_packets_enabled)
+ return -1;
- status = rte_table_action_ttl_read(a,
- data,
+ rule = table_rule_find(table, match);
+ if (rule == NULL)
+ return -1;
+
+ if (!pipeline_is_running(p)) {
+ status = rte_table_action_ttl_read(table->a,
+ rule->data,
stats,
clear);
@@ -1987,7 +2159,7 @@ pipeline_table_rule_ttl_read(const char *pipeline_name,
/* Write request */
req->type = PIPELINE_REQ_TABLE_RULE_TTL_READ;
req->id = table_id;
- req->table_rule_ttl_read.data = data;
+ req->table_rule_ttl_read.data = rule->data;
req->table_rule_ttl_read.clear = clear;
/* Send request and wait for response */
@@ -1997,7 +2169,7 @@ pipeline_table_rule_ttl_read(const char *pipeline_name,
/* Read response */
status = rsp->status;
- if (status)
+ if (status == 0)
memcpy(stats, &rsp->table_rule_ttl_read.stats, sizeof(*stats));
/* Free response */
@@ -2006,6 +2178,71 @@ pipeline_table_rule_ttl_read(const char *pipeline_name,
return status;
}
+int
+pipeline_table_rule_time_read(const char *pipeline_name,
+ uint32_t table_id,
+ struct table_rule_match *match,
+ uint64_t *timestamp)
+{
+ struct pipeline *p;
+ struct table *table;
+ struct pipeline_msg_req *req;
+ struct pipeline_msg_rsp *rsp;
+ struct table_rule *rule;
+ int status;
+
+ /* Check input params */
+ if ((pipeline_name == NULL) ||
+ (match == NULL) ||
+ (timestamp == NULL))
+ return -1;
+
+ p = pipeline_find(pipeline_name);
+ if ((p == NULL) ||
+ (table_id >= p->n_tables) ||
+ match_check(match, p, table_id))
+ return -1;
+
+ table = &p->table[table_id];
+
+ rule = table_rule_find(table, match);
+ if (rule == NULL)
+ return -1;
+
+ if (!pipeline_is_running(p)) {
+ status = rte_table_action_time_read(table->a,
+ rule->data,
+ timestamp);
+
+ return status;
+ }
+
+ /* Allocate request */
+ req = pipeline_msg_alloc();
+ if (req == NULL)
+ return -1;
+
+ /* Write request */
+ req->type = PIPELINE_REQ_TABLE_RULE_TIME_READ;
+ req->id = table_id;
+ req->table_rule_time_read.data = rule->data;
+
+ /* Send request and wait for response */
+ rsp = pipeline_msg_send_recv(p, req);
+ if (rsp == NULL)
+ return -1;
+
+ /* Read response */
+ status = rsp->status;
+ if (status == 0)
+ *timestamp = rsp->table_rule_time_read.timestamp;
+
+ /* Free response */
+ pipeline_msg_free(rsp);
+
+ return status;
+}
+
/**
* Data plane threads: message handling
*/
@@ -2605,107 +2842,32 @@ static struct pipeline_msg_rsp *
pipeline_msg_handle_table_rule_add_bulk(struct pipeline_data *p,
struct pipeline_msg_req *req)
{
-
struct pipeline_msg_rsp *rsp = (struct pipeline_msg_rsp *) req;
uint32_t table_id = req->id;
- struct table_rule_match *match = req->table_rule_add_bulk.match;
- struct table_rule_action *action = req->table_rule_add_bulk.action;
- struct rte_pipeline_table_entry **data =
- (struct rte_pipeline_table_entry **)req->table_rule_add_bulk.data;
- uint32_t n_rules = req->table_rule_add_bulk.n_rules;
+ struct table_rule_list *list = req->table_rule_add_bulk.list;
uint32_t bulk = req->table_rule_add_bulk.bulk;
- struct rte_table_action *a = p->table_data[table_id].a;
- union table_rule_match_low_level *match_ll;
- uint8_t *action_ll;
- void **match_ll_ptr;
- struct rte_pipeline_table_entry **action_ll_ptr;
- int *found, status;
- uint32_t i;
-
- /* Memory allocation */
- match_ll = calloc(n_rules, sizeof(union table_rule_match_low_level));
- action_ll = calloc(n_rules, TABLE_RULE_ACTION_SIZE_MAX);
- match_ll_ptr = calloc(n_rules, sizeof(void *));
- action_ll_ptr =
- calloc(n_rules, sizeof(struct rte_pipeline_table_entry *));
- found = calloc(n_rules, sizeof(int));
-
- if ((match_ll == NULL) ||
- (action_ll == NULL) ||
- (match_ll_ptr == NULL) ||
- (action_ll_ptr == NULL) ||
- (found == NULL))
- goto fail;
-
- for (i = 0; i < n_rules; i++) {
- match_ll_ptr[i] = (void *)&match_ll[i];
- action_ll_ptr[i] =
- (struct rte_pipeline_table_entry *)&action_ll[i * TABLE_RULE_ACTION_SIZE_MAX];
- }
+ uint32_t n_rules_added;
+ int status;
- /* Rule match conversion */
- for (i = 0; i < n_rules; i++) {
- status = match_convert(&match[i], match_ll_ptr[i], 1);
- if (status)
- goto fail;
- }
+ struct table_ll table_ll = {
+ .p = p->p,
+ .table_id = table_id,
+ .a = p->table_data[table_id].a,
+ .bulk_supported = bulk,
+ };
- /* Rule action conversion */
- for (i = 0; i < n_rules; i++) {
- status = action_convert(a, &action[i], action_ll_ptr[i]);
- if (status)
- goto fail;
+ status = table_rule_add_bulk_ll(&table_ll, list, &n_rules_added);
+ if (status) {
+ rsp->status = -1;
+ rsp->table_rule_add_bulk.n_rules = 0;
+ return rsp;
}
- /* Add rule (match, action) to table */
- if (bulk) {
- status = rte_pipeline_table_entry_add_bulk(p->p,
- table_id,
- match_ll_ptr,
- action_ll_ptr,
- n_rules,
- found,
- data);
- if (status)
- n_rules = 0;
- } else
- for (i = 0; i < n_rules; i++) {
- status = rte_pipeline_table_entry_add(p->p,
- table_id,
- match_ll_ptr[i],
- action_ll_ptr[i],
- &found[i],
- &data[i]);
- if (status) {
- n_rules = i;
- break;
- }
- }
-
/* Write response */
rsp->status = 0;
- rsp->table_rule_add_bulk.n_rules = n_rules;
-
- /* Free */
- free(found);
- free(action_ll_ptr);
- free(match_ll_ptr);
- free(action_ll);
- free(match_ll);
-
- return rsp;
-
-fail:
- free(found);
- free(action_ll_ptr);
- free(match_ll_ptr);
- free(action_ll);
- free(match_ll);
-
- rsp->status = -1;
- rsp->table_rule_add_bulk.n_rules = 0;
+ rsp->table_rule_add_bulk.n_rules = n_rules_added;
return rsp;
}
@@ -2856,6 +3018,22 @@ pipeline_msg_handle_table_rule_ttl_read(struct pipeline_data *p,
return rsp;
}
+static struct pipeline_msg_rsp *
+pipeline_msg_handle_table_rule_time_read(struct pipeline_data *p,
+ struct pipeline_msg_req *req)
+{
+ struct pipeline_msg_rsp *rsp = (struct pipeline_msg_rsp *) req;
+ uint32_t table_id = req->id;
+ void *data = req->table_rule_time_read.data;
+ struct rte_table_action *a = p->table_data[table_id].a;
+
+ rsp->status = rte_table_action_time_read(a,
+ data,
+ &rsp->table_rule_time_read.timestamp);
+
+ return rsp;
+}
+
static void
pipeline_msg_handle(struct pipeline_data *p)
{
@@ -2932,6 +3110,10 @@ pipeline_msg_handle(struct pipeline_data *p)
rsp = pipeline_msg_handle_table_rule_ttl_read(p, req);
break;
+ case PIPELINE_REQ_TABLE_RULE_TIME_READ:
+ rsp = pipeline_msg_handle_table_rule_time_read(p, req);
+ break;
+
default:
rsp = (struct pipeline_msg_rsp *) req;
rsp->status = -1;
diff --git a/examples/multi_process/client_server_mp/mp_server/main.c b/examples/multi_process/client_server_mp/mp_server/main.c
index 93a9a089..0ddc63e9 100644
--- a/examples/multi_process/client_server_mp/mp_server/main.c
+++ b/examples/multi_process/client_server_mp/mp_server/main.c
@@ -12,6 +12,7 @@
#include <sys/queue.h>
#include <errno.h>
#include <netinet/ip.h>
+#include <signal.h>
#include <rte_common.h>
#include <rte_memory.h>
@@ -264,9 +265,23 @@ do_packet_forwarding(void)
}
}
+static void
+signal_handler(int signal)
+{
+ uint16_t port_id;
+
+ if (signal == SIGINT)
+ RTE_ETH_FOREACH_DEV(port_id) {
+ rte_eth_dev_stop(port_id);
+ rte_eth_dev_close(port_id);
+ }
+ exit(0);
+}
+
int
main(int argc, char *argv[])
{
+ signal(SIGINT, signal_handler);
/* initialise the system */
if (init(argc, argv) < 0 )
return -1;
diff --git a/examples/vm_power_manager/power_manager.c b/examples/vm_power_manager/power_manager.c
index b7769c3c..f9e8c0ab 100644
--- a/examples/vm_power_manager/power_manager.c
+++ b/examples/vm_power_manager/power_manager.c
@@ -95,6 +95,7 @@ power_manager_init(void)
unsigned int i, num_cpus = 0, num_freqs = 0;
int ret = 0;
struct core_info *ci;
+ unsigned int max_core_num;
rte_power_set_env(PM_ENV_ACPI_CPUFREQ);
@@ -105,7 +106,12 @@ power_manager_init(void)
return -1;
}
- for (i = 0; i < ci->core_count; i++) {
+ if (ci->core_count > POWER_MGR_MAX_CPUS)
+ max_core_num = POWER_MGR_MAX_CPUS;
+ else
+ max_core_num = ci->core_count;
+
+ for (i = 0; i < max_core_num; i++) {
if (ci->cd[i].global_enabled_cpus) {
if (rte_power_init(i) < 0)
RTE_LOG(ERR, POWER_MANAGER,
@@ -165,6 +171,7 @@ power_manager_exit(void)
unsigned int i;
int ret = 0;
struct core_info *ci;
+ unsigned int max_core_num;
ci = get_core_info();
if (!ci) {
@@ -173,7 +180,12 @@ power_manager_exit(void)
return -1;
}
- for (i = 0; i < ci->core_count; i++) {
+ if (ci->core_count > POWER_MGR_MAX_CPUS)
+ max_core_num = POWER_MGR_MAX_CPUS;
+ else
+ max_core_num = ci->core_count;
+
+ for (i = 0; i < max_core_num; i++) {
if (ci->cd[i].global_enabled_cpus) {
if (rte_power_exit(i) < 0) {
RTE_LOG(ERR, POWER_MANAGER, "Unable to shutdown power manager "