diff options
Diffstat (limited to 'drivers/net/softnic')
-rw-r--r-- | drivers/net/softnic/Makefile | 4 | ||||
-rw-r--r-- | drivers/net/softnic/conn.c | 1 | ||||
-rw-r--r-- | drivers/net/softnic/hash_func.h | 359 | ||||
-rw-r--r-- | drivers/net/softnic/hash_func_arm64.h | 261 | ||||
-rw-r--r-- | drivers/net/softnic/meson.build | 8 | ||||
-rw-r--r-- | drivers/net/softnic/rte_eth_softnic.c | 42 | ||||
-rw-r--r-- | drivers/net/softnic/rte_eth_softnic_action.c | 67 | ||||
-rw-r--r-- | drivers/net/softnic/rte_eth_softnic_cli.c | 883 | ||||
-rw-r--r-- | drivers/net/softnic/rte_eth_softnic_cryptodev.c | 125 | ||||
-rw-r--r-- | drivers/net/softnic/rte_eth_softnic_flow.c | 2287 | ||||
-rw-r--r-- | drivers/net/softnic/rte_eth_softnic_internals.h | 219 | ||||
-rw-r--r-- | drivers/net/softnic/rte_eth_softnic_meter.c | 728 | ||||
-rw-r--r-- | drivers/net/softnic/rte_eth_softnic_pipeline.c | 161 | ||||
-rw-r--r-- | drivers/net/softnic/rte_eth_softnic_thread.c | 118 |
14 files changed, 4553 insertions, 710 deletions
diff --git a/drivers/net/softnic/Makefile b/drivers/net/softnic/Makefile index ea9b65f4..484e76cd 100644 --- a/drivers/net/softnic/Makefile +++ b/drivers/net/softnic/Makefile @@ -14,6 +14,7 @@ CFLAGS += $(WERROR_FLAGS) LDLIBS += -lrte_pipeline -lrte_port -lrte_table LDLIBS += -lrte_eal -lrte_mbuf -lrte_mempool -lrte_ring LDLIBS += -lrte_ethdev -lrte_net -lrte_kvargs -lrte_sched +LDLIBS += -lrte_cryptodev LDLIBS += -lrte_bus_vdev EXPORT_MAP := rte_pmd_softnic_version.map @@ -33,6 +34,9 @@ SRCS-$(CONFIG_RTE_LIBRTE_PMD_SOFTNIC) += rte_eth_softnic_action.c SRCS-$(CONFIG_RTE_LIBRTE_PMD_SOFTNIC) += rte_eth_softnic_pipeline.c SRCS-$(CONFIG_RTE_LIBRTE_PMD_SOFTNIC) += rte_eth_softnic_thread.c SRCS-$(CONFIG_RTE_LIBRTE_PMD_SOFTNIC) += rte_eth_softnic_cli.c +SRCS-$(CONFIG_RTE_LIBRTE_PMD_SOFTNIC) += rte_eth_softnic_flow.c +SRCS-$(CONFIG_RTE_LIBRTE_PMD_SOFTNIC) += rte_eth_softnic_meter.c +SRCS-$(CONFIG_RTE_LIBRTE_PMD_SOFTNIC) += rte_eth_softnic_cryptodev.c SRCS-$(CONFIG_RTE_LIBRTE_PMD_SOFTNIC) += parser.c SRCS-$(CONFIG_RTE_LIBRTE_PMD_SOFTNIC) += conn.c diff --git a/drivers/net/softnic/conn.c b/drivers/net/softnic/conn.c index 990cf40f..8b665808 100644 --- a/drivers/net/softnic/conn.c +++ b/drivers/net/softnic/conn.c @@ -8,7 +8,6 @@ #include <unistd.h> #include <sys/types.h> -#define __USE_GNU #include <sys/socket.h> #include <sys/epoll.h> diff --git a/drivers/net/softnic/hash_func.h b/drivers/net/softnic/hash_func.h deleted file mode 100644 index 198d2b20..00000000 --- a/drivers/net/softnic/hash_func.h +++ /dev/null @@ -1,359 +0,0 @@ -/* SPDX-License-Identifier: BSD-3-Clause - * Copyright(c) 2010-2018 Intel Corporation - */ - -#ifndef __INCLUDE_HASH_FUNC_H__ -#define __INCLUDE_HASH_FUNC_H__ - -#include <rte_common.h> - -static inline uint64_t -hash_xor_key8(void *key, void *mask, __rte_unused uint32_t key_size, - uint64_t seed) -{ - uint64_t *k = key; - uint64_t *m = mask; - uint64_t xor0; - - xor0 = seed ^ (k[0] & m[0]); - - return (xor0 >> 32) ^ xor0; -} - -static inline uint64_t -hash_xor_key16(void *key, void *mask, __rte_unused uint32_t key_size, - uint64_t seed) -{ - uint64_t *k = key; - uint64_t *m = mask; - uint64_t xor0; - - xor0 = ((k[0] & m[0]) ^ seed) ^ (k[1] & m[1]); - - return (xor0 >> 32) ^ xor0; -} - -static inline uint64_t -hash_xor_key24(void *key, void *mask, __rte_unused uint32_t key_size, - uint64_t seed) -{ - uint64_t *k = key; - uint64_t *m = mask; - uint64_t xor0; - - xor0 = ((k[0] & m[0]) ^ seed) ^ (k[1] & m[1]); - - xor0 ^= k[2] & m[2]; - - return (xor0 >> 32) ^ xor0; -} - -static inline uint64_t -hash_xor_key32(void *key, void *mask, __rte_unused uint32_t key_size, - uint64_t seed) -{ - uint64_t *k = key; - uint64_t *m = mask; - uint64_t xor0, xor1; - - xor0 = ((k[0] & m[0]) ^ seed) ^ (k[1] & m[1]); - xor1 = (k[2] & m[2]) ^ (k[3] & m[3]); - - xor0 ^= xor1; - - return (xor0 >> 32) ^ xor0; -} - -static inline uint64_t -hash_xor_key40(void *key, void *mask, __rte_unused uint32_t key_size, - uint64_t seed) -{ - uint64_t *k = key; - uint64_t *m = mask; - uint64_t xor0, xor1; - - xor0 = ((k[0] & m[0]) ^ seed) ^ (k[1] & m[1]); - xor1 = (k[2] & m[2]) ^ (k[3] & m[3]); - - xor0 ^= xor1; - - xor0 ^= k[4] & m[4]; - - return (xor0 >> 32) ^ xor0; -} - -static inline uint64_t -hash_xor_key48(void *key, void *mask, __rte_unused uint32_t key_size, - uint64_t seed) -{ - uint64_t *k = key; - uint64_t *m = mask; - uint64_t xor0, xor1, xor2; - - xor0 = ((k[0] & m[0]) ^ seed) ^ (k[1] & m[1]); - xor1 = (k[2] & m[2]) ^ (k[3] & m[3]); - xor2 = (k[4] & m[4]) ^ (k[5] & m[5]); - - xor0 ^= xor1; - - xor0 ^= xor2; - - return (xor0 >> 32) ^ xor0; -} - -static inline uint64_t -hash_xor_key56(void *key, void *mask, __rte_unused uint32_t key_size, - uint64_t seed) -{ - uint64_t *k = key; - uint64_t *m = mask; - uint64_t xor0, xor1, xor2; - - xor0 = ((k[0] & m[0]) ^ seed) ^ (k[1] & m[1]); - xor1 = (k[2] & m[2]) ^ (k[3] & m[3]); - xor2 = (k[4] & m[4]) ^ (k[5] & m[5]); - - xor0 ^= xor1; - xor2 ^= k[6] & m[6]; - - xor0 ^= xor2; - - return (xor0 >> 32) ^ xor0; -} - -static inline uint64_t -hash_xor_key64(void *key, void *mask, __rte_unused uint32_t key_size, - uint64_t seed) -{ - uint64_t *k = key; - uint64_t *m = mask; - uint64_t xor0, xor1, xor2, xor3; - - xor0 = ((k[0] & m[0]) ^ seed) ^ (k[1] & m[1]); - xor1 = (k[2] & m[2]) ^ (k[3] & m[3]); - xor2 = (k[4] & m[4]) ^ (k[5] & m[5]); - xor3 = (k[6] & m[6]) ^ (k[7] & m[7]); - - xor0 ^= xor1; - xor2 ^= xor3; - - xor0 ^= xor2; - - return (xor0 >> 32) ^ xor0; -} - -#if defined(RTE_ARCH_X86_64) - -#include <x86intrin.h> - -static inline uint64_t -hash_crc_key8(void *key, void *mask, __rte_unused uint32_t key_size, - uint64_t seed) -{ - uint64_t *k = key; - uint64_t *m = mask; - uint64_t crc0; - - crc0 = _mm_crc32_u64(seed, k[0] & m[0]); - - return crc0; -} - -static inline uint64_t -hash_crc_key16(void *key, void *mask, __rte_unused uint32_t key_size, - uint64_t seed) -{ - uint64_t *k = key; - uint64_t *m = mask; - uint64_t k0, crc0, crc1; - - k0 = k[0] & m[0]; - - crc0 = _mm_crc32_u64(k0, seed); - crc1 = _mm_crc32_u64(k0 >> 32, k[1] & m[1]); - - crc0 ^= crc1; - - return crc0; -} - -static inline uint64_t -hash_crc_key24(void *key, void *mask, __rte_unused uint32_t key_size, - uint64_t seed) -{ - uint64_t *k = key; - uint64_t *m = mask; - uint64_t k0, k2, crc0, crc1; - - k0 = k[0] & m[0]; - k2 = k[2] & m[2]; - - crc0 = _mm_crc32_u64(k0, seed); - crc1 = _mm_crc32_u64(k0 >> 32, k[1] & m[1]); - - crc0 = _mm_crc32_u64(crc0, k2); - - crc0 ^= crc1; - - return crc0; -} - -static inline uint64_t -hash_crc_key32(void *key, void *mask, __rte_unused uint32_t key_size, - uint64_t seed) -{ - uint64_t *k = key; - uint64_t *m = mask; - uint64_t k0, k2, crc0, crc1, crc2, crc3; - - k0 = k[0] & m[0]; - k2 = k[2] & m[2]; - - crc0 = _mm_crc32_u64(k0, seed); - crc1 = _mm_crc32_u64(k0 >> 32, k[1] & m[1]); - - crc2 = _mm_crc32_u64(k2, k[3] & m[3]); - crc3 = k2 >> 32; - - crc0 = _mm_crc32_u64(crc0, crc1); - crc1 = _mm_crc32_u64(crc2, crc3); - - crc0 ^= crc1; - - return crc0; -} - -static inline uint64_t -hash_crc_key40(void *key, void *mask, __rte_unused uint32_t key_size, - uint64_t seed) -{ - uint64_t *k = key; - uint64_t *m = mask; - uint64_t k0, k2, crc0, crc1, crc2, crc3; - - k0 = k[0] & m[0]; - k2 = k[2] & m[2]; - - crc0 = _mm_crc32_u64(k0, seed); - crc1 = _mm_crc32_u64(k0 >> 32, k[1] & m[1]); - - crc2 = _mm_crc32_u64(k2, k[3] & m[3]); - crc3 = _mm_crc32_u64(k2 >> 32, k[4] & m[4]); - - crc0 = _mm_crc32_u64(crc0, crc1); - crc1 = _mm_crc32_u64(crc2, crc3); - - crc0 ^= crc1; - - return crc0; -} - -static inline uint64_t -hash_crc_key48(void *key, void *mask, __rte_unused uint32_t key_size, - uint64_t seed) -{ - uint64_t *k = key; - uint64_t *m = mask; - uint64_t k0, k2, k5, crc0, crc1, crc2, crc3; - - k0 = k[0] & m[0]; - k2 = k[2] & m[2]; - k5 = k[5] & m[5]; - - crc0 = _mm_crc32_u64(k0, seed); - crc1 = _mm_crc32_u64(k0 >> 32, k[1] & m[1]); - - crc2 = _mm_crc32_u64(k2, k[3] & m[3]); - crc3 = _mm_crc32_u64(k2 >> 32, k[4] & m[4]); - - crc0 = _mm_crc32_u64(crc0, (crc1 << 32) ^ crc2); - crc1 = _mm_crc32_u64(crc3, k5); - - crc0 ^= crc1; - - return crc0; -} - -static inline uint64_t -hash_crc_key56(void *key, void *mask, __rte_unused uint32_t key_size, - uint64_t seed) -{ - uint64_t *k = key; - uint64_t *m = mask; - uint64_t k0, k2, k5, crc0, crc1, crc2, crc3, crc4, crc5; - - k0 = k[0] & m[0]; - k2 = k[2] & m[2]; - k5 = k[5] & m[5]; - - crc0 = _mm_crc32_u64(k0, seed); - crc1 = _mm_crc32_u64(k0 >> 32, k[1] & m[1]); - - crc2 = _mm_crc32_u64(k2, k[3] & m[3]); - crc3 = _mm_crc32_u64(k2 >> 32, k[4] & m[4]); - - crc4 = _mm_crc32_u64(k5, k[6] & m[6]); - crc5 = k5 >> 32; - - crc0 = _mm_crc32_u64(crc0, (crc1 << 32) ^ crc2); - crc1 = _mm_crc32_u64(crc3, (crc4 << 32) ^ crc5); - - crc0 ^= crc1; - - return crc0; -} - -static inline uint64_t -hash_crc_key64(void *key, void *mask, __rte_unused uint32_t key_size, - uint64_t seed) -{ - uint64_t *k = key; - uint64_t *m = mask; - uint64_t k0, k2, k5, crc0, crc1, crc2, crc3, crc4, crc5; - - k0 = k[0] & m[0]; - k2 = k[2] & m[2]; - k5 = k[5] & m[5]; - - crc0 = _mm_crc32_u64(k0, seed); - crc1 = _mm_crc32_u64(k0 >> 32, k[1] & m[1]); - - crc2 = _mm_crc32_u64(k2, k[3] & m[3]); - crc3 = _mm_crc32_u64(k2 >> 32, k[4] & m[4]); - - crc4 = _mm_crc32_u64(k5, k[6] & m[6]); - crc5 = _mm_crc32_u64(k5 >> 32, k[7] & m[7]); - - crc0 = _mm_crc32_u64(crc0, (crc1 << 32) ^ crc2); - crc1 = _mm_crc32_u64(crc3, (crc4 << 32) ^ crc5); - - crc0 ^= crc1; - - return crc0; -} - -#define hash_default_key8 hash_crc_key8 -#define hash_default_key16 hash_crc_key16 -#define hash_default_key24 hash_crc_key24 -#define hash_default_key32 hash_crc_key32 -#define hash_default_key40 hash_crc_key40 -#define hash_default_key48 hash_crc_key48 -#define hash_default_key56 hash_crc_key56 -#define hash_default_key64 hash_crc_key64 - -#elif defined(RTE_ARCH_ARM64) -#include "hash_func_arm64.h" -#else - -#define hash_default_key8 hash_xor_key8 -#define hash_default_key16 hash_xor_key16 -#define hash_default_key24 hash_xor_key24 -#define hash_default_key32 hash_xor_key32 -#define hash_default_key40 hash_xor_key40 -#define hash_default_key48 hash_xor_key48 -#define hash_default_key56 hash_xor_key56 -#define hash_default_key64 hash_xor_key64 - -#endif - -#endif diff --git a/drivers/net/softnic/hash_func_arm64.h b/drivers/net/softnic/hash_func_arm64.h deleted file mode 100644 index ae6c0f41..00000000 --- a/drivers/net/softnic/hash_func_arm64.h +++ /dev/null @@ -1,261 +0,0 @@ -/*- - * BSD LICENSE - * - * Copyright(c) 2017 Linaro Limited. All rights reserved. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Intel Corporation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -#ifndef __HASH_FUNC_ARM64_H__ -#define __HASH_FUNC_ARM64_H__ - -#define _CRC32CX(crc, val) \ - __asm__("crc32cx %w[c], %w[c], %x[v]":[c] "+r" (crc):[v] "r" (val)) - -static inline uint64_t -hash_crc_key8(void *key, void *mask, __rte_unused uint32_t key_size, - uint64_t seed) -{ - uint64_t *k = key; - uint64_t *m = mask; - uint32_t crc0; - - crc0 = seed; - _CRC32CX(crc0, k[0] & m[0]); - - return crc0; -} - -static inline uint64_t -hash_crc_key16(void *key, void *mask, __rte_unused uint32_t key_size, - uint64_t seed) -{ - uint64_t *k = key, k0; - uint64_t *m = mask; - uint32_t crc0, crc1; - - k0 = k[0] & m[0]; - - crc0 = k0; - _CRC32CX(crc0, seed); - crc1 = k0 >> 32; - _CRC32CX(crc1, k[1] & m[1]); - - crc0 ^= crc1; - - return crc0; -} - -static inline uint64_t -hash_crc_key24(void *key, void *mask, __rte_unused uint32_t key_size, - uint64_t seed) -{ - uint64_t *k = key, k0, k2; - uint64_t *m = mask; - uint32_t crc0, crc1; - - k0 = k[0] & m[0]; - k2 = k[2] & m[2]; - - crc0 = k0; - _CRC32CX(crc0, seed); - crc1 = k0 >> 32; - _CRC32CX(crc1, k[1] & m[1]); - - _CRC32CX(crc0, k2); - - crc0 ^= crc1; - - return crc0; -} - -static inline uint64_t -hash_crc_key32(void *key, void *mask, __rte_unused uint32_t key_size, - uint64_t seed) -{ - uint64_t *k = key, k0, k2; - uint64_t *m = mask; - uint32_t crc0, crc1, crc2, crc3; - - k0 = k[0] & m[0]; - k2 = k[2] & m[2]; - - crc0 = k0; - _CRC32CX(crc0, seed); - crc1 = k0 >> 32; - _CRC32CX(crc1, k[1] & m[1]); - - crc2 = k2; - _CRC32CX(crc2, k[3] & m[3]); - crc3 = k2 >> 32; - - _CRC32CX(crc0, crc1); - _CRC32CX(crc2, crc3); - - crc0 ^= crc2; - - return crc0; -} - -static inline uint64_t -hash_crc_key40(void *key, void *mask, __rte_unused uint32_t key_size, - uint64_t seed) -{ - uint64_t *k = key, k0, k2; - uint64_t *m = mask; - uint32_t crc0, crc1, crc2, crc3; - - k0 = k[0] & m[0]; - k2 = k[2] & m[2]; - - crc0 = k0; - _CRC32CX(crc0, seed); - crc1 = k0 >> 32; - _CRC32CX(crc1, k[1] & m[1]); - - crc2 = k2; - _CRC32CX(crc2, k[3] & m[3]); - crc3 = k2 >> 32; - _CRC32CX(crc3, k[4] & m[4]); - - _CRC32CX(crc0, crc1); - _CRC32CX(crc2, crc3); - - crc0 ^= crc2; - - return crc0; -} - -static inline uint64_t -hash_crc_key48(void *key, void *mask, __rte_unused uint32_t key_size, - uint64_t seed) -{ - uint64_t *k = key, k0, k2, k5; - uint64_t *m = mask; - uint32_t crc0, crc1, crc2, crc3; - - k0 = k[0] & m[0]; - k2 = k[2] & m[2]; - k5 = k[5] & m[5]; - - crc0 = k0; - _CRC32CX(crc0, seed); - crc1 = k0 >> 32; - _CRC32CX(crc1, k[1] & m[1]); - - crc2 = k2; - _CRC32CX(crc2, k[3] & m[3]); - crc3 = k2 >> 32; - _CRC32CX(crc3, k[4] & m[4]); - - _CRC32CX(crc0, ((uint64_t)crc1 << 32) ^ crc2); - _CRC32CX(crc3, k5); - - crc0 ^= crc3; - - return crc0; -} - -static inline uint64_t -hash_crc_key56(void *key, void *mask, __rte_unused uint32_t key_size, - uint64_t seed) -{ - uint64_t *k = key, k0, k2, k5; - uint64_t *m = mask; - uint32_t crc0, crc1, crc2, crc3, crc4, crc5; - - k0 = k[0] & m[0]; - k2 = k[2] & m[2]; - k5 = k[5] & m[5]; - - crc0 = k0; - _CRC32CX(crc0, seed); - crc1 = k0 >> 32; - _CRC32CX(crc1, k[1] & m[1]); - - crc2 = k2; - _CRC32CX(crc2, k[3] & m[3]); - crc3 = k2 >> 32; - _CRC32CX(crc3, k[4] & m[4]); - - crc4 = k5; - _CRC32CX(crc4, k[6] & m[6]); - crc5 = k5 >> 32; - - _CRC32CX(crc0, ((uint64_t)crc1 << 32) ^ crc2); - _CRC32CX(crc3, ((uint64_t)crc4 << 32) ^ crc5); - - crc0 ^= crc3; - - return crc0; -} - -static inline uint64_t -hash_crc_key64(void *key, void *mask, __rte_unused uint32_t key_size, - uint64_t seed) -{ - uint64_t *k = key, k0, k2, k5; - uint64_t *m = mask; - uint32_t crc0, crc1, crc2, crc3, crc4, crc5; - - k0 = k[0] & m[0]; - k2 = k[2] & m[2]; - k5 = k[5] & m[5]; - - crc0 = k0; - _CRC32CX(crc0, seed); - crc1 = k0 >> 32; - _CRC32CX(crc1, k[1] & m[1]); - - crc2 = k2; - _CRC32CX(crc2, k[3] & m[3]); - crc3 = k2 >> 32; - _CRC32CX(crc3, k[4] & m[4]); - - crc4 = k5; - _CRC32CX(crc4, k[6] & m[6]); - crc5 = k5 >> 32; - _CRC32CX(crc5, k[7] & m[7]); - - _CRC32CX(crc0, ((uint64_t)crc1 << 32) ^ crc2); - _CRC32CX(crc3, ((uint64_t)crc4 << 32) ^ crc5); - - crc0 ^= crc3; - - return crc0; -} - -#define hash_default_key8 hash_crc_key8 -#define hash_default_key16 hash_crc_key16 -#define hash_default_key24 hash_crc_key24 -#define hash_default_key32 hash_crc_key32 -#define hash_default_key40 hash_crc_key40 -#define hash_default_key48 hash_crc_key48 -#define hash_default_key56 hash_crc_key56 -#define hash_default_key64 hash_crc_key64 - -#endif diff --git a/drivers/net/softnic/meson.build b/drivers/net/softnic/meson.build index ff982274..da249c06 100644 --- a/drivers/net/softnic/meson.build +++ b/drivers/net/softnic/meson.build @@ -1,6 +1,9 @@ # SPDX-License-Identifier: BSD-3-Clause # Copyright(c) 2018 Intel Corporation +if host_machine.system() != 'linux' + build = false +endif allow_experimental_apis = true install_headers('rte_eth_softnic.h') sources = files('rte_eth_softnic_tm.c', @@ -13,6 +16,9 @@ sources = files('rte_eth_softnic_tm.c', 'rte_eth_softnic_pipeline.c', 'rte_eth_softnic_thread.c', 'rte_eth_softnic_cli.c', + 'rte_eth_softnic_flow.c', + 'rte_eth_softnic_meter.c', + 'rte_eth_softnic_cryptodev.c', 'parser.c', 'conn.c') -deps += ['pipeline', 'port', 'table', 'sched'] +deps += ['pipeline', 'port', 'table', 'sched', 'cryptodev'] diff --git a/drivers/net/softnic/rte_eth_softnic.c b/drivers/net/softnic/rte_eth_softnic.c index 30fb3952..743a7c58 100644 --- a/drivers/net/softnic/rte_eth_softnic.c +++ b/drivers/net/softnic/rte_eth_softnic.c @@ -14,6 +14,7 @@ #include <rte_errno.h> #include <rte_ring.h> #include <rte_tm_driver.h> +#include <rte_mtr_driver.h> #include "rte_eth_softnic.h" #include "rte_eth_softnic_internals.h" @@ -27,7 +28,7 @@ #define PMD_PARAM_TM_QSIZE2 "tm_qsize2" #define PMD_PARAM_TM_QSIZE3 "tm_qsize3" -static const char *pmd_valid_args[] = { +static const char * const pmd_valid_args[] = { PMD_PARAM_FIRMWARE, PMD_PARAM_CONN_PORT, PMD_PARAM_CPU_ID, @@ -46,7 +47,7 @@ static const char welcome[] = static const char prompt[] = "softnic> "; -struct softnic_conn_params conn_params_default = { +static const struct softnic_conn_params conn_params_default = { .welcome = welcome, .prompt = prompt, .addr = "0.0.0.0", @@ -73,7 +74,6 @@ static const struct rte_eth_dev_info pmd_dev_info = { .nb_min = 0, .nb_align = 1, }, - .rx_offload_capa = DEV_RX_OFFLOAD_CRC_STRIP, }; static int pmd_softnic_logtype; @@ -190,6 +190,7 @@ pmd_dev_stop(struct rte_eth_dev *dev) softnic_mempool_free(p); tm_hierarchy_free(p); + softnic_mtr_free(p); } static void @@ -206,6 +207,21 @@ pmd_link_update(struct rte_eth_dev *dev __rte_unused, } static int +pmd_filter_ctrl(struct rte_eth_dev *dev __rte_unused, + enum rte_filter_type filter_type, + enum rte_filter_op filter_op, + void *arg) +{ + if (filter_type == RTE_ETH_FILTER_GENERIC && + filter_op == RTE_ETH_FILTER_GET) { + *(const void **)arg = &pmd_flow_ops; + return 0; + } + + return -ENOTSUP; +} + +static int pmd_tm_ops_get(struct rte_eth_dev *dev __rte_unused, void *arg) { *(const struct rte_tm_ops **)arg = &pmd_tm_ops; @@ -213,6 +229,14 @@ pmd_tm_ops_get(struct rte_eth_dev *dev __rte_unused, void *arg) return 0; } +static int +pmd_mtr_ops_get(struct rte_eth_dev *dev __rte_unused, void *arg) +{ + *(const struct rte_mtr_ops **)arg = &pmd_mtr_ops; + + return 0; +} + static const struct eth_dev_ops pmd_ops = { .dev_configure = pmd_dev_configure, .dev_start = pmd_dev_start, @@ -222,7 +246,9 @@ static const struct eth_dev_ops pmd_ops = { .dev_infos_get = pmd_dev_infos_get, .rx_queue_setup = pmd_rx_queue_setup, .tx_queue_setup = pmd_tx_queue_setup, + .filter_ctrl = pmd_filter_ctrl, .tm_ops_get = pmd_tm_ops_get, + .mtr_ops_get = pmd_mtr_ops_get, }; static uint16_t @@ -265,12 +291,14 @@ pmd_init(struct pmd_params *params) /* Resources */ tm_hierarchy_init(p); + softnic_mtr_init(p); softnic_mempool_init(p); softnic_swq_init(p); softnic_link_init(p); softnic_tmgr_init(p); softnic_tap_init(p); + softnic_cryptodev_init(p); softnic_port_in_action_profile_init(p); softnic_table_action_profile_init(p); softnic_pipeline_init(p); @@ -319,6 +347,7 @@ pmd_free(struct pmd_internals *p) softnic_mempool_free(p); tm_hierarchy_free(p); + softnic_mtr_free(p); rte_free(p); } @@ -528,7 +557,6 @@ static int pmd_remove(struct rte_vdev_device *vdev) { struct rte_eth_dev *dev = NULL; - struct pmd_internals *p; if (!vdev) return -EINVAL; @@ -539,12 +567,12 @@ pmd_remove(struct rte_vdev_device *vdev) dev = rte_eth_dev_allocated(rte_vdev_device_name(vdev)); if (dev == NULL) return -ENODEV; - p = dev->data->dev_private; /* Free device data structures*/ - rte_free(dev->data); + pmd_free(dev->data->dev_private); + dev->data->dev_private = NULL; /* already freed */ + dev->data->mac_addrs = NULL; /* statically allocated */ rte_eth_dev_release_port(dev); - pmd_free(p); return 0; } diff --git a/drivers/net/softnic/rte_eth_softnic_action.c b/drivers/net/softnic/rte_eth_softnic_action.c index c25f4dd9..92c744dc 100644 --- a/drivers/net/softnic/rte_eth_softnic_action.c +++ b/drivers/net/softnic/rte_eth_softnic_action.c @@ -7,8 +7,8 @@ #include <string.h> #include <rte_string_fns.h> +#include <rte_table_hash_func.h> -#include "hash_func.h" #include "rte_eth_softnic_internals.h" /** @@ -72,35 +72,35 @@ softnic_port_in_action_profile_create(struct pmd_internals *p, params->lb.f_hash == NULL) { switch (params->lb.key_size) { case 8: - params->lb.f_hash = hash_default_key8; + params->lb.f_hash = rte_table_hash_crc_key8; break; case 16: - params->lb.f_hash = hash_default_key16; + params->lb.f_hash = rte_table_hash_crc_key16; break; case 24: - params->lb.f_hash = hash_default_key24; + params->lb.f_hash = rte_table_hash_crc_key24; break; case 32: - params->lb.f_hash = hash_default_key32; + params->lb.f_hash = rte_table_hash_crc_key32; break; case 40: - params->lb.f_hash = hash_default_key40; + params->lb.f_hash = rte_table_hash_crc_key40; break; case 48: - params->lb.f_hash = hash_default_key48; + params->lb.f_hash = rte_table_hash_crc_key48; break; case 56: - params->lb.f_hash = hash_default_key56; + params->lb.f_hash = rte_table_hash_crc_key56; break; case 64: - params->lb.f_hash = hash_default_key64; + params->lb.f_hash = rte_table_hash_crc_key64; break; default: @@ -223,35 +223,35 @@ softnic_table_action_profile_create(struct pmd_internals *p, params->lb.f_hash == NULL) { switch (params->lb.key_size) { case 8: - params->lb.f_hash = hash_default_key8; + params->lb.f_hash = rte_table_hash_crc_key8; break; case 16: - params->lb.f_hash = hash_default_key16; + params->lb.f_hash = rte_table_hash_crc_key16; break; case 24: - params->lb.f_hash = hash_default_key24; + params->lb.f_hash = rte_table_hash_crc_key24; break; case 32: - params->lb.f_hash = hash_default_key32; + params->lb.f_hash = rte_table_hash_crc_key32; break; case 40: - params->lb.f_hash = hash_default_key40; + params->lb.f_hash = rte_table_hash_crc_key40; break; case 48: - params->lb.f_hash = hash_default_key48; + params->lb.f_hash = rte_table_hash_crc_key48; break; case 56: - params->lb.f_hash = hash_default_key56; + params->lb.f_hash = rte_table_hash_crc_key56; break; case 64: - params->lb.f_hash = hash_default_key64; + params->lb.f_hash = rte_table_hash_crc_key64; break; default: @@ -364,6 +364,39 @@ softnic_table_action_profile_create(struct pmd_internals *p, } } + if (params->action_mask & (1LLU << RTE_TABLE_ACTION_TAG)) { + status = rte_table_action_profile_action_register(ap, + RTE_TABLE_ACTION_TAG, + NULL); + + if (status) { + rte_table_action_profile_free(ap); + return NULL; + } + } + + if (params->action_mask & (1LLU << RTE_TABLE_ACTION_DECAP)) { + status = rte_table_action_profile_action_register(ap, + RTE_TABLE_ACTION_DECAP, + NULL); + + if (status) { + rte_table_action_profile_free(ap); + return NULL; + } + } + + if (params->action_mask & (1LLU << RTE_TABLE_ACTION_SYM_CRYPTO)) { + status = rte_table_action_profile_action_register(ap, + RTE_TABLE_ACTION_SYM_CRYPTO, + ¶ms->sym_crypto); + + if (status) { + rte_table_action_profile_free(ap); + return NULL; + } + } + status = rte_table_action_profile_freeze(ap); if (status) { rte_table_action_profile_free(ap); diff --git a/drivers/net/softnic/rte_eth_softnic_cli.c b/drivers/net/softnic/rte_eth_softnic_cli.c index 0c7448cc..c6640d65 100644 --- a/drivers/net/softnic/rte_eth_softnic_cli.c +++ b/drivers/net/softnic/rte_eth_softnic_cli.c @@ -9,6 +9,8 @@ #include <rte_common.h> #include <rte_cycles.h> +#include <rte_string_fns.h> +#include <rte_cryptodev.h> #include "rte_eth_softnic_internals.h" #include "parser.h" @@ -1089,6 +1091,67 @@ cmd_tap(struct pmd_internals *softnic, } /** + * cryptodev <tap_name> dev <device_name> | dev_id <device_id> + * queue <n_queues> <queue_size> + **/ + +static void +cmd_cryptodev(struct pmd_internals *softnic, + char **tokens, + uint32_t n_tokens, + char *out, + size_t out_size) +{ + struct softnic_cryptodev_params params; + char *name; + + memset(¶ms, 0, sizeof(params)); + if (n_tokens != 7) { + snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); + return; + } + + name = tokens[1]; + + if (strcmp(tokens[2], "dev") == 0) + params.dev_name = tokens[3]; + else if (strcmp(tokens[2], "dev_id") == 0) { + if (softnic_parser_read_uint32(¶ms.dev_id, tokens[3]) < 0) { + snprintf(out, out_size, MSG_ARG_INVALID, + "dev_id"); + return; + } + } else { + snprintf(out, out_size, MSG_ARG_INVALID, + "cryptodev"); + return; + } + + if (strcmp(tokens[4], "queue")) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, + "4"); + return; + } + + if (softnic_parser_read_uint32(¶ms.n_queues, tokens[5]) < 0) { + snprintf(out, out_size, MSG_ARG_INVALID, + "q"); + return; + } + + if (softnic_parser_read_uint32(¶ms.queue_size, tokens[6]) < 0) { + snprintf(out, out_size, MSG_ARG_INVALID, + "queue_size"); + return; + } + + if (softnic_cryptodev_create(softnic, name, ¶ms) == NULL) { + snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); + return; + } +} + +/** * port in action profile <profile_name> * [filter match | mismatch offset <key_offset> mask <key_mask> key <key_value> port <port_id>] * [balance offset <key_offset> mask <key_mask> port <port_id0> ... <port_id15>] @@ -1272,13 +1335,17 @@ cmd_port_in_action_profile(struct pmd_internals *softnic, * tc <n_tc> * stats none | pkts | bytes | both] * [tm spp <n_subports_per_port> pps <n_pipes_per_subport>] - * [encap ether | vlan | qinq | mpls | pppoe] + * [encap ether | vlan | qinq | mpls | pppoe | + * vxlan offset <ether_offset> ipv4 | ipv6 vlan on | off] * [nat src | dst * proto udp | tcp] * [ttl drop | fwd * stats none | pkts] * [stats pkts | bytes | both] * [time] + * [tag] + * [decap] + * */ static void cmd_table_action_profile(struct pmd_internals *softnic, @@ -1478,6 +1545,8 @@ cmd_table_action_profile(struct pmd_internals *softnic, if (t0 < n_tokens && (strcmp(tokens[t0], "encap") == 0)) { + uint32_t n_extra_tokens = 0; + if (n_tokens < t0 + 2) { snprintf(out, out_size, MSG_ARG_MISMATCH, "action profile encap"); @@ -1494,13 +1563,61 @@ cmd_table_action_profile(struct pmd_internals *softnic, p.encap.encap_mask = 1LLU << RTE_TABLE_ACTION_ENCAP_MPLS; } else if (strcmp(tokens[t0 + 1], "pppoe") == 0) { p.encap.encap_mask = 1LLU << RTE_TABLE_ACTION_ENCAP_PPPOE; + } else if (strcmp(tokens[t0 + 1], "vxlan") == 0) { + if (n_tokens < t0 + 2 + 5) { + snprintf(out, out_size, MSG_ARG_MISMATCH, + "action profile encap vxlan"); + return; + } + + if (strcmp(tokens[t0 + 2], "offset") != 0) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, + "vxlan: offset"); + return; + } + + if (softnic_parser_read_uint32(&p.encap.vxlan.data_offset, + tokens[t0 + 2 + 1]) != 0) { + snprintf(out, out_size, MSG_ARG_INVALID, + "vxlan: ether_offset"); + return; + } + + if (strcmp(tokens[t0 + 2 + 2], "ipv4") == 0) + p.encap.vxlan.ip_version = 1; + else if (strcmp(tokens[t0 + 2 + 2], "ipv6") == 0) + p.encap.vxlan.ip_version = 0; + else { + snprintf(out, out_size, MSG_ARG_INVALID, + "vxlan: ipv4 or ipv6"); + return; + } + + if (strcmp(tokens[t0 + 2 + 3], "vlan") != 0) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, + "vxlan: vlan"); + return; + } + + if (strcmp(tokens[t0 + 2 + 4], "on") == 0) + p.encap.vxlan.vlan = 1; + else if (strcmp(tokens[t0 + 2 + 4], "off") == 0) + p.encap.vxlan.vlan = 0; + else { + snprintf(out, out_size, MSG_ARG_INVALID, + "vxlan: on or off"); + return; + } + + p.encap.encap_mask = 1LLU << RTE_TABLE_ACTION_ENCAP_VXLAN; + n_extra_tokens = 5; + } else { snprintf(out, out_size, MSG_ARG_MISMATCH, "encap"); return; } - p.action_mask |= 1LLU << RTE_TABLE_ACTION_ENCAP; - t0 += 2; + t0 += 2 + n_extra_tokens; } /* encap */ if (t0 < n_tokens && @@ -1610,6 +1727,18 @@ cmd_table_action_profile(struct pmd_internals *softnic, t0 += 1; } /* time */ + if (t0 < n_tokens && + (strcmp(tokens[t0], "tag") == 0)) { + p.action_mask |= 1LLU << RTE_TABLE_ACTION_TAG; + t0 += 1; + } /* tag */ + + if (t0 < n_tokens && + (strcmp(tokens[t0], "decap") == 0)) { + p.action_mask |= 1LLU << RTE_TABLE_ACTION_DECAP; + t0 += 1; + } /* decap */ + if (t0 < n_tokens) { snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); return; @@ -1682,6 +1811,7 @@ cmd_pipeline(struct pmd_internals *softnic, * | tmgr <tmgr_name> * | tap <tap_name> mempool <mempool_name> mtu <mtu> * | source mempool <mempool_name> file <file_name> bpp <n_bytes_per_pkt> + * | cryptodev <cryptodev_name> rxq <queue_id> * [action <port_in_action_profile_name>] * [disabled] */ @@ -1697,6 +1827,8 @@ cmd_pipeline_port_in(struct pmd_internals *softnic, uint32_t t0; int enabled, status; + memset(&p, 0, sizeof(p)); + if (n_tokens < 7) { snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); return; @@ -1735,7 +1867,7 @@ cmd_pipeline_port_in(struct pmd_internals *softnic, p.type = PORT_IN_RXQ; - p.dev_name = tokens[t0 + 1]; + strcpy(p.dev_name, tokens[t0 + 1]); if (strcmp(tokens[t0 + 2], "rxq") != 0) { snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rxq"); @@ -1758,7 +1890,7 @@ cmd_pipeline_port_in(struct pmd_internals *softnic, p.type = PORT_IN_SWQ; - p.dev_name = tokens[t0 + 1]; + strcpy(p.dev_name, tokens[t0 + 1]); t0 += 2; } else if (strcmp(tokens[t0], "tmgr") == 0) { @@ -1770,7 +1902,7 @@ cmd_pipeline_port_in(struct pmd_internals *softnic, p.type = PORT_IN_TMGR; - p.dev_name = tokens[t0 + 1]; + strcpy(p.dev_name, tokens[t0 + 1]); t0 += 2; } else if (strcmp(tokens[t0], "tap") == 0) { @@ -1782,7 +1914,7 @@ cmd_pipeline_port_in(struct pmd_internals *softnic, p.type = PORT_IN_TAP; - p.dev_name = tokens[t0 + 1]; + strcpy(p.dev_name, tokens[t0 + 1]); if (strcmp(tokens[t0 + 2], "mempool") != 0) { snprintf(out, out_size, MSG_ARG_NOT_FOUND, @@ -1814,8 +1946,6 @@ cmd_pipeline_port_in(struct pmd_internals *softnic, p.type = PORT_IN_SOURCE; - p.dev_name = NULL; - if (strcmp(tokens[t0 + 1], "mempool") != 0) { snprintf(out, out_size, MSG_ARG_NOT_FOUND, "mempool"); @@ -1846,12 +1976,32 @@ cmd_pipeline_port_in(struct pmd_internals *softnic, } t0 += 7; + } else if (strcmp(tokens[t0], "cryptodev") == 0) { + if (n_tokens < t0 + 3) { + snprintf(out, out_size, MSG_ARG_MISMATCH, + "pipeline port in cryptodev"); + return; + } + + p.type = PORT_IN_CRYPTODEV; + + strlcpy(p.dev_name, tokens[t0 + 1], sizeof(p.dev_name)); + if (softnic_parser_read_uint16(&p.rxq.queue_id, + tokens[t0 + 3]) != 0) { + snprintf(out, out_size, MSG_ARG_INVALID, + "rxq"); + return; + } + + p.cryptodev.arg_callback = NULL; + p.cryptodev.f_callback = NULL; + + t0 += 4; } else { snprintf(out, out_size, MSG_ARG_INVALID, tokens[0]); return; } - p.action_profile_name = NULL; if (n_tokens > t0 && (strcmp(tokens[t0], "action") == 0)) { if (n_tokens < t0 + 2) { @@ -1859,7 +2009,7 @@ cmd_pipeline_port_in(struct pmd_internals *softnic, return; } - p.action_profile_name = tokens[t0 + 1]; + strcpy(p.action_profile_name, tokens[t0 + 1]); t0 += 2; } @@ -1895,6 +2045,7 @@ cmd_pipeline_port_in(struct pmd_internals *softnic, * | tmgr <tmgr_name> * | tap <tap_name> * | sink [file <file_name> pkts <max_n_pkts>] + * | cryptodev <cryptodev_name> txq <txq_id> offset <crypto_op_offset> */ static void cmd_pipeline_port_out(struct pmd_internals *softnic, @@ -1945,7 +2096,7 @@ cmd_pipeline_port_out(struct pmd_internals *softnic, p.type = PORT_OUT_TXQ; - p.dev_name = tokens[7]; + strcpy(p.dev_name, tokens[7]); if (strcmp(tokens[8], "txq") != 0) { snprintf(out, out_size, MSG_ARG_NOT_FOUND, "txq"); @@ -1966,7 +2117,7 @@ cmd_pipeline_port_out(struct pmd_internals *softnic, p.type = PORT_OUT_SWQ; - p.dev_name = tokens[7]; + strcpy(p.dev_name, tokens[7]); } else if (strcmp(tokens[6], "tmgr") == 0) { if (n_tokens != 8) { snprintf(out, out_size, MSG_ARG_MISMATCH, @@ -1976,7 +2127,7 @@ cmd_pipeline_port_out(struct pmd_internals *softnic, p.type = PORT_OUT_TMGR; - p.dev_name = tokens[7]; + strcpy(p.dev_name, tokens[7]); } else if (strcmp(tokens[6], "tap") == 0) { if (n_tokens != 8) { snprintf(out, out_size, MSG_ARG_MISMATCH, @@ -1986,7 +2137,7 @@ cmd_pipeline_port_out(struct pmd_internals *softnic, p.type = PORT_OUT_TAP; - p.dev_name = tokens[7]; + strcpy(p.dev_name, tokens[7]); } else if (strcmp(tokens[6], "sink") == 0) { if ((n_tokens != 7) && (n_tokens != 11)) { snprintf(out, out_size, MSG_ARG_MISMATCH, @@ -1996,8 +2147,6 @@ cmd_pipeline_port_out(struct pmd_internals *softnic, p.type = PORT_OUT_SINK; - p.dev_name = NULL; - if (n_tokens == 7) { p.sink.file_name = NULL; p.sink.max_n_pkts = 0; @@ -2021,6 +2170,40 @@ cmd_pipeline_port_out(struct pmd_internals *softnic, return; } } + } else if (strcmp(tokens[6], "cryptodev") == 0) { + if (n_tokens != 12) { + snprintf(out, out_size, MSG_ARG_MISMATCH, + "pipeline port out cryptodev"); + return; + } + + p.type = PORT_OUT_CRYPTODEV; + + strlcpy(p.dev_name, tokens[7], sizeof(p.dev_name)); + + if (strcmp(tokens[8], "txq")) { + snprintf(out, out_size, MSG_ARG_MISMATCH, + "pipeline port out cryptodev"); + return; + } + + if (softnic_parser_read_uint16(&p.cryptodev.queue_id, tokens[9]) + != 0) { + snprintf(out, out_size, MSG_ARG_INVALID, "queue_id"); + return; + } + + if (strcmp(tokens[10], "offset")) { + snprintf(out, out_size, MSG_ARG_MISMATCH, + "pipeline port out cryptodev"); + return; + } + + if (softnic_parser_read_uint32(&p.cryptodev.op_offset, + tokens[11]) != 0) { + snprintf(out, out_size, MSG_ARG_INVALID, "queue_id"); + return; + } } else { snprintf(out, out_size, MSG_ARG_INVALID, tokens[0]); return; @@ -2064,12 +2247,13 @@ cmd_pipeline_table(struct pmd_internals *softnic, char *out, size_t out_size) { - uint8_t key_mask[TABLE_RULE_MATCH_SIZE_MAX]; struct softnic_table_params p; char *pipeline_name; uint32_t t0; int status; + memset(&p, 0, sizeof(p)); + if (n_tokens < 5) { snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); return; @@ -2203,12 +2387,11 @@ cmd_pipeline_table(struct pmd_internals *softnic, } if ((softnic_parse_hex_string(tokens[t0 + 5], - key_mask, &key_mask_size) != 0) || + p.match.hash.key_mask, &key_mask_size) != 0) || key_mask_size != p.match.hash.key_size) { snprintf(out, out_size, MSG_ARG_INVALID, "key_mask"); return; } - p.match.hash.key_mask = key_mask; if (strcmp(tokens[t0 + 6], "offset") != 0) { snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset"); @@ -2295,7 +2478,6 @@ cmd_pipeline_table(struct pmd_internals *softnic, return; } - p.action_profile_name = NULL; if (n_tokens > t0 && (strcmp(tokens[t0], "action") == 0)) { if (n_tokens < t0 + 2) { @@ -2303,7 +2485,7 @@ cmd_pipeline_table(struct pmd_internals *softnic, return; } - p.action_profile_name = tokens[t0 + 1]; + strcpy(p.action_profile_name, tokens[t0 + 1]); t0 += 2; } @@ -3176,10 +3358,30 @@ parse_match(char **tokens, * [label2 <label> <tc> <ttl> * [label3 <label> <tc> <ttl>]]] * | pppoe <da> <sa> <session_id>] + * | vxlan ether <da> <sa> + * [vlan <pcp> <dei> <vid>] + * ipv4 <sa> <da> <dscp> <ttl> + * | ipv6 <sa> <da> <flow_label> <dscp> <hop_limit> + * udp <sp> <dp> + * vxlan <vni>] * [nat ipv4 | ipv6 <addr> <port>] * [ttl dec | keep] * [stats] * [time] + * [tag <tag>] + * [decap <n>] + * [sym_crypto + * encrypt | decrypt + * type + * | cipher + * cipher_algo <algo> cipher_key <key> cipher_iv <iv> + * | cipher_auth + * cipher_algo <algo> cipher_key <key> cipher_iv <iv> + * auth_algo <algo> auth_key <key> digest_size <size> + * | aead + * aead_algo <algo> aead_key <key> aead_iv <iv> aead_aad <aad> + * digest_size <size> + * data_offset <data_offset>] * * where: * <pa> ::= g | y | r | drop @@ -3575,6 +3777,122 @@ parse_table_action_encap(char **tokens, return 1 + 4; } + /* vxlan */ + if (n_tokens && (strcmp(tokens[0], "vxlan") == 0)) { + uint32_t n = 0; + + n_tokens--; + tokens++; + n++; + + /* ether <da> <sa> */ + if ((n_tokens < 3) || + strcmp(tokens[0], "ether") || + softnic_parse_mac_addr(tokens[1], &a->encap.vxlan.ether.da) || + softnic_parse_mac_addr(tokens[2], &a->encap.vxlan.ether.sa)) + return 0; + + n_tokens -= 3; + tokens += 3; + n += 3; + + /* [vlan <pcp> <dei> <vid>] */ + if (strcmp(tokens[0], "vlan") == 0) { + uint32_t pcp, dei, vid; + + if ((n_tokens < 4) || + softnic_parser_read_uint32(&pcp, tokens[1]) || + (pcp > 7) || + softnic_parser_read_uint32(&dei, tokens[2]) || + (dei > 1) || + softnic_parser_read_uint32(&vid, tokens[3]) || + (vid > 0xFFF)) + return 0; + + a->encap.vxlan.vlan.pcp = pcp; + a->encap.vxlan.vlan.dei = dei; + a->encap.vxlan.vlan.vid = vid; + + n_tokens -= 4; + tokens += 4; + n += 4; + } + + /* ipv4 <sa> <da> <dscp> <ttl> + | ipv6 <sa> <da> <flow_label> <dscp> <hop_limit> */ + if (strcmp(tokens[0], "ipv4") == 0) { + struct in_addr sa, da; + uint8_t dscp, ttl; + + if ((n_tokens < 5) || + softnic_parse_ipv4_addr(tokens[1], &sa) || + softnic_parse_ipv4_addr(tokens[2], &da) || + softnic_parser_read_uint8(&dscp, tokens[3]) || + (dscp > 64) || + softnic_parser_read_uint8(&ttl, tokens[4])) + return 0; + + a->encap.vxlan.ipv4.sa = rte_be_to_cpu_32(sa.s_addr); + a->encap.vxlan.ipv4.da = rte_be_to_cpu_32(da.s_addr); + a->encap.vxlan.ipv4.dscp = dscp; + a->encap.vxlan.ipv4.ttl = ttl; + + n_tokens -= 5; + tokens += 5; + n += 5; + } else if (strcmp(tokens[0], "ipv6") == 0) { + struct in6_addr sa, da; + uint32_t flow_label; + uint8_t dscp, hop_limit; + + if ((n_tokens < 6) || + softnic_parse_ipv6_addr(tokens[1], &sa) || + softnic_parse_ipv6_addr(tokens[2], &da) || + softnic_parser_read_uint32(&flow_label, tokens[3]) || + softnic_parser_read_uint8(&dscp, tokens[4]) || + (dscp > 64) || + softnic_parser_read_uint8(&hop_limit, tokens[5])) + return 0; + + memcpy(a->encap.vxlan.ipv6.sa, sa.s6_addr, 16); + memcpy(a->encap.vxlan.ipv6.da, da.s6_addr, 16); + a->encap.vxlan.ipv6.flow_label = flow_label; + a->encap.vxlan.ipv6.dscp = dscp; + a->encap.vxlan.ipv6.hop_limit = hop_limit; + + n_tokens -= 6; + tokens += 6; + n += 6; + } else + return 0; + + /* udp <sp> <dp> */ + if ((n_tokens < 3) || + strcmp(tokens[0], "udp") || + softnic_parser_read_uint16(&a->encap.vxlan.udp.sp, tokens[1]) || + softnic_parser_read_uint16(&a->encap.vxlan.udp.dp, tokens[2])) + return 0; + + n_tokens -= 3; + tokens += 3; + n += 3; + + /* vxlan <vni> */ + if ((n_tokens < 2) || + strcmp(tokens[0], "vxlan") || + softnic_parser_read_uint32(&a->encap.vxlan.vxlan.vni, tokens[1]) || + (a->encap.vxlan.vxlan.vni > 0xFFFFFF)) + return 0; + + n_tokens -= 2; + tokens += 2; + n += 2; + + a->encap.type = RTE_TABLE_ACTION_ENCAP_VXLAN; + a->action_mask |= 1 << RTE_TABLE_ACTION_ENCAP; + return 1 + n; + } + return 0; } @@ -3669,6 +3987,400 @@ parse_table_action_time(char **tokens, return 1; } +static void +parse_free_sym_crypto_param_data(struct rte_table_action_sym_crypto_params *p) +{ + struct rte_crypto_sym_xform *xform[2] = {NULL}; + uint32_t i; + + xform[0] = p->xform; + if (xform[0]) + xform[1] = xform[0]->next; + + for (i = 0; i < 2; i++) { + if (xform[i] == NULL) + continue; + + switch (xform[i]->type) { + case RTE_CRYPTO_SYM_XFORM_CIPHER: + if (xform[i]->cipher.key.data) + free(xform[i]->cipher.key.data); + if (p->cipher_auth.cipher_iv.val) + free(p->cipher_auth.cipher_iv.val); + if (p->cipher_auth.cipher_iv_update.val) + free(p->cipher_auth.cipher_iv_update.val); + break; + case RTE_CRYPTO_SYM_XFORM_AUTH: + if (xform[i]->auth.key.data) + free(xform[i]->cipher.key.data); + if (p->cipher_auth.auth_iv.val) + free(p->cipher_auth.cipher_iv.val); + if (p->cipher_auth.auth_iv_update.val) + free(p->cipher_auth.cipher_iv_update.val); + break; + case RTE_CRYPTO_SYM_XFORM_AEAD: + if (xform[i]->aead.key.data) + free(xform[i]->cipher.key.data); + if (p->aead.iv.val) + free(p->aead.iv.val); + if (p->aead.aad.val) + free(p->aead.aad.val); + break; + default: + continue; + } + } + +} + +static struct rte_crypto_sym_xform * +parse_table_action_cipher(struct rte_table_action_sym_crypto_params *p, + char **tokens, uint32_t n_tokens, uint32_t encrypt, + uint32_t *used_n_tokens) +{ + struct rte_crypto_sym_xform *xform_cipher; + int status; + size_t len; + + if (n_tokens < 7 || strcmp(tokens[1], "cipher_algo") || + strcmp(tokens[3], "cipher_key") || + strcmp(tokens[5], "cipher_iv")) + return NULL; + + xform_cipher = calloc(1, sizeof(*xform_cipher)); + if (xform_cipher == NULL) + return NULL; + + xform_cipher->type = RTE_CRYPTO_SYM_XFORM_CIPHER; + xform_cipher->cipher.op = encrypt ? RTE_CRYPTO_CIPHER_OP_ENCRYPT : + RTE_CRYPTO_CIPHER_OP_DECRYPT; + + /* cipher_algo */ + status = rte_cryptodev_get_cipher_algo_enum( + &xform_cipher->cipher.algo, tokens[2]); + if (status < 0) + goto error_exit; + + /* cipher_key */ + len = strlen(tokens[4]); + xform_cipher->cipher.key.data = calloc(1, len / 2 + 1); + if (xform_cipher->cipher.key.data == NULL) + goto error_exit; + + status = softnic_parse_hex_string(tokens[4], + xform_cipher->cipher.key.data, + (uint32_t *)&len); + if (status < 0) + goto error_exit; + + xform_cipher->cipher.key.length = (uint16_t)len; + + /* cipher_iv */ + len = strlen(tokens[6]); + + p->cipher_auth.cipher_iv.val = calloc(1, len / 2 + 1); + if (p->cipher_auth.cipher_iv.val == NULL) + goto error_exit; + + status = softnic_parse_hex_string(tokens[6], + p->cipher_auth.cipher_iv.val, + (uint32_t *)&len); + if (status < 0) + goto error_exit; + + xform_cipher->cipher.iv.length = (uint16_t)len; + xform_cipher->cipher.iv.offset = RTE_TABLE_ACTION_SYM_CRYPTO_IV_OFFSET; + p->cipher_auth.cipher_iv.length = (uint32_t)len; + *used_n_tokens = 7; + + return xform_cipher; + +error_exit: + if (xform_cipher->cipher.key.data) + free(xform_cipher->cipher.key.data); + + if (p->cipher_auth.cipher_iv.val) { + free(p->cipher_auth.cipher_iv.val); + p->cipher_auth.cipher_iv.val = NULL; + } + + free(xform_cipher); + + return NULL; +} + +static struct rte_crypto_sym_xform * +parse_table_action_cipher_auth(struct rte_table_action_sym_crypto_params *p, + char **tokens, uint32_t n_tokens, uint32_t encrypt, + uint32_t *used_n_tokens) +{ + struct rte_crypto_sym_xform *xform_cipher; + struct rte_crypto_sym_xform *xform_auth; + int status; + size_t len; + + if (n_tokens < 13 || + strcmp(tokens[7], "auth_algo") || + strcmp(tokens[9], "auth_key") || + strcmp(tokens[11], "digest_size")) + return NULL; + + xform_auth = calloc(1, sizeof(*xform_auth)); + if (xform_auth == NULL) + return NULL; + + xform_auth->type = RTE_CRYPTO_SYM_XFORM_AUTH; + xform_auth->auth.op = encrypt ? RTE_CRYPTO_AUTH_OP_GENERATE : + RTE_CRYPTO_AUTH_OP_VERIFY; + + /* auth_algo */ + status = rte_cryptodev_get_auth_algo_enum(&xform_auth->auth.algo, + tokens[8]); + if (status < 0) + goto error_exit; + + /* auth_key */ + len = strlen(tokens[10]); + xform_auth->auth.key.data = calloc(1, len / 2 + 1); + if (xform_auth->auth.key.data == NULL) + goto error_exit; + + status = softnic_parse_hex_string(tokens[10], + xform_auth->auth.key.data, (uint32_t *)&len); + if (status < 0) + goto error_exit; + + xform_auth->auth.key.length = (uint16_t)len; + + if (strcmp(tokens[11], "digest_size")) + goto error_exit; + + status = softnic_parser_read_uint16(&xform_auth->auth.digest_length, + tokens[12]); + if (status < 0) + goto error_exit; + + xform_cipher = parse_table_action_cipher(p, tokens, 7, encrypt, + used_n_tokens); + if (xform_cipher == NULL) + goto error_exit; + + *used_n_tokens += 6; + + if (encrypt) { + xform_cipher->next = xform_auth; + return xform_cipher; + } else { + xform_auth->next = xform_cipher; + return xform_auth; + } + +error_exit: + if (xform_auth->auth.key.data) + free(xform_auth->auth.key.data); + if (p->cipher_auth.auth_iv.val) { + free(p->cipher_auth.auth_iv.val); + p->cipher_auth.auth_iv.val = 0; + } + + free(xform_auth); + + return NULL; +} + +static struct rte_crypto_sym_xform * +parse_table_action_aead(struct rte_table_action_sym_crypto_params *p, + char **tokens, uint32_t n_tokens, uint32_t encrypt, + uint32_t *used_n_tokens) +{ + struct rte_crypto_sym_xform *xform_aead; + int status; + size_t len; + + if (n_tokens < 11 || strcmp(tokens[1], "aead_algo") || + strcmp(tokens[3], "aead_key") || + strcmp(tokens[5], "aead_iv") || + strcmp(tokens[7], "aead_aad") || + strcmp(tokens[9], "digest_size")) + return NULL; + + xform_aead = calloc(1, sizeof(*xform_aead)); + if (xform_aead == NULL) + return NULL; + + xform_aead->type = RTE_CRYPTO_SYM_XFORM_AEAD; + xform_aead->aead.op = encrypt ? RTE_CRYPTO_AEAD_OP_ENCRYPT : + RTE_CRYPTO_AEAD_OP_DECRYPT; + + /* aead_algo */ + status = rte_cryptodev_get_aead_algo_enum(&xform_aead->aead.algo, + tokens[2]); + if (status < 0) + goto error_exit; + + /* aead_key */ + len = strlen(tokens[4]); + xform_aead->aead.key.data = calloc(1, len / 2 + 1); + if (xform_aead->aead.key.data == NULL) + goto error_exit; + + status = softnic_parse_hex_string(tokens[4], xform_aead->aead.key.data, + (uint32_t *)&len); + if (status < 0) + goto error_exit; + + xform_aead->aead.key.length = (uint16_t)len; + + /* aead_iv */ + len = strlen(tokens[6]); + p->aead.iv.val = calloc(1, len / 2 + 1); + if (p->aead.iv.val == NULL) + goto error_exit; + + status = softnic_parse_hex_string(tokens[6], p->aead.iv.val, + (uint32_t *)&len); + if (status < 0) + goto error_exit; + + xform_aead->aead.iv.length = (uint16_t)len; + xform_aead->aead.iv.offset = RTE_TABLE_ACTION_SYM_CRYPTO_IV_OFFSET; + p->aead.iv.length = (uint32_t)len; + + /* aead_aad */ + len = strlen(tokens[8]); + p->aead.aad.val = calloc(1, len / 2 + 1); + if (p->aead.aad.val == NULL) + goto error_exit; + + status = softnic_parse_hex_string(tokens[8], p->aead.aad.val, (uint32_t *)&len); + if (status < 0) + goto error_exit; + + xform_aead->aead.aad_length = (uint16_t)len; + p->aead.aad.length = (uint32_t)len; + + /* digest_size */ + status = softnic_parser_read_uint16(&xform_aead->aead.digest_length, + tokens[10]); + if (status < 0) + goto error_exit; + + *used_n_tokens = 11; + + return xform_aead; + +error_exit: + if (xform_aead->aead.key.data) + free(xform_aead->aead.key.data); + if (p->aead.iv.val) { + free(p->aead.iv.val); + p->aead.iv.val = NULL; + } + if (p->aead.aad.val) { + free(p->aead.aad.val); + p->aead.aad.val = NULL; + } + + free(xform_aead); + + return NULL; +} + + +static uint32_t +parse_table_action_sym_crypto(char **tokens, + uint32_t n_tokens, + struct softnic_table_rule_action *a) +{ + struct rte_table_action_sym_crypto_params *p = &a->sym_crypto; + struct rte_crypto_sym_xform *xform = NULL; + uint32_t used_n_tokens; + uint32_t encrypt; + int status; + + if ((n_tokens < 12) || + strcmp(tokens[0], "sym_crypto") || + strcmp(tokens[2], "type")) + return 0; + + memset(p, 0, sizeof(*p)); + + if (strcmp(tokens[1], "encrypt") == 0) + encrypt = 1; + else + encrypt = 0; + + status = softnic_parser_read_uint32(&p->data_offset, tokens[n_tokens - 1]); + if (status < 0) + return 0; + + if (strcmp(tokens[3], "cipher") == 0) { + tokens += 3; + n_tokens -= 3; + + xform = parse_table_action_cipher(p, tokens, n_tokens, encrypt, + &used_n_tokens); + } else if (strcmp(tokens[3], "cipher_auth") == 0) { + tokens += 3; + n_tokens -= 3; + + xform = parse_table_action_cipher_auth(p, tokens, n_tokens, + encrypt, &used_n_tokens); + } else if (strcmp(tokens[3], "aead") == 0) { + tokens += 3; + n_tokens -= 3; + + xform = parse_table_action_aead(p, tokens, n_tokens, encrypt, + &used_n_tokens); + } + + if (xform == NULL) + return 0; + + p->xform = xform; + + if (strcmp(tokens[used_n_tokens], "data_offset")) { + parse_free_sym_crypto_param_data(p); + return 0; + } + + a->action_mask |= 1 << RTE_TABLE_ACTION_SYM_CRYPTO; + + return used_n_tokens + 5; +} + +static uint32_t +parse_table_action_tag(char **tokens, + uint32_t n_tokens, + struct softnic_table_rule_action *a) +{ + if (n_tokens < 2 || + strcmp(tokens[0], "tag")) + return 0; + + if (softnic_parser_read_uint32(&a->tag.tag, tokens[1])) + return 0; + + a->action_mask |= 1 << RTE_TABLE_ACTION_TAG; + return 2; +} + +static uint32_t +parse_table_action_decap(char **tokens, + uint32_t n_tokens, + struct softnic_table_rule_action *a) +{ + if (n_tokens < 2 || + strcmp(tokens[0], "decap")) + return 0; + + if (softnic_parser_read_uint16(&a->decap.n, tokens[1])) + return 0; + + a->action_mask |= 1 << RTE_TABLE_ACTION_DECAP; + return 2; +} + static uint32_t parse_table_action(char **tokens, uint32_t n_tokens, @@ -3813,6 +4525,47 @@ parse_table_action(char **tokens, n_tokens -= n; } + if (n_tokens && (strcmp(tokens[0], "tag") == 0)) { + uint32_t n; + + n = parse_table_action_tag(tokens, n_tokens, a); + if (n == 0) { + snprintf(out, out_size, MSG_ARG_INVALID, + "action tag"); + return 0; + } + + tokens += n; + n_tokens -= n; + } + + if (n_tokens && (strcmp(tokens[0], "decap") == 0)) { + uint32_t n; + + n = parse_table_action_decap(tokens, n_tokens, a); + if (n == 0) { + snprintf(out, out_size, MSG_ARG_INVALID, + "action decap"); + return 0; + } + + tokens += n; + n_tokens -= n; + } + + if (n_tokens && (strcmp(tokens[0], "sym_crypto") == 0)) { + uint32_t n; + + n = parse_table_action_sym_crypto(tokens, n_tokens, a); + if (n == 0) { + snprintf(out, out_size, MSG_ARG_INVALID, + "action sym_crypto"); + } + + tokens += n; + n_tokens -= n; + } + if (n_tokens0 - n_tokens == 1) { snprintf(out, out_size, MSG_ARG_INVALID, "action"); return 0; @@ -4797,6 +5550,81 @@ cmd_softnic_thread_pipeline_disable(struct pmd_internals *softnic, } } +/** + * flowapi map + * group <group_id> + * ingress | egress + * pipeline <pipeline_name> + * table <table_id> + */ +static void +cmd_softnic_flowapi_map(struct pmd_internals *softnic, + char **tokens, + uint32_t n_tokens, + char *out, + size_t out_size) +{ + char *pipeline_name; + uint32_t group_id, table_id; + int ingress, status; + + if (n_tokens != 9) { + snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); + return; + } + + if (strcmp(tokens[1], "map") != 0) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "map"); + return; + } + + if (strcmp(tokens[2], "group") != 0) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "group"); + return; + } + + if (softnic_parser_read_uint32(&group_id, tokens[3]) != 0) { + snprintf(out, out_size, MSG_ARG_INVALID, "group_id"); + return; + } + + if (strcmp(tokens[4], "ingress") == 0) { + ingress = 1; + } else if (strcmp(tokens[4], "egress") == 0) { + ingress = 0; + } else { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "ingress | egress"); + return; + } + + if (strcmp(tokens[5], "pipeline") != 0) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pipeline"); + return; + } + + pipeline_name = tokens[6]; + + if (strcmp(tokens[7], "table") != 0) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "table"); + return; + } + + if (softnic_parser_read_uint32(&table_id, tokens[8]) != 0) { + snprintf(out, out_size, MSG_ARG_INVALID, "table_id"); + return; + } + + status = flow_attr_map_set(softnic, + group_id, + ingress, + pipeline_name, + table_id); + if (status) { + snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); + return; + } +} + void softnic_cli_process(char *in, char *out, size_t out_size, void *arg) { @@ -4877,6 +5705,11 @@ softnic_cli_process(char *in, char *out, size_t out_size, void *arg) return; } + if (strcmp(tokens[0], "cryptodev") == 0) { + cmd_cryptodev(softnic, tokens, n_tokens, out, out_size); + return; + } + if (strcmp(tokens[0], "port") == 0) { cmd_port_in_action_profile(softnic, tokens, n_tokens, out, out_size); return; @@ -5089,6 +5922,12 @@ softnic_cli_process(char *in, char *out, size_t out_size, void *arg) } } + if (strcmp(tokens[0], "flowapi") == 0) { + cmd_softnic_flowapi_map(softnic, tokens, n_tokens, out, + out_size); + return; + } + snprintf(out, out_size, MSG_CMD_UNKNOWN, tokens[0]); } diff --git a/drivers/net/softnic/rte_eth_softnic_cryptodev.c b/drivers/net/softnic/rte_eth_softnic_cryptodev.c new file mode 100644 index 00000000..1480f6dd --- /dev/null +++ b/drivers/net/softnic/rte_eth_softnic_cryptodev.c @@ -0,0 +1,125 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2018 Intel Corporation + */ + +#include <stdlib.h> +#include <stdio.h> + +#include <rte_cryptodev.h> +#include <rte_cryptodev_pmd.h> +#include <rte_string_fns.h> + +#include "rte_eth_softnic_internals.h" + +int +softnic_cryptodev_init(struct pmd_internals *p) +{ + TAILQ_INIT(&p->cryptodev_list); + + return 0; +} + +void +softnic_cryptodev_free(struct pmd_internals *p) +{ + for ( ; ; ) { + struct softnic_cryptodev *cryptodev; + + cryptodev = TAILQ_FIRST(&p->cryptodev_list); + if (cryptodev == NULL) + break; + + TAILQ_REMOVE(&p->cryptodev_list, cryptodev, node); + free(cryptodev); + } +} + +struct softnic_cryptodev * +softnic_cryptodev_find(struct pmd_internals *p, + const char *name) +{ + struct softnic_cryptodev *cryptodev; + + if (name == NULL) + return NULL; + + TAILQ_FOREACH(cryptodev, &p->cryptodev_list, node) + if (strcmp(cryptodev->name, name) == 0) + return cryptodev; + + return NULL; +} + +struct softnic_cryptodev * +softnic_cryptodev_create(struct pmd_internals *p, + const char *name, + struct softnic_cryptodev_params *params) +{ + struct rte_cryptodev_info dev_info; + struct rte_cryptodev_config dev_conf; + struct rte_cryptodev_qp_conf queue_conf; + struct softnic_cryptodev *cryptodev; + uint32_t dev_id, i; + uint32_t socket_id; + int status; + + /* Check input params */ + if ((name == NULL) || + softnic_cryptodev_find(p, name) || + (params->n_queues == 0) || + (params->queue_size == 0)) + return NULL; + + if (params->dev_name) { + status = rte_cryptodev_get_dev_id(params->dev_name); + if (status == -1) + return NULL; + + dev_id = (uint32_t)status; + } else { + if (rte_cryptodev_pmd_is_valid_dev(params->dev_id) == 0) + return NULL; + + dev_id = params->dev_id; + } + + socket_id = rte_cryptodev_socket_id(dev_id); + rte_cryptodev_info_get(dev_id, &dev_info); + + if (dev_info.max_nb_queue_pairs < params->n_queues) + return NULL; + if (dev_info.feature_flags & RTE_CRYPTODEV_FF_HW_ACCELERATED) + return NULL; + + dev_conf.socket_id = socket_id; + dev_conf.nb_queue_pairs = params->n_queues; + + status = rte_cryptodev_configure(dev_id, &dev_conf); + if (status < 0) + return NULL; + + queue_conf.nb_descriptors = params->queue_size; + for (i = 0; i < params->n_queues; i++) { + status = rte_cryptodev_queue_pair_setup(dev_id, i, + &queue_conf, socket_id, NULL); + if (status < 0) + return NULL; + } + + if (rte_cryptodev_start(dev_id) < 0) + return NULL; + + cryptodev = calloc(1, sizeof(struct softnic_cryptodev)); + if (cryptodev == NULL) { + rte_cryptodev_stop(dev_id); + return NULL; + } + + strlcpy(cryptodev->name, name, sizeof(cryptodev->name)); + cryptodev->dev_id = dev_id; + cryptodev->n_queues = params->n_queues; + + TAILQ_INSERT_TAIL(&p->cryptodev_list, cryptodev, node); + + return cryptodev; +} diff --git a/drivers/net/softnic/rte_eth_softnic_flow.c b/drivers/net/softnic/rte_eth_softnic_flow.c new file mode 100644 index 00000000..285af462 --- /dev/null +++ b/drivers/net/softnic/rte_eth_softnic_flow.c @@ -0,0 +1,2287 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2018 Intel Corporation + */ +#include <stdint.h> +#include <stdlib.h> +#include <string.h> + +#include <rte_common.h> +#include <rte_byteorder.h> +#include <rte_malloc.h> +#include <rte_string_fns.h> +#include <rte_flow.h> +#include <rte_flow_driver.h> +#include <rte_tailq.h> + +#include "rte_eth_softnic_internals.h" +#include "rte_eth_softnic.h" + +#define rte_htons rte_cpu_to_be_16 +#define rte_htonl rte_cpu_to_be_32 + +#define rte_ntohs rte_be_to_cpu_16 +#define rte_ntohl rte_be_to_cpu_32 + +static struct rte_flow * +softnic_flow_find(struct softnic_table *table, + struct softnic_table_rule_match *rule_match) +{ + struct rte_flow *flow; + + TAILQ_FOREACH(flow, &table->flows, node) + if (memcmp(&flow->match, rule_match, sizeof(*rule_match)) == 0) + return flow; + + return NULL; +} + +int +flow_attr_map_set(struct pmd_internals *softnic, + uint32_t group_id, + int ingress, + const char *pipeline_name, + uint32_t table_id) +{ + struct pipeline *pipeline; + struct flow_attr_map *map; + + if (group_id >= SOFTNIC_FLOW_MAX_GROUPS || + pipeline_name == NULL) + return -1; + + pipeline = softnic_pipeline_find(softnic, pipeline_name); + if (pipeline == NULL || + table_id >= pipeline->n_tables) + return -1; + + map = (ingress) ? &softnic->flow.ingress_map[group_id] : + &softnic->flow.egress_map[group_id]; + strcpy(map->pipeline_name, pipeline_name); + map->table_id = table_id; + map->valid = 1; + + return 0; +} + +struct flow_attr_map * +flow_attr_map_get(struct pmd_internals *softnic, + uint32_t group_id, + int ingress) +{ + if (group_id >= SOFTNIC_FLOW_MAX_GROUPS) + return NULL; + + return (ingress) ? &softnic->flow.ingress_map[group_id] : + &softnic->flow.egress_map[group_id]; +} + +static int +flow_pipeline_table_get(struct pmd_internals *softnic, + const struct rte_flow_attr *attr, + const char **pipeline_name, + uint32_t *table_id, + struct rte_flow_error *error) +{ + struct flow_attr_map *map; + + if (attr == NULL) + return rte_flow_error_set(error, + EINVAL, + RTE_FLOW_ERROR_TYPE_ATTR, + NULL, + "Null attr"); + + if (!attr->ingress && !attr->egress) + return rte_flow_error_set(error, + EINVAL, + RTE_FLOW_ERROR_TYPE_ATTR_INGRESS, + attr, + "Ingress/egress not specified"); + + if (attr->ingress && attr->egress) + return rte_flow_error_set(error, + EINVAL, + RTE_FLOW_ERROR_TYPE_ATTR_INGRESS, + attr, + "Setting both ingress and egress is not allowed"); + + map = flow_attr_map_get(softnic, + attr->group, + attr->ingress); + if (map == NULL || + map->valid == 0) + return rte_flow_error_set(error, + EINVAL, + RTE_FLOW_ERROR_TYPE_ATTR_GROUP, + attr, + "Invalid group ID"); + + if (pipeline_name) + *pipeline_name = map->pipeline_name; + + if (table_id) + *table_id = map->table_id; + + return 0; +} + +union flow_item { + uint8_t raw[TABLE_RULE_MATCH_SIZE_MAX]; + struct rte_flow_item_eth eth; + struct rte_flow_item_vlan vlan; + struct rte_flow_item_ipv4 ipv4; + struct rte_flow_item_ipv6 ipv6; + struct rte_flow_item_icmp icmp; + struct rte_flow_item_udp udp; + struct rte_flow_item_tcp tcp; + struct rte_flow_item_sctp sctp; + struct rte_flow_item_vxlan vxlan; + struct rte_flow_item_e_tag e_tag; + struct rte_flow_item_nvgre nvgre; + struct rte_flow_item_mpls mpls; + struct rte_flow_item_gre gre; + struct rte_flow_item_gtp gtp; + struct rte_flow_item_esp esp; + struct rte_flow_item_geneve geneve; + struct rte_flow_item_vxlan_gpe vxlan_gpe; + struct rte_flow_item_arp_eth_ipv4 arp_eth_ipv4; + struct rte_flow_item_ipv6_ext ipv6_ext; + struct rte_flow_item_icmp6 icmp6; + struct rte_flow_item_icmp6_nd_ns icmp6_nd_ns; + struct rte_flow_item_icmp6_nd_na icmp6_nd_na; + struct rte_flow_item_icmp6_nd_opt icmp6_nd_opt; + struct rte_flow_item_icmp6_nd_opt_sla_eth icmp6_nd_opt_sla_eth; + struct rte_flow_item_icmp6_nd_opt_tla_eth icmp6_nd_opt_tla_eth; +}; + +static const union flow_item flow_item_raw_mask; + +static int +flow_item_is_proto(enum rte_flow_item_type type, + const void **mask, + size_t *size) +{ + switch (type) { + case RTE_FLOW_ITEM_TYPE_RAW: + *mask = &flow_item_raw_mask; + *size = sizeof(flow_item_raw_mask); + return 1; /* TRUE */ + + case RTE_FLOW_ITEM_TYPE_ETH: + *mask = &rte_flow_item_eth_mask; + *size = sizeof(struct rte_flow_item_eth); + return 1; /* TRUE */ + + case RTE_FLOW_ITEM_TYPE_VLAN: + *mask = &rte_flow_item_vlan_mask; + *size = sizeof(struct rte_flow_item_vlan); + return 1; + + case RTE_FLOW_ITEM_TYPE_IPV4: + *mask = &rte_flow_item_ipv4_mask; + *size = sizeof(struct rte_flow_item_ipv4); + return 1; + + case RTE_FLOW_ITEM_TYPE_IPV6: + *mask = &rte_flow_item_ipv6_mask; + *size = sizeof(struct rte_flow_item_ipv6); + return 1; + + case RTE_FLOW_ITEM_TYPE_ICMP: + *mask = &rte_flow_item_icmp_mask; + *size = sizeof(struct rte_flow_item_icmp); + return 1; + + case RTE_FLOW_ITEM_TYPE_UDP: + *mask = &rte_flow_item_udp_mask; + *size = sizeof(struct rte_flow_item_udp); + return 1; + + case RTE_FLOW_ITEM_TYPE_TCP: + *mask = &rte_flow_item_tcp_mask; + *size = sizeof(struct rte_flow_item_tcp); + return 1; + + case RTE_FLOW_ITEM_TYPE_SCTP: + *mask = &rte_flow_item_sctp_mask; + *size = sizeof(struct rte_flow_item_sctp); + return 1; + + case RTE_FLOW_ITEM_TYPE_VXLAN: + *mask = &rte_flow_item_vxlan_mask; + *size = sizeof(struct rte_flow_item_vxlan); + return 1; + + case RTE_FLOW_ITEM_TYPE_E_TAG: + *mask = &rte_flow_item_e_tag_mask; + *size = sizeof(struct rte_flow_item_e_tag); + return 1; + + case RTE_FLOW_ITEM_TYPE_NVGRE: + *mask = &rte_flow_item_nvgre_mask; + *size = sizeof(struct rte_flow_item_nvgre); + return 1; + + case RTE_FLOW_ITEM_TYPE_MPLS: + *mask = &rte_flow_item_mpls_mask; + *size = sizeof(struct rte_flow_item_mpls); + return 1; + + case RTE_FLOW_ITEM_TYPE_GRE: + *mask = &rte_flow_item_gre_mask; + *size = sizeof(struct rte_flow_item_gre); + return 1; + + case RTE_FLOW_ITEM_TYPE_GTP: + case RTE_FLOW_ITEM_TYPE_GTPC: + case RTE_FLOW_ITEM_TYPE_GTPU: + *mask = &rte_flow_item_gtp_mask; + *size = sizeof(struct rte_flow_item_gtp); + return 1; + + case RTE_FLOW_ITEM_TYPE_ESP: + *mask = &rte_flow_item_esp_mask; + *size = sizeof(struct rte_flow_item_esp); + return 1; + + case RTE_FLOW_ITEM_TYPE_GENEVE: + *mask = &rte_flow_item_geneve_mask; + *size = sizeof(struct rte_flow_item_geneve); + return 1; + + case RTE_FLOW_ITEM_TYPE_VXLAN_GPE: + *mask = &rte_flow_item_vxlan_gpe_mask; + *size = sizeof(struct rte_flow_item_vxlan_gpe); + return 1; + + case RTE_FLOW_ITEM_TYPE_ARP_ETH_IPV4: + *mask = &rte_flow_item_arp_eth_ipv4_mask; + *size = sizeof(struct rte_flow_item_arp_eth_ipv4); + return 1; + + case RTE_FLOW_ITEM_TYPE_IPV6_EXT: + *mask = &rte_flow_item_ipv6_ext_mask; + *size = sizeof(struct rte_flow_item_ipv6_ext); + return 1; + + case RTE_FLOW_ITEM_TYPE_ICMP6: + *mask = &rte_flow_item_icmp6_mask; + *size = sizeof(struct rte_flow_item_icmp6); + return 1; + + case RTE_FLOW_ITEM_TYPE_ICMP6_ND_NS: + *mask = &rte_flow_item_icmp6_nd_ns_mask; + *size = sizeof(struct rte_flow_item_icmp6_nd_ns); + return 1; + + case RTE_FLOW_ITEM_TYPE_ICMP6_ND_NA: + *mask = &rte_flow_item_icmp6_nd_na_mask; + *size = sizeof(struct rte_flow_item_icmp6_nd_na); + return 1; + + case RTE_FLOW_ITEM_TYPE_ICMP6_ND_OPT: + *mask = &rte_flow_item_icmp6_nd_opt_mask; + *size = sizeof(struct rte_flow_item_icmp6_nd_opt); + return 1; + + case RTE_FLOW_ITEM_TYPE_ICMP6_ND_OPT_SLA_ETH: + *mask = &rte_flow_item_icmp6_nd_opt_sla_eth_mask; + *size = sizeof(struct rte_flow_item_icmp6_nd_opt_sla_eth); + return 1; + + case RTE_FLOW_ITEM_TYPE_ICMP6_ND_OPT_TLA_ETH: + *mask = &rte_flow_item_icmp6_nd_opt_tla_eth_mask; + *size = sizeof(struct rte_flow_item_icmp6_nd_opt_tla_eth); + return 1; + + default: return 0; /* FALSE */ + } +} + +static int +flow_item_raw_preprocess(const struct rte_flow_item *item, + union flow_item *item_spec, + union flow_item *item_mask, + size_t *item_size, + int *item_disabled, + struct rte_flow_error *error) +{ + const struct rte_flow_item_raw *item_raw_spec = item->spec; + const struct rte_flow_item_raw *item_raw_mask = item->mask; + const uint8_t *pattern; + const uint8_t *pattern_mask; + uint8_t *spec = (uint8_t *)item_spec; + uint8_t *mask = (uint8_t *)item_mask; + size_t pattern_length, pattern_offset, i; + int disabled; + + if (!item->spec) + return rte_flow_error_set(error, + ENOTSUP, + RTE_FLOW_ERROR_TYPE_ITEM, + item, + "RAW: Null specification"); + + if (item->last) + return rte_flow_error_set(error, + ENOTSUP, + RTE_FLOW_ERROR_TYPE_ITEM, + item, + "RAW: Range not allowed (last must be NULL)"); + + if (item_raw_spec->relative == 0) + return rte_flow_error_set(error, + ENOTSUP, + RTE_FLOW_ERROR_TYPE_ITEM, + item, + "RAW: Absolute offset not supported"); + + if (item_raw_spec->search) + return rte_flow_error_set(error, + ENOTSUP, + RTE_FLOW_ERROR_TYPE_ITEM, + item, + "RAW: Search not supported"); + + if (item_raw_spec->offset < 0) + return rte_flow_error_set(error, + ENOTSUP, RTE_FLOW_ERROR_TYPE_ITEM, + item, + "RAW: Negative offset not supported"); + + if (item_raw_spec->length == 0) + return rte_flow_error_set(error, + ENOTSUP, + RTE_FLOW_ERROR_TYPE_ITEM, + item, + "RAW: Zero pattern length"); + + if (item_raw_spec->offset + item_raw_spec->length > + TABLE_RULE_MATCH_SIZE_MAX) + return rte_flow_error_set(error, + ENOTSUP, + RTE_FLOW_ERROR_TYPE_ITEM, + item, + "RAW: Item too big"); + + if (!item_raw_spec->pattern && item_raw_mask && item_raw_mask->pattern) + return rte_flow_error_set(error, + ENOTSUP, + RTE_FLOW_ERROR_TYPE_ITEM, + item, + "RAW: Non-NULL pattern mask not allowed with NULL pattern"); + + pattern = item_raw_spec->pattern; + pattern_mask = (item_raw_mask) ? item_raw_mask->pattern : NULL; + pattern_length = (size_t)item_raw_spec->length; + pattern_offset = (size_t)item_raw_spec->offset; + + disabled = 0; + if (pattern_mask == NULL) + disabled = 1; + else + for (i = 0; i < pattern_length; i++) + if ((pattern)[i]) + disabled = 1; + + memset(spec, 0, TABLE_RULE_MATCH_SIZE_MAX); + if (pattern) + memcpy(&spec[pattern_offset], pattern, pattern_length); + + memset(mask, 0, TABLE_RULE_MATCH_SIZE_MAX); + if (pattern_mask) + memcpy(&mask[pattern_offset], pattern_mask, pattern_length); + + *item_size = pattern_offset + pattern_length; + *item_disabled = disabled; + + return 0; +} + +static int +flow_item_proto_preprocess(const struct rte_flow_item *item, + union flow_item *item_spec, + union flow_item *item_mask, + size_t *item_size, + int *item_disabled, + struct rte_flow_error *error) +{ + const void *mask_default; + uint8_t *spec = (uint8_t *)item_spec; + uint8_t *mask = (uint8_t *)item_mask; + size_t size, i; + + if (!flow_item_is_proto(item->type, &mask_default, &size)) + return rte_flow_error_set(error, + ENOTSUP, + RTE_FLOW_ERROR_TYPE_ITEM, + item, + "Item type not supported"); + + if (item->type == RTE_FLOW_ITEM_TYPE_RAW) + return flow_item_raw_preprocess(item, + item_spec, + item_mask, + item_size, + item_disabled, + error); + + /* spec */ + if (!item->spec) { + /* If spec is NULL, then last and mask also have to be NULL. */ + if (item->last || item->mask) + return rte_flow_error_set(error, + EINVAL, + RTE_FLOW_ERROR_TYPE_ITEM, + item, + "Invalid item (NULL spec with non-NULL last or mask)"); + + memset(item_spec, 0, size); + memset(item_mask, 0, size); + *item_size = size; + *item_disabled = 1; /* TRUE */ + return 0; + } + + memcpy(spec, item->spec, size); + *item_size = size; + + /* mask */ + if (item->mask) + memcpy(mask, item->mask, size); + else + memcpy(mask, mask_default, size); + + /* disabled */ + for (i = 0; i < size; i++) + if (mask[i]) + break; + *item_disabled = (i == size) ? 1 : 0; + + /* Apply mask over spec. */ + for (i = 0; i < size; i++) + spec[i] &= mask[i]; + + /* last */ + if (item->last) { + uint8_t last[size]; + + /* init last */ + memcpy(last, item->last, size); + for (i = 0; i < size; i++) + last[i] &= mask[i]; + + /* check for range */ + for (i = 0; i < size; i++) + if (last[i] != spec[i]) + return rte_flow_error_set(error, + ENOTSUP, + RTE_FLOW_ERROR_TYPE_ITEM, + item, + "Range not supported"); + } + + return 0; +} + +/*** + * Skip disabled protocol items and VOID items + * until any of the mutually exclusive conditions + * from the list below takes place: + * (A) A protocol present in the proto_mask + * is met (either ENABLED or DISABLED); + * (B) A protocol NOT present in the proto_mask is met in ENABLED state; + * (C) The END item is met. + */ +static int +flow_item_skip_disabled_protos(const struct rte_flow_item **item, + uint64_t proto_mask, + size_t *length, + struct rte_flow_error *error) +{ + size_t len = 0; + + for ( ; (*item)->type != RTE_FLOW_ITEM_TYPE_END; (*item)++) { + union flow_item spec, mask; + size_t size; + int disabled = 0, status; + + if ((*item)->type == RTE_FLOW_ITEM_TYPE_VOID) + continue; + + status = flow_item_proto_preprocess(*item, + &spec, + &mask, + &size, + &disabled, + error); + if (status) + return status; + + if ((proto_mask & (1LLU << (*item)->type)) || + !disabled) + break; + + len += size; + } + + if (length) + *length = len; + + return 0; +} + +#define FLOW_ITEM_PROTO_IP \ + ((1LLU << RTE_FLOW_ITEM_TYPE_IPV4) | \ + (1LLU << RTE_FLOW_ITEM_TYPE_IPV6)) + +static void +flow_item_skip_void(const struct rte_flow_item **item) +{ + for ( ; ; (*item)++) + if ((*item)->type != RTE_FLOW_ITEM_TYPE_VOID) + return; +} + +#define IP_PROTOCOL_TCP 0x06 +#define IP_PROTOCOL_UDP 0x11 +#define IP_PROTOCOL_SCTP 0x84 + +static int +mask_to_depth(uint64_t mask, + uint32_t *depth) +{ + uint64_t n; + + if (mask == UINT64_MAX) { + if (depth) + *depth = 64; + + return 0; + } + + mask = ~mask; + + if (mask & (mask + 1)) + return -1; + + n = __builtin_popcountll(mask); + if (depth) + *depth = (uint32_t)(64 - n); + + return 0; +} + +static int +ipv4_mask_to_depth(uint32_t mask, + uint32_t *depth) +{ + uint32_t d; + int status; + + status = mask_to_depth(mask | (UINT64_MAX << 32), &d); + if (status) + return status; + + d -= 32; + if (depth) + *depth = d; + + return 0; +} + +static int +ipv6_mask_to_depth(uint8_t *mask, + uint32_t *depth) +{ + uint64_t *m = (uint64_t *)mask; + uint64_t m0 = rte_be_to_cpu_64(m[0]); + uint64_t m1 = rte_be_to_cpu_64(m[1]); + uint32_t d0, d1; + int status; + + status = mask_to_depth(m0, &d0); + if (status) + return status; + + status = mask_to_depth(m1, &d1); + if (status) + return status; + + if (d0 < 64 && d1) + return -1; + + if (depth) + *depth = d0 + d1; + + return 0; +} + +static int +port_mask_to_range(uint16_t port, + uint16_t port_mask, + uint16_t *port0, + uint16_t *port1) +{ + int status; + uint16_t p0, p1; + + status = mask_to_depth(port_mask | (UINT64_MAX << 16), NULL); + if (status) + return -1; + + p0 = port & port_mask; + p1 = p0 | ~port_mask; + + if (port0) + *port0 = p0; + + if (port1) + *port1 = p1; + + return 0; +} + +static int +flow_rule_match_acl_get(struct pmd_internals *softnic __rte_unused, + struct pipeline *pipeline __rte_unused, + struct softnic_table *table __rte_unused, + const struct rte_flow_attr *attr, + const struct rte_flow_item *item, + struct softnic_table_rule_match *rule_match, + struct rte_flow_error *error) +{ + union flow_item spec, mask; + size_t size, length = 0; + int disabled = 0, status; + uint8_t ip_proto, ip_proto_mask; + + memset(rule_match, 0, sizeof(*rule_match)); + rule_match->match_type = TABLE_ACL; + rule_match->match.acl.priority = attr->priority; + + /* VOID or disabled protos only, if any. */ + status = flow_item_skip_disabled_protos(&item, + FLOW_ITEM_PROTO_IP, &length, error); + if (status) + return status; + + /* IP only. */ + status = flow_item_proto_preprocess(item, &spec, &mask, + &size, &disabled, error); + if (status) + return status; + + switch (item->type) { + case RTE_FLOW_ITEM_TYPE_IPV4: + { + uint32_t sa_depth, da_depth; + + status = ipv4_mask_to_depth(rte_ntohl(mask.ipv4.hdr.src_addr), + &sa_depth); + if (status) + return rte_flow_error_set(error, + EINVAL, + RTE_FLOW_ERROR_TYPE_ITEM, + item, + "ACL: Illegal IPv4 header source address mask"); + + status = ipv4_mask_to_depth(rte_ntohl(mask.ipv4.hdr.dst_addr), + &da_depth); + if (status) + return rte_flow_error_set(error, + EINVAL, + RTE_FLOW_ERROR_TYPE_ITEM, + item, + "ACL: Illegal IPv4 header destination address mask"); + + ip_proto = spec.ipv4.hdr.next_proto_id; + ip_proto_mask = mask.ipv4.hdr.next_proto_id; + + rule_match->match.acl.ip_version = 1; + rule_match->match.acl.ipv4.sa = + rte_ntohl(spec.ipv4.hdr.src_addr); + rule_match->match.acl.ipv4.da = + rte_ntohl(spec.ipv4.hdr.dst_addr); + rule_match->match.acl.sa_depth = sa_depth; + rule_match->match.acl.da_depth = da_depth; + rule_match->match.acl.proto = ip_proto; + rule_match->match.acl.proto_mask = ip_proto_mask; + break; + } /* RTE_FLOW_ITEM_TYPE_IPV4 */ + + case RTE_FLOW_ITEM_TYPE_IPV6: + { + uint32_t sa_depth, da_depth; + + status = ipv6_mask_to_depth(mask.ipv6.hdr.src_addr, &sa_depth); + if (status) + return rte_flow_error_set(error, + EINVAL, + RTE_FLOW_ERROR_TYPE_ITEM, + item, + "ACL: Illegal IPv6 header source address mask"); + + status = ipv6_mask_to_depth(mask.ipv6.hdr.dst_addr, &da_depth); + if (status) + return rte_flow_error_set(error, + EINVAL, + RTE_FLOW_ERROR_TYPE_ITEM, + item, + "ACL: Illegal IPv6 header destination address mask"); + + ip_proto = spec.ipv6.hdr.proto; + ip_proto_mask = mask.ipv6.hdr.proto; + + rule_match->match.acl.ip_version = 0; + memcpy(rule_match->match.acl.ipv6.sa, + spec.ipv6.hdr.src_addr, + sizeof(spec.ipv6.hdr.src_addr)); + memcpy(rule_match->match.acl.ipv6.da, + spec.ipv6.hdr.dst_addr, + sizeof(spec.ipv6.hdr.dst_addr)); + rule_match->match.acl.sa_depth = sa_depth; + rule_match->match.acl.da_depth = da_depth; + rule_match->match.acl.proto = ip_proto; + rule_match->match.acl.proto_mask = ip_proto_mask; + break; + } /* RTE_FLOW_ITEM_TYPE_IPV6 */ + + default: + return rte_flow_error_set(error, + ENOTSUP, + RTE_FLOW_ERROR_TYPE_ITEM, + item, + "ACL: IP protocol required"); + } /* switch */ + + if (ip_proto_mask != UINT8_MAX) + return rte_flow_error_set(error, + EINVAL, + RTE_FLOW_ERROR_TYPE_ITEM, + item, + "ACL: Illegal IP protocol mask"); + + item++; + + /* VOID only, if any. */ + flow_item_skip_void(&item); + + /* TCP/UDP/SCTP only. */ + status = flow_item_proto_preprocess(item, &spec, &mask, + &size, &disabled, error); + if (status) + return status; + + switch (item->type) { + case RTE_FLOW_ITEM_TYPE_TCP: + { + uint16_t sp0, sp1, dp0, dp1; + + if (ip_proto != IP_PROTOCOL_TCP) + return rte_flow_error_set(error, + EINVAL, + RTE_FLOW_ERROR_TYPE_ITEM, + item, + "ACL: Item type is TCP, but IP protocol is not"); + + status = port_mask_to_range(rte_ntohs(spec.tcp.hdr.src_port), + rte_ntohs(mask.tcp.hdr.src_port), + &sp0, + &sp1); + + if (status) + return rte_flow_error_set(error, + EINVAL, + RTE_FLOW_ERROR_TYPE_ITEM, + item, + "ACL: Illegal TCP source port mask"); + + status = port_mask_to_range(rte_ntohs(spec.tcp.hdr.dst_port), + rte_ntohs(mask.tcp.hdr.dst_port), + &dp0, + &dp1); + + if (status) + return rte_flow_error_set(error, + EINVAL, + RTE_FLOW_ERROR_TYPE_ITEM, + item, + "ACL: Illegal TCP destination port mask"); + + rule_match->match.acl.sp0 = sp0; + rule_match->match.acl.sp1 = sp1; + rule_match->match.acl.dp0 = dp0; + rule_match->match.acl.dp1 = dp1; + + break; + } /* RTE_FLOW_ITEM_TYPE_TCP */ + + case RTE_FLOW_ITEM_TYPE_UDP: + { + uint16_t sp0, sp1, dp0, dp1; + + if (ip_proto != IP_PROTOCOL_UDP) + return rte_flow_error_set(error, + EINVAL, + RTE_FLOW_ERROR_TYPE_ITEM, + item, + "ACL: Item type is UDP, but IP protocol is not"); + + status = port_mask_to_range(rte_ntohs(spec.udp.hdr.src_port), + rte_ntohs(mask.udp.hdr.src_port), + &sp0, + &sp1); + if (status) + return rte_flow_error_set(error, + EINVAL, + RTE_FLOW_ERROR_TYPE_ITEM, + item, + "ACL: Illegal UDP source port mask"); + + status = port_mask_to_range(rte_ntohs(spec.udp.hdr.dst_port), + rte_ntohs(mask.udp.hdr.dst_port), + &dp0, + &dp1); + if (status) + return rte_flow_error_set(error, + EINVAL, + RTE_FLOW_ERROR_TYPE_ITEM, + item, + "ACL: Illegal UDP destination port mask"); + + rule_match->match.acl.sp0 = sp0; + rule_match->match.acl.sp1 = sp1; + rule_match->match.acl.dp0 = dp0; + rule_match->match.acl.dp1 = dp1; + + break; + } /* RTE_FLOW_ITEM_TYPE_UDP */ + + case RTE_FLOW_ITEM_TYPE_SCTP: + { + uint16_t sp0, sp1, dp0, dp1; + + if (ip_proto != IP_PROTOCOL_SCTP) + return rte_flow_error_set(error, + EINVAL, + RTE_FLOW_ERROR_TYPE_ITEM, + item, + "ACL: Item type is SCTP, but IP protocol is not"); + + status = port_mask_to_range(rte_ntohs(spec.sctp.hdr.src_port), + rte_ntohs(mask.sctp.hdr.src_port), + &sp0, + &sp1); + + if (status) + return rte_flow_error_set(error, + EINVAL, + RTE_FLOW_ERROR_TYPE_ITEM, + item, + "ACL: Illegal SCTP source port mask"); + + status = port_mask_to_range(rte_ntohs(spec.sctp.hdr.dst_port), + rte_ntohs(mask.sctp.hdr.dst_port), + &dp0, + &dp1); + if (status) + return rte_flow_error_set(error, + EINVAL, + RTE_FLOW_ERROR_TYPE_ITEM, + item, + "ACL: Illegal SCTP destination port mask"); + + rule_match->match.acl.sp0 = sp0; + rule_match->match.acl.sp1 = sp1; + rule_match->match.acl.dp0 = dp0; + rule_match->match.acl.dp1 = dp1; + + break; + } /* RTE_FLOW_ITEM_TYPE_SCTP */ + + default: + return rte_flow_error_set(error, + ENOTSUP, + RTE_FLOW_ERROR_TYPE_ITEM, + item, + "ACL: TCP/UDP/SCTP required"); + } /* switch */ + + item++; + + /* VOID or disabled protos only, if any. */ + status = flow_item_skip_disabled_protos(&item, 0, NULL, error); + if (status) + return status; + + /* END only. */ + if (item->type != RTE_FLOW_ITEM_TYPE_END) + return rte_flow_error_set(error, + EINVAL, + RTE_FLOW_ERROR_TYPE_ITEM, + item, + "ACL: Expecting END item"); + + return 0; +} + +/*** + * Both *tmask* and *fmask* are byte arrays of size *tsize* and *fsize* + * respectively. + * They are located within a larger buffer at offsets *toffset* and *foffset* + * respectivelly. Both *tmask* and *fmask* represent bitmasks for the larger + * buffer. + * Question: are the two masks equivalent? + * + * Notes: + * 1. Offset basically indicates that the first offset bytes in the buffer + * are "don't care", so offset is equivalent to pre-pending an "all-zeros" + * array of *offset* bytes to the *mask*. + * 2. Each *mask* might contain a number of zero bytes at the beginning or + * at the end. + * 3. Bytes in the larger buffer after the end of the *mask* are also considered + * "don't care", so they are equivalent to appending an "all-zeros" array of + * bytes to the *mask*. + * + * Example: + * Buffer = [xx xx xx xx xx xx xx xx], buffer size = 8 bytes + * tmask = [00 22 00 33 00], toffset = 2, tsize = 5 + * => buffer mask = [00 00 00 22 00 33 00 00] + * fmask = [22 00 33], foffset = 3, fsize = 3 => + * => buffer mask = [00 00 00 22 00 33 00 00] + * Therefore, the tmask and fmask from this example are equivalent. + */ +static int +hash_key_mask_is_same(uint8_t *tmask, + size_t toffset, + size_t tsize, + uint8_t *fmask, + size_t foffset, + size_t fsize, + size_t *toffset_plus, + size_t *foffset_plus) +{ + size_t tpos; /* Position of first non-zero byte in the tmask buffer. */ + size_t fpos; /* Position of first non-zero byte in the fmask buffer. */ + + /* Compute tpos and fpos. */ + for (tpos = 0; tmask[tpos] == 0; tpos++) + ; + for (fpos = 0; fmask[fpos] == 0; fpos++) + ; + + if (toffset + tpos != foffset + fpos) + return 0; /* FALSE */ + + tsize -= tpos; + fsize -= fpos; + + if (tsize < fsize) { + size_t i; + + for (i = 0; i < tsize; i++) + if (tmask[tpos + i] != fmask[fpos + i]) + return 0; /* FALSE */ + + for ( ; i < fsize; i++) + if (fmask[fpos + i]) + return 0; /* FALSE */ + } else { + size_t i; + + for (i = 0; i < fsize; i++) + if (tmask[tpos + i] != fmask[fpos + i]) + return 0; /* FALSE */ + + for ( ; i < tsize; i++) + if (tmask[tpos + i]) + return 0; /* FALSE */ + } + + if (toffset_plus) + *toffset_plus = tpos; + + if (foffset_plus) + *foffset_plus = fpos; + + return 1; /* TRUE */ +} + +static int +flow_rule_match_hash_get(struct pmd_internals *softnic __rte_unused, + struct pipeline *pipeline __rte_unused, + struct softnic_table *table, + const struct rte_flow_attr *attr __rte_unused, + const struct rte_flow_item *item, + struct softnic_table_rule_match *rule_match, + struct rte_flow_error *error) +{ + struct softnic_table_rule_match_hash key, key_mask; + struct softnic_table_hash_params *params = &table->params.match.hash; + size_t offset = 0, length = 0, tpos, fpos; + int status; + + memset(&key, 0, sizeof(key)); + memset(&key_mask, 0, sizeof(key_mask)); + + /* VOID or disabled protos only, if any. */ + status = flow_item_skip_disabled_protos(&item, 0, &offset, error); + if (status) + return status; + + if (item->type == RTE_FLOW_ITEM_TYPE_END) + return rte_flow_error_set(error, + EINVAL, + RTE_FLOW_ERROR_TYPE_ITEM, + item, + "HASH: END detected too early"); + + /* VOID or any protocols (enabled or disabled). */ + for ( ; item->type != RTE_FLOW_ITEM_TYPE_END; item++) { + union flow_item spec, mask; + size_t size; + int disabled, status; + + if (item->type == RTE_FLOW_ITEM_TYPE_VOID) + continue; + + status = flow_item_proto_preprocess(item, + &spec, + &mask, + &size, + &disabled, + error); + if (status) + return status; + + if (length + size > sizeof(key)) { + if (disabled) + break; + + return rte_flow_error_set(error, + ENOTSUP, + RTE_FLOW_ERROR_TYPE_ITEM, + item, + "HASH: Item too big"); + } + + memcpy(&key.key[length], &spec, size); + memcpy(&key_mask.key[length], &mask, size); + length += size; + } + + if (item->type != RTE_FLOW_ITEM_TYPE_END) { + /* VOID or disabled protos only, if any. */ + status = flow_item_skip_disabled_protos(&item, 0, NULL, error); + if (status) + return status; + + /* END only. */ + if (item->type != RTE_FLOW_ITEM_TYPE_END) + return rte_flow_error_set(error, + EINVAL, + RTE_FLOW_ERROR_TYPE_ITEM, + item, + "HASH: Expecting END item"); + } + + /* Compare flow key mask against table key mask. */ + offset += sizeof(struct rte_mbuf) + RTE_PKTMBUF_HEADROOM; + + if (!hash_key_mask_is_same(params->key_mask, + params->key_offset, + params->key_size, + key_mask.key, + offset, + length, + &tpos, + &fpos)) + return rte_flow_error_set(error, + EINVAL, + RTE_FLOW_ERROR_TYPE_UNSPECIFIED, + NULL, + "HASH: Item list is not observing the match format"); + + /* Rule match. */ + memset(rule_match, 0, sizeof(*rule_match)); + rule_match->match_type = TABLE_HASH; + memcpy(&rule_match->match.hash.key[tpos], + &key.key[fpos], + RTE_MIN(sizeof(rule_match->match.hash.key) - tpos, + length - fpos)); + + return 0; +} + +static int +flow_rule_match_get(struct pmd_internals *softnic, + struct pipeline *pipeline, + struct softnic_table *table, + const struct rte_flow_attr *attr, + const struct rte_flow_item *item, + struct softnic_table_rule_match *rule_match, + struct rte_flow_error *error) +{ + switch (table->params.match_type) { + case TABLE_ACL: + return flow_rule_match_acl_get(softnic, + pipeline, + table, + attr, + item, + rule_match, + error); + + /* FALLTHROUGH */ + + case TABLE_HASH: + return flow_rule_match_hash_get(softnic, + pipeline, + table, + attr, + item, + rule_match, + error); + + /* FALLTHROUGH */ + + default: + return rte_flow_error_set(error, + ENOTSUP, + RTE_FLOW_ERROR_TYPE_UNSPECIFIED, + NULL, + "Unsupported pipeline table match type"); + } +} + +static int +flow_rule_action_get(struct pmd_internals *softnic, + struct pipeline *pipeline, + struct softnic_table *table, + const struct rte_flow_attr *attr, + const struct rte_flow_action *action, + struct softnic_table_rule_action *rule_action, + struct rte_flow_error *error) +{ + struct softnic_table_action_profile *profile; + struct softnic_table_action_profile_params *params; + int n_jump_queue_rss_drop = 0; + int n_count = 0; + int n_mark = 0; + int n_vxlan_decap = 0; + + profile = softnic_table_action_profile_find(softnic, + table->params.action_profile_name); + if (profile == NULL) + return rte_flow_error_set(error, + EINVAL, + RTE_FLOW_ERROR_TYPE_UNSPECIFIED, + action, + "JUMP: Table action profile"); + + params = &profile->params; + + for ( ; action->type != RTE_FLOW_ACTION_TYPE_END; action++) { + if (action->type == RTE_FLOW_ACTION_TYPE_VOID) + continue; + + switch (action->type) { + case RTE_FLOW_ACTION_TYPE_JUMP: + { + const struct rte_flow_action_jump *conf = action->conf; + struct flow_attr_map *map; + + if (conf == NULL) + return rte_flow_error_set(error, + EINVAL, + RTE_FLOW_ERROR_TYPE_ACTION, + action, + "JUMP: Null configuration"); + + if (n_jump_queue_rss_drop) + return rte_flow_error_set(error, + EINVAL, + RTE_FLOW_ERROR_TYPE_ACTION, + action, + "Only one termination action is" + " allowed per flow"); + + if ((params->action_mask & + (1LLU << RTE_TABLE_ACTION_FWD)) == 0) + return rte_flow_error_set(error, + EINVAL, + RTE_FLOW_ERROR_TYPE_UNSPECIFIED, + NULL, + "JUMP action not enabled for this table"); + + n_jump_queue_rss_drop = 1; + + map = flow_attr_map_get(softnic, + conf->group, + attr->ingress); + if (map == NULL || map->valid == 0) + return rte_flow_error_set(error, + EINVAL, + RTE_FLOW_ERROR_TYPE_UNSPECIFIED, + NULL, + "JUMP: Invalid group mapping"); + + if (strcmp(pipeline->name, map->pipeline_name) != 0) + return rte_flow_error_set(error, + ENOTSUP, + RTE_FLOW_ERROR_TYPE_UNSPECIFIED, + NULL, + "JUMP: Jump to table in different pipeline"); + + /* RTE_TABLE_ACTION_FWD */ + rule_action->fwd.action = RTE_PIPELINE_ACTION_TABLE; + rule_action->fwd.id = map->table_id; + rule_action->action_mask |= 1 << RTE_TABLE_ACTION_FWD; + break; + } /* RTE_FLOW_ACTION_TYPE_JUMP */ + + case RTE_FLOW_ACTION_TYPE_QUEUE: + { + char name[NAME_SIZE]; + struct rte_eth_dev *dev; + const struct rte_flow_action_queue *conf = action->conf; + uint32_t port_id; + int status; + + if (conf == NULL) + return rte_flow_error_set(error, + EINVAL, + RTE_FLOW_ERROR_TYPE_ACTION, + action, + "QUEUE: Null configuration"); + + if (n_jump_queue_rss_drop) + return rte_flow_error_set(error, + EINVAL, + RTE_FLOW_ERROR_TYPE_ACTION, + action, + "Only one termination action is allowed" + " per flow"); + + if ((params->action_mask & + (1LLU << RTE_TABLE_ACTION_FWD)) == 0) + return rte_flow_error_set(error, + EINVAL, + RTE_FLOW_ERROR_TYPE_UNSPECIFIED, + NULL, + "QUEUE action not enabled for this table"); + + n_jump_queue_rss_drop = 1; + + dev = ETHDEV(softnic); + if (dev == NULL || + conf->index >= dev->data->nb_rx_queues) + return rte_flow_error_set(error, + EINVAL, + RTE_FLOW_ERROR_TYPE_ACTION, + action, + "QUEUE: Invalid RX queue ID"); + + sprintf(name, "RXQ%u", (uint32_t)conf->index); + + status = softnic_pipeline_port_out_find(softnic, + pipeline->name, + name, + &port_id); + if (status) + return rte_flow_error_set(error, + ENOTSUP, + RTE_FLOW_ERROR_TYPE_ACTION, + action, + "QUEUE: RX queue not accessible from this pipeline"); + + /* RTE_TABLE_ACTION_FWD */ + rule_action->fwd.action = RTE_PIPELINE_ACTION_PORT; + rule_action->fwd.id = port_id; + rule_action->action_mask |= 1 << RTE_TABLE_ACTION_FWD; + break; + } /*RTE_FLOW_ACTION_TYPE_QUEUE */ + + case RTE_FLOW_ACTION_TYPE_RSS: + { + const struct rte_flow_action_rss *conf = action->conf; + uint32_t i; + + if (conf == NULL) + return rte_flow_error_set(error, + EINVAL, + RTE_FLOW_ERROR_TYPE_ACTION, + action, + "RSS: Null configuration"); + + if (!rte_is_power_of_2(conf->queue_num)) + return rte_flow_error_set(error, + EINVAL, + RTE_FLOW_ERROR_TYPE_ACTION_CONF, + conf, + "RSS: Number of queues must be a power of 2"); + + if (conf->queue_num > RTE_DIM(rule_action->lb.out)) + return rte_flow_error_set(error, + EINVAL, + RTE_FLOW_ERROR_TYPE_ACTION_CONF, + conf, + "RSS: Number of queues too big"); + + if (n_jump_queue_rss_drop) + return rte_flow_error_set(error, + EINVAL, + RTE_FLOW_ERROR_TYPE_ACTION, + action, + "Only one termination action is allowed per flow"); + + if (((params->action_mask & + (1LLU << RTE_TABLE_ACTION_FWD)) == 0) || + ((params->action_mask & + (1LLU << RTE_TABLE_ACTION_LB)) == 0)) + return rte_flow_error_set(error, + ENOTSUP, + RTE_FLOW_ERROR_TYPE_UNSPECIFIED, + NULL, + "RSS action not supported by this table"); + + if (params->lb.out_offset != + pipeline->params.offset_port_id) + return rte_flow_error_set(error, + EINVAL, + RTE_FLOW_ERROR_TYPE_UNSPECIFIED, + NULL, + "RSS action not supported by this pipeline"); + + n_jump_queue_rss_drop = 1; + + /* RTE_TABLE_ACTION_LB */ + for (i = 0; i < conf->queue_num; i++) { + char name[NAME_SIZE]; + struct rte_eth_dev *dev; + uint32_t port_id; + int status; + + dev = ETHDEV(softnic); + if (dev == NULL || + conf->queue[i] >= + dev->data->nb_rx_queues) + return rte_flow_error_set(error, + EINVAL, + RTE_FLOW_ERROR_TYPE_ACTION, + action, + "RSS: Invalid RX queue ID"); + + sprintf(name, "RXQ%u", + (uint32_t)conf->queue[i]); + + status = softnic_pipeline_port_out_find(softnic, + pipeline->name, + name, + &port_id); + if (status) + return rte_flow_error_set(error, + ENOTSUP, + RTE_FLOW_ERROR_TYPE_ACTION, + action, + "RSS: RX queue not accessible from this pipeline"); + + rule_action->lb.out[i] = port_id; + } + + for ( ; i < RTE_DIM(rule_action->lb.out); i++) + rule_action->lb.out[i] = + rule_action->lb.out[i % conf->queue_num]; + + rule_action->action_mask |= 1 << RTE_TABLE_ACTION_LB; + + /* RTE_TABLE_ACTION_FWD */ + rule_action->fwd.action = RTE_PIPELINE_ACTION_PORT_META; + rule_action->action_mask |= 1 << RTE_TABLE_ACTION_FWD; + break; + } /* RTE_FLOW_ACTION_TYPE_RSS */ + + case RTE_FLOW_ACTION_TYPE_DROP: + { + const void *conf = action->conf; + + if (conf != NULL) + return rte_flow_error_set(error, + EINVAL, + RTE_FLOW_ERROR_TYPE_ACTION, + action, + "DROP: No configuration required"); + + if (n_jump_queue_rss_drop) + return rte_flow_error_set(error, + EINVAL, + RTE_FLOW_ERROR_TYPE_ACTION, + action, + "Only one termination action is allowed per flow"); + if ((params->action_mask & + (1LLU << RTE_TABLE_ACTION_FWD)) == 0) + return rte_flow_error_set(error, + ENOTSUP, + RTE_FLOW_ERROR_TYPE_UNSPECIFIED, + NULL, + "DROP action not supported by this table"); + + n_jump_queue_rss_drop = 1; + + /* RTE_TABLE_ACTION_FWD */ + rule_action->fwd.action = RTE_PIPELINE_ACTION_DROP; + rule_action->action_mask |= 1 << RTE_TABLE_ACTION_FWD; + break; + } /* RTE_FLOW_ACTION_TYPE_DROP */ + + case RTE_FLOW_ACTION_TYPE_COUNT: + { + const struct rte_flow_action_count *conf = action->conf; + + if (conf == NULL) + return rte_flow_error_set(error, + EINVAL, + RTE_FLOW_ERROR_TYPE_ACTION, + action, + "COUNT: Null configuration"); + + if (conf->shared) + return rte_flow_error_set(error, + ENOTSUP, + RTE_FLOW_ERROR_TYPE_ACTION_CONF, + conf, + "COUNT: Shared counters not supported"); + + if (n_count) + return rte_flow_error_set(error, + ENOTSUP, + RTE_FLOW_ERROR_TYPE_ACTION, + action, + "Only one COUNT action per flow"); + + if ((params->action_mask & + (1LLU << RTE_TABLE_ACTION_STATS)) == 0) + return rte_flow_error_set(error, + ENOTSUP, + RTE_FLOW_ERROR_TYPE_UNSPECIFIED, + NULL, + "COUNT action not supported by this table"); + + n_count = 1; + + /* RTE_TABLE_ACTION_STATS */ + rule_action->stats.n_packets = 0; + rule_action->stats.n_bytes = 0; + rule_action->action_mask |= 1 << RTE_TABLE_ACTION_STATS; + break; + } /* RTE_FLOW_ACTION_TYPE_COUNT */ + + case RTE_FLOW_ACTION_TYPE_MARK: + { + const struct rte_flow_action_mark *conf = action->conf; + + if (conf == NULL) + return rte_flow_error_set(error, + EINVAL, + RTE_FLOW_ERROR_TYPE_ACTION, + action, + "MARK: Null configuration"); + + if (n_mark) + return rte_flow_error_set(error, + ENOTSUP, + RTE_FLOW_ERROR_TYPE_ACTION, + action, + "Only one MARK action per flow"); + + if ((params->action_mask & + (1LLU << RTE_TABLE_ACTION_TAG)) == 0) + return rte_flow_error_set(error, + ENOTSUP, + RTE_FLOW_ERROR_TYPE_UNSPECIFIED, + NULL, + "MARK action not supported by this table"); + + n_mark = 1; + + /* RTE_TABLE_ACTION_TAG */ + rule_action->tag.tag = conf->id; + rule_action->action_mask |= 1 << RTE_TABLE_ACTION_TAG; + break; + } /* RTE_FLOW_ACTION_TYPE_MARK */ + + case RTE_FLOW_ACTION_TYPE_VXLAN_DECAP: + { + const struct rte_flow_action_mark *conf = action->conf; + + if (conf) + return rte_flow_error_set(error, + EINVAL, + RTE_FLOW_ERROR_TYPE_ACTION, + action, + "VXLAN DECAP: Non-null configuration"); + + if (n_vxlan_decap) + return rte_flow_error_set(error, + ENOTSUP, + RTE_FLOW_ERROR_TYPE_ACTION, + action, + "Only one VXLAN DECAP action per flow"); + + if ((params->action_mask & + (1LLU << RTE_TABLE_ACTION_DECAP)) == 0) + return rte_flow_error_set(error, + ENOTSUP, + RTE_FLOW_ERROR_TYPE_UNSPECIFIED, + NULL, + "VXLAN DECAP action not supported by this table"); + + n_vxlan_decap = 1; + + /* RTE_TABLE_ACTION_DECAP */ + rule_action->decap.n = 50; /* Ether/IPv4/UDP/VXLAN */ + rule_action->action_mask |= 1 << RTE_TABLE_ACTION_DECAP; + break; + } /* RTE_FLOW_ACTION_TYPE_VXLAN_DECAP */ + + case RTE_FLOW_ACTION_TYPE_METER: + { + const struct rte_flow_action_meter *conf = action->conf; + struct softnic_mtr_meter_profile *mp; + struct softnic_mtr *m; + uint32_t table_id = table - pipeline->table; + uint32_t meter_profile_id; + int status; + + if ((params->action_mask & (1LLU << RTE_TABLE_ACTION_MTR)) == 0) + return rte_flow_error_set(error, + EINVAL, + RTE_FLOW_ERROR_TYPE_UNSPECIFIED, + NULL, + "METER: Table action not supported"); + + if (params->mtr.n_tc != 1) + return rte_flow_error_set(error, + EINVAL, + RTE_FLOW_ERROR_TYPE_UNSPECIFIED, + NULL, + "METER: Multiple TCs not supported"); + + if (conf == NULL) + return rte_flow_error_set(error, + EINVAL, + RTE_FLOW_ERROR_TYPE_ACTION, + action, + "METER: Null configuration"); + + m = softnic_mtr_find(softnic, conf->mtr_id); + + if (m == NULL) + return rte_flow_error_set(error, + EINVAL, + RTE_FLOW_ERROR_TYPE_ACTION_CONF, + NULL, + "METER: Invalid meter ID"); + + if (m->flow) + return rte_flow_error_set(error, + EINVAL, + RTE_FLOW_ERROR_TYPE_ACTION_CONF, + NULL, + "METER: Meter already attached to a flow"); + + meter_profile_id = m->params.meter_profile_id; + mp = softnic_mtr_meter_profile_find(softnic, meter_profile_id); + + /* Add meter profile to pipeline table */ + if (!softnic_pipeline_table_meter_profile_find(table, + meter_profile_id)) { + struct rte_table_action_meter_profile profile; + + memset(&profile, 0, sizeof(profile)); + profile.alg = RTE_TABLE_ACTION_METER_TRTCM; + profile.trtcm.cir = mp->params.trtcm_rfc2698.cir; + profile.trtcm.pir = mp->params.trtcm_rfc2698.pir; + profile.trtcm.cbs = mp->params.trtcm_rfc2698.cbs; + profile.trtcm.pbs = mp->params.trtcm_rfc2698.pbs; + + status = softnic_pipeline_table_mtr_profile_add(softnic, + pipeline->name, + table_id, + meter_profile_id, + &profile); + if (status) { + rte_flow_error_set(error, + EINVAL, + RTE_FLOW_ERROR_TYPE_UNSPECIFIED, + NULL, + "METER: Table meter profile add failed"); + return -1; + } + } + + /* RTE_TABLE_ACTION_METER */ + rule_action->mtr.mtr[0].meter_profile_id = meter_profile_id; + rule_action->mtr.mtr[0].policer[e_RTE_METER_GREEN] = + (enum rte_table_action_policer)m->params.action[RTE_MTR_GREEN]; + rule_action->mtr.mtr[0].policer[e_RTE_METER_YELLOW] = + (enum rte_table_action_policer)m->params.action[RTE_MTR_YELLOW]; + rule_action->mtr.mtr[0].policer[e_RTE_METER_RED] = + (enum rte_table_action_policer)m->params.action[RTE_MTR_RED]; + rule_action->mtr.tc_mask = 1; + rule_action->action_mask |= 1 << RTE_TABLE_ACTION_MTR; + break; + } /* RTE_FLOW_ACTION_TYPE_METER */ + + case RTE_FLOW_ACTION_TYPE_VXLAN_ENCAP: + { + const struct rte_flow_action_vxlan_encap *conf = + action->conf; + const struct rte_flow_item *item; + union flow_item spec, mask; + int disabled = 0, status; + size_t size; + + if (conf == NULL) + return rte_flow_error_set(error, + EINVAL, + RTE_FLOW_ERROR_TYPE_ACTION, + action, + "VXLAN ENCAP: Null configuration"); + + item = conf->definition; + if (item == NULL) + return rte_flow_error_set(error, + EINVAL, + RTE_FLOW_ERROR_TYPE_ACTION, + action, + "VXLAN ENCAP: Null configuration definition"); + + if (!(params->action_mask & + (1LLU << RTE_TABLE_ACTION_ENCAP))) + return rte_flow_error_set(error, + EINVAL, + RTE_FLOW_ERROR_TYPE_UNSPECIFIED, + NULL, + "VXLAN ENCAP: Encap action not enabled for this table"); + + /* Check for Ether. */ + flow_item_skip_void(&item); + status = flow_item_proto_preprocess(item, &spec, &mask, + &size, &disabled, error); + if (status) + return status; + + if (item->type != RTE_FLOW_ITEM_TYPE_ETH) { + return rte_flow_error_set(error, + EINVAL, + RTE_FLOW_ERROR_TYPE_ITEM, + item, + "VXLAN ENCAP: first encap item should be ether"); + } + ether_addr_copy(&spec.eth.dst, + &rule_action->encap.vxlan.ether.da); + ether_addr_copy(&spec.eth.src, + &rule_action->encap.vxlan.ether.sa); + + item++; + + /* Check for VLAN. */ + flow_item_skip_void(&item); + status = flow_item_proto_preprocess(item, &spec, &mask, + &size, &disabled, error); + if (status) + return status; + + if (item->type == RTE_FLOW_ITEM_TYPE_VLAN) { + if (!params->encap.vxlan.vlan) + return rte_flow_error_set(error, + ENOTSUP, + RTE_FLOW_ERROR_TYPE_ITEM, + item, + "VXLAN ENCAP: vlan encap not supported by table"); + + uint16_t tci = rte_ntohs(spec.vlan.tci); + rule_action->encap.vxlan.vlan.pcp = + tci >> 13; + rule_action->encap.vxlan.vlan.dei = + (tci >> 12) & 0x1; + rule_action->encap.vxlan.vlan.vid = + tci & 0xfff; + + item++; + + flow_item_skip_void(&item); + status = flow_item_proto_preprocess(item, &spec, + &mask, &size, &disabled, error); + if (status) + return status; + } else { + if (params->encap.vxlan.vlan) + return rte_flow_error_set(error, + ENOTSUP, + RTE_FLOW_ERROR_TYPE_ITEM, + item, + "VXLAN ENCAP: expecting vlan encap item"); + } + + /* Check for IPV4/IPV6. */ + switch (item->type) { + case RTE_FLOW_ITEM_TYPE_IPV4: + { + rule_action->encap.vxlan.ipv4.sa = + rte_ntohl(spec.ipv4.hdr.src_addr); + rule_action->encap.vxlan.ipv4.da = + rte_ntohl(spec.ipv4.hdr.dst_addr); + rule_action->encap.vxlan.ipv4.dscp = + spec.ipv4.hdr.type_of_service >> 2; + rule_action->encap.vxlan.ipv4.ttl = + spec.ipv4.hdr.time_to_live; + break; + } + case RTE_FLOW_ITEM_TYPE_IPV6: + { + uint32_t vtc_flow; + + memcpy(&rule_action->encap.vxlan.ipv6.sa, + &spec.ipv6.hdr.src_addr, + sizeof(spec.ipv6.hdr.src_addr)); + memcpy(&rule_action->encap.vxlan.ipv6.da, + &spec.ipv6.hdr.dst_addr, + sizeof(spec.ipv6.hdr.dst_addr)); + vtc_flow = rte_ntohl(spec.ipv6.hdr.vtc_flow); + rule_action->encap.vxlan.ipv6.flow_label = + vtc_flow & 0xfffff; + rule_action->encap.vxlan.ipv6.dscp = + (vtc_flow >> 22) & 0x3f; + rule_action->encap.vxlan.ipv6.hop_limit = + spec.ipv6.hdr.hop_limits; + break; + } + default: + return rte_flow_error_set(error, + EINVAL, + RTE_FLOW_ERROR_TYPE_ITEM, + item, + "VXLAN ENCAP: encap item after ether should be ipv4/ipv6"); + } + + item++; + + /* Check for UDP. */ + flow_item_skip_void(&item); + status = flow_item_proto_preprocess(item, &spec, &mask, + &size, &disabled, error); + if (status) + return status; + + if (item->type != RTE_FLOW_ITEM_TYPE_UDP) { + return rte_flow_error_set(error, + EINVAL, + RTE_FLOW_ERROR_TYPE_ITEM, + item, + "VXLAN ENCAP: encap item after ipv4/ipv6 should be udp"); + } + rule_action->encap.vxlan.udp.sp = + rte_ntohs(spec.udp.hdr.src_port); + rule_action->encap.vxlan.udp.dp = + rte_ntohs(spec.udp.hdr.dst_port); + + item++; + + /* Check for VXLAN. */ + flow_item_skip_void(&item); + status = flow_item_proto_preprocess(item, &spec, &mask, + &size, &disabled, error); + if (status) + return status; + + if (item->type != RTE_FLOW_ITEM_TYPE_VXLAN) { + return rte_flow_error_set(error, + EINVAL, + RTE_FLOW_ERROR_TYPE_ITEM, + item, + "VXLAN ENCAP: encap item after udp should be vxlan"); + } + rule_action->encap.vxlan.vxlan.vni = + (spec.vxlan.vni[0] << 16U | + spec.vxlan.vni[1] << 8U + | spec.vxlan.vni[2]); + + item++; + + /* Check for END. */ + flow_item_skip_void(&item); + + if (item->type != RTE_FLOW_ITEM_TYPE_END) + return rte_flow_error_set(error, + EINVAL, + RTE_FLOW_ERROR_TYPE_ITEM, + item, + "VXLAN ENCAP: expecting END item"); + + rule_action->encap.type = RTE_TABLE_ACTION_ENCAP_VXLAN; + rule_action->action_mask |= 1 << RTE_TABLE_ACTION_ENCAP; + break; + } /* RTE_FLOW_ACTION_TYPE_VXLAN_ENCAP */ + + default: + return -ENOTSUP; + } + } + + if (n_jump_queue_rss_drop == 0) + return rte_flow_error_set(error, + EINVAL, + RTE_FLOW_ERROR_TYPE_ACTION, + action, + "Flow does not have any terminating action"); + + return 0; +} + +static int +pmd_flow_validate(struct rte_eth_dev *dev, + const struct rte_flow_attr *attr, + const struct rte_flow_item item[], + const struct rte_flow_action action[], + struct rte_flow_error *error) +{ + struct softnic_table_rule_match rule_match; + struct softnic_table_rule_action rule_action; + + struct pmd_internals *softnic = dev->data->dev_private; + struct pipeline *pipeline; + struct softnic_table *table; + const char *pipeline_name = NULL; + uint32_t table_id = 0; + int status; + + /* Check input parameters. */ + if (attr == NULL) + return rte_flow_error_set(error, + EINVAL, + RTE_FLOW_ERROR_TYPE_ATTR, + NULL, "Null attr"); + + if (item == NULL) + return rte_flow_error_set(error, + EINVAL, + RTE_FLOW_ERROR_TYPE_ITEM, + NULL, + "Null item"); + + if (action == NULL) + return rte_flow_error_set(error, + EINVAL, + RTE_FLOW_ERROR_TYPE_ACTION, + NULL, + "Null action"); + + /* Identify the pipeline table to add this flow to. */ + status = flow_pipeline_table_get(softnic, attr, &pipeline_name, + &table_id, error); + if (status) + return status; + + pipeline = softnic_pipeline_find(softnic, pipeline_name); + if (pipeline == NULL) + return rte_flow_error_set(error, + EINVAL, + RTE_FLOW_ERROR_TYPE_UNSPECIFIED, + NULL, + "Invalid pipeline name"); + + if (table_id >= pipeline->n_tables) + return rte_flow_error_set(error, + EINVAL, + RTE_FLOW_ERROR_TYPE_UNSPECIFIED, + NULL, + "Invalid pipeline table ID"); + + table = &pipeline->table[table_id]; + + /* Rule match. */ + memset(&rule_match, 0, sizeof(rule_match)); + status = flow_rule_match_get(softnic, + pipeline, + table, + attr, + item, + &rule_match, + error); + if (status) + return status; + + /* Rule action. */ + memset(&rule_action, 0, sizeof(rule_action)); + status = flow_rule_action_get(softnic, + pipeline, + table, + attr, + action, + &rule_action, + error); + if (status) + return status; + + return 0; +} + +static struct softnic_mtr * +flow_action_meter_get(struct pmd_internals *softnic, + const struct rte_flow_action *action) +{ + for ( ; action->type != RTE_FLOW_ACTION_TYPE_END; action++) + if (action->type == RTE_FLOW_ACTION_TYPE_METER) { + const struct rte_flow_action_meter *conf = action->conf; + + if (conf == NULL) + return NULL; + + return softnic_mtr_find(softnic, conf->mtr_id); + } + + return NULL; +} + +static void +flow_meter_owner_reset(struct pmd_internals *softnic, + struct rte_flow *flow) +{ + struct softnic_mtr_list *ml = &softnic->mtr.mtrs; + struct softnic_mtr *m; + + TAILQ_FOREACH(m, ml, node) + if (m->flow == flow) { + m->flow = NULL; + break; + } +} + +static void +flow_meter_owner_set(struct pmd_internals *softnic, + struct rte_flow *flow, + struct softnic_mtr *mtr) +{ + /* Reset current flow meter */ + flow_meter_owner_reset(softnic, flow); + + /* Set new flow meter */ + mtr->flow = flow; +} + +static int +is_meter_action_enable(struct pmd_internals *softnic, + struct softnic_table *table) +{ + struct softnic_table_action_profile *profile = + softnic_table_action_profile_find(softnic, + table->params.action_profile_name); + struct softnic_table_action_profile_params *params = &profile->params; + + return (params->action_mask & (1LLU << RTE_TABLE_ACTION_MTR)) ? 1 : 0; +} + +static struct rte_flow * +pmd_flow_create(struct rte_eth_dev *dev, + const struct rte_flow_attr *attr, + const struct rte_flow_item item[], + const struct rte_flow_action action[], + struct rte_flow_error *error) +{ + struct softnic_table_rule_match rule_match; + struct softnic_table_rule_action rule_action; + void *rule_data; + + struct pmd_internals *softnic = dev->data->dev_private; + struct pipeline *pipeline; + struct softnic_table *table; + struct rte_flow *flow; + struct softnic_mtr *mtr; + const char *pipeline_name = NULL; + uint32_t table_id = 0; + int new_flow, status; + + /* Check input parameters. */ + if (attr == NULL) { + rte_flow_error_set(error, + EINVAL, + RTE_FLOW_ERROR_TYPE_ATTR, + NULL, + "Null attr"); + return NULL; + } + + if (item == NULL) { + rte_flow_error_set(error, + EINVAL, + RTE_FLOW_ERROR_TYPE_ITEM, + NULL, + "Null item"); + return NULL; + } + + if (action == NULL) { + rte_flow_error_set(error, + EINVAL, + RTE_FLOW_ERROR_TYPE_ACTION, + NULL, + "Null action"); + return NULL; + } + + /* Identify the pipeline table to add this flow to. */ + status = flow_pipeline_table_get(softnic, attr, &pipeline_name, + &table_id, error); + if (status) + return NULL; + + pipeline = softnic_pipeline_find(softnic, pipeline_name); + if (pipeline == NULL) { + rte_flow_error_set(error, + EINVAL, + RTE_FLOW_ERROR_TYPE_UNSPECIFIED, + NULL, + "Invalid pipeline name"); + return NULL; + } + + if (table_id >= pipeline->n_tables) { + rte_flow_error_set(error, + EINVAL, + RTE_FLOW_ERROR_TYPE_UNSPECIFIED, + NULL, + "Invalid pipeline table ID"); + return NULL; + } + + table = &pipeline->table[table_id]; + + /* Rule match. */ + memset(&rule_match, 0, sizeof(rule_match)); + status = flow_rule_match_get(softnic, + pipeline, + table, + attr, + item, + &rule_match, + error); + if (status) + return NULL; + + /* Rule action. */ + memset(&rule_action, 0, sizeof(rule_action)); + status = flow_rule_action_get(softnic, + pipeline, + table, + attr, + action, + &rule_action, + error); + if (status) + return NULL; + + /* Flow find/allocate. */ + new_flow = 0; + flow = softnic_flow_find(table, &rule_match); + if (flow == NULL) { + new_flow = 1; + flow = calloc(1, sizeof(struct rte_flow)); + if (flow == NULL) { + rte_flow_error_set(error, + ENOMEM, + RTE_FLOW_ERROR_TYPE_UNSPECIFIED, + NULL, + "Not enough memory for new flow"); + return NULL; + } + } + + /* Rule add. */ + status = softnic_pipeline_table_rule_add(softnic, + pipeline_name, + table_id, + &rule_match, + &rule_action, + &rule_data); + if (status) { + if (new_flow) + free(flow); + + rte_flow_error_set(error, + EINVAL, + RTE_FLOW_ERROR_TYPE_UNSPECIFIED, + NULL, + "Pipeline table rule add failed"); + return NULL; + } + + /* Flow fill in. */ + memcpy(&flow->match, &rule_match, sizeof(rule_match)); + memcpy(&flow->action, &rule_action, sizeof(rule_action)); + flow->data = rule_data; + flow->pipeline = pipeline; + flow->table_id = table_id; + + mtr = flow_action_meter_get(softnic, action); + if (mtr) + flow_meter_owner_set(softnic, flow, mtr); + + /* Flow add to list. */ + if (new_flow) + TAILQ_INSERT_TAIL(&table->flows, flow, node); + + return flow; +} + +static int +pmd_flow_destroy(struct rte_eth_dev *dev, + struct rte_flow *flow, + struct rte_flow_error *error) +{ + struct pmd_internals *softnic = dev->data->dev_private; + struct softnic_table *table; + int status; + + /* Check input parameters. */ + if (flow == NULL) + return rte_flow_error_set(error, + EINVAL, + RTE_FLOW_ERROR_TYPE_HANDLE, + NULL, + "Null flow"); + + table = &flow->pipeline->table[flow->table_id]; + + /* Rule delete. */ + status = softnic_pipeline_table_rule_delete(softnic, + flow->pipeline->name, + flow->table_id, + &flow->match); + if (status) + return rte_flow_error_set(error, + EINVAL, + RTE_FLOW_ERROR_TYPE_UNSPECIFIED, + NULL, + "Pipeline table rule delete failed"); + + /* Update dependencies */ + if (is_meter_action_enable(softnic, table)) + flow_meter_owner_reset(softnic, flow); + + /* Flow delete. */ + TAILQ_REMOVE(&table->flows, flow, node); + free(flow); + + return 0; +} + +static int +pmd_flow_flush(struct rte_eth_dev *dev, + struct rte_flow_error *error) +{ + struct pmd_internals *softnic = dev->data->dev_private; + struct pipeline *pipeline; + int fail_to_del_rule = 0; + uint32_t i; + + TAILQ_FOREACH(pipeline, &softnic->pipeline_list, node) { + /* Remove all the flows added to the tables. */ + for (i = 0; i < pipeline->n_tables; i++) { + struct softnic_table *table = &pipeline->table[i]; + struct rte_flow *flow; + void *temp; + int status; + + TAILQ_FOREACH_SAFE(flow, &table->flows, node, temp) { + /* Rule delete. */ + status = softnic_pipeline_table_rule_delete + (softnic, + pipeline->name, + i, + &flow->match); + if (status) + fail_to_del_rule = 1; + /* Update dependencies */ + if (is_meter_action_enable(softnic, table)) + flow_meter_owner_reset(softnic, flow); + + /* Flow delete. */ + TAILQ_REMOVE(&table->flows, flow, node); + free(flow); + } + } + } + + if (fail_to_del_rule) + return rte_flow_error_set(error, + EINVAL, + RTE_FLOW_ERROR_TYPE_UNSPECIFIED, + NULL, + "Some of the rules could not be deleted"); + + return 0; +} + +static int +pmd_flow_query(struct rte_eth_dev *dev __rte_unused, + struct rte_flow *flow, + const struct rte_flow_action *action __rte_unused, + void *data, + struct rte_flow_error *error) +{ + struct rte_table_action_stats_counters stats; + struct softnic_table *table; + struct rte_flow_query_count *flow_stats = data; + int status; + + /* Check input parameters. */ + if (flow == NULL) + return rte_flow_error_set(error, + EINVAL, + RTE_FLOW_ERROR_TYPE_HANDLE, + NULL, + "Null flow"); + + if (data == NULL) + return rte_flow_error_set(error, + EINVAL, + RTE_FLOW_ERROR_TYPE_UNSPECIFIED, + NULL, + "Null data"); + + table = &flow->pipeline->table[flow->table_id]; + + /* Rule stats read. */ + status = rte_table_action_stats_read(table->a, + flow->data, + &stats, + flow_stats->reset); + if (status) + return rte_flow_error_set(error, + EINVAL, + RTE_FLOW_ERROR_TYPE_UNSPECIFIED, + NULL, + "Pipeline table rule stats read failed"); + + /* Fill in flow stats. */ + flow_stats->hits_set = + (table->ap->params.stats.n_packets_enabled) ? 1 : 0; + flow_stats->bytes_set = + (table->ap->params.stats.n_bytes_enabled) ? 1 : 0; + flow_stats->hits = stats.n_packets; + flow_stats->bytes = stats.n_bytes; + + return 0; +} + +const struct rte_flow_ops pmd_flow_ops = { + .validate = pmd_flow_validate, + .create = pmd_flow_create, + .destroy = pmd_flow_destroy, + .flush = pmd_flow_flush, + .query = pmd_flow_query, + .isolate = NULL, +}; diff --git a/drivers/net/softnic/rte_eth_softnic_internals.h b/drivers/net/softnic/rte_eth_softnic_internals.h index a25eb874..e12b8ae4 100644 --- a/drivers/net/softnic/rte_eth_softnic_internals.h +++ b/drivers/net/softnic/rte_eth_softnic_internals.h @@ -18,8 +18,11 @@ #include <rte_table_action.h> #include <rte_pipeline.h> +#include <rte_ethdev_core.h> #include <rte_ethdev_driver.h> #include <rte_tm_driver.h> +#include <rte_flow_driver.h> +#include <rte_mtr_driver.h> #include "rte_eth_softnic.h" #include "conn.h" @@ -44,6 +47,57 @@ struct pmd_params { }; /** + * Ethdev Flow API + */ +struct rte_flow; + +TAILQ_HEAD(flow_list, rte_flow); + +struct flow_attr_map { + char pipeline_name[NAME_SIZE]; + uint32_t table_id; + int valid; +}; + +#ifndef SOFTNIC_FLOW_MAX_GROUPS +#define SOFTNIC_FLOW_MAX_GROUPS 64 +#endif + +struct flow_internals { + struct flow_attr_map ingress_map[SOFTNIC_FLOW_MAX_GROUPS]; + struct flow_attr_map egress_map[SOFTNIC_FLOW_MAX_GROUPS]; +}; + +/** + * Meter + */ + +/* MTR meter profile */ +struct softnic_mtr_meter_profile { + TAILQ_ENTRY(softnic_mtr_meter_profile) node; + uint32_t meter_profile_id; + struct rte_mtr_meter_profile params; + uint32_t n_users; +}; + +TAILQ_HEAD(softnic_mtr_meter_profile_list, softnic_mtr_meter_profile); + +/* MTR meter object */ +struct softnic_mtr { + TAILQ_ENTRY(softnic_mtr) node; + uint32_t mtr_id; + struct rte_mtr_params params; + struct rte_flow *flow; +}; + +TAILQ_HEAD(softnic_mtr_list, softnic_mtr); + +struct mtr_internals { + struct softnic_mtr_meter_profile_list meter_profiles; + struct softnic_mtr_list mtrs; +}; + +/** * MEMPOOL */ struct softnic_mempool_params { @@ -225,6 +279,25 @@ struct softnic_tap { TAILQ_HEAD(softnic_tap_list, softnic_tap); /** + * Cryptodev + */ +struct softnic_cryptodev_params { + const char *dev_name; + uint32_t dev_id; /**< Valid only when *dev_name* is NULL. */ + uint32_t n_queues; + uint32_t queue_size; +}; + +struct softnic_cryptodev { + TAILQ_ENTRY(softnic_cryptodev) node; + char name[NAME_SIZE]; + uint16_t dev_id; + uint32_t n_queues; +}; + +TAILQ_HEAD(softnic_cryptodev_list, softnic_cryptodev); + +/** * Input port action */ struct softnic_port_in_action_profile_params { @@ -255,6 +328,7 @@ struct softnic_table_action_profile_params { struct rte_table_action_nat_config nat; struct rte_table_action_ttl_config ttl; struct rte_table_action_stats_config stats; + struct rte_table_action_sym_crypto_config sym_crypto; }; struct softnic_table_action_profile { @@ -266,6 +340,15 @@ struct softnic_table_action_profile { TAILQ_HEAD(softnic_table_action_profile_list, softnic_table_action_profile); +struct softnic_table_meter_profile { + TAILQ_ENTRY(softnic_table_meter_profile) node; + uint32_t meter_profile_id; + struct rte_table_action_meter_profile profile; +}; + +TAILQ_HEAD(softnic_table_meter_profile_list, + softnic_table_meter_profile); + /** * Pipeline */ @@ -280,12 +363,13 @@ enum softnic_port_in_type { PORT_IN_TMGR, PORT_IN_TAP, PORT_IN_SOURCE, + PORT_IN_CRYPTODEV, }; struct softnic_port_in_params { /* Read */ enum softnic_port_in_type type; - const char *dev_name; + char dev_name[NAME_SIZE]; union { struct { uint16_t queue_id; @@ -301,11 +385,17 @@ struct softnic_port_in_params { const char *file_name; uint32_t n_bytes_per_pkt; } source; + + struct { + uint16_t queue_id; + void *f_callback; + void *arg_callback; + } cryptodev; }; uint32_t burst_size; /* Action */ - const char *action_profile_name; + char action_profile_name[NAME_SIZE]; }; enum softnic_port_out_type { @@ -314,11 +404,12 @@ enum softnic_port_out_type { PORT_OUT_TMGR, PORT_OUT_TAP, PORT_OUT_SINK, + PORT_OUT_CRYPTODEV, }; struct softnic_port_out_params { enum softnic_port_out_type type; - const char *dev_name; + char dev_name[NAME_SIZE]; union { struct { uint16_t queue_id; @@ -328,6 +419,11 @@ struct softnic_port_out_params { const char *file_name; uint32_t max_n_pkts; } sink; + + struct { + uint16_t queue_id; + uint32_t op_offset; + } cryptodev; }; uint32_t burst_size; int retry; @@ -353,11 +449,15 @@ struct softnic_table_array_params { uint32_t key_offset; }; +#ifndef TABLE_RULE_MATCH_SIZE_MAX +#define TABLE_RULE_MATCH_SIZE_MAX 256 +#endif + struct softnic_table_hash_params { uint32_t n_keys; uint32_t key_offset; uint32_t key_size; - uint8_t *key_mask; + uint8_t key_mask[TABLE_RULE_MATCH_SIZE_MAX]; uint32_t n_buckets; int extendable_bucket; }; @@ -379,7 +479,7 @@ struct softnic_table_params { } match; /* Action */ - const char *action_profile_name; + char action_profile_name[NAME_SIZE]; }; struct softnic_port_in { @@ -388,10 +488,17 @@ struct softnic_port_in { struct rte_port_in_action *a; }; +struct softnic_port_out { + struct softnic_port_out_params params; +}; + struct softnic_table { struct softnic_table_params params; struct softnic_table_action_profile *ap; struct rte_table_action *a; + struct flow_list flows; + struct rte_table_action_dscp_table dscp_table; + struct softnic_table_meter_profile_list meter_profiles; }; struct pipeline { @@ -399,7 +506,9 @@ struct pipeline { char name[NAME_SIZE]; struct rte_pipeline *p; + struct pipeline_params params; struct softnic_port_in port_in[RTE_PIPELINE_PORT_IN_MAX]; + struct softnic_port_out port_out[RTE_PIPELINE_PORT_OUT_MAX]; struct softnic_table table[RTE_PIPELINE_TABLE_MAX]; uint32_t n_ports_in; uint32_t n_ports_out; @@ -489,12 +598,16 @@ struct pmd_internals { struct tm_internals tm; /**< Traffic Management */ } soft; + struct flow_internals flow; + struct mtr_internals mtr; + struct softnic_conn *conn; struct softnic_mempool_list mempool_list; struct softnic_swq_list swq_list; struct softnic_link_list link_list; struct softnic_tmgr_port_list tmgr_port_list; struct softnic_tap_list tap_list; + struct softnic_cryptodev_list cryptodev_list; struct softnic_port_in_action_profile_list port_in_action_profile_list; struct softnic_table_action_profile_list table_action_profile_list; struct pipeline_list pipeline_list; @@ -502,6 +615,58 @@ struct pmd_internals { struct softnic_thread_data thread_data[RTE_MAX_LCORE]; }; +static inline struct rte_eth_dev * +ETHDEV(struct pmd_internals *softnic) +{ + uint16_t port_id; + int status; + + if (softnic == NULL) + return NULL; + + status = rte_eth_dev_get_port_by_name(softnic->params.name, &port_id); + if (status) + return NULL; + + return &rte_eth_devices[port_id]; +} + +/** + * Ethdev Flow API + */ +int +flow_attr_map_set(struct pmd_internals *softnic, + uint32_t group_id, + int ingress, + const char *pipeline_name, + uint32_t table_id); + +struct flow_attr_map * +flow_attr_map_get(struct pmd_internals *softnic, + uint32_t group_id, + int ingress); + +extern const struct rte_flow_ops pmd_flow_ops; + +/** + * Meter + */ +int +softnic_mtr_init(struct pmd_internals *p); + +void +softnic_mtr_free(struct pmd_internals *p); + +struct softnic_mtr * +softnic_mtr_find(struct pmd_internals *p, + uint32_t mtr_id); + +struct softnic_mtr_meter_profile * +softnic_mtr_meter_profile_find(struct pmd_internals *p, + uint32_t meter_profile_id); + +extern const struct rte_mtr_ops pmd_mtr_ops; + /** * MEMPOOL */ @@ -610,6 +775,24 @@ softnic_tap_create(struct pmd_internals *p, const char *name); /** + * Sym Crypto + */ +int +softnic_cryptodev_init(struct pmd_internals *p); + +void +softnic_cryptodev_free(struct pmd_internals *p); + +struct softnic_cryptodev * +softnic_cryptodev_find(struct pmd_internals *p, + const char *name); + +struct softnic_cryptodev * +softnic_cryptodev_create(struct pmd_internals *p, + const char *name, + struct softnic_cryptodev_params *params); + +/** * Input port action */ int @@ -683,10 +866,20 @@ softnic_pipeline_port_out_create(struct pmd_internals *p, struct softnic_port_out_params *params); int +softnic_pipeline_port_out_find(struct pmd_internals *softnic, + const char *pipeline_name, + const char *name, + uint32_t *port_id); + +int softnic_pipeline_table_create(struct pmd_internals *p, const char *pipeline_name, struct softnic_table_params *params); +struct softnic_table_meter_profile * +softnic_pipeline_table_meter_profile_find(struct softnic_table *table, + uint32_t meter_profile_id); + struct softnic_table_rule_match_acl { int ip_version; @@ -718,10 +911,6 @@ struct softnic_table_rule_match_array { uint32_t pos; }; -#ifndef TABLE_RULE_MATCH_SIZE_MAX -#define TABLE_RULE_MATCH_SIZE_MAX 256 -#endif - struct softnic_table_rule_match_hash { uint8_t key[TABLE_RULE_MATCH_SIZE_MAX]; }; @@ -760,6 +949,18 @@ struct softnic_table_rule_action { struct rte_table_action_ttl_params ttl; struct rte_table_action_stats_params stats; struct rte_table_action_time_params time; + struct rte_table_action_tag_params tag; + struct rte_table_action_decap_params decap; + struct rte_table_action_sym_crypto_params sym_crypto; +}; + +struct rte_flow { + TAILQ_ENTRY(rte_flow) node; + struct softnic_table_rule_match match; + struct softnic_table_rule_action action; + void *data; + struct pipeline *pipeline; + uint32_t table_id; }; int diff --git a/drivers/net/softnic/rte_eth_softnic_meter.c b/drivers/net/softnic/rte_eth_softnic_meter.c new file mode 100644 index 00000000..73ecf3b1 --- /dev/null +++ b/drivers/net/softnic/rte_eth_softnic_meter.c @@ -0,0 +1,728 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2018 Intel Corporation + */ + +#include <stdint.h> +#include <stdlib.h> +#include <string.h> + +#include <rte_mtr.h> +#include <rte_mtr_driver.h> + +#include "rte_eth_softnic_internals.h" + +int +softnic_mtr_init(struct pmd_internals *p) +{ + /* Initialize meter profiles list */ + TAILQ_INIT(&p->mtr.meter_profiles); + + /* Initialize MTR objects list */ + TAILQ_INIT(&p->mtr.mtrs); + + return 0; +} + +void +softnic_mtr_free(struct pmd_internals *p) +{ + /* Remove MTR objects */ + for ( ; ; ) { + struct softnic_mtr *m; + + m = TAILQ_FIRST(&p->mtr.mtrs); + if (m == NULL) + break; + + TAILQ_REMOVE(&p->mtr.mtrs, m, node); + free(m); + } + + /* Remove meter profiles */ + for ( ; ; ) { + struct softnic_mtr_meter_profile *mp; + + mp = TAILQ_FIRST(&p->mtr.meter_profiles); + if (mp == NULL) + break; + + TAILQ_REMOVE(&p->mtr.meter_profiles, mp, node); + free(mp); + } +} + +struct softnic_mtr_meter_profile * +softnic_mtr_meter_profile_find(struct pmd_internals *p, + uint32_t meter_profile_id) +{ + struct softnic_mtr_meter_profile_list *mpl = &p->mtr.meter_profiles; + struct softnic_mtr_meter_profile *mp; + + TAILQ_FOREACH(mp, mpl, node) + if (meter_profile_id == mp->meter_profile_id) + return mp; + + return NULL; +} + +static int +meter_profile_check(struct rte_eth_dev *dev, + uint32_t meter_profile_id, + struct rte_mtr_meter_profile *profile, + struct rte_mtr_error *error) +{ + struct pmd_internals *p = dev->data->dev_private; + struct softnic_mtr_meter_profile *mp; + + /* Meter profile ID must be valid. */ + if (meter_profile_id == UINT32_MAX) + return -rte_mtr_error_set(error, + EINVAL, + RTE_MTR_ERROR_TYPE_METER_PROFILE_ID, + NULL, + "Meter profile id not valid"); + + /* Meter profile must not exist. */ + mp = softnic_mtr_meter_profile_find(p, meter_profile_id); + if (mp) + return -rte_mtr_error_set(error, + EEXIST, + RTE_MTR_ERROR_TYPE_METER_PROFILE_ID, + NULL, + "Meter prfile already exists"); + + /* Profile must not be NULL. */ + if (profile == NULL) + return -rte_mtr_error_set(error, + EINVAL, + RTE_MTR_ERROR_TYPE_METER_PROFILE, + NULL, + "profile null"); + + /* Traffic metering algorithm : TRTCM_RFC2698 */ + if (profile->alg != RTE_MTR_TRTCM_RFC2698) + return -rte_mtr_error_set(error, + EINVAL, + RTE_MTR_ERROR_TYPE_METER_PROFILE, + NULL, + "Metering alg not supported"); + + return 0; +} + +/* MTR meter profile add */ +static int +pmd_mtr_meter_profile_add(struct rte_eth_dev *dev, + uint32_t meter_profile_id, + struct rte_mtr_meter_profile *profile, + struct rte_mtr_error *error) +{ + struct pmd_internals *p = dev->data->dev_private; + struct softnic_mtr_meter_profile_list *mpl = &p->mtr.meter_profiles; + struct softnic_mtr_meter_profile *mp; + int status; + + /* Check input params */ + status = meter_profile_check(dev, meter_profile_id, profile, error); + if (status) + return status; + + /* Memory allocation */ + mp = calloc(1, sizeof(struct softnic_mtr_meter_profile)); + if (mp == NULL) + return -rte_mtr_error_set(error, + ENOMEM, + RTE_MTR_ERROR_TYPE_UNSPECIFIED, + NULL, + "Memory alloc failed"); + + /* Fill in */ + mp->meter_profile_id = meter_profile_id; + memcpy(&mp->params, profile, sizeof(mp->params)); + + /* Add to list */ + TAILQ_INSERT_TAIL(mpl, mp, node); + + return 0; +} + +/* MTR meter profile delete */ +static int +pmd_mtr_meter_profile_delete(struct rte_eth_dev *dev, + uint32_t meter_profile_id, + struct rte_mtr_error *error) +{ + struct pmd_internals *p = dev->data->dev_private; + struct softnic_mtr_meter_profile *mp; + + /* Meter profile must exist */ + mp = softnic_mtr_meter_profile_find(p, meter_profile_id); + if (mp == NULL) + return -rte_mtr_error_set(error, + EINVAL, + RTE_MTR_ERROR_TYPE_METER_PROFILE_ID, + NULL, + "Meter profile id invalid"); + + /* Check unused */ + if (mp->n_users) + return -rte_mtr_error_set(error, + EBUSY, + RTE_MTR_ERROR_TYPE_METER_PROFILE_ID, + NULL, + "Meter profile in use"); + + /* Remove from list */ + TAILQ_REMOVE(&p->mtr.meter_profiles, mp, node); + free(mp); + + return 0; +} + +struct softnic_mtr * +softnic_mtr_find(struct pmd_internals *p, uint32_t mtr_id) +{ + struct softnic_mtr_list *ml = &p->mtr.mtrs; + struct softnic_mtr *m; + + TAILQ_FOREACH(m, ml, node) + if (m->mtr_id == mtr_id) + return m; + + return NULL; +} + + +static int +mtr_check(struct pmd_internals *p, + uint32_t mtr_id, + struct rte_mtr_params *params, + int shared, + struct rte_mtr_error *error) +{ + /* MTR id valid */ + if (softnic_mtr_find(p, mtr_id)) + return -rte_mtr_error_set(error, + EEXIST, + RTE_MTR_ERROR_TYPE_MTR_ID, + NULL, + "MTR object already exists"); + + /* MTR params must not be NULL */ + if (params == NULL) + return -rte_mtr_error_set(error, + EINVAL, + RTE_MTR_ERROR_TYPE_MTR_PARAMS, + NULL, + "MTR object params null"); + + /* Previous meter color not supported */ + if (params->use_prev_mtr_color) + return -rte_mtr_error_set(error, + EINVAL, + RTE_MTR_ERROR_TYPE_MTR_PARAMS, + NULL, + "Previous meter color not supported"); + + /* Shared MTR object not supported */ + if (shared) + return -rte_mtr_error_set(error, + EINVAL, + RTE_MTR_ERROR_TYPE_SHARED, + NULL, + "Shared MTR object not supported"); + + return 0; +} + +/* MTR object create */ +static int +pmd_mtr_create(struct rte_eth_dev *dev, + uint32_t mtr_id, + struct rte_mtr_params *params, + int shared, + struct rte_mtr_error *error) +{ + struct pmd_internals *p = dev->data->dev_private; + struct softnic_mtr_list *ml = &p->mtr.mtrs; + struct softnic_mtr_meter_profile *mp; + struct softnic_mtr *m; + int status; + + /* Check parameters */ + status = mtr_check(p, mtr_id, params, shared, error); + if (status) + return status; + + /* Meter profile must exist */ + mp = softnic_mtr_meter_profile_find(p, params->meter_profile_id); + if (mp == NULL) + return -rte_mtr_error_set(error, + EINVAL, + RTE_MTR_ERROR_TYPE_METER_PROFILE_ID, + NULL, + "Meter profile id not valid"); + + /* Memory allocation */ + m = calloc(1, sizeof(struct softnic_mtr)); + if (m == NULL) + return -rte_mtr_error_set(error, + ENOMEM, + RTE_MTR_ERROR_TYPE_UNSPECIFIED, + NULL, + "Memory alloc failed"); + + /* Fill in */ + m->mtr_id = mtr_id; + memcpy(&m->params, params, sizeof(m->params)); + + /* Add to list */ + TAILQ_INSERT_TAIL(ml, m, node); + + /* Update dependencies */ + mp->n_users++; + + return 0; +} + +/* MTR object destroy */ +static int +pmd_mtr_destroy(struct rte_eth_dev *dev, + uint32_t mtr_id, + struct rte_mtr_error *error) +{ + struct pmd_internals *p = dev->data->dev_private; + struct softnic_mtr_list *ml = &p->mtr.mtrs; + struct softnic_mtr_meter_profile *mp; + struct softnic_mtr *m; + + /* MTR object must exist */ + m = softnic_mtr_find(p, mtr_id); + if (m == NULL) + return -rte_mtr_error_set(error, + EEXIST, + RTE_MTR_ERROR_TYPE_MTR_ID, + NULL, + "MTR object id not valid"); + + /* MTR object must not have any owner */ + if (m->flow != NULL) + return -rte_mtr_error_set(error, + EINVAL, + RTE_MTR_ERROR_TYPE_UNSPECIFIED, + NULL, + "MTR object is being used"); + + /* Get meter profile */ + mp = softnic_mtr_meter_profile_find(p, m->params.meter_profile_id); + if (mp == NULL) + return -rte_mtr_error_set(error, + EINVAL, + RTE_MTR_ERROR_TYPE_METER_PROFILE_ID, + NULL, + "MTR object meter profile invalid"); + + /* Update dependencies */ + mp->n_users--; + + /* Remove from list */ + TAILQ_REMOVE(ml, m, node); + free(m); + + return 0; +} + +/* MTR object meter profile update */ +static int +pmd_mtr_meter_profile_update(struct rte_eth_dev *dev, + uint32_t mtr_id, + uint32_t meter_profile_id, + struct rte_mtr_error *error) +{ + struct pmd_internals *p = dev->data->dev_private; + struct softnic_mtr_meter_profile *mp_new, *mp_old; + struct softnic_mtr *m; + int status; + + /* MTR object id must be valid */ + m = softnic_mtr_find(p, mtr_id); + if (m == NULL) + return -rte_mtr_error_set(error, + EEXIST, + RTE_MTR_ERROR_TYPE_MTR_ID, + NULL, + "MTR object id not valid"); + + /* Meter profile id must be valid */ + mp_new = softnic_mtr_meter_profile_find(p, meter_profile_id); + if (mp_new == NULL) + return -rte_mtr_error_set(error, + EINVAL, + RTE_MTR_ERROR_TYPE_METER_PROFILE_ID, + NULL, + "Meter profile not valid"); + + /* MTR object already set to meter profile id */ + if (m->params.meter_profile_id == meter_profile_id) + return 0; + + /* MTR object owner table update */ + if (m->flow) { + uint32_t table_id = m->flow->table_id; + struct softnic_table *table = &m->flow->pipeline->table[table_id]; + struct softnic_table_rule_action action; + + if (!softnic_pipeline_table_meter_profile_find(table, + meter_profile_id)) { + struct rte_table_action_meter_profile profile; + + memset(&profile, 0, sizeof(profile)); + + profile.alg = RTE_TABLE_ACTION_METER_TRTCM; + profile.trtcm.cir = mp_new->params.trtcm_rfc2698.cir; + profile.trtcm.pir = mp_new->params.trtcm_rfc2698.pir; + profile.trtcm.cbs = mp_new->params.trtcm_rfc2698.cbs; + profile.trtcm.pbs = mp_new->params.trtcm_rfc2698.pbs; + + /* Add meter profile to pipeline table */ + status = softnic_pipeline_table_mtr_profile_add(p, + m->flow->pipeline->name, + table_id, + meter_profile_id, + &profile); + if (status) + return -rte_mtr_error_set(error, + EINVAL, + RTE_MTR_ERROR_TYPE_UNSPECIFIED, + NULL, + "Table meter profile add failed"); + } + + /* Set meter action */ + memcpy(&action, &m->flow->action, sizeof(action)); + + action.mtr.mtr[0].meter_profile_id = meter_profile_id; + + /* Re-add rule */ + status = softnic_pipeline_table_rule_add(p, + m->flow->pipeline->name, + table_id, + &m->flow->match, + &action, + &m->flow->data); + if (status) + return -rte_mtr_error_set(error, + EINVAL, + RTE_MTR_ERROR_TYPE_UNSPECIFIED, + NULL, + "Pipeline table rule add failed"); + + /* Flow: update meter action */ + memcpy(&m->flow->action, &action, sizeof(m->flow->action)); + } + + mp_old = softnic_mtr_meter_profile_find(p, m->params.meter_profile_id); + + /* Meter: Set meter profile */ + m->params.meter_profile_id = meter_profile_id; + + /* Update dependencies*/ + mp_old->n_users--; + mp_new->n_users++; + + return 0; +} + +/* MTR object meter DSCP table update */ +static int +pmd_mtr_meter_dscp_table_update(struct rte_eth_dev *dev, + uint32_t mtr_id, + enum rte_mtr_color *dscp_table, + struct rte_mtr_error *error) +{ + struct pmd_internals *p = dev->data->dev_private; + struct rte_table_action_dscp_table dt; + struct pipeline *pipeline; + struct softnic_table *table; + struct softnic_mtr *m; + uint32_t table_id, i; + int status; + + /* MTR object id must be valid */ + m = softnic_mtr_find(p, mtr_id); + if (m == NULL) + return -rte_mtr_error_set(error, + EEXIST, + RTE_MTR_ERROR_TYPE_MTR_ID, + NULL, + "MTR object id not valid"); + + /* MTR object owner valid? */ + if (m->flow == NULL) + return 0; + + pipeline = m->flow->pipeline; + table_id = m->flow->table_id; + table = &pipeline->table[table_id]; + + memcpy(&dt, &table->dscp_table, sizeof(dt)); + for (i = 0; i < RTE_DIM(dt.entry); i++) + dt.entry[i].color = (enum rte_meter_color)dscp_table[i]; + + /* Update table */ + status = softnic_pipeline_table_dscp_table_update(p, + pipeline->name, + table_id, + UINT64_MAX, + &dt); + if (status) + return -rte_mtr_error_set(error, + EINVAL, + RTE_MTR_ERROR_TYPE_UNSPECIFIED, + NULL, + "Table action dscp table update failed"); + + return 0; +} + +/* MTR object policer action update */ +static int +pmd_mtr_policer_actions_update(struct rte_eth_dev *dev, + uint32_t mtr_id, + uint32_t action_mask, + enum rte_mtr_policer_action *actions, + struct rte_mtr_error *error) +{ + struct pmd_internals *p = dev->data->dev_private; + struct softnic_mtr *m; + uint32_t i; + int status; + + /* MTR object id must be valid */ + m = softnic_mtr_find(p, mtr_id); + if (m == NULL) + return -rte_mtr_error_set(error, + EEXIST, + RTE_MTR_ERROR_TYPE_MTR_ID, + NULL, + "MTR object id not valid"); + + /* Valid policer actions */ + if (actions == NULL) + return -rte_mtr_error_set(error, + EINVAL, + RTE_MTR_ERROR_TYPE_UNSPECIFIED, + NULL, + "Invalid actions"); + + for (i = 0; i < RTE_MTR_COLORS; i++) { + if (action_mask & (1 << i)) { + if (actions[i] != MTR_POLICER_ACTION_COLOR_GREEN && + actions[i] != MTR_POLICER_ACTION_COLOR_YELLOW && + actions[i] != MTR_POLICER_ACTION_COLOR_RED && + actions[i] != MTR_POLICER_ACTION_DROP) { + return -rte_mtr_error_set(error, + EINVAL, + RTE_MTR_ERROR_TYPE_UNSPECIFIED, + NULL, + " Invalid action value"); + } + } + } + + /* MTR object owner valid? */ + if (m->flow) { + struct pipeline *pipeline = m->flow->pipeline; + struct softnic_table *table = &pipeline->table[m->flow->table_id]; + struct softnic_table_rule_action action; + + memcpy(&action, &m->flow->action, sizeof(action)); + + /* Set action */ + for (i = 0; i < RTE_MTR_COLORS; i++) + if (action_mask & (1 << i)) + action.mtr.mtr[0].policer[i] = + (enum rte_table_action_policer)actions[i]; + + /* Re-add the rule */ + status = softnic_pipeline_table_rule_add(p, + pipeline->name, + m->flow->table_id, + &m->flow->match, + &action, + &m->flow->data); + if (status) + return -rte_mtr_error_set(error, + EINVAL, + RTE_MTR_ERROR_TYPE_UNSPECIFIED, + NULL, + "Pipeline table rule re-add failed"); + + /* Flow: Update meter action */ + memcpy(&m->flow->action, &action, sizeof(m->flow->action)); + + /* Reset the meter stats */ + rte_table_action_meter_read(table->a, m->flow->data, + 1, NULL, 1); + } + + /* Meter: Update policer actions */ + for (i = 0; i < RTE_MTR_COLORS; i++) + if (action_mask & (1 << i)) + m->params.action[i] = actions[i]; + + return 0; +} + +#define MTR_STATS_PKTS_DEFAULT (RTE_MTR_STATS_N_PKTS_GREEN | \ + RTE_MTR_STATS_N_PKTS_YELLOW | \ + RTE_MTR_STATS_N_PKTS_RED | \ + RTE_MTR_STATS_N_PKTS_DROPPED) + +#define MTR_STATS_BYTES_DEFAULT (RTE_MTR_STATS_N_BYTES_GREEN | \ + RTE_MTR_STATS_N_BYTES_YELLOW | \ + RTE_MTR_STATS_N_BYTES_RED | \ + RTE_MTR_STATS_N_BYTES_DROPPED) + +/* MTR object stats read */ +static void +mtr_stats_convert(struct softnic_mtr *m, + struct rte_table_action_mtr_counters_tc *in, + struct rte_mtr_stats *out, + uint64_t *out_mask) +{ + memset(&out, 0, sizeof(out)); + *out_mask = 0; + + if (in->n_packets_valid) { + uint32_t i; + + for (i = 0; i < RTE_MTR_COLORS; i++) { + if (m->params.action[i] == MTR_POLICER_ACTION_COLOR_GREEN) + out->n_pkts[RTE_MTR_GREEN] += in->n_packets[i]; + + if (m->params.action[i] == MTR_POLICER_ACTION_COLOR_YELLOW) + out->n_pkts[RTE_MTR_YELLOW] += in->n_packets[i]; + + if (m->params.action[i] == MTR_POLICER_ACTION_COLOR_RED) + out->n_pkts[RTE_MTR_RED] += in->n_packets[i]; + + if (m->params.action[i] == MTR_POLICER_ACTION_DROP) + out->n_pkts_dropped += in->n_packets[i]; + } + + *out_mask |= MTR_STATS_PKTS_DEFAULT; + } + + if (in->n_bytes_valid) { + uint32_t i; + + for (i = 0; i < RTE_MTR_COLORS; i++) { + if (m->params.action[i] == MTR_POLICER_ACTION_COLOR_GREEN) + out->n_bytes[RTE_MTR_GREEN] += in->n_bytes[i]; + + if (m->params.action[i] == MTR_POLICER_ACTION_COLOR_YELLOW) + out->n_bytes[RTE_MTR_YELLOW] += in->n_bytes[i]; + + if (m->params.action[i] == MTR_POLICER_ACTION_COLOR_RED) + out->n_bytes[RTE_MTR_RED] += in->n_bytes[i]; + + if (m->params.action[i] == MTR_POLICER_ACTION_DROP) + out->n_bytes_dropped += in->n_bytes[i]; + } + + *out_mask |= MTR_STATS_BYTES_DEFAULT; + } +} + +/* MTR object stats read */ +static int +pmd_mtr_stats_read(struct rte_eth_dev *dev, + uint32_t mtr_id, + struct rte_mtr_stats *stats, + uint64_t *stats_mask, + int clear, + struct rte_mtr_error *error) +{ + struct pmd_internals *p = dev->data->dev_private; + struct rte_table_action_mtr_counters counters; + struct pipeline *pipeline; + struct softnic_table *table; + struct softnic_mtr *m; + int status; + + /* MTR object id must be valid */ + m = softnic_mtr_find(p, mtr_id); + if (m == NULL) + return -rte_mtr_error_set(error, + EEXIST, + RTE_MTR_ERROR_TYPE_MTR_ID, + NULL, + "MTR object id not valid"); + + /* MTR meter object owner valid? */ + if (m->flow == NULL) { + if (stats != NULL) + memset(stats, 0, sizeof(*stats)); + + if (stats_mask) + *stats_mask = MTR_STATS_PKTS_DEFAULT | + MTR_STATS_BYTES_DEFAULT; + + return 0; + } + + pipeline = m->flow->pipeline; + table = &pipeline->table[m->flow->table_id]; + + /* Meter stats read. */ + status = rte_table_action_meter_read(table->a, + m->flow->data, + 1, + &counters, + clear); + if (status) + return -rte_mtr_error_set(error, + EINVAL, + RTE_MTR_ERROR_TYPE_UNSPECIFIED, + NULL, + "Meter stats read failed"); + + /* Stats format conversion. */ + if (stats || stats_mask) { + struct rte_mtr_stats s; + uint64_t s_mask = 0; + + mtr_stats_convert(m, + &counters.stats[0], + &s, + &s_mask); + + if (stats) + memcpy(stats, &s, sizeof(*stats)); + + if (stats_mask) + *stats_mask = s_mask; + } + + return 0; +} + +const struct rte_mtr_ops pmd_mtr_ops = { + .capabilities_get = NULL, + + .meter_profile_add = pmd_mtr_meter_profile_add, + .meter_profile_delete = pmd_mtr_meter_profile_delete, + + .create = pmd_mtr_create, + .destroy = pmd_mtr_destroy, + .meter_enable = NULL, + .meter_disable = NULL, + + .meter_profile_update = pmd_mtr_meter_profile_update, + .meter_dscp_table_update = pmd_mtr_meter_dscp_table_update, + .policer_actions_update = pmd_mtr_policer_actions_update, + .stats_update = NULL, + + .stats_read = pmd_mtr_stats_read, +}; diff --git a/drivers/net/softnic/rte_eth_softnic_pipeline.c b/drivers/net/softnic/rte_eth_softnic_pipeline.c index 45136a4a..5e180f8f 100644 --- a/drivers/net/softnic/rte_eth_softnic_pipeline.c +++ b/drivers/net/softnic/rte_eth_softnic_pipeline.c @@ -15,18 +15,18 @@ #include <rte_port_source_sink.h> #include <rte_port_fd.h> #include <rte_port_sched.h> +#include <rte_port_sym_crypto.h> #include <rte_table_acl.h> #include <rte_table_array.h> #include <rte_table_hash.h> +#include <rte_table_hash_func.h> #include <rte_table_lpm.h> #include <rte_table_lpm_ipv6.h> #include <rte_table_stub.h> #include "rte_eth_softnic_internals.h" -#include "hash_func.h" - #ifndef PIPELINE_MSGQ_SIZE #define PIPELINE_MSGQ_SIZE 64 #endif @@ -43,17 +43,52 @@ softnic_pipeline_init(struct pmd_internals *p) return 0; } +static void +softnic_pipeline_table_free(struct softnic_table *table) +{ + for ( ; ; ) { + struct rte_flow *flow; + + flow = TAILQ_FIRST(&table->flows); + if (flow == NULL) + break; + + TAILQ_REMOVE(&table->flows, flow, node); + free(flow); + } + + for ( ; ; ) { + struct softnic_table_meter_profile *mp; + + mp = TAILQ_FIRST(&table->meter_profiles); + if (mp == NULL) + break; + + TAILQ_REMOVE(&table->meter_profiles, mp, node); + free(mp); + } +} + void softnic_pipeline_free(struct pmd_internals *p) { for ( ; ; ) { struct pipeline *pipeline; + uint32_t table_id; pipeline = TAILQ_FIRST(&p->pipeline_list); if (pipeline == NULL) break; TAILQ_REMOVE(&p->pipeline_list, pipeline, node); + + for (table_id = 0; table_id < pipeline->n_tables; table_id++) { + struct softnic_table *table = + &pipeline->table[table_id]; + + softnic_pipeline_table_free(table); + } + rte_ring_free(pipeline->msgq_req); rte_ring_free(pipeline->msgq_rsp); rte_pipeline_free(pipeline->p); @@ -160,6 +195,7 @@ softnic_pipeline_create(struct pmd_internals *softnic, /* Node fill in */ strlcpy(pipeline->name, name, sizeof(pipeline->name)); pipeline->p = p; + memcpy(&pipeline->params, params, sizeof(*params)); pipeline->n_ports_in = 0; pipeline->n_ports_out = 0; pipeline->n_tables = 0; @@ -189,6 +225,7 @@ softnic_pipeline_port_in_create(struct pmd_internals *softnic, struct rte_port_sched_reader_params sched; struct rte_port_fd_reader_params fd; struct rte_port_source_params source; + struct rte_port_sym_crypto_reader_params cryptodev; } pp; struct pipeline *pipeline; @@ -213,7 +250,7 @@ softnic_pipeline_port_in_create(struct pmd_internals *softnic, return -1; ap = NULL; - if (params->action_profile_name) { + if (strlen(params->action_profile_name)) { ap = softnic_port_in_action_profile_find(softnic, params->action_profile_name); if (ap == NULL) @@ -306,6 +343,23 @@ softnic_pipeline_port_in_create(struct pmd_internals *softnic, break; } + case PORT_IN_CRYPTODEV: + { + struct softnic_cryptodev *cryptodev; + + cryptodev = softnic_cryptodev_find(softnic, params->dev_name); + if (cryptodev == NULL) + return -1; + + pp.cryptodev.cryptodev_id = cryptodev->dev_id; + pp.cryptodev.queue_id = params->cryptodev.queue_id; + pp.cryptodev.f_callback = params->cryptodev.f_callback; + pp.cryptodev.arg_callback = params->cryptodev.arg_callback; + p.ops = &rte_port_sym_crypto_reader_ops; + p.arg_create = &pp.cryptodev; + break; + } + default: return -1; } @@ -392,15 +446,18 @@ softnic_pipeline_port_out_create(struct pmd_internals *softnic, struct rte_port_sched_writer_params sched; struct rte_port_fd_writer_params fd; struct rte_port_sink_params sink; + struct rte_port_sym_crypto_writer_params cryptodev; } pp; union { struct rte_port_ethdev_writer_nodrop_params ethdev; struct rte_port_ring_writer_nodrop_params ring; struct rte_port_fd_writer_nodrop_params fd; + struct rte_port_sym_crypto_writer_nodrop_params cryptodev; } pp_nodrop; struct pipeline *pipeline; + struct softnic_port_out *port_out; uint32_t port_id; int status; @@ -526,6 +583,40 @@ softnic_pipeline_port_out_create(struct pmd_internals *softnic, break; } + case PORT_OUT_CRYPTODEV: + { + struct softnic_cryptodev *cryptodev; + + cryptodev = softnic_cryptodev_find(softnic, params->dev_name); + if (cryptodev == NULL) + return -1; + + if (params->cryptodev.queue_id >= cryptodev->n_queues) + return -1; + + pp.cryptodev.cryptodev_id = cryptodev->dev_id; + pp.cryptodev.queue_id = params->cryptodev.queue_id; + pp.cryptodev.tx_burst_sz = params->burst_size; + pp.cryptodev.crypto_op_offset = params->cryptodev.op_offset; + + pp_nodrop.cryptodev.cryptodev_id = cryptodev->dev_id; + pp_nodrop.cryptodev.queue_id = params->cryptodev.queue_id; + pp_nodrop.cryptodev.tx_burst_sz = params->burst_size; + pp_nodrop.cryptodev.n_retries = params->retry; + pp_nodrop.cryptodev.crypto_op_offset = + params->cryptodev.op_offset; + + if (params->retry == 0) { + p.ops = &rte_port_sym_crypto_writer_ops; + p.arg_create = &pp.cryptodev; + } else { + p.ops = &rte_port_sym_crypto_writer_nodrop_ops; + p.arg_create = &pp_nodrop.cryptodev; + } + + break; + } + default: return -1; } @@ -542,6 +633,8 @@ softnic_pipeline_port_out_create(struct pmd_internals *softnic, return -1; /* Pipeline */ + port_out = &pipeline->port_out[pipeline->n_ports_out]; + memcpy(&port_out->params, params, sizeof(*params)); pipeline->n_ports_out++; return 0; @@ -730,7 +823,7 @@ softnic_pipeline_table_create(struct pmd_internals *softnic, return -1; ap = NULL; - if (params->action_profile_name) { + if (strlen(params->action_profile_name)) { ap = softnic_table_action_profile_find(softnic, params->action_profile_name); if (ap == NULL) @@ -797,28 +890,28 @@ softnic_pipeline_table_create(struct pmd_internals *softnic, switch (params->match.hash.key_size) { case 8: - f_hash = hash_default_key8; + f_hash = rte_table_hash_crc_key8; break; case 16: - f_hash = hash_default_key16; + f_hash = rte_table_hash_crc_key16; break; case 24: - f_hash = hash_default_key24; + f_hash = rte_table_hash_crc_key24; break; case 32: - f_hash = hash_default_key32; + f_hash = rte_table_hash_crc_key32; break; case 40: - f_hash = hash_default_key40; + f_hash = rte_table_hash_crc_key40; break; case 48: - f_hash = hash_default_key48; + f_hash = rte_table_hash_crc_key48; break; case 56: - f_hash = hash_default_key56; + f_hash = rte_table_hash_crc_key56; break; case 64: - f_hash = hash_default_key64; + f_hash = rte_table_hash_crc_key64; break; default: return -1; @@ -960,7 +1053,51 @@ softnic_pipeline_table_create(struct pmd_internals *softnic, memcpy(&table->params, params, sizeof(*params)); table->ap = ap; table->a = action; + TAILQ_INIT(&table->flows); + TAILQ_INIT(&table->meter_profiles); + memset(&table->dscp_table, 0, sizeof(table->dscp_table)); pipeline->n_tables++; return 0; } + +int +softnic_pipeline_port_out_find(struct pmd_internals *softnic, + const char *pipeline_name, + const char *name, + uint32_t *port_id) +{ + struct pipeline *pipeline; + uint32_t i; + + if (softnic == NULL || + pipeline_name == NULL || + name == NULL || + port_id == NULL) + return -1; + + pipeline = softnic_pipeline_find(softnic, pipeline_name); + if (pipeline == NULL) + return -1; + + for (i = 0; i < pipeline->n_ports_out; i++) + if (strcmp(pipeline->port_out[i].params.dev_name, name) == 0) { + *port_id = i; + return 0; + } + + return -1; +} + +struct softnic_table_meter_profile * +softnic_pipeline_table_meter_profile_find(struct softnic_table *table, + uint32_t meter_profile_id) +{ + struct softnic_table_meter_profile *mp; + + TAILQ_FOREACH(mp, &table->meter_profiles, node) + if (mp->meter_profile_id == meter_profile_id) + return mp; + + return NULL; +} diff --git a/drivers/net/softnic/rte_eth_softnic_thread.c b/drivers/net/softnic/rte_eth_softnic_thread.c index 8a150903..4572adfa 100644 --- a/drivers/net/softnic/rte_eth_softnic_thread.c +++ b/drivers/net/softnic/rte_eth_softnic_thread.c @@ -1680,6 +1680,8 @@ softnic_pipeline_table_mtr_profile_add(struct pmd_internals *softnic, struct pipeline *p; struct pipeline_msg_req *req; struct pipeline_msg_rsp *rsp; + struct softnic_table *table; + struct softnic_table_meter_profile *mp; int status; /* Check input params */ @@ -1692,20 +1694,40 @@ softnic_pipeline_table_mtr_profile_add(struct pmd_internals *softnic, table_id >= p->n_tables) return -1; - if (!pipeline_is_running(p)) { - struct rte_table_action *a = p->table[table_id].a; + table = &p->table[table_id]; + mp = softnic_pipeline_table_meter_profile_find(table, meter_profile_id); + if (mp) + return -1; - status = rte_table_action_meter_profile_add(a, + /* Resource Allocation */ + mp = calloc(1, sizeof(struct softnic_table_meter_profile)); + if (mp == NULL) + return -1; + + mp->meter_profile_id = meter_profile_id; + memcpy(&mp->profile, profile, sizeof(mp->profile)); + + if (!pipeline_is_running(p)) { + status = rte_table_action_meter_profile_add(table->a, meter_profile_id, profile); + if (status) { + free(mp); + return status; + } + + /* Add profile to the table. */ + TAILQ_INSERT_TAIL(&table->meter_profiles, mp, node); return status; } /* Allocate request */ req = pipeline_msg_alloc(); - if (req == NULL) + if (req == NULL) { + free(mp); return -1; + } /* Write request */ req->type = PIPELINE_REQ_TABLE_MTR_PROFILE_ADD; @@ -1715,11 +1737,17 @@ softnic_pipeline_table_mtr_profile_add(struct pmd_internals *softnic, /* Send request and wait for response */ rsp = pipeline_msg_send_recv(p, req); - if (rsp == NULL) + if (rsp == NULL) { + free(mp); return -1; + } /* Read response */ status = rsp->status; + if (status == 0) + TAILQ_INSERT_TAIL(&table->meter_profiles, mp, node); + else + free(mp); /* Free response */ pipeline_msg_free(rsp); @@ -1874,6 +1902,11 @@ softnic_pipeline_table_dscp_table_update(struct pmd_internals *softnic, dscp_mask, dscp_table); + /* Update table dscp table */ + if (!status) + memcpy(&p->table[table_id].dscp_table, dscp_table, + sizeof(p->table[table_id].dscp_table)); + return status; } @@ -1897,6 +1930,11 @@ softnic_pipeline_table_dscp_table_update(struct pmd_internals *softnic, /* Read response */ status = rsp->status; + /* Update table dscp table */ + if (!status) + memcpy(&p->table[table_id].dscp_table, dscp_table, + sizeof(p->table[table_id].dscp_table)); + /* Free response */ pipeline_msg_free(rsp); @@ -2202,29 +2240,37 @@ match_convert(struct softnic_table_rule_match *mh, ml->acl_add.field_value[0].mask_range.u8 = mh->match.acl.proto_mask; - ml->acl_add.field_value[1].value.u32 = sa32[0]; + ml->acl_add.field_value[1].value.u32 = + rte_be_to_cpu_32(sa32[0]); ml->acl_add.field_value[1].mask_range.u32 = sa32_depth[0]; - ml->acl_add.field_value[2].value.u32 = sa32[1]; + ml->acl_add.field_value[2].value.u32 = + rte_be_to_cpu_32(sa32[1]); ml->acl_add.field_value[2].mask_range.u32 = sa32_depth[1]; - ml->acl_add.field_value[3].value.u32 = sa32[2]; + ml->acl_add.field_value[3].value.u32 = + rte_be_to_cpu_32(sa32[2]); ml->acl_add.field_value[3].mask_range.u32 = sa32_depth[2]; - ml->acl_add.field_value[4].value.u32 = sa32[3]; + ml->acl_add.field_value[4].value.u32 = + rte_be_to_cpu_32(sa32[3]); ml->acl_add.field_value[4].mask_range.u32 = sa32_depth[3]; - ml->acl_add.field_value[5].value.u32 = da32[0]; + ml->acl_add.field_value[5].value.u32 = + rte_be_to_cpu_32(da32[0]); ml->acl_add.field_value[5].mask_range.u32 = da32_depth[0]; - ml->acl_add.field_value[6].value.u32 = da32[1]; + ml->acl_add.field_value[6].value.u32 = + rte_be_to_cpu_32(da32[1]); ml->acl_add.field_value[6].mask_range.u32 = da32_depth[1]; - ml->acl_add.field_value[7].value.u32 = da32[2]; + ml->acl_add.field_value[7].value.u32 = + rte_be_to_cpu_32(da32[2]); ml->acl_add.field_value[7].mask_range.u32 = da32_depth[2]; - ml->acl_add.field_value[8].value.u32 = da32[3]; + ml->acl_add.field_value[8].value.u32 = + rte_be_to_cpu_32(da32[3]); ml->acl_add.field_value[8].mask_range.u32 = da32_depth[3]; @@ -2264,36 +2310,36 @@ match_convert(struct softnic_table_rule_match *mh, mh->match.acl.proto_mask; ml->acl_delete.field_value[1].value.u32 = - sa32[0]; + rte_be_to_cpu_32(sa32[0]); ml->acl_delete.field_value[1].mask_range.u32 = sa32_depth[0]; ml->acl_delete.field_value[2].value.u32 = - sa32[1]; + rte_be_to_cpu_32(sa32[1]); ml->acl_delete.field_value[2].mask_range.u32 = sa32_depth[1]; ml->acl_delete.field_value[3].value.u32 = - sa32[2]; + rte_be_to_cpu_32(sa32[2]); ml->acl_delete.field_value[3].mask_range.u32 = sa32_depth[2]; ml->acl_delete.field_value[4].value.u32 = - sa32[3]; + rte_be_to_cpu_32(sa32[3]); ml->acl_delete.field_value[4].mask_range.u32 = sa32_depth[3]; ml->acl_delete.field_value[5].value.u32 = - da32[0]; + rte_be_to_cpu_32(da32[0]); ml->acl_delete.field_value[5].mask_range.u32 = da32_depth[0]; ml->acl_delete.field_value[6].value.u32 = - da32[1]; + rte_be_to_cpu_32(da32[1]); ml->acl_delete.field_value[6].mask_range.u32 = da32_depth[1]; ml->acl_delete.field_value[7].value.u32 = - da32[2]; + rte_be_to_cpu_32(da32[2]); ml->acl_delete.field_value[7].mask_range.u32 = da32_depth[2]; ml->acl_delete.field_value[8].value.u32 = - da32[3]; + rte_be_to_cpu_32(da32[3]); ml->acl_delete.field_value[8].mask_range.u32 = da32_depth[3]; @@ -2432,6 +2478,36 @@ action_convert(struct rte_table_action *a, return status; } + if (action->action_mask & (1LLU << RTE_TABLE_ACTION_TAG)) { + status = rte_table_action_apply(a, + data, + RTE_TABLE_ACTION_TAG, + &action->tag); + + if (status) + return status; + } + + if (action->action_mask & (1LLU << RTE_TABLE_ACTION_DECAP)) { + status = rte_table_action_apply(a, + data, + RTE_TABLE_ACTION_DECAP, + &action->decap); + + if (status) + return status; + } + + if (action->action_mask & (1LLU << RTE_TABLE_ACTION_SYM_CRYPTO)) { + status = rte_table_action_apply(a, + data, + RTE_TABLE_ACTION_SYM_CRYPTO, + &action->sym_crypto); + + if (status) + return status; + } + return 0; } |