From 80428fe54e0ba576a481c86b36d25627b21c53f1 Mon Sep 17 00:00:00 2001 From: amountain <1342237361@qq.com> Date: Wed, 16 Sep 2026 19:39:37 +0800 Subject: [PATCH 1/3] Add ub_bench tool source code - Core: ub_bench.c (main entry, mode dispatch) - New features: ub_bench_run.c/h (sequential mode), ub_bench_hist.c/h (histogram) - Inherited from urma_perftest: ub_bench_run_test/parameters/resources/mgmt - New params: --mode, --threads, --qps, --sweep, --sweep-duration, --bw-only - Supports all original urma_perftest commands (write_bw, write_lat, etc.) - Pipeline latency uses user_ctx (not ring buffer) for per-WR timestamp - Build: CMakeLists.txt - Headers: include/ub/, include/urma/ --- CMakeLists.txt | 97 + include/ub/ub_get_clock.h | 53 + include/ub/ub_util.h | 308 +++ include/urma/urma_api.h | 1177 ++++++++++ include/urma/urma_opcode.h | 262 +++ include/urma/urma_provider.h | 423 ++++ include/urma/urma_types.h | 1454 ++++++++++++ include/urma/urma_types_str.h | 248 +++ include/urma/urma_ubagg.h | 298 +++ src/ub_bench.c | 234 ++ src/ub_bench_hist.c | 47 + src/ub_bench_hist.h | 91 + src/ub_bench_log.c | 12 + src/ub_bench_log.h | 54 + src/ub_bench_mgmt.c | 128 ++ src/ub_bench_mgmt.h | 34 + src/ub_bench_mgmt_tcp.c | 485 ++++ src/ub_bench_mgmt_tcp.h | 35 + src/ub_bench_mgmt_ub.c | 880 ++++++++ src/ub_bench_mgmt_ub.h | 37 + src/ub_bench_parameters.c | 2000 +++++++++++++++++ src/ub_bench_parameters.h | 419 ++++ src/ub_bench_resources.c | 3085 ++++++++++++++++++++++++++ src/ub_bench_resources.h | 205 ++ src/ub_bench_run.c | 568 +++++ src/ub_bench_run.h | 15 + src/ub_bench_run_test.c | 3899 +++++++++++++++++++++++++++++++++ src/ub_bench_run_test.h | 37 + 28 files changed, 16585 insertions(+) create mode 100644 CMakeLists.txt create mode 100644 include/ub/ub_get_clock.h create mode 100644 include/ub/ub_util.h create mode 100644 include/urma/urma_api.h create mode 100644 include/urma/urma_opcode.h create mode 100644 include/urma/urma_provider.h create mode 100644 include/urma/urma_types.h create mode 100644 include/urma/urma_types_str.h create mode 100644 include/urma/urma_ubagg.h create mode 100644 src/ub_bench.c create mode 100644 src/ub_bench_hist.c create mode 100644 src/ub_bench_hist.h create mode 100644 src/ub_bench_log.c create mode 100644 src/ub_bench_log.h create mode 100644 src/ub_bench_mgmt.c create mode 100644 src/ub_bench_mgmt.h create mode 100644 src/ub_bench_mgmt_tcp.c create mode 100644 src/ub_bench_mgmt_tcp.h create mode 100644 src/ub_bench_mgmt_ub.c create mode 100644 src/ub_bench_mgmt_ub.h create mode 100644 src/ub_bench_parameters.c create mode 100644 src/ub_bench_parameters.h create mode 100644 src/ub_bench_resources.c create mode 100644 src/ub_bench_resources.h create mode 100644 src/ub_bench_run.c create mode 100644 src/ub_bench_run.h create mode 100644 src/ub_bench_run_test.c create mode 100644 src/ub_bench_run_test.h diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..f8d11e4 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,97 @@ +# SPDX-License-Identifier: MIT +# Copyright (c) Huawei Technologies Co., Ltd. 2021-2025. All rights reserved. + +cmake_minimum_required(VERSION 3.10) +project(ub_bench C) + +set(CMAKE_C_STANDARD 99) +set(CMAKE_SKIP_RPATH TRUE) + +# 交叉编译工具?if(CROSS_COMPILE) + set(CMAKE_C_COMPILER "${CROSS_COMPILE}") + message(STATUS "CMAKE_C_COMPILER: ${CROSS_COMPILE}") +endif() + +# 安全加固编译选项(与 UMDK src/urma/CMakeLists.txt 保持一致) +set(UB_BENCH_C_FLAGS " -Wall -Werror -Wformat -Wfloat-equal -Wtrampolines -g -O2 \ +-fno-strict-aliasing -fstack-protector-strong -D_FORTIFY_SOURCE=2 -fPIE -fPIC") + +# 架构相关编译选项 +set(UB_BENCH_FLAGS_ARM64 " -march=armv8-a+crc -DUB_ARCH_ARM64") +set(UB_BENCH_FLAGS_x86_64 " -msse4.2 -DUB_ARCH_X86_64") +if("${X86_CROSS_COMPILATION}" STREQUAL "enable") + set(UB_BENCH_FLAGS_x86_64 " -DUB_ARCH_X86_64") + message(STATUS "x86 cross compilation, disabling msse4.2!") +endif() + +if("${CMAKE_HOST_SYSTEM_PROCESSOR}" STREQUAL "aarch64") + set(CMAKE_C_FLAGS "${UB_BENCH_C_FLAGS} ${UB_BENCH_FLAGS_ARM64}") +else() + set(CMAKE_C_FLAGS "${UB_BENCH_C_FLAGS} ${UB_BENCH_FLAGS_x86_64}") +endif() + +# 安全加固链接选项 +set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -rdynamic -pie \ +-Wl,-z,noexecstack,-z,relro,-z,now") + +# 可? ASAN (AddressSanitizer / LeakSanitizer / UndefinedBehaviorSanitizer) +if("${ASAN}" STREQUAL "enable") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=address -fsanitize-recover=address \ +-fsanitize=leak -fsanitize=undefined -fno-omit-frame-pointer") + message(STATUS "ASAN enabled") +endif() + +# 可? PERF_CYCLE 性能周期计数 +if("${PERF_CYCLE}" STREQUAL "enable") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DPERF_CYCLE_FLAG") + message(STATUS "PERF_CYCLE enabled") +endif() + +message(STATUS "CMAKE_C_FLAGS = ${CMAKE_C_FLAGS}") + +# 查找系统已安装的 liburma ?liburma_common +find_library(URMA_LIB NAMES urma) +if(NOT URMA_LIB) + message(FATAL_ERROR + "liburma not found. Please install UMDK first.") +endif() +message(STATUS "Found urma: ${URMA_LIB}") + +find_library(URMA_COMMON_LIB NAMES urma_common) +if(NOT URMA_COMMON_LIB) + message(FATAL_ERROR + "liburma_common not found. Please install UMDK first.") +endif() +message(STATUS "Found urma_common: ${URMA_COMMON_LIB}") + +add_executable(ub_bench + src/ub_bench.c + src/ub_bench_hist.c + src/ub_bench_run.c + src/ub_bench_log.c + src/ub_bench_mgmt.c + src/ub_bench_mgmt_tcp.c + src/ub_bench_mgmt_ub.c + src/ub_bench_parameters.c + src/ub_bench_resources.c + src/ub_bench_run_test.c +) + +target_include_directories(ub_bench + PRIVATE + ${CMAKE_SOURCE_DIR}/include/urma + ${CMAKE_SOURCE_DIR}/include/ub + ${CMAKE_SOURCE_DIR}/src +) + +target_link_libraries(ub_bench + PRIVATE + ${URMA_LIB} + ${URMA_COMMON_LIB} + pthread + m +) + +install(TARGETS ub_bench + DESTINATION /usr/bin +) diff --git a/include/ub/ub_get_clock.h b/include/ub/ub_get_clock.h new file mode 100644 index 0000000..955a104 --- /dev/null +++ b/include/ub/ub_get_clock.h @@ -0,0 +1,53 @@ +/* + * SPDX-License-Identifier: MIT + * Copyright (c) Huawei Technologies Co., Ltd. 2022-2025. All rights reserved. + * Description: clock for ub_bench + * Author: Qian Guoxin + * Create: 2022-04-03 + * Note: + * History: 2022-04-03 create file + */ + +#ifndef UB_GET_CLOCK_H +#define UB_GET_CLOCK_H + +#include +#include + +#ifdef __cplusplus +extern "C" +{ +#endif + +#define CLOCK_SIZE_OF_INT (32) + +#if defined(__x86_64__) +static inline uint64_t get_cycles(void) +{ + uint32_t low, high; + uint64_t val; + asm volatile ("rdtsc" : "=a" (low), "=d" (high)); + val = high; + val = (val << CLOCK_SIZE_OF_INT) | low; + return val; +} +#elif defined(__aarch64__) +static inline uint64_t get_cycles(void) +{ + uint64_t freq; + asm volatile("isb" : : : "memory"); + asm volatile("mrs %0, cntvct_el0" : "=r" (freq)); + return freq; +} +#else +#warning get_cycles not implemented +#endif + +/* Warning: Function takes more than 200 ms to run. */ +extern double get_cpu_mhz(bool cpu_freq_warn); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/ub/ub_util.h b/include/ub/ub_util.h new file mode 100644 index 0000000..ec262d6 --- /dev/null +++ b/include/ub/ub_util.h @@ -0,0 +1,308 @@ +/* + * SPDX-License-Identifier: MIT + * Copyright (c) Huawei Technologies Co., Ltd. 2020-2025. All rights reserved. + * Description: ub util head file + * Author: Lilijun + * Create: 2020-8-11 + * Note: + * History: + */ + + +#ifndef UB_UTIL_H +#define UB_UTIL_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" +{ +#endif + +#if __GNUC__ && !defined(__CHECKER__) +#define UB_UNUSED __attribute__((__unused__)) +#define UB_LIKELY(CONDITION) __builtin_expect(!!(CONDITION), 1) +#define UB_UNLIKELY(CONDITION) __builtin_expect(!!(CONDITION), 0) +#else +#define UB_UNUSED +#define UB_LIKELY(CONDITION) (!!(CONDITION)) +#define UB_UNLIKELY(CONDITION) (!!(CONDITION)) +#endif + +#define UB_CPU_ALLOC_SIZE(count) \ + ((((count) + __NCPUBITS - 1) / __NCPUBITS) * sizeof(__cpu_mask)) +#define UB_CPU_ALLOC(count) (malloc(UB_CPU_ALLOC_SIZE(count))) +#define CPUSET_NBITS(setsize) (8 * (setsize)) +#define UB_CPU_ISSET_S(cpu, setsize, cpusetp) \ + ({ size_t __cpu = (cpu); \ + __cpu < 8 * (setsize) \ + ? ((((__cpu_mask *) ((cpusetp)->__bits))[__CPUELT (__cpu)] \ + & __CPUMASK (__cpu))) != 0 \ + : 0; }) + +#define UB_CONSTRUCTOR(f) \ + static void f(void) __attribute__((constructor)); \ + static void f(void) + +#ifndef NDEBUG +#define UB_ASSERT(CONDITION) \ + if (UB_LIKELY(!(CONDITION))) { \ + assert(CONDITION); \ + } +#else +#define UB_ASSERT(CONDITION) ((void)(CONDITION)) +#endif + +static inline void ub_abort(void) +{ + abort(); +} + +#define UB_SOURCE_LOCATOR __FILE__ ":" UB_STRINGIZE(__LINE__) +#define UB_STRINGIZE(AUX) #AUX + +#ifndef MAX +#define MAX(X, Y) ((X) > (Y) ? (X) : (Y)) +#define MIN(X, Y) ((X) < (Y) ? (X) : (Y)) +#endif + +typedef enum urma_huge_page_size { + UB_HUGE_PAGE_SIZE_2MB, + UB_HUGE_PAGE_SIZE_1GB, + UB_HUGE_PAGE_SIZE_ANY, +} urma_huge_page_size_t; + +/* get the 1 bits count. */ +static inline unsigned int ub_count_1bits(uint64_t x) +{ + return (unsigned int)__builtin_popcountll(x); +} + +/* get the last 1-bit of x */ +static inline uintmax_t ub_rightmost_1bit(uintmax_t x) +{ + return x & (uintmax_t)(-x); +} + +/* clear the last 1-bit of x */ +static inline uintmax_t ub_zero_rightmost_1bit(uintmax_t x) +{ + return x & (x - 1); +} + +/* Undefined when x == 0 */ +static inline int ub_count_trail_zero(uint64_t x) +{ + return (__builtin_constant_p(x <= UINT32_MAX) && x <= UINT32_MAX + ? __builtin_ctz((unsigned int)x) + : __builtin_ctzll(x)); +} + +#define BITS_PER_LONG 64 +#define BITS_PER_LONG_SHIFT 6 +#define BITS_PER_LONG_MASK (BITS_PER_LONG - 1) +#define NANO_IN_SEC 1000000000 +/** for bit ops */ +#define BITS_PER_BYTE 8 +#define BITS_PER_UINT32 32 + +#define ARRAY_SIZE(ARRAY) (sizeof(ARRAY) / sizeof((ARRAY)[0])) + +#ifndef DIV_ROUND_UP +#define DIV_ROUND_UP(n, d) (((n) + (d) - 1) / (d)) +#endif + +#ifndef ROUND_UP +#define ROUND_UP(n, d) (DIV_ROUND_UP(n, d) * (d)) +#endif + +#ifndef ROUND_DOWN +#define ROUND_DOWN(n, d) ((n) / (d) * (d)) +#endif + +#ifndef IS_POW2 +#define IS_POW2(n) (((n) != 0) && (((n) & ((n) - 1)) == 0)) +#endif + +static inline bool ub_is_pow2(uint64_t x) +{ + return IS_POW2(x); +} + +#define BITS_TO_LONGS(cnt) DIV_ROUND_UP((cnt), BITS_PER_LONG) + +#define for_each_set_bit(bit, addr, size) \ + for ((bit) = ub_find_first_bit((addr), (size)); \ + (bit) < (size); \ + (bit) = ub_find_next_bit((addr), (size), (bit) + 1)) + +static inline void __attribute__((always_inline)) set_bit(uint32_t nr, unsigned long *addr) +{ + if (nr >= (sizeof(*addr) * BITS_PER_BYTE)) { + return; + } + addr[nr >> BITS_PER_LONG_SHIFT] |= 1UL << (nr & BITS_PER_LONG_MASK); +} + +static inline void __attribute__((always_inline)) clear_bit(uint32_t nr, unsigned long *addr) +{ + if (nr >= (sizeof(*addr) * BITS_PER_BYTE)) { + return; + } + addr[nr >> BITS_PER_LONG_SHIFT] &= ~(1UL << (nr & BITS_PER_LONG_MASK)); +} + +static inline int __attribute__((always_inline)) test_bit(unsigned int nr, const unsigned long *addr) +{ + return ((1UL << (nr & BITS_PER_LONG_MASK)) & + (((unsigned long *)addr)[nr >> BITS_PER_LONG_SHIFT])) != 0; +} + +static inline void __attribute__((always_inline)) bitmap_zero(unsigned int nbits, unsigned long *addr) +{ + size_t len = BITS_TO_LONGS(nbits) * sizeof(unsigned long); + memset(addr, 0, len); +} + +#define BITOP_WORD(nr) ((nr) >> BITS_PER_LONG_SHIFT) + +static inline unsigned long __attribute__((always_inline)) ub_ffs(unsigned long word) +{ + return (unsigned long)((unsigned long)__builtin_ffsl(word) - 1UL); +} + +/* + * Find the first set bit in unsigned long array. For example, + * array[2] has two unsigned long with array[1] is set to 128(1000 0000). + * Then ub_find_first_bit returns 71(64+7). If all bits are not set, + * then the total size of bits will be returned. + * @array: unsigned long array for searching + * @size: total size of bits, not the number of array elements. For example, + * array[2] has size 128 and array size 2. + */ +unsigned long ub_find_first_bit(const unsigned long *array, unsigned long size); + +unsigned long ub_find_next_bit(const unsigned long *array, unsigned long size, unsigned long offset); + +unsigned long ub_find_next_zero_bit(const unsigned long *array, unsigned long size, unsigned long offset); + +/* ffz - find first zero bit in word */ +static inline unsigned long __attribute__((always_inline)) ffz(unsigned long word) +{ + return (unsigned long)((unsigned long)__builtin_ffsl(~(word)) - 1UL); +} + +unsigned long ub_find_first_zero_bit(const unsigned long *array, unsigned long size); + +#define OBJ_OFFSETOF(obj_ptr, field) offsetof(typeof(*(obj_ptr)), field) + +/* get the size of field in the struct_type. */ +#define SIZEOF_FIELD(struct_type, field) (sizeof(((struct_type *)NULL)->field)) + +/* get the offset of the end of field in the struct. */ +#define OFFSET_OF_FIELD_END(struct_type, field) \ + (offsetof(struct_type, field) + SIZEOF_FIELD(struct_type, field)) + +/* get the structure object from the pointer of the given field by struct type */ +#define CONTAINER_OF_FIELD(field_ptr, struct_type, field) \ + ((struct_type *)(void *)((char *)(field_ptr) - offsetof(struct_type, field))) + +/* get the structure object from the pointer of the given field by type of obj_ptr */ +#define OBJ_CONTAINING(field_ptr, obj_ptr, field) \ + ((typeof(obj_ptr))(void *)((char *)(field_ptr) - OBJ_OFFSETOF(obj_ptr, field))) + +/* get the structure object from the pointer of the given field by struct type, + * Then assign the structure object to the obj_ptr + */ +#define ASSIGN_CONTAINER_PTR(obj_ptr, field_ptr, field) \ + ((obj_ptr) = OBJ_CONTAINING(field_ptr, obj_ptr, field), (void)0) + +/* initialize obj_ptr and ASSIGN_CONTAINER_PTR to avoid compile warnings. */ +#define INIT_CONTAINER_PTR(obj_ptr, field_ptr, field) \ + ((obj_ptr) = NULL, ASSIGN_CONTAINER_PTR(obj_ptr, field_ptr, field)) + +int safe_write_value_to_file(const char *path, const char *str); + +/* easy to covert string and integer */ +struct str_int { + char *s; + int integer; +}; + +static inline int get_int_from_string(const struct str_int *array, int array_size, const char *str) +{ + int i; + for (i = 0; i < array_size; i++) { + if (strcmp(array[i].s, str) == 0) { + return (int)array[i].integer; + } + } + return -1; +} + +static inline char *get_string_from_int(const struct str_int *array, int array_size, int num) +{ + int i; + for (i = 0; i < array_size; i++) { + if (array[i].integer == num) { + return array[i].s; + } + } + return NULL; +} + +bool hexits_value(const char *s, size_t n, uintmax_t *value); + +bool is_valid_digit(const char *digit_str); +int ub_str_to_bool(const char *buf, bool *bool_res); +int ub_str_to_u8(const char *buf, uint8_t *u8); +int ub_str_to_u16(const char *buf, uint16_t *u16); +int ub_str_to_u32(const char *buf, uint32_t *u32); +int ub_str_to_u64(const char *buf, uint64_t *u64); +int ub_str_to_int(const char *buf, int *integer); +int ub_hex_str_to_u64(const char *p, uint64_t *out, uint64_t max); +int ub_parse_sysfs_val(const char *filename, unsigned long *val); +void *ub_hugemalloc(size_t i_length, urma_huge_page_size_t hps, void *p_addr_hint); +int ub_hugefree(void *p_addr, size_t i_length); +int memset_s_large_buf(void *dest, size_t destMax, int c, size_t count); +int memcpy_s_large_buf(void *dest, size_t destMax, const void *src, size_t count); + +#define RETVAL_SZ 256 +static char g_ub_util_ret[RETVAL_SZ] = { 0 }; + +static inline const char *ub_strerror(int errnum) +{ + if (strerror_r(errnum, g_ub_util_ret, RETVAL_SZ) != 0) { + if (snprintf(g_ub_util_ret, RETVAL_SZ - 1, "Unknown error %d", errnum) <= 0) { + return NULL; + } + } + return g_ub_util_ret; +} + +static inline uint64_t gethrtime_epoch(void) +{ + struct timespec ts; + if (clock_gettime(CLOCK_REALTIME, &ts) != 0) { + return (uint64_t)(-1); + } + + return (uint64_t)((ts.tv_sec * NANO_IN_SEC) + ts.tv_nsec); +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/urma/urma_api.h b/include/urma/urma_api.h new file mode 100644 index 0000000..38ad949 --- /dev/null +++ b/include/urma/urma_api.h @@ -0,0 +1,1177 @@ +/* + * SPDX-License-Identifier: MIT + * Copyright (c) Huawei Technologies Co., Ltd. 2021-2025. All rights reserved. + * Description: URMA API + * Author: Ouyang changchun, Bojie Li, Yan Fangfang, Qian Guoxin + * Create: 2021-07-13 + * Note: + * History: 2021-07-13 Create File + */ +#ifndef URMA_API_H +#define URMA_API_H + +#include +#include + +#include "urma_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Init urma environment. + * @param[in] [Required] conf: urma init attr, a random uasid will be assigned when conf is null. + * Return: 0 on success, other value on error + */ +urma_status_t urma_init(urma_init_attr_t *conf); + +/** + * Un-init urma environment, it will free uasid. + * Return: 0 on success, other value on error + */ +urma_status_t urma_uninit(void); + +/* Device Manage API */ + /** + * Get device list. + * @param[out] num_devices: number of urma device; + * Return: pointer array of urma_device; NULL means no device returned; + * Note: urma_free_device_list() needs to be called to free memory; + */ +urma_device_t **urma_get_device_list(int *num_devices); + +/** +* free device list. +* @param[in] [Required] device_list: pointer array of urma_device,return value of urma_get_device_list. + Can be called after using urma_device list; +* Return: void; +*/ +void urma_free_device_list(urma_device_t **device_list); + +/** +* Get eid list. +* @param[in] [Required] dev: device pointer +* @param[out] cnt: Return the number of valid eids; +* Return: If it succeeds, it will return the eid_info array pointer, and the number of elements +* is cnt; if it fails, it will return NULL; it will be released by the user calling +*/ +urma_eid_info_t *urma_get_eid_list(urma_device_t *dev, uint32_t *cnt); + +/** +* free eid list. +* @param[in] [Required] eid_list: The eid array pointer to be released +* Return: void; +*/ +void urma_free_eid_list(urma_eid_info_t *eid_list); + +/** + * Get device by device name. + * @param[in] [Required] dev_name: device's name; + * Return: urma_device; NULL means no device returned; + */ +urma_device_t *urma_get_device_by_name(char *dev_name); + + /** + * Get device by device eid. + * @param[in] [Required] eid: device's eid; + * @param[in] [Required] type: device's transport type; + * Return: urma_device; NULL means no device returned; + */ +urma_device_t *urma_get_device_by_eid(urma_eid_t eid, urma_transport_type_t type); + +/** + * Query the attributes and capabilities of urma devices. + * @param[in] [Required] dev: urma_device; + * @param[out] dev_attr: Return device attributes, user needs to allocate and free the memory; + * Return: 0 on success, other value on error + */ +urma_status_t urma_query_device(urma_device_t *dev, urma_device_attr_t *dev_attr); + +/** + * Create an urma context on the urma device. + * @param[in] [Required] dev: urma device, by get_device apis. + * @param[in] [Required] eid_index: device's eid index. + * Return urma context pointer on success, NULL on error. + */ +urma_context_t *urma_create_context(urma_device_t *dev, uint32_t eid_index); + +/** + * Delete the created urma context. + * @param[in] [Required] ctx: handle of the created context. + * Return: 0 on success, other value on error + */ +urma_status_t urma_delete_context(urma_context_t *ctx); + +/** + * Set option of urma context. + * @param[in] [Required] ctx: handle of the created context. + * Return: 0 on success, other value on error + */ +urma_status_t urma_set_context_opt(urma_context_t *ctx, urma_opt_name_t opt_name, const void *opt_value, + size_t opt_len); + +/** + * Create a jetty for completion (jfc). + * @param[in] [Required] ctx: the urma context created before; + * @param[in] [Required] jfc_cfg: configuration including: depth, flag, jfce, user context; + * Return: the handle of created jfc, not NULL on success; NULL on error + */ +urma_jfc_t *urma_create_jfc(urma_context_t *ctx, urma_jfc_cfg_t *jfc_cfg); + +/** + * Modify JFC attributes. + * @param[in] [Required] jfc: specify JFC; + * @param[in] [Required] attr: attributes to be modified; + * Return: 0 on success, other value on error + */ +urma_status_t urma_modify_jfc(urma_jfc_t *jfc, urma_jfc_attr_t *attr); + +/** + * Delete the created jfc. + * @param[in] [Required] jfc: handle of the created jfc; + * Return: 0 on success, other value on error + */ +urma_status_t urma_delete_jfc(urma_jfc_t *jfc); + +/** + * Alloc a jfc. + * @param[in] [Required] urma_ctx: the urma context created before; + * @param[in] [Required] cfg: configuration including: depth, flag, jfce, user context; + * @param[out] [Required] jfc: handle of the allocated jfc; + * Return: 0 on success, other value on error + */ +urma_status_t urma_alloc_jfc(urma_context_t *urma_ctx, urma_jfc_cfg_t *cfg, urma_jfc_t **jfc); + +/** + * Set the opt of jfc. + * @param[in] [Required] jfc: the jfc allocated before; + * @param[in] [Required] opt: the opt to change cfg of jfc; + * @param[in] [Required] len: the len of the opt value(byte); + * @param[in] [Required] buf: the buffer containing the value to set; + * Return: 0 on success, other value on error + */ +urma_status_t urma_set_jfc_opt(urma_jfc_t *jfc, uint64_t opt, void *buf, uint32_t len); + +/** + * Active the allocated jfc. + * @param[in] [Required] jfc: the jfc allocated before; + * Return: 0 on success, other value on error + */ +urma_status_t urma_active_jfc(urma_jfc_t *jfc); + +/** + * Get the opt of jfc. + * @param[in] [Required] jfc: the jfc allocated before; + * @param[in] [Required] opt: the opt to change cfg of jfc; + * @param[in] [Required] len: the len of the opt value(byte); + * @param[out] [Required] buf: the buffer to store the value; + * Return: 0 on success, other value on error + */ +urma_status_t urma_get_jfc_opt(urma_jfc_t *jfc, uint64_t opt, void *buf, uint32_t len); + +/** + * Deactive the created jfc. + * @param[in] [Required] jfc: the jfc actived before; + * Return: 0 on success, other value on error + */ +urma_status_t urma_deactive_jfc(urma_jfc_t *jfc); + +/** + * Free the created jfc. + * @param[in] [Required] jfc: the jfc allocated before; + * After free, the jfc pointer is no longer allowed to be accessed. + * Return: 0 on success, other value on error + */ +urma_status_t urma_free_jfc(urma_jfc_t *jfc); + +/** + * Delete the created jfc in a batch. + * @param[in] [Required] jfc_arr: the array of the jfc pointer; + * @param[in] [Required] jfc_num: array length; + * @param[out] [Required] bad_jfc: the address of the first failed jfc pointer; + * Return: 0 on success, EINVAL on invalid parameter, other value on other batch + * delete errors. + * If delete error happens(except invalid parameter), stop at the first failed + * jfc and return, these jfc before the failed jfc will be deleted normally. + */ +urma_status_t urma_delete_jfc_batch(urma_jfc_t **jfc_arr, int jfc_num, urma_jfc_t **bad_jfc); + +/** + * Create a jetty for send (jfs). + * @param[in] [Required] ctx: the urma context created before; + * @param[in] [Required] jfs_cfg: address to pu the jfs config; + * Return: the handle of created jfs, not NULL on success, NULL on error + */ +urma_jfs_t *urma_create_jfs(urma_context_t *ctx, urma_jfs_cfg_t *jfs_cfg); + +/** + * Modify a jetty for send (jfs). + * @param[in] [Required] jfs: the jfs created before; + * @param[in] [Required] attr: attributes to be modified; + * Return: 0 on success, other value on error + */ +urma_status_t urma_modify_jfs(urma_jfs_t *jfs, urma_jfs_attr_t *attr); + +/** + * Query a jetty for send (jfs). + * @param[in] [Required] jfs: the jfs created before; + * @param[out] [Required] cfg: config of jfs; + * @param[out] [Required] attr: attributes of jfs; + * Return: 0 on success, other value on error + */ +urma_status_t urma_query_jfs(urma_jfs_t *jfs, urma_jfs_cfg_t *cfg, urma_jfs_attr_t *attr); + +/** + * Delete the created jfs. + * @param[in] [Required] jfs: the jfs created before; + * Return: 0 on success, other value on error + */ +urma_status_t urma_delete_jfs(urma_jfs_t *jfs); + +/** + * Delete the created jfs in a batch. + * @param[in] [Required] jfs_arr: the array of the jfs pointer; + * @param[in] [Required] jfs_num: array length; + * @param[out] [Required] bad_jfs: the address of the first failed jfs pointer; + * Return: 0 on success, EINVAL on invalid parameter, other value on other batch + * delete errors. + * If delete error happens(except invalid parameter), stop at the first failed + * jfs and return, these jfs before the failed jfs will be deleted normally. + */ +urma_status_t urma_delete_jfs_batch(urma_jfs_t **jfs_arr, int jfs_num, urma_jfs_t **bad_jfs); + +/** + * Poll the CRs for all the WRs that posted to JFS, but are not completed. + * Call the API after modify JFS to error, or polled a suspened done CR. + * CRs with status of URMA_CR_WR_FLUSH_ERR will be returned on success. + * @param[in] [Required] jfs: the jfs created before; + * @param[in] [Required] cr_cnt: Number of CR expected to be received.; + * @param[out] [Required] cr: Address for storing CR; + * Return: the number of CR returned, 0 means no CR returned, -1 on error + */ +int urma_flush_jfs(urma_jfs_t *jfs, int cr_cnt, urma_cr_t *cr); + +/** + * Alloc a jfs. + * @param[in] [Required] urma_ctx: the urma context created before; + * @param[in] [Required] cfg: configuration including: depth, flag, jfce, user context; + * @param[out] [Required] jfs: handle of the allocated jfs; + * Return: 0 on success, other value on error + */ +urma_status_t urma_alloc_jfs(urma_context_t *urma_ctx, urma_jfs_cfg_t *cfg, urma_jfs_t **jfs); + +/** + * Set the opt of jfs. + * @param[in] [Required] jfs: the jfs allocated before; + * @param[in] [Required] opt: the opt to change cfg of jfs; + * @param[in] [Required] len: the len of the opt value(byte); + * @param[in] [Required] buf: the buffer to store the value; + * Return: 0 on success, other value on error + */ +urma_status_t urma_set_jfs_opt(urma_jfs_t *jfs, uint64_t opt, void *buf, uint32_t len); + +/** + * Active the created jfs. + * @param[in] [Required] jfs: the jfs allocated before; + * Return: 0 on success, other value on error + */ +urma_status_t urma_active_jfs(urma_jfs_t *jfs); + +/** + * Get the opt of jfs. + * @param[in] [Required] jfs: the jfs allocated before; + * @param[in] [Required] opt: the opt to change cfg of jfs; + * @param[in] [Required] len: the len of the opt value(byte); + * @param[out] [Required] buf: the buffer to store the value; + * Return: 0 on success, other value on error + */ +urma_status_t urma_get_jfs_opt(urma_jfs_t *jfs, uint64_t opt, void *buf, uint32_t len); + +/** + * Deactive the created jfs. + * @param[in] [Required] jfs: the jfs actived before; + * Return: 0 on success, other value on error + */ +urma_status_t urma_deactive_jfs(urma_jfs_t *jfs); + +/** + * Free the created jfs. + * @param[in] [Required] jfs: the jfs allocated before; + * After free, the jfs pointer is no longer allowed to be accessed. + * Return: 0 on success, other value on error + */ +urma_status_t urma_free_jfs(urma_jfs_t *jfs); + + /** + * Create a jetty for receive (jfr). + * @param[in] [Required] ctx: the urma context created before; + * @param[in] [Required] jfr_cfg: address to put the jfr config; + * Return: the handle of created jfr, not NULL on success, NULL on error + */ +urma_jfr_t *urma_create_jfr(urma_context_t *ctx, urma_jfr_cfg_t *jfr_cfg); + +/** + * Modify JFR attributes. + * @param[in] [Required] jfr: specify JFR; + * @param[in] [Required] attr: attributes to be modified; + * Return: 0 on success, other value on error + */ +urma_status_t urma_modify_jfr(urma_jfr_t *jfr, urma_jfr_attr_t *attr); + +/** + * Query a jetty for recv(jfr). + * @param[in] [Required] jfr: the jfr created before; + * @param[out] [Required] cfg: config of jfr; + * @param[out] [Required] attr: attributes of jfr; + * Return: 0 on success, other value on error + */ +urma_status_t urma_query_jfr(urma_jfr_t *jfr, urma_jfr_cfg_t *cfg, urma_jfr_attr_t *attr); + +/** + * Delete the created jfr. + * @param[in] [Required] jfr: the jfr created before; + * Return: 0 on success, other value on error + */ +urma_status_t urma_delete_jfr(urma_jfr_t *jfr); + +/** + * Delete the created jfr in a batch. + * @param[in] [Required] jfr_arr: the array of the jfr pointer; + * @param[in] [Required] jfr_num: array length; + * @param[out] [Required] bad_jfr: the address of the first failed jfr pointer; + * Return: 0 on success, EINVAL on invalid parameter, other value on other batch + * delete errors. + * If delete error happens(except invalid parameter), stop at the first failed + * jfr and return, these jfr before the failed jfr will be deleted normally. + */ +urma_status_t urma_delete_jfr_batch(urma_jfr_t **jfr_arr, int jfr_num, urma_jfr_t **bad_jfr); + +/** + * Import a remote jfr to local node. + * @param[in] [Required] ctx: the urma context created before; + * @param[in] [Required] rjfr: the information of remote jfr to import into user node, trans_mode required, + * trans_mode same to create_jfr trans_mode; + * @param[in] [Required] token_value: token to put into output jetty/protection table; + * Return: the address of target jfr, not NULL on success, NULL on error + */ +urma_target_jetty_t *urma_import_jfr(urma_context_t *ctx, urma_rjfr_t *rjfr, urma_token_t *token_value); + +/** + * Import a remote jfr to local node by control plane. + * Note: trans_mode from rjfr should be the same as the trans_mode of get_tp_list, + * users should obey this rule in case of unexpected errors. + * @param[in] [Required] ctx: the urma context created before; + * @param[in] [Required] rjfr: the information of remote jfr to import into user node, trans_mode required, + * trans_mode same to create_jfr trans_mode; + * @param[in] [Required] token_value: token to put into output jetty/protection table; + * @param[in] [Required] cfg: tp active configuration to exchange with target; + * Return: the address of target jfr, not NULL on success, NULL on error + */ +urma_target_jetty_t *urma_import_jfr_ex(urma_context_t *ctx, urma_rjfr_t *rjfr, urma_token_t *token_value, + urma_import_jfr_ex_cfg_t *cfg); + +/** + * Unimport the imported remote jfr. + * @param[in] [Required] target_jfr: the target jfr to unimport; + * Return: 0 on success, other value on error + */ +urma_status_t urma_unimport_jfr(urma_target_jetty_t *target_jfr); + +/** + * Advise jfr: construct the transport channel for jfs and remote jfr. + * @param[in] [Required] jfs: jfs to use to construct the transport channel; + * @param[in] [Required] tjfr: target jfr information including full qualified jfr id; + * Return: 0 on success, URMA_EEXIST if the jfr has been advised, other value on error + */ +urma_status_t urma_advise_jfr(urma_jfs_t *jfs, urma_target_jetty_t *tjfr); + +/** + * Async API for urma_advise_jfr + * Advise jfr: construct the transport channel for jfs and remote jfr. + * @param[in] [Required] jfs: jfs to use to construct the transport channel; + * @param[in] [Required] tjfr: target jfr information including full qulified jfr id; + * @param[in] [Required] cb_func: user defined callback function. + * @param[in] [Required] cb_arg: user defined arguments for the callback function. + * Return: 0 on success, URMA_EEXIST if the jfr has been advised, other value on error. + * Note: User must define callback function to handle result, + * as the async respone will call the cb_func and pass the result to it. + */ +urma_status_t urma_advise_jfr_async(urma_jfs_t *jfs, urma_target_jetty_t *tjfr, urma_advise_async_cb_func cb_fun, + void *cb_arg); + +/** + * Unadvise jfr: disconnect the transport channel for jfs and remote jfr. Optional API for optimization + * @param[in] [Required] jfs: jfs to use to construct the transport channel; + * @param[in] [Required] tjfr: target jfr information including full qualified jfr id; + * Return: 0 on success, other value on error + */ +urma_status_t urma_unadvise_jfr(urma_jfs_t *jfs, urma_target_jetty_t *tjfr); + +/** + * Alloc a jfr. + * @param[in] [Required] urma_ctx: the urma context created before; + * @param[in] [Required] cfg: configuration including: depth, flag, jfce, user context; + * @param[out] [Required] jfr: handle of the allocated jfr; + * Return: 0 on success, other value on error + */ +urma_status_t urma_alloc_jfr(urma_context_t *urma_ctx, urma_jfr_cfg_t *cfg, urma_jfr_t **jfr); + +/** + * Set the opt of jfr. + * @param[in] [Required] jfr: handle of the allocated jfr; + * @param[in] [Required] opt: the opt to change cfg of jfr; + * @param[in] [Required] len: the len of the opt value(byte); + * @param[in] [Required] buf: the buffer to store the value; + * Return: 0 on success, other value on error + */ +urma_status_t urma_set_jfr_opt(urma_jfr_t *jfr, uint64_t opt, void *buf, uint32_t len); + +/** + * Active the allocated jfr. + * @param[in] [Required] jfr: handle of the allocated jfr; + * Return: 0 on success, other value on error + */ +urma_status_t urma_active_jfr(urma_jfr_t *jfr); + +/** + * Get the opt of jfr. + * @param[in] [Required] jfr: handle of the allocated jfr; + * @param[in] [Required] opt: the opt to change cfg of jfr; + * @param[in] [Required] len: the len of the opt value(byte); + * @param[out] [Required] buf: the buffer to store the value; + * Return: 0 on success, other value on error + */ +urma_status_t urma_get_jfr_opt(urma_jfr_t *jfr, uint64_t opt, void *buf, uint32_t len); + +/** + * Deactive the actived jfr. + * @param[in] [Required] jfr: handle of the allocated jfr; + * Return: 0 on success, other value on error + */ +urma_status_t urma_deactive_jfr(urma_jfr_t *jfr); + +/** + * Free the allocated jfr. + * @param[in] [Required] jfr: handle of the allocated jfr; + * After free, the jfr pointer is no longer allowed to be accessed. + * Return: 0 on success, other value on error + */ +urma_status_t urma_free_jfr(urma_jfr_t *jfr); + +/** + ******************** Beginning of URMA JETTY APIs *************************** + */ + +/** + * Create jetty, which is a pair of jfs and jfr + * @param[in] [Required] ctx: the urma context created before; + * @param[in] [Required] jetty_cfg: pointer of the jetty config; + * Return: the handle of created jetty, not NULL on success, NULL on error + */ +urma_jetty_t *urma_create_jetty(urma_context_t *ctx, urma_jetty_cfg_t *jetty_cfg); + +/** + * Modify jetty attributes. + * @param[in] [Required] jetty: specify jetty; + * @param[in] [Required] attr: attributes to be modified; + * Return: 0 on success, other value on error + */ +urma_status_t urma_modify_jetty(urma_jetty_t *jetty, urma_jetty_attr_t *attr); + +/** + * Query jetty attributes. + * @param[in] [Required] jetty: specify jetty; + * @param[out] [Required] cfg: cconfig to query; + * @param[out] [Required] attr: attributes to query; + * Return: 0 on success, other value on error + */ +urma_status_t urma_query_jetty(urma_jetty_t *jetty, urma_jetty_cfg_t *cfg, urma_jetty_attr_t *attr); + +/** + * Delete the created jetty. + * @param[in] [Required] jetty: the jetty created before; + * Return: 0 on success, other value on error + */ +urma_status_t urma_delete_jetty(urma_jetty_t *jetty); + +/** + * Delete the created jetty in a batch. + * @param[in] [Required] jetty_arr: the array of the jetty pointer; + * @param[in] [Required] jetty_num: array length; + * @param[out] [Required] bad_jetty: the address of the first failed jetty pointer; + * Return: 0 on success, EINVAL on invalid parameter, other value on other batch + * delete errors. + * If delete error happens(except invalid parameter), stop at the first failed + * jetty and return, these jetty before the failed jetty will be deleted normally. + */ +urma_status_t urma_delete_jetty_batch(urma_jetty_t **jetty_arr, int jetty_num, urma_jetty_t **bad_jetty); + +/** + * Import a remote jetty. + * @param[in] [Required] ctx: the urma context created before; + * @param[in] [Required] rjetty: information of remote jetty to import, including jetty id and trans_mode, + * trans_mode same to create_jetty trans_mode; + * @param[in] [Required] token_value: token to put into output jetty protection table; + * Return: the address of target jetty, not NULL on success, NULL on error + */ +urma_target_jetty_t *urma_import_jetty(urma_context_t *ctx, urma_rjetty_t *rjetty, urma_token_t *token_value); + +/** + * Import a remote jetty by control plane. + * Note: trans_mode from rjetty should be the same as the trans_mode of get_tp_list, + * users should obey this rule in case of unexpected errors. + * @param[in] [Required] ctx: the urma context created before; + * @param[in] [Required] rjetty: information of remote jetty to import, including jetty id and trans_mode, + * trans_mode same to create_jetty trans_mode; + * @param[in] [Required] token_value: token to put into output jetty protection table; + * @param[in] [Required] cfg: tp active configuration to exchange with target; + * Return: the address of target jetty, not NULL on success, NULL on error + */ +urma_target_jetty_t *urma_import_jetty_ex(urma_context_t *ctx, urma_rjetty_t *rjetty, urma_token_t *token_value, + urma_import_jetty_ex_cfg_t *cfg); + +/** + * Unimport the imported remote jetty. + * @param[in] [Required] tjetty: the target jetty to unimport; + * Return: 0 on success, other value on error + */ +urma_status_t urma_unimport_jetty(urma_target_jetty_t *tjetty); + +/** + * Advise jetty: construct the transport channel between local jetty and remote jetty. + * @param[in] [Required] jetty: local jetty to construct the transport channel; + * @param[in] [Required] tjetty: target jetty imported before; + * Return: 0 on success, URMA_EEXIST if the jetty has been advised, other value on error + * Note: A local jetty can be advised with several remote jetties. A connectionless jetty is free to call the adivse API + */ +/* todo: available after implementing URMA_TM_RM(IB_RC) */ +urma_status_t urma_advise_jetty(urma_jetty_t *jetty, urma_target_jetty_t *tjetty); + +/** + * Unadvise jetty: deconstruct the transport channel between local jetty and remote jetty. + * @param[in] [Required] jetty: local jetty to deconstruct the transport channel; + * @param[in] [Required] tjetty: target jetty imported before; + * Return: 0 on success, other value on error + */ +/* todo: available after implementing URMA_TM_RM(IB_RC) */ +urma_status_t urma_unadvise_jetty(urma_jetty_t *jetty, urma_target_jetty_t *tjetty); + +/** + * Bind jetty: construct the transport channel between local jetty and remote jetty. + * @param[in] [Required] jetty: local jetty to construct the transport channel; + * @param[in] [Required] tjetty: target jetty imported before; + * Return: 0 on success, URMA_EEXIST if the jetty has been binded, other value on error + * Note: A local jetty can be binded with only one remote jetty. Only supported by jetty under URMA_TM_RC. + */ +urma_status_t urma_bind_jetty(urma_jetty_t *jetty, urma_target_jetty_t *tjetty); + +/** + * Bind jetty: construct the transport channel between local jetty and remote jetty by control plane. + * Note: trans_mode from tjetty should be the same as the trans_mode of get_tp_list, + * users should obey this rule in case of unexpected errors. + * @param[in] [Required] jetty: local jetty to construct the transport channel; + * @param[in] [Required] tjetty: target jetty imported before; + * Return: 0 on success, URMA_EEXIST if the jetty has been binded, other value on error; + * @param[in] [Required] cfg: tp active configuration to exchange with target; + * Note: A local jetty can be binded with only one remote jetty. Only supported by jetty under URMA_TM_RC. + */ +urma_status_t urma_bind_jetty_ex(urma_jetty_t *jetty, urma_target_jetty_t *tjetty, urma_bind_jetty_ex_cfg_t *cfg); + +/** + * Unbind jetty: deconstruct the transport channel between local jetty and remote jetty. + * @param[in] [Required] jetty: local jetty to deconstruct the transport channel; + * Return: 0 on success, other value on error + */ +urma_status_t urma_unbind_jetty(urma_jetty_t *jetty); + +/** + * Poll the CRs for all the WRs that posted to Jetty, but are not completed. + * Call the API after modify Jetty to error, or polled a suspened done CR. + * CRs with status of URMA_CR_WR_FLUSH_ERR will be returned on success. + * @param[in] [Required] jetty: the jetty created before; + * @param[in] [Required] cr_cnt: Number of CR expected to be received.; + * @param[out] [Required] cr: Address for storing CR; + * Return: the number of CR returned, 0 means no CR returned, -1 on error + */ +int urma_flush_jetty(urma_jetty_t *jetty, int cr_cnt, urma_cr_t *cr); + +/** + * Get remote jetty information for proxy transmission. + * @param[in] [Required] jetty: the jetty created before; + * @param[out] [Required] rjetty: pointer to the remote jetty information; + * @param[out] [Required] length: length of the encapsulated data structure; + * Return: 0 on success, other value on error + */ +urma_status_t urma_get_rjetty(urma_jetty_t *jetty, urma_rjetty_t **rjetty, uint32_t *length); + +/** + * Free the remote jetty information allocated by urma_get_rjetty. + * @param[in] [Required] rjetty: the remote jetty information to free; + */ +void urma_put_rjetty(urma_rjetty_t *rjetty); + +/** + * Import a remote jetty asynchronously. + * @param[in] [Required] notifier: data structure used for sensing asynchronous link establishment results; + * @param[in] [Required] rjetty: information of remote jetty to import, including jetty id and trans_mode, + * trans_mode same to create_jetty trans_mode; + * @param[in] [Required] token_value: token to put into output jetty protection table; + * @param[in] [Required] user_ctx: user_ctx create by user; + * @param[in] [Required] timeout: task timeout set by user (milliseconds); + * Return: the address of target jetty, not NULL on success, NULL on error + */ +urma_target_jetty_t *urma_import_jetty_async(urma_notifier_t *notifier, const urma_rjetty_t *rjetty, + const urma_token_t *token_value, uint64_t user_ctx, int timeout); + +/** + * Unimport the imported remote jetty asynchronously. + * @param[in] [Required] tjetty: the target jetty to unimport; + * Return: 0 on success, other value on error + */ +urma_status_t urma_unimport_jetty_async(urma_target_jetty_t *tjetty); + +/** + * Bind jetty asynchronously: construct the transport channel between local jetty and remote jetty. + * @param[in] [Required] notifier: data structure used for sensing asynchronous link establishment results; + * @param[in] [Required] jetty: local jetty to construct the transport channel; + * @param[in] [Required] tjetty: target jetty imported before; + * @param[in] [Required] user_ctx: user_ctx create by user; + * @param[in] [Required] timeout: task timeout set by user (milliseconds); + * Return: 0 on success, URMA_EEXIST if the jetty has been binded, other value on error + * Note: A local jetty can be binded with only one remote jetty. Only supported by jetty under URMA_TM_RC. + */ +urma_status_t urma_bind_jetty_async(urma_notifier_t *notifier, urma_jetty_t *jetty, urma_target_jetty_t *tjetty, + uint64_t user_ctx, int timeout); + +/** + * Unbind jetty: deconstruct the transport channel between local jetty and remote jetty asynchronously. + * @param[in] [Required] jetty: local jetty to deconstruct the transport channel; + * Return: 0 on success, other value on error + */ +urma_status_t urma_unbind_jetty_async(urma_jetty_t *jetty); + +/** + * Create a data structure for sensing asynchronous link establishment results. + * @param[in] [Required] ctx: the urma context created before; + * Return: the address of urma notifier, not NULL on success, NULL on error + */ +urma_notifier_t *urma_create_notifier(urma_context_t *ctx); + +/** + * Delete the created notifier. + * @param[in] [Required] notifier: data structure used for sensing asynchronous link establishment results; + * Return: 0 on success, other value on error + */ +urma_status_t urma_delete_notifier(urma_notifier_t *notifier); + +/** + * Alloc a jetty. + * @param[in] [Required] urma_ctx: the urma context created before; + * @param[in] [Required] jetty_cfg: configuration including: depth, flag, jfce, user context; + * @param[out] [Required] jetty: handle of the allocated jetty; + * Return: 0 on success, other value on error + */ +urma_status_t urma_alloc_jetty(urma_context_t *urma_ctx, urma_jetty_cfg_t *cfg, urma_jetty_t **jetty); + +/** + * Set the opt of jetty. + * @param[in] [Required] jetty: handle of the allocated jetty; + * @param[in] [Required] opt: the opt to change cfg of jetty; + * @param[in] [Required] len: the len of the opt value(byte); + * @param[in] [Required] buf: the buffer to store the value; + * Return: 0 on success, other value on error + */ +urma_status_t urma_set_jetty_opt(urma_jetty_t *jetty, uint64_t opt, void *buf, uint32_t len); + +/** + * Active the allocated jetty. + * @param[in] [Required] jetty: handle of the allocated jetty; + * Return: 0 on success, other value on error + */ +urma_status_t urma_active_jetty(urma_jetty_t *jetty); + +/** + * Get the opt of jetty. + * @param[in] [Required] jetty: handle of the allocated jetty; + * @param[in] [Required] opt: the opt to change cfg of jetty; + * @param[in] [Required] len: the len of the opt value(byte); + * @param[out] [Required] buf: the buffer to store the value; + * Return: 0 on success, other value on error + */ +urma_status_t urma_get_jetty_opt(urma_jetty_t *jetty, uint64_t opt, void *buf, uint32_t len); + +/** + * Deactive the actived jetty. + * @param[in] [Required] jetty: handle of the allocated jetty; + * Return: 0 on success, other value on error + */ +urma_status_t urma_deactive_jetty(urma_jetty_t *jetty); + +/** + * Free the allocated jetty. + * @param[in] [Required] jetty: handle of the allocated jetty; + * After free, the jfc pointer is no longer allowed to be accessed. + * Return: 0 on success, other value on error + */ +urma_status_t urma_free_jetty(urma_jetty_t *jetty); + +/** + * Wait for asynchronous event notification to obtain the connection establishment result. + * @param[in] [Required] notifier: data structure used for sensing asynchronous link establishment results; + * @param[in] [Required] cnt: expected number of target jetty to return; + * @param[in] [Required] timeout: max time to wait (milliseconds), + timeout = 0: return immediately even if no events are ready, + timeout = -1: an infinite timeout; + * @param[out] [Required] notify: created by user to store target jetty results; + * Return: the number of target jetty returned, 0 means no target jetty returned, -1 on error + */ +int urma_wait_notify(urma_notifier_t *notifier, uint32_t cnt, urma_notify_t *notify, int timeout); + +/** + * This interface is no longer functional and will be removed later. + * Keep parameter checks to ensure the function works as before. + */ +urma_status_t urma_ack_notify(urma_context_t *ctx, uint32_t cnt, urma_notify_t *notify); + +/** + ******************** Beginning of URMA JETTY GROUP APIs *************************** + */ + +/** + * Create jetty group + * @param[in] [Required] ctx: the urma context created before; + * @param[in] [Required] cfg: pointer of the jetty group config; + * Return: the handle of created jetty group, not NULL on success, NULL on error + */ +urma_jetty_grp_t *urma_create_jetty_grp(urma_context_t *ctx, urma_jetty_grp_cfg_t *cfg); + +/** + * Destroy jetty group + * @param[in] [Required] jetty_grp: the Jetty group created before; + * Return: 0 on success, other value on error + */ +urma_status_t urma_delete_jetty_grp(urma_jetty_grp_t *jetty_grp); + +/** + * Create a jfce + * @param[in] [Required] ctx: the urma context created before; + * Return: the address of created jfce, not NULL on success, NULL on error + */ +urma_jfce_t *urma_create_jfce(urma_context_t *ctx); + +/** + * Delete a jfce + * @param[in] [Required] jfce: the jfce to be deleted; + * Return: 0 on success, other value on error + */ +urma_status_t urma_delete_jfce(urma_jfce_t *jfce); + +/** + * Get asyn event. + * @param[in] [Required] ctx: handle of the created urma context; + * @param[out] [Required] event: the address to put event + * Return: 0 on success, other value on error + */ +urma_status_t urma_get_async_event(urma_context_t *ctx, urma_async_event_t *event); + +/** + * Ack asyn event. + * @param[in] [Required] event: the address to ack event; + * Return: void + */ +void urma_ack_async_event(urma_async_event_t *event); + +/** + * Request to assign a token id. token id is used to register the segment with the protection table. + * @param[in] [Required] ctx: specifies the urma context. + * Return: pointer to key id on success, NULL on error. + */ +urma_token_id_t *urma_alloc_token_id(urma_context_t *ctx); + +/** + * Request to assign a token id. token id is used to register multiple segments with the protection table. + * Can use table mode or entry mode based on flag. + * @param[in] [Required] ctx: specifies the urma context. + * @param[in] [Required] flag: decides the mode of token id. use table mode if enable multi_seg in flag. + * Return: pointer to key id on success, NULL on error. + * Note: if use table mode, the VA address page alignment is required when register the segments. + */ +urma_token_id_t *urma_alloc_token_id_ex(urma_context_t *ctx, urma_token_id_flag_t flag); + +/** + * Request to release token id. + * @param[in] [Required] token_id: Specifies the token id to be released. + * Return: 0 on success, other value on error + */ +urma_status_t urma_free_token_id(urma_token_id_t *token_id); + +/** + * Register a memory segment on specified va address for local or remote access. + * @param[in] [Required] ctx: the created urma context pointer; + * @param[in] [Required] seg_cfg: Specify cfg of seg to be registered, including address, len, token, and so on; + * Return: pointer to target segment on success, NULL on error + * And the immedidate data wrote from clients is polled from this common jfc. + */ +urma_target_seg_t *urma_register_seg(urma_context_t *ctx, urma_seg_cfg_t *seg_cfg); + +/** + * Unregister a local memory segment on specified va address. + * @param[in] [Required] target_seg: target segment to be unregistered; + * Return: 0 on success, other value on error + */ +urma_status_t urma_unregister_seg(urma_target_seg_t *target_seg); + +/** + * Import a memory segment on specified ubva address. + * @param[in] [Required] ctx: the created urma context pointer; + * @param[in] [Required] seg: handle of memory segment to import; + * @param[in] [Required] token_value: token of remote side to put into output protection table; + * @param[in] [Optional] addr: the virtual address to which the segment will be mapped; + * @param[in] [Required] flag: flag to indicate the import attribute of memory segment; + * Return: pointer to target segment on success, NULL on error + */ +urma_target_seg_t *urma_import_seg(urma_context_t *ctx, urma_seg_t *seg, urma_token_t *token_value, uint64_t addr, + urma_import_seg_flag_t flag); + +/** + * Unimport a memory segment on specified ubva address. + * @param[in] [Required] tseg: the address of the target segment to unimport; + * Return: 0 on success, other value on error + */ +urma_status_t urma_unimport_seg(urma_target_seg_t *tseg); + +/** + * Get segment context for proxy transmission. + * @param[in] [Required] tseg: the target segment registered before; + * @param[out] [Required] seg: pointer to the segment context; + * @param[out] [Required] size: size of the encapsulated data structure; + * Return: 0 on success, other value on error + */ +urma_status_t urma_get_seg_ctx(urma_target_seg_t *tseg, urma_seg_t **seg, uint32_t *size); + +/** + * Free the segment context allocated by urma_get_seg_ctx. + * @param[in] [Required] seg: the segment context to free; + */ +void urma_put_seg_ctx(urma_seg_t *seg); + +/** + * post a request to read, write, atomic or send data. + * @param[in] jfs: the jfs created before, which is used to put command; + * @param[in] wr: the posting request all information, including src addr, dst addr, len, jfc, flag, ordering etc. + * @param[in] bad_wr: the first of failure request. + * Return: 0 on success, other value on error + */ +urma_status_t urma_post_jfs_wr(urma_jfs_t *jfs, urma_jfs_wr_t *wr, urma_jfs_wr_t **bad_wr); + +/** + * post a request to recv data. + * @param[in] jfr: the jfr created before, which is used to put command; + * @param[in] wr: the posting request all information, including sge, flag. + * @param[in] bad_wr: the first of failure request. + * Return: 0 on success, other value on error + */ +urma_status_t urma_post_jfr_wr(urma_jfr_t *jfr, urma_jfr_wr_t *wr, urma_jfr_wr_t **bad_wr); + +/** + * post a request to read, write, atomic or send data. + * @param[in] jetty: the jetty created before, which is used to put command; + * @param[in] wr: the posting request all information, including src addr, dst addr, len, jfc, flag, ordering etc. + * @param[in] bad_wr: the first of failure request. + * Return: 0 on success, other value on error + */ +urma_status_t urma_post_jetty_send_wr(urma_jetty_t *jetty, urma_jfs_wr_t *wr, urma_jfs_wr_t **bad_wr); + +/** + * post a request to recv data. + * @param[in] jetty: the jetty created before, which is used to put command; + * @param[in] wr: the posting request all information, including sge, flag. + * @param[in] bad_wr: the first of failure request. + * Return: 0 on success, other value on error + */ +urma_status_t urma_post_jetty_recv_wr(urma_jetty_t *jetty, urma_jfr_wr_t *wr, urma_jfr_wr_t **bad_wr); + +/** + * Write data to remote node. + * @param[in] jfs: the jfs created before, which is used to put command; + * @param[in] target_jfr: destination jetty receiver; + * @param[in] dst_tseg: the dst target seg imported before; + * @param[in] src_tseg: the src target seg registered before; + * @param[in] dst: destination address(mapping va on user node or rva in ubva on home node) to be written into + * @param[in] src: source address(local process address space) to fetch data + * @param[in] len: the data len to be written + * @param[in] flag: flag to control jfs work request attritube + * @param[in] user_ctx: the user context, such as request id(rid) etc. + * Return: 0 on success, other value on error + */ +urma_status_t urma_write(urma_jfs_t *jfs, urma_target_jetty_t *target_jfr, urma_target_seg_t *dst_tseg, + urma_target_seg_t *src_tseg, uint64_t dst, uint64_t src, uint32_t len, urma_jfs_wr_flag_t flag, + uint64_t user_ctx); + +/** + * Read data from remote node. + * @param[in] jfs: the jfs created before, which is used to put command; + * @param[in] target_jfr: destination jetty receiver; + * @param[in] dst_tseg: the seg registered before; + * @param[in] src_tseg: the target seg imported before; + * @param[in] dst: destination address(local process address space) to be written into + * @param[in] src: source address(mapping va or rva in ubva) to fetch data + * @param[in] len: the data len to be written + * @param[in] flag: the flag to control jfs work request attritube + * @param[in] user_ctx: the user context, such as request id(rid) etc. + * Return: 0 on success, other value on error + */ +urma_status_t urma_read(urma_jfs_t *jfs, urma_target_jetty_t *target_jfr, urma_target_seg_t *dst_tseg, + urma_target_seg_t *src_tseg, uint64_t dst, uint64_t src, uint32_t len, urma_jfs_wr_flag_t flag, + uint64_t user_ctx); + +/** + * Send data to remote node. + * @param[in] jfs: the jfs created before, which is used to put command; + * @param[in] target_jfr: destination jetty receiver(with full qualifed jfr id); + * @param[in] src_tseg: the seg registered before, can be NULL only when flag.bs.inline_flag == URMA_INLINE_ENABLE + * @param[in] src: source address for sending; + * @param[in] len: data length; + * @param[in] flag: flag to control jfs work request attritube + * @param[in] user_ctx: the user context, such as request id(rid) etc; + * Return: 0 on success, other value on error. + */ +urma_status_t urma_send(urma_jfs_t *jfs, urma_target_jetty_t *target_jfr, urma_target_seg_t *src_tseg, uint64_t src, + uint32_t len, urma_jfs_wr_flag_t flag, uint64_t user_ctx); + +/** + * Assign local buffer to receive data from remote node. + * @param[in] jfr: jetty receiver; + * @param[in] recv_tseg: the locally registered segment before for receiving; + * @param[in] buf: buffer address for receiving; + * @param[in] len: buffer length; + * @param[in] user_ctx: the user context, such as request id(rid) etc; + * Return: 0 on success, other value on error. + */ +urma_status_t urma_recv(urma_jfr_t *jfr, urma_target_seg_t *recv_tseg, uint64_t buf, uint32_t len, uint64_t user_ctx); + +/** + * Poll jfc to get completion record. + * @param[in] jfc: jetty completion queue to poll + * @param[in] cr_cnt: the expected number of completion record to get + * @param[out] cr: the completion record array to fill at least cr_cnt completion records + * Return: the number of completion record returned, 0 means no completion record returned, less than 0 on error + * Note that: at most 16 completion records can be polled for RDMA device + */ +int urma_poll_jfc(urma_jfc_t *jfc, int cr_cnt, urma_cr_t *cr); + +/** + * Arm jfc with interrupt mode. + * @param[in] jfc: jetty completion queue to arm to interrupt mode + * @param[in] solicited_only: indicate it will trigger event only for packets with solicited flag. + * Return: 0 on success, other value on error + */ +urma_status_t urma_rearm_jfc(urma_jfc_t *jfc, bool solicited_only); + +/** + * Wait jfce for event of any completion message is generated. + * @param[in] jfce: jetty event channel to wait on + * @param[in] jfc_cnt: expected jfc count to return + * @param[in] time_out: max time to wait (milliseconds), + * timeout = 0: return immediately even if no events are ready, + * timeout = -1: an infinite timeout + * @param[out] jfc: address to put the jfc handle + * Return: the number of jfc returned, 0 means no jfc returned, -1 on error + * Note: User should check error when wait_jfc returns 0, errno ERESTARTSYS(512) + * means wait operation was interrupted by a signal and this error should + * be ignored, users should continue to wait jfc. + */ +int urma_wait_jfc(urma_jfce_t *jfce, uint32_t jfc_cnt, int time_out, urma_jfc_t *jfc[]); + +/** + * Confirm that a JFC generated event has been processed. + * @param[in] jfc: jfc pointer array to be acknowledged + * @param[in] nevents: event count array to be acknowledged + * @param[in] jfc_cnt: number of elements in the array + * Return: void + */ +void urma_ack_jfc(urma_jfc_t *jfc[], uint32_t nevents[], uint32_t jfc_cnt); + +/** + * Get or allocate a uasid. + * @param[out] uasid: the address to put uasid + * Return: 0 on success, other value on error + */ +urma_status_t urma_get_uasid(uint32_t *uasid); + +/** + * User defined control of the context. + * @param[in] ctx: the created urma context pointer; + * @param[in] in: user ioctl cmd; + * @param[out] out: result of execution; + * Return: 0 on success, other value on error + * Note: This API only supports UB hardware currently. + */ +urma_status_t urma_user_ctl(urma_context_t *ctx, urma_user_ctl_in_t *in, urma_user_ctl_out_t *out); + +/** + * User register own log function, default rsyslog. + * @param[in] func: log callback func; + * Return: 0 on success, other value on error + */ +urma_status_t urma_register_log_func(urma_log_cb_t func); + +/** + * User register location log function with file, function and line info. + * @param[in] func: location log callback function; + * Return: 0 on success, other value on error + * Note: If both urma_register_log_func and urma_register_loc_log_func are called, + * the last registered function will be used. + */ +urma_status_t urma_register_loc_log_func(urma_loc_log_cb func); + +/** + * User unregister own log function, use rsyslog. + * Return: 0 on success, other value on error + */ +urma_status_t urma_unregister_log_func(void); + +/** + * get log level. + * Return: urma_vlog_level_t + */ +urma_vlog_level_t urma_log_get_level(void); + +/** + * set log level. + * @param[in] level: log level to set; + */ +void urma_log_set_level(urma_vlog_level_t level); + +/** + * get log thread tag. + * Return: const char * + */ +const char *urma_log_get_thread_tag(void); + +/** + * set log thread tag. + * @param[in] tag: log tag per thread; + */ +void urma_log_set_thread_tag(const char *tag); + +/** + * User tp only. + * Get tpn of tp created when creating jetty. + * @param[in] jetty: the created jetty pointer; + * Return: >= 0 on success, return as tpn; < 0 on error + */ +int urma_get_tpn(urma_jetty_t *jetty); + +/** + * Get net address info list, user tp only. + * @param[in] ctx: the created urma context pointer; + * @param[out] cnt: numer of net address info; + * Return: pointer of net address list; NULL on error + */ +urma_net_addr_info_t *urma_get_net_addr_list(urma_context_t *ctx, uint32_t *cnt); + +/** + * Free net address info list. + * @param[in] net_addr_list: pointer of net address list + */ +void urma_free_net_addr_list(urma_net_addr_info_t *net_addr_list); + +/** + * Modify tp by user connection. + * @param[in] ctx: the created urma context pointer; + * @param[in] tpn: tpn of tp created before; + * @param[in] cfg: tp configurations filled by user; + * @param[in] attr: tp attributes filled by user; + * @param[in] mask: bitmap configurations for tp attributes; + * Return: 0 on success; other values on error + */ +int urma_modify_tp(urma_context_t *ctx, uint32_t tpn, urma_tp_cfg_t *cfg, urma_tp_attr_t *attr, + urma_tp_attr_mask_t mask); + +/** + * get available tp list from control plane. + * @param[in] [Required] ctx: the created urma context pointer; + * @param[in] [Required] tp_cfg: tp configuration to get; + * @param[in && out] [Required] tp_cnt: tp_cnt is the length of tp_list buffer as in parameter; + * tp_cnt is the number of tp as out parameter; + * @param[out] [Required] tp_list: tp list to get, the buffer is allocated by user; + * Return: 0 on success, other value on error + */ +urma_status_t urma_get_tp_list(urma_context_t *ctx, urma_get_tp_cfg_t *cfg, uint32_t *tp_cnt, urma_tp_info_t *tp_list); + +/** + * set tp attribution values in control plane. + * @param[in] [Required] ctx: the created urma context pointer; + * @param[in] [Required] tp_handle: tp_handle got by urma_get_tp_list; + * @param[in] [Required] tp_attr_cnt: number of tp attributions; + * @param[in] [Required] tp_attr_bitmap: tp attributions bitmap, current bitmap is as follow: + * 0-retry_times_init: 3 bit 1-at: 5 bit 2-SIP: 128 bit + * 3-DIP: 128 bit 4-SMA: 48 bit 5-DMA: 48 bit + * 6-vlan_id: 12 bit 7-vlan_en: 1 bit 8-dscp: 6 bit + * 9-at_times: 5 bit 10-sl: 4 bit 11-ttl: 8 bit + * @param[in] [Required] tp_attr: tp attribution values to set; + * Return: 0 on success, other value on error + */ +urma_status_t urma_set_tp_attr(const urma_context_t *ctx, const uint64_t tp_handle, const uint8_t tp_attr_cnt, + const uint32_t tp_attr_bitmap, const urma_tp_attr_value_t *tp_attr); + +/** + * get tp attribution values in control plane. + * @param[in] [Required] ctx: the created urma context pointer; + * @param[in] [Required] tp_handle: tp_handle got by urma_get_tp_list; + * @param[out] [Required] tp_attr_cnt: number of tp attributions; + * @param[out] [Required] tp_attr_bitmap: tp attributions bitmap, current bitmap is as follow: + * 0-retry_times_init: 3 bit 1-at: 5 bit 2-SIP: 128 bit + * 3-DIP: 128 bit 4-SMA: 48 bit 5-DMA: 48 bit + * 6-vlan_id: 12 bit 7-vlan_en: 1 bit 8-dscp: 6 bit + * 9-at_times: 5 bit 10-sl: 4 bit 11-ttl: 8 bit + * @param[out] [Required] tp_attr: tp attribution values to get; + * Return: 0 on success, other value on error + */ +urma_status_t urma_get_tp_attr(const urma_context_t *ctx, const uint64_t tp_handle, uint8_t *tp_attr_cnt, + uint32_t *tp_attr_bitmap, urma_tp_attr_value_t *tp_attr); + +/** + * get eid by ip info + * @param[in] ctx: the created urma context pointer; + * @param[in] net_addr: the ip info (type and net_addr are valid, vlan, mac, prefix_len will not be used); + * @param[out] eid: device's eid; + * Return: 0 on success, other value on error + */ +urma_status_t urma_get_eid_by_ip(const urma_context_t *ctx, const urma_net_addr_t *net_addr, urma_eid_t *eid); + +/** + * get ip info by eid. + * @param[in] ctx: the created urma context pointer; + * @param[in] eid: device's eid; + * @param[out] net_addr: the ip info (type and net_addr are valid, vlan, mac, prefix_len will not be used); + * Return: 0 on success, other value on error + */ +urma_status_t urma_get_ip_by_eid(const urma_context_t *ctx, const urma_eid_t *eid, urma_net_addr_t *net_addr); + + +/** + * get source mac address. + + * @param[in] ctx: the created urma context pointer; + * @param[out] mac: the mac address of source; + * Return: 0 on success, other value on error + */ +urma_status_t urma_get_smac(const urma_context_t *ctx, uint8_t *mac); + +/** + * get dest mac address. + * @param[in] ctx: the created urma context pointer; + * @param[in] net_addr: the ip info (type and net_addr are valid, vlan, mac, prefix_len will not be used); + * @param[out] mac: the mac address of dest; + * Return: 0 on success, other value on error + */ +urma_status_t urma_get_dmac(const urma_context_t *ctx, const urma_net_addr_t *net_addr, uint8_t *mac); + +#ifdef __cplusplus + } +#endif + +#endif diff --git a/include/urma/urma_opcode.h b/include/urma/urma_opcode.h new file mode 100644 index 0000000..d1ef56f --- /dev/null +++ b/include/urma/urma_opcode.h @@ -0,0 +1,262 @@ +/* + * SPDX-License-Identifier: MIT + * Copyright (c) Huawei Technologies Co., Ltd. 2021-2025. All rights reserved. + * Description: URMA opcode header file + * Author: Ouyang Changchun, Yan Fangfang, Qian Guoxin + * Create: 2021-09-26 + * Note: + * History: 2021-09-26 Create File + */ + +#ifndef URMA_OPCODE_H +#define URMA_OPCODE_H + +#include + +/* urma bit field value */ +#define URMA_TOKEN_NONE 0 /* Indicates the verification policy of the key. */ +#define URMA_TOKEN_PLAIN_TEXT 1 +#define URMA_TOKEN_SIGNED 2 +#define URMA_TOKEN_ALL_ENCRYPTED 3 +#define URMA_TOKEN_RESERVED 4 + +#define URMA_TOKEN_ID_INVALID 0 +#define URMA_TOKEN_ID_VALID 1 + +#define URMA_DSVA_DISABLE 0 /* Indicates whether it is a segment of dsva. */ +#define URMA_DSVA_ENABLE 1 + +#define URMA_NON_CACHEABLE 0 /* Indicates whether the segment can be cached by multiple hosts. */ +#define URMA_CACHEABLE 1 + +/* If URMA_ACCESS_LOCAL_ONLY is set, local access will have all the permissions of + * READ, WRITE, and ATOMIC but external access is denied. + * If URMA_ACCESS_LOCAL_ONLY is not set, in addition to having all permissions for local access, + * the configuration of external access permissions is determined by the following three types, and + * it takes effect according to the combination of READ, WRITE, and ATOMIC configured by the user. + */ +#define URMA_ACCESS_LOCAL_ONLY (0x1 << 0) +#define URMA_ACCESS_READ (0x1 << 1) +#define URMA_ACCESS_WRITE (0x1 << 2) +#define URMA_ACCESS_ATOMIC (0x1 << 3) + +#define URMA_LOCAL_MEMORY 0 /* Indicates that the physical memory is remote. */ +#define URMA_REMOTE_MEMORY 1 + +#define URMA_SEG_NOMAP 0 /* Indicates that the current process has mapped this segment */ +#define URMA_SEG_MAPPED 1 + +#define URMA_ADDR_TYPE_MVA 0 +#define URMA_ADDR_TYPE_UBVA 1 + +#define URMA_COMPLETE_ENABLE 1 /* Notify the source after the task is completed. */ +#define URMA_COMPLETE_DISABLE 0 /* Do not notify the source after the task is complete. */ + +#define URMA_COMPLETE_TYPE_JFC 0 /* Complete notification via JFC. */ +#define URMA_COMPLETE_TYPE_CF 1 /* Complete notification via DDR address */ + +#define URMA_DEPENDENCY_NONE 0 /* There is no dependency between commands. */ +#define URMA_DEPENDENCY_FIRST \ + 1 /* Subsequent commands depend on the execution result \ + of the current command. */ +#define URMA_DEPENDENCY_DELAY \ + 2 /* The current command is executed only when the command \ + that the preamble depends on is executed successfully. */ + +#define URMA_NOTIFY_DISABLE 0 /* The destination is not notified when the task is completed. */ +#define URMA_NOTIFY_ENABLE 1 /* Notify the destination when the task is completed. */ + +#define URMA_NOTIFY_TYPE_JFC 0 /* Complete notification via JFC. */ +#define URMA_NOTIFY_TYPE_RVA 1 /* Complete notification via DDR address. */ + +#define URMA_INLINE_DISABLE 0 /* The data is generated by source_address assignment. */ +#define URMA_INLINE_ENABLE 1 /* The data is carried in the command. */ + +#define URMA_SOLICITED_DISABLE 0 /* There is no interruption when notifying through JFC. */ +#define URMA_SOLICITED_ENABLE 1 /* Interrupt occurred while notifying via JFC. */ + +#define URMA_FENCE_DISABLE 0 /* There is no fence. */ +#define URMA_FENCE_ENABLE 1 /* Fence with previous WRs. */ + +#define URMA_REGULAR 1 /* regular, specifies stride format. */ +#define URMA_IRREGULAR 0 /* irregular, specifies S/G format. */ + +#define URMA_NO_TAG_MATCHING 0 +#define URMA_WITH_TAG_MATCHING 1 + +#define URMA_NONPOST_LS 0 +#define URMA_POST_LS 1 + +#define URMA_NO_SHARE_JFR 0 +#define URMA_SHARE_JFR 1 + +#define URMA_TYPICAL_RNR_RETRY 7 /* typical value of rnr retry for jfs cfg */ +#define URMA_TYPICAL_ERR_TIMEOUT 17 /* typical value of err_timeout for jfs cfg */ +#define URMA_TYPICAL_MIN_RNR_TIMER 12 /* typical value of min_rnr_timer for jfr cfg */ +#define URMA_MAX_PRIORITY 15 + +/* operation information */ +typedef enum urma_place_order { + URMA_NO_ORDER = 0, // No order + URMA_RELAX_ORDER, // Relax order + URMA_STRONG_ORDER // Strong order +} urma_place_order_t; + +/* opcode definition */ +typedef enum urma_opcode { + URMA_OPC_WRITE = 0x00, + URMA_OPC_WRITE_IMM = 0x01, + URMA_OPC_WRITE_NOTIFY = 0x02, // not support result will return for URMA_OPC_WRITE_NOTIFY + URMA_OPC_READ = 0x10, + URMA_OPC_CAS = 0x20, + URMA_OPC_SWAP = 0x21, + URMA_OPC_FADD = 0x22, + URMA_OPC_FSUB = 0x23, + URMA_OPC_FAND = 0x24, + URMA_OPC_FOR = 0x25, + URMA_OPC_FXOR = 0x26, + URMA_OPC_SEND = 0x40, // remote JFR/jetty ID + URMA_OPC_SEND_IMM = 0x41, // remote JFR/jetty ID + URMA_OPC_SEND_INVALIDATE = 0x42, // remote JFR/jetty ID and seg token id + URMA_OPC_NOP = 0x51, + URMA_OPC_WRITE_ATOMIC = 0x60, // Non-standard definition of OPCODE + URMA_OPC_FLUSH_DMA = 0x80, + URMA_OPC_LAST +} urma_opcode_t; + +typedef int urma_status_t; +#define URMA_SUCCESS 0 +#define URMA_EAGAIN EAGAIN // Resource temporarily unavailable +#define URMA_ENOMEM ENOMEM // Failed to allocate memory +#define URMA_ENOPERM EPERM // Operation not permitted +#define URMA_ETIMEOUT ETIMEDOUT // Operation time out +#define URMA_EINVAL EINVAL // Invalid argument +#define URMA_EEXIST EEXIST // Exist +#define URMA_EINPROGRESS EINPROGRESS +#define URMA_FAIL 0x1000 /* 0x1000 */ + +/* completion information */ +typedef enum urma_cr_status { // completion record status + URMA_CR_SUCCESS = 0, + URMA_CR_UNSUPPORTED_OPCODE_ERR, /* Opcode in the WR is not supported */ + URMA_CR_LOC_LEN_ERR, /* Local data too long error */ + URMA_CR_LOC_OPERATION_ERR, /* Local operation err */ + URMA_CR_LOC_ACCESS_ERR, /* Access to local memory error */ + URMA_CR_REM_RESP_LEN_ERR, /* Local Operation Error, with sub-status of Remote Response Length Error */ + URMA_CR_REM_UNSUPPORTED_REQ_ERR, + URMA_CR_REM_OPERATION_ERR, /* Error when target jetty can not complete the operation */ + URMA_CR_REM_ACCESS_ABORT_ERR, /* Error when target jetty access memory error or abort the operation */ + URMA_CR_ACK_TIMEOUT_ERR, /* Retransmission exceeds the maximum number of times */ + URMA_CR_RNR_RETRY_CNT_EXC_ERR, /* RNR retries exceeded the maximum number: remote jfr has no buffer */ + URMA_CR_WR_FLUSH_ERR, /* Jetty in the error state, and the hardware has processed the WR. */ + URMA_CR_WR_SUSPEND_DONE, /* Hardware constructs a fake CQE, and user_ctx is invalid. */ + URMA_CR_WR_FLUSH_ERR_DONE, /* Hardware constructs a fake CQE, and user_ctx is invalid. */ + URMA_CR_WR_UNHANDLED, /* Return of flush jetty/jfs, and the hardware has not processed the WR. */ + URMA_CR_LOC_DATA_POISON, /* Local Data Poison */ + URMA_CR_REM_DATA_POISON, /* Remote Data Poison */ +} urma_cr_status_t; + +typedef enum urma_cr_opcode { + URMA_CR_OPC_SEND = 0x00, + URMA_CR_OPC_SEND_WITH_IMM, + URMA_CR_OPC_SEND_WITH_INV, + URMA_CR_OPC_WRITE_WITH_IMM, + URMA_CR_OPC_FLUSH_WRITE, +} urma_cr_opcode_t; + +/* event information */ +typedef enum urma_async_event_type { + URMA_EVENT_JFC_ERR, + URMA_EVENT_JFS_ERR, + URMA_EVENT_JFR_ERR, + URMA_EVENT_JFR_LIMIT, + URMA_EVENT_JETTY_ERR, + URMA_EVENT_JETTY_LIMIT, + URMA_EVENT_JETTY_GRP_ERR, + URMA_EVENT_PORT_ACTIVE, + URMA_EVENT_PORT_DOWN, + URMA_EVENT_DEV_FATAL, + URMA_EVENT_EID_CHANGE, // eid change, HNM and other management roles will be modified. + URMA_EVENT_ELR_ERR, /* Entity level error */ + URMA_EVENT_ELR_DONE /* Entity flush done */ +} urma_async_event_type_t; + +typedef enum urma_jfc_state { + URMA_JFC_STATE_INVALID = 0, + URMA_JFC_STATE_VALID, + URMA_JFC_STATE_ERROR +} urma_jfc_state_t; + +typedef enum urma_jetty_state { + URMA_JETTY_STATE_RESET = 0, + URMA_JETTY_STATE_READY, + URMA_JETTY_STATE_SUSPENDED, + URMA_JETTY_STATE_ERROR +} urma_jetty_state_t; + +typedef enum urma_jfr_state { + URMA_JFR_STATE_RESET = 0, + URMA_JFR_STATE_READY, + URMA_JFR_STATE_ERROR +} urma_jfr_state_t; + +#define URMA_JFS_DEPTH 0x0001 +#define URMA_JFS_FLAG 0x0002 +#define URMA_JFS_TRANS_MODE 0x0003 +#define URMA_JFS_PRIORITY 0x0004 +#define URMA_JFS_MAX_SGE 0x0005 +#define URMA_JFS_MAX_RSGE 0x0006 +#define URMA_JFS_MAX_INLINE_DATA 0x0007 +#define URMA_JFS_RNR_RETRY 0x0008 +#define URMA_JFS_ERR_TIMEOUT 0x0009 +#define URMA_JFS_BIND_JFC 0x000a +#define URMA_JFS_USER_CTX 0x000b +#define URMA_JFS_SQE_BASE_ADDR 0x000c +#define URMA_JFS_ID 0x000d +#define URMA_JFS_DB_ADDR 0x000e +#define URMA_JFS_DB_STATUS 0x000f +#define URMA_JFS_PI 0x0010 +#define URMA_JFS_PI_TYPE 0x0011 +#define URMA_JFS_CI 0x0012 +#define URMA_JFS_FULL_CTX 0x0013 + +#define URMA_JFR_DEPTH 0x1001 +#define URMA_JFR_FLAG 0x1002 +#define URMA_JFR_TRANS_MODE 0x1003 +#define URMA_JFR_MAX_SGE 0x1004 +#define URMA_JFR_MIN_RNR_TIMER 0x1005 +#define URMA_JFR_BIND_JFC 0x1006 +#define URMA_JFR_TOKEN_VALUE 0x1007 +#define URMA_JFR_USER_CTX 0x1008 +#define URMA_JFR_RQE_BASE_ADDR 0x1009 +#define URMA_JFR_ID 0x100a +#define URMA_JFR_DB_ADDR 0x100b +#define URMA_JFR_DB_STATUS 0x100c +#define URMA_JFR_PI 0x100d +#define URMA_JFR_PI_TYPE 0x100e +#define URMA_JFR_CI 0x100f +#define URMA_JFR_FULL_CTX 0x1010 + +#define URMA_JFC_DEPTH 0x2001 +#define URMA_JFC_CEQN 0x2002 +#define URMA_JFC_FLAG 0x2003 +#define URMA_JFC_BIND_JFCE 0x2004 +#define URMA_JFC_USER_CTX 0x2005 +#define URMA_JFC_CQE_BASE_ADDR 0x2006 +#define URMA_JFC_ID 0x2007 +#define URMA_JFC_DB_ADDR 0x2008 +#define URMA_JFC_DB_STATUS 0x2009 +#define URMA_JFC_PI 0x200a +#define URMA_JFC_PI_TYPE 0x200b +#define URMA_JFC_CI 0x200c +#define URMA_JFC_FULL_CTX 0x200d + +#define URMA_JETTY_ID 0x3001 +#define URMA_JETTY_FLAG 0x3002 +#define URMA_JETTY_BIND_JFR 0x3003 +#define URMA_JETTY_BIND_RX_JFC 0x3004 +#define URMA_JETTY_BIND_JTG 0x3005 +#define URMA_JETTY_USER_CTX 0x3006 +#define URMA_JETTY_FULL_CTX 0x3007 + +#endif // URMA_OPCODE_H diff --git a/include/urma/urma_provider.h b/include/urma/urma_provider.h new file mode 100644 index 0000000..d2510e3 --- /dev/null +++ b/include/urma/urma_provider.h @@ -0,0 +1,423 @@ +/* + * SPDX-License-Identifier: MIT + * Copyright (c) Huawei Technologies Co., Ltd. 2021-2025. All rights reserved. + * Description: Liburma interface open to provier + * Author: Qian Guoxin + * Create: 2021-07-31 + * Note: + * History: 2021-07-31 create file + */ + +#ifndef URMA_PROVIDER_H +#define URMA_PROVIDER_H + +#include + +#include "urma_api.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define URMA_SYSFS_DEV_FLAG_DRIVER_CREATED (0x1) +#define URMA_CFG_MASK 0 + +typedef enum { + TARGET_CFG, + TARGET_OPT, + TARGET_JFS_CFG, +} urma_field_target_t; + +typedef struct { + uint64_t opt; /* opt id (eg. URMA_JFC_DEPTH) */ + uint64_t mask; /* bit mask value for this opt (eg. URMA_JFC_DEPTH_MASK) */ + urma_field_target_t tgt; /* which sub-struct the field belongs to */ + size_t offset; /* offsetof(sub-struct, member) */ + size_t size; /* sizeof(member) */ +} opt_map_t; + +extern const opt_map_t JFS_OPT_TABLE[]; +extern const size_t JFS_OPT_MAP_COUNT; +extern const opt_map_t JFR_OPT_TABLE[]; +extern const size_t JFR_OPT_MAP_COUNT; +extern const opt_map_t JFC_OPT_TABLE[]; +extern const size_t JFC_OPT_MAP_COUNT; +extern const opt_map_t JETTY_OPT_TABLE[]; +extern const size_t JETTY_OPT_MAP_COUNT; + +typedef struct urma_match_entry { + uint16_t vendor_id; + uint16_t device_id; +} urma_match_entry_t; + +typedef struct urma_udrv { + uint64_t in_addr; + uint32_t in_len; + uint64_t out_addr; + uint32_t out_len; +} urma_udrv_t; + +typedef struct urma_ops { + /* OPs name */ + const char *name; + + /* Jetty OPs */ + urma_jfc_t *(*create_jfc)(urma_context_t *ctx, urma_jfc_cfg_t *jfc_cfg); + urma_status_t (*modify_jfc)(urma_jfc_t *jfc, urma_jfc_attr_t *attr); + urma_status_t (*delete_jfc)(urma_jfc_t *jfc); + urma_status_t (*delete_jfc_batch)(urma_jfc_t **jfc, int jfc_num, urma_jfc_t **bad_jfc); + urma_status_t (*alloc_jfc)(urma_context_t *ctx, urma_jfc_cfg_t *cfg, urma_jfc_t **jfc); + urma_status_t (*set_jfc_opt)(urma_jfc_t *jfc, uint64_t opt, void *buf, uint32_t len); + urma_status_t (*active_jfc)(urma_jfc_t *jfc); + urma_status_t (*get_jfc_opt)(urma_jfc_t *jfc, uint64_t opt, void *buf, uint32_t len); + urma_status_t (*deactive_jfc)(urma_jfc_t *jfc); + urma_status_t (*free_jfc)(urma_jfc_t *jfc); + urma_jfs_t *(*create_jfs)(urma_context_t *ctx, urma_jfs_cfg_t *jfs); + urma_status_t (*modify_jfs)(urma_jfs_t *jfs, urma_jfs_attr_t *attr); + urma_status_t (*query_jfs)(urma_jfs_t *jfs, urma_jfs_cfg_t *cfg, urma_jfs_attr_t *attr); + int (*flush_jfs)(urma_jfs_t *jfs, int cr_cnt, urma_cr_t *cr); + urma_status_t (*delete_jfs)(urma_jfs_t *jfs); + urma_status_t (*delete_jfs_batch)(urma_jfs_t **jfs_arr, int jfs_num, urma_jfs_t **bad_jfs); + urma_status_t (*alloc_jfs)(urma_context_t *ctx, urma_jfs_cfg_t *cfg, urma_jfs_t **jfs); + urma_status_t (*set_jfs_opt)(urma_jfs_t *jfs, uint64_t opt, void *buf, uint32_t len); + urma_status_t (*active_jfs)(urma_jfs_t *jfs); + urma_status_t (*get_jfs_opt)(urma_jfs_t *jfs, uint64_t opt, void *buf, uint32_t len); + urma_status_t (*deactive_jfs)(urma_jfs_t *jfs); + urma_status_t (*free_jfs)(urma_jfs_t *jfs); + urma_jfr_t *(*create_jfr)(urma_context_t *ctx, urma_jfr_cfg_t *jfr); + urma_status_t (*modify_jfr)(urma_jfr_t *jfr, urma_jfr_attr_t *attr); + urma_status_t (*query_jfr)(urma_jfr_t *jfr, urma_jfr_cfg_t *cfg, urma_jfr_attr_t *attr); + urma_status_t (*delete_jfr)(urma_jfr_t *jfr); + urma_status_t (*delete_jfr_batch)(urma_jfr_t **jfr_arr, int jfr_num, urma_jfr_t **bad_jfr); + urma_target_jetty_t *(*import_jfr)(urma_context_t *ctx, urma_rjfr_t *rjfr, urma_token_t *token); + urma_status_t (*unimport_jfr)(urma_target_jetty_t *target_jfr); + urma_status_t (*advise_jfr)(urma_jfs_t *jfs, urma_target_jetty_t *tjfr); + urma_status_t (*unadvise_jfr)(urma_jfs_t *jfs, urma_target_jetty_t *tjfr); + urma_status_t (*advise_jfr_async)(urma_jfs_t *jfs, urma_target_jetty_t *tjfr, urma_advise_async_cb_func cb_fun, + void *cb_arg); + urma_status_t (*alloc_jfr)(urma_context_t *ctx, urma_jfr_cfg_t *cfg, urma_jfr_t **jfr); + urma_status_t (*set_jfr_opt)(urma_jfr_t *jfr, uint64_t opt, void *buf, uint32_t len); + urma_status_t (*active_jfr)(urma_jfr_t *jfr); + urma_status_t (*get_jfr_opt)(urma_jfr_t *jfr, uint64_t opt, void *buf, uint32_t len); + urma_status_t (*deactive_jfr)(urma_jfr_t *jfr); + urma_status_t (*free_jfr)(urma_jfr_t *jfr); + urma_jetty_t *(*create_jetty)(urma_context_t *ctx, urma_jetty_cfg_t *jetty_cfg); + urma_status_t (*modify_jetty)(urma_jetty_t *jetty, urma_jetty_attr_t *jetty_attr); + urma_status_t (*query_jetty)(urma_jetty_t *jetty, urma_jetty_cfg_t *cfg, urma_jetty_attr_t *attr); + int (*flush_jetty)(urma_jetty_t *jetty, int cr_cnt, urma_cr_t *cr); + urma_status_t (*delete_jetty)(urma_jetty_t *jetty); + urma_status_t (*delete_jetty_batch)(urma_jetty_t **jetty_arr, int jetty_num, urma_jetty_t **bad_jetty); + urma_target_jetty_t *(*import_jetty)(urma_context_t *ctx, urma_rjetty_t *rjetty, urma_token_t *rjetty_token); + urma_status_t (*unimport_jetty)(urma_target_jetty_t *target_jetty); + urma_status_t (*advise_jetty)(urma_jetty_t *jetty, urma_target_jetty_t *tjetty); + urma_status_t (*unadvise_jetty)(urma_jetty_t *jetty, urma_target_jetty_t *tjetty); + urma_status_t (*advise_jetty_async)(urma_jetty_t *jetty, urma_target_jetty_t *tjetty, + urma_advise_async_cb_func cb_fun, void *cb_arg); + urma_status_t (*bind_jetty)(urma_jetty_t *jetty, urma_target_jetty_t *tjetty); + urma_status_t (*unbind_jetty)(urma_jetty_t *jetty); + urma_status_t (*alloc_jetty)(urma_context_t *ctx, urma_jetty_cfg_t *cfg, urma_jetty_t **jetty); + urma_status_t (*set_jetty_opt)(urma_jetty_t *jetty, uint64_t opt, void *buf, uint32_t len); + urma_status_t (*active_jetty)(urma_jetty_t *jetty); + urma_status_t (*get_jetty_opt)(urma_jetty_t *jetty, uint64_t opt, void *buf, uint32_t len); + urma_status_t (*deactive_jetty)(urma_jetty_t *jetty); + urma_status_t (*free_jetty)(urma_jetty_t *jetty); + urma_jetty_grp_t *(*create_jetty_grp)(urma_context_t *ctx, urma_jetty_grp_cfg_t *cfg); + urma_status_t (*delete_jetty_grp)(urma_jetty_grp_t *jetty_grp); + urma_jfce_t *(*create_jfce)(urma_context_t *ctx); + urma_status_t (*delete_jfce)(urma_jfce_t *jfce); + /** + * Get tpn of current jetty + * @param[in] jetty: the jetty pointer created before + * Return: 0 or positive as correct tpn; negative as get tpn failure + */ + int (*get_tpn)(urma_jetty_t *jetty); + int (*modify_tp)(urma_context_t *ctx, uint32_t tpn, urma_tp_cfg_t *cfg, urma_tp_attr_t *attr, + urma_tp_attr_mask_t mask); + /* Control plane OPs */ + urma_status_t (*get_tp_list)(urma_context_t *ctx, urma_get_tp_cfg_t *cfg, uint32_t *tp_cnt, + urma_tp_info_t *tp_list); + urma_status_t (*set_tp_attr)(const urma_context_t *ctx, const uint64_t tp_handle, const uint8_t tp_attr_cnt, + const uint32_t tp_attr_bitmap, const urma_tp_attr_value_t *tp_attr); + urma_status_t (*get_tp_attr)(const urma_context_t *ctx, const uint64_t tp_handle, uint8_t *tp_attr_cnt, + uint32_t *tp_attr_bitmap, urma_tp_attr_value_t *tp_attr); + urma_target_jetty_t *(*import_jetty_ex)(urma_context_t *ctx, urma_rjetty_t *rjetty, urma_token_t *token_value, + urma_active_tp_cfg_t *active_tp_cfg); + urma_target_jetty_t *(*import_jfr_ex)(urma_context_t *ctx, urma_rjfr_t *rjfr, urma_token_t *token_value, + urma_active_tp_cfg_t *active_tp_cfg); + urma_status_t (*bind_jetty_ex)(urma_jetty_t *jetty, urma_target_jetty_t *tjetty, + urma_active_tp_cfg_t *active_tp_cfg); + + /* Segment OPs */ + urma_token_id_t *(*alloc_token_id)(urma_context_t *ctx); + urma_token_id_t *(*alloc_token_id_ex)(urma_context_t *ctx, urma_token_id_flag_t flag); + urma_status_t (*free_token_id)(urma_token_id_t *token_id); + urma_target_seg_t *(*register_seg)(urma_context_t *ctx, urma_seg_cfg_t *seg_cfg); + urma_status_t (*unregister_seg)(urma_target_seg_t *target_seg); + urma_target_seg_t *(*import_seg)(urma_context_t *ctx, urma_seg_t *seg, urma_token_t *token, uint64_t addr, + urma_import_seg_flag_t flag); + urma_status_t (*unimport_seg)(urma_target_seg_t *target_seg); + + /* Events OPs */ + urma_status_t (*get_async_event)(urma_context_t *ctx, urma_async_event_t *event); + void (*ack_async_event)(urma_async_event_t *event); + + /* Other OPs */ + int (*user_ctl)(urma_context_t *ctx, urma_user_ctl_in_t *in, urma_user_ctl_out_t *out); + + /* Dataplane OPs */ + urma_status_t (*post_jfs_wr)(urma_jfs_t *jfs, urma_jfs_wr_t *wr, urma_jfs_wr_t **bad_wr); + urma_status_t (*post_jfr_wr)(urma_jfr_t *jfr, urma_jfr_wr_t *wr, urma_jfr_wr_t **bad_wr); + urma_status_t (*post_jetty_send_wr)(urma_jetty_t *jetty, urma_jfs_wr_t *wr, urma_jfs_wr_t **bad_wr); + urma_status_t (*post_jetty_recv_wr)(urma_jetty_t *jetty, urma_jfr_wr_t *wr, urma_jfr_wr_t **bad_wr); + int (*poll_jfc)(urma_jfc_t *jfc, int cr_cnt, urma_cr_t *cr); + urma_status_t (*rearm_jfc)(urma_jfc_t *jfc, bool solicited_only); + int (*wait_jfc)(urma_jfce_t *jfce, uint32_t jfc_cnt, int time_out, urma_jfc_t *jfc[]); + void (*ack_jfc)(urma_jfc_t *jfc[], uint32_t nevents[], uint32_t jfc_cnt); + + /* Jetty async OPs */ + urma_target_jetty_t *(*import_jetty_async)(urma_notifier_t *notifier, const urma_rjetty_t *rjetty, + const urma_token_t *token_value, uint64_t user_ctx, int timeout); + urma_status_t (*unimport_jetty_async)(urma_target_jetty_t *target_jetty); + + urma_status_t (*bind_jetty_async)(urma_notifier_t *notifier, urma_jetty_t *jetty, urma_target_jetty_t *tjetty, + uint64_t user_ctx, int timeout); + urma_status_t (*unbind_jetty_async)(urma_jetty_t *jetty); + + urma_notifier_t *(*create_notifier)(urma_context_t *ctx); + urma_status_t (*delete_notifier)(urma_notifier_t *notifier); + int (*wait_notify)(urma_notifier_t *notifier, uint32_t cnt, urma_notify_t *notify, int timeout); + void (*ack_notify)(uint32_t cnt, urma_notify_t *notify); + urma_status_t (*get_eid_by_ip)(const urma_context_t *ctx, const urma_net_addr_t *net_addr, urma_eid_t *eid); + urma_status_t (*get_ip_by_eid)(const urma_context_t *ctx, const urma_eid_t *eid, urma_net_addr_t *net_addr); + urma_status_t (*get_smac)(const urma_context_t *ctx, uint8_t *mac); + urma_status_t (*get_dmac)(const urma_context_t *ctx, const urma_net_addr_t *net_addr, uint8_t *mac); +} urma_ops_t; + +typedef struct urma_provider_attr { + uint32_t version; /* compatible with abi verison of kernel driver */ + urma_transport_type_t transport_type; +} urma_provider_attr_t; + +typedef struct urma_provider_ops { + const char *name; + urma_provider_attr_t attr; + urma_match_entry_t *match_table; + urma_status_t (*init)(urma_init_attr_t *conf); + urma_status_t (*uninit)(void); + /* Device OPs */ + urma_status_t (*query_device)(urma_device_t *dev, urma_device_attr_t *dev_attr); + urma_context_t *(*create_context)(urma_device_t *dev, uint32_t eid_index, int dev_fd); + urma_status_t (*delete_context)(urma_context_t *ctx); + urma_status_t (*get_uasid)(uint32_t *uasid); /* obsolete */ + /* Log Ops */ + urma_status_t (*register_log_func)(urma_log_cb_t func); + urma_status_t (*unregister_log_func)(void); +} urma_provider_ops_t; + +typedef struct urma_import_tseg_cfg { + urma_ubva_t ubva; + uint64_t len; + urma_seg_attr_t attr; + uint32_t token_id; + urma_token_t *token; + urma_import_seg_flag_t flag; + uint64_t mva; +} urma_import_tseg_cfg_t; + +typedef struct urma_tjfr_cfg { + urma_jfr_id_t jfr_id; + urma_import_jetty_flag_t flag; + urma_token_t *token; + urma_transport_mode_t trans_mode; + urma_tp_type_t tp_type; +} urma_tjfr_cfg_t; + +typedef struct urma_tjetty_cfg { + urma_jetty_id_t jetty_id; + urma_import_jetty_flag_t flag; + urma_token_t *token; + urma_transport_mode_t trans_mode; + urma_jetty_grp_policy_t policy; + urma_target_type_t type; + urma_tp_type_t tp_type; +} urma_tjetty_cfg_t; + +typedef struct urma_context_cfg { + struct urma_device *dev; + struct urma_ops *ops; + uint32_t eid_index; + int dev_fd; + uint32_t uasid; +} urma_context_cfg_t; + +#ifndef URMA_CMD_UDRV_PRIV +#define URMA_CMD_UDRV_PRIV +typedef struct urma_cmd_udrv_priv { + uint64_t in_addr; + uint32_t in_len; + uint64_t out_addr; + uint32_t out_len; +} urma_cmd_udrv_priv_t; +#endif + +typedef struct urma_post_and_ret_db_in { + bool is_jetty; + union { + urma_jfs_t *jfs; + urma_jetty_t *jetty; + }; + urma_jfs_wr_t *wr; +} urma_post_and_ret_db_in_t; + +typedef struct urma_post_and_ret_db_out { + urma_jfs_wr_t **bad_wr; + uint64_t db_addr; + uint64_t db_data; +} urma_post_and_ret_db_out_t; + +int urma_register_provider_ops(urma_provider_ops_t *provider_ops); +int urma_unregister_provider_ops(urma_provider_ops_t *provider_ops); +ssize_t urma_read_sysfs_file(const char *dir, const char *file, char *buf, size_t size); + +int urma_cmd_create_context(urma_context_t *ctx, urma_context_cfg_t *cfg, urma_cmd_udrv_priv_t *udata); +int urma_cmd_delete_context(urma_context_t *ctx); + +/* Return jfce fd */ +int urma_cmd_create_jfce(urma_context_t *ctx); + +int urma_cmd_create_jfc(urma_context_t *ctx, urma_jfc_t *jfc, urma_jfc_cfg_t *cfg, urma_cmd_udrv_priv_t *udata); +int urma_cmd_modify_jfc(urma_jfc_t *jfc, urma_jfc_attr_t *attr, urma_cmd_udrv_priv_t *udata); +int urma_cmd_delete_jfc(urma_jfc_t *jfc); +int urma_cmd_delete_jfc_batch(urma_jfc_t **jfc_arr, int jfc_num, urma_jfc_t **bad_jfc); + +/* Return number of events on success, -1 on error */ +int urma_cmd_wait_jfc(int jfce_fd, uint32_t jfc_cnt, int time_out, urma_jfc_t *jfc[]); +void urma_cmd_ack_jfc(urma_jfc_t *jfc[], uint32_t nevents[], uint32_t jfc_cnt); +int urma_cmd_alloc_jfc(urma_context_t *ctx, urma_jfc_cfg_t *cfg, urma_jfc_t *jfc, urma_cmd_udrv_priv_t *udata); +int urma_cmd_set_jfc_opt(urma_jfc_t *jfc, uint64_t opt, void *buf, uint32_t len, urma_cmd_udrv_priv_t *udata); +int urma_cmd_active_jfc(urma_jfc_t *jfc, urma_cmd_udrv_priv_t *udata); +int urma_cmd_get_jfc_opt(urma_jfc_t *jfc, uint64_t opt, void *buf, uint32_t len, urma_cmd_udrv_priv_t *udata); +int urma_cmd_deactive_jfc(urma_jfc_t *jfc, urma_cmd_udrv_priv_t *udata); +int urma_cmd_free_jfc(urma_jfc_t *jfc, urma_cmd_udrv_priv_t *udata); + +int urma_cmd_create_jfs(urma_context_t *ctx, urma_jfs_t *jfs, urma_jfs_cfg_t *cfg, urma_cmd_udrv_priv_t *udata); +int urma_cmd_modify_jfs(urma_jfs_t *jfs, urma_jfs_attr_t *attr, urma_cmd_udrv_priv_t *udata); +int urma_cmd_query_jfs(urma_jfs_t *jfs, urma_jfs_cfg_t *cfg, urma_jfs_attr_t *attr); +int urma_cmd_delete_jfs(urma_jfs_t *jfs); +int urma_cmd_delete_jfs_batch(urma_jfs_t **jfs_arr, int jfs_num, urma_jfs_t **bad_jfs); +int urma_cmd_alloc_jfs(urma_context_t *ctx, urma_jfs_cfg_t *cfg, urma_jfs_t *jfs, urma_cmd_udrv_priv_t *udata); +int urma_cmd_set_jfs_opt(urma_jfs_t *jfs, uint64_t opt, void *buf, uint32_t len, urma_cmd_udrv_priv_t *udata); +int urma_cmd_active_jfs(urma_jfs_t *jfs, urma_cmd_udrv_priv_t *udata); +int urma_cmd_get_jfs_opt(urma_jfs_t *jfs, uint64_t opt, void *buf, uint32_t len, urma_cmd_udrv_priv_t *udata); +int urma_cmd_deactive_jfs(urma_jfs_t *jfs, urma_cmd_udrv_priv_t *udata); +int urma_cmd_free_jfs(urma_jfs_t *jfs, urma_cmd_udrv_priv_t *udata); + +int urma_cmd_create_jfr(urma_context_t *ctx, urma_jfr_t *jfr, urma_jfr_cfg_t *cfg, urma_cmd_udrv_priv_t *udata); +int urma_cmd_modify_jfr(urma_jfr_t *jfr, urma_jfr_attr_t *attr, urma_cmd_udrv_priv_t *udata); +int urma_cmd_query_jfr(urma_jfr_t *jfr, urma_jfr_cfg_t *cfg, urma_jfr_attr_t *attr); +int urma_cmd_delete_jfr(urma_jfr_t *jfr); +int urma_cmd_delete_jfr_batch(urma_jfr_t **jfr_arr, int jfr_num, urma_jfr_t **bad_jfr); +int urma_cmd_alloc_jfr(urma_context_t *ctx, urma_jfr_cfg_t *cfg, urma_jfr_t *jfr, urma_cmd_udrv_priv_t *udata); +int urma_cmd_set_jfr_opt(urma_jfr_t *jfr, uint64_t opt, void *buf, uint32_t len, urma_cmd_udrv_priv_t *udata); +int urma_cmd_active_jfr(urma_jfr_t *jfr, urma_cmd_udrv_priv_t *udata); +int urma_cmd_get_jfr_opt(urma_jfr_t *jfr, uint64_t opt, void *buf, uint32_t len, urma_cmd_udrv_priv_t *udata); +int urma_cmd_deactive_jfr(urma_jfr_t *jfr, urma_cmd_udrv_priv_t *udata); +int urma_cmd_free_jfr(urma_jfr_t *jfr, urma_cmd_udrv_priv_t *udata); + +int urma_cmd_import_jfr(urma_context_t *ctx, urma_target_jetty_t *tjfr, urma_tjfr_cfg_t *cfg, + urma_cmd_udrv_priv_t *udata); +int urma_cmd_import_jfr_ex(urma_context_t *ctx, urma_target_jetty_t *tjfr, urma_tjfr_cfg_t *cfg, + urma_import_jfr_ex_cfg_t *ex_cfg, urma_cmd_udrv_priv_t *udata); +int urma_cmd_unimport_jfr(urma_target_jetty_t *tjfr); + +/* Advise cmds */ +int urma_cmd_advise_jfr(urma_jfs_t *jfs, urma_target_jetty_t *tjfr, urma_cmd_udrv_priv_t *udata); +int urma_cmd_unadvise_jfr(urma_jfs_t *jfs, urma_target_jetty_t *tjfr); + +int urma_cmd_create_jetty(urma_context_t *ctx, urma_jetty_t *jetty, urma_jetty_cfg_t *cfg, urma_cmd_udrv_priv_t *udata); +int urma_cmd_modify_jetty(urma_jetty_t *jetty, urma_jetty_attr_t *attr, urma_cmd_udrv_priv_t *udata); +int urma_cmd_query_jetty(urma_jetty_t *jetty, urma_jetty_cfg_t *cfg, urma_jetty_attr_t *attr); +int urma_cmd_delete_jetty(urma_jetty_t *jetty); +int urma_cmd_delete_jetty_batch(urma_jetty_t **jetty_arr, int jetty_num, urma_jetty_t **bad_jetty); +int urma_cmd_alloc_jetty(urma_context_t *ctx, urma_jetty_cfg_t *cfg, urma_jetty_t *jetty, urma_cmd_udrv_priv_t *udata); +int urma_cmd_set_jetty_opt(urma_jetty_t *jetty, uint64_t opt, void *buf, uint32_t len, urma_cmd_udrv_priv_t *udata); +int urma_cmd_active_jetty(urma_jetty_t *jetty, urma_cmd_udrv_priv_t *udata); +int urma_cmd_get_jetty_opt(urma_jetty_t *jetty, uint64_t opt, void *buf, uint32_t len, urma_cmd_udrv_priv_t *udata); +int urma_cmd_deactive_jetty(urma_jetty_t *jetty, urma_cmd_udrv_priv_t *udata); +int urma_cmd_free_jetty(urma_jetty_t *jetty, urma_cmd_udrv_priv_t *udata); + +int urma_cmd_import_jetty(urma_context_t *ctx, urma_target_jetty_t *tjetty, urma_tjetty_cfg_t *cfg, + urma_cmd_udrv_priv_t *udata); +int urma_cmd_import_jetty_ex(urma_context_t *ctx, urma_target_jetty_t *tjetty, urma_tjetty_cfg_t *cfg, + urma_import_jetty_ex_cfg_t *ex_cfg, urma_cmd_udrv_priv_t *udata); +int urma_cmd_unimport_jetty(urma_target_jetty_t *tjetty); + +int urma_cmd_advise_jetty(urma_jetty_t *jetty, urma_target_jetty_t *tjetty, urma_cmd_udrv_priv_t *udata); +int urma_cmd_unadvise_jetty(urma_jetty_t *jetty, urma_target_jetty_t *tjetty); + +int urma_cmd_bind_jetty(urma_jetty_t *jetty, urma_target_jetty_t *tjetty, urma_cmd_udrv_priv_t *udata); +int urma_cmd_bind_jetty_ex(urma_jetty_t *jetty, urma_target_jetty_t *tjetty, urma_bind_jetty_ex_cfg_t *ex_cfg, + urma_cmd_udrv_priv_t *udata); +int urma_cmd_unbind_jetty(urma_jetty_t *jetty); + +int urma_cmd_create_jetty_grp(urma_context_t *ctx, urma_jetty_grp_t *jetty_grp, urma_jetty_grp_cfg_t *cfg, + urma_cmd_udrv_priv_t *udata); +int urma_cmd_delete_jetty_grp(urma_jetty_grp_t *jetty_grp); + +int urma_cmd_alloc_token_id(urma_context_t *ctx, urma_token_id_t *token_id, urma_cmd_udrv_priv_t *udata); +int urma_cmd_alloc_token_id_ex(urma_context_t *ctx, urma_token_id_t *token_id, urma_token_id_flag_t flag, + urma_cmd_udrv_priv_t *udata); +int urma_cmd_free_token_id(urma_token_id_t *token_id); + +int urma_cmd_register_seg(urma_context_t *ctx, urma_target_seg_t *tseg, urma_seg_cfg_t *cfg, + urma_cmd_udrv_priv_t *udata); +int urma_cmd_unregister_seg(urma_target_seg_t *tseg); + +int urma_cmd_import_seg(urma_context_t *ctx, urma_target_seg_t *tseg, urma_import_tseg_cfg_t *cfg, + urma_cmd_udrv_priv_t *udata); +int urma_cmd_unimport_seg(urma_target_seg_t *tseg); + +urma_status_t urma_cmd_get_async_event(urma_context_t *ctx, urma_async_event_t *event); +void urma_cmd_ack_async_event(urma_async_event_t *event); + +/* Return user control res, for 0 on success, others on error */ +int urma_cmd_user_ctl(urma_context_t *ctx, urma_user_ctl_in_t *in, urma_user_ctl_out_t *out, urma_udrv_t *udrv_data); +int urma_cmd_get_eid_list(int dev_fd, uint32_t max_eid_cnt, urma_eid_info_t *eid_list, uint32_t *eid_cnt); +int urma_cmd_get_net_addr_list(urma_context_t *ctx, uint32_t max_netaddr_cnt, urma_net_addr_info_t *net_addr_info, + uint32_t *cnt); +int urma_cmd_modify_tp(urma_context_t *ctx, uint32_t tpn, urma_tp_cfg_t *cfg, urma_tp_attr_t *attr, + urma_tp_attr_mask_t mask); +struct urma_sysfs_dev; +int urma_cmd_query_device_attr(int dev_fd, struct urma_sysfs_dev *sysfs_dev); +int urma_register_sysfs_dev(struct urma_sysfs_dev *dev); + +int urma_cmd_import_jetty_async(urma_notifier_t *notifier, urma_target_jetty_t *tjetty, urma_tjetty_cfg_t *cfg, + uint64_t user_ctx, int timeout, urma_cmd_udrv_priv_t *udata); +int urma_cmd_unimport_jetty_async(urma_target_jetty_t *tjetty); + +int urma_cmd_bind_jetty_async(urma_notifier_t *notifier, urma_jetty_t *jetty, urma_target_jetty_t *tjetty, + uint64_t user_ctx, int timeout, urma_cmd_udrv_priv_t *udata); +int urma_cmd_unbind_jetty_async(urma_jetty_t *jetty); + +int urma_cmd_create_notifier(urma_context_t *ctx); +int urma_cmd_wait_notify(urma_notifier_t *notifier, uint32_t cnt, urma_notify_t *notify, int timeout); + +int urma_cmd_get_tp_list(urma_context_t *ctx, urma_get_tp_cfg_t *cfg, uint32_t *tp_cnt, urma_tp_info_t *tp_list, + urma_cmd_udrv_priv_t *udata); +int urma_cmd_set_tp_attr(const urma_context_t *ctx, const uint64_t tp_handle, const uint8_t tp_attr_cnt, + const uint32_t tp_attr_bitmap, const urma_tp_attr_value_t *tp_attr, + urma_cmd_udrv_priv_t *udata); +int urma_cmd_get_tp_attr(const urma_context_t *ctx, const uint64_t tp_handle, uint8_t *tp_attr_cnt, + uint32_t *tp_attr_bitmap, urma_tp_attr_value_t *tp_attr, urma_cmd_udrv_priv_t *udata); +int urma_cmd_exchange_tp_info(urma_context_t *ctx, urma_get_tp_cfg_t *cfg, uint64_t local_tp_handle, uint32_t tx_psn, + uint64_t *peer_tp_handle, uint32_t *rx_psn); +int urma_cmd_get_eid_by_ip(const urma_context_t *ctx, const urma_net_addr_t *net_addr, urma_eid_t *eid); +int urma_cmd_get_ip_by_eid(const urma_context_t *ctx, const urma_eid_t *eid, urma_net_addr_t *net_addr); +int urma_cmd_get_smac(const urma_context_t *ctx, uint8_t *mac); +int urma_cmd_get_dmac(const urma_context_t *ctx, const urma_net_addr_t *net_addr, uint8_t *mac); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/urma/urma_types.h b/include/urma/urma_types.h new file mode 100644 index 0000000..843ac85 --- /dev/null +++ b/include/urma/urma_types.h @@ -0,0 +1,1454 @@ +/* + * SPDX-License-Identifier: MIT + * Copyright (c) Huawei Technologies Co., Ltd. 2021-2025. All rights reserved. + * Description: URMA type header file + * Author: Ouyang Changchun, Bojie Li, Yan Fangfang, Qian Guoxin + * Create: 2021-07-13 + * Note: + * History: 2021-07-13 Create File + */ + +#ifndef URMA_TYPES_H +#define URMA_TYPES_H + +#include +#include +#include +#include +#include + +#ifndef __cplusplus +#include +#else +#include +#endif + +#include "urma_opcode.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define URMA_GET_VERSION(a, b) (((a) << 16) + ((b) > 65535 ? 65535 : (b))) +#define URMA_API_VERSION ((0 << 16) + 9) // Current Version: 0.9 +#define MAX_PORT_CNT 8 +#define URMA_MAX_JETTY_IN_JETTY_GRP 32U +#define URMA_MAX_NAME 64 +#define URMA_MAX_PATH 4096 +#define URMA_EID_SIZE (16) +#define URMA_MAX_PRIORITY_CNT 16 +#define URMA_IPV4_MAP_IPV6_PREFIX (0x0000ffff) +#define URMA_MAX_EID_CNT 1024 /* refer to UBCORE_MAX_SIP */ +#define URMA_CC_IDX_TABLE_SIZE 80 /* support 8 priorities and 10 algorithms */ + /* same as UBCORE_CC_IDX_TABLE_SIZE */ +#define URMA_OPT_REVERSED_NUM 4 + +#define URMA_EID_STR_LEN (39) +#define EID_FMT "%2.2x%2.2x:%2.2x%2.2x:%2.2x%2.2x:%2.2x%2.2x:%2.2x%2.2x:%2.2x%2.2x:%2.2x%2.2x:%2.2x%2.2x" +#define EID_RAW_ARGS(eid) \ + eid[0], eid[1], eid[2], eid[3], eid[4], eid[5], eid[6], eid[7], eid[8], eid[9], eid[10], eid[11], eid[12], \ + eid[13], eid[14], eid[15] +#define EID_ARGS(eid) EID_RAW_ARGS((eid).raw) +#define URMA_SEG_TOKEN_ID_INVALID 0xffffffff + +/* refer to UBCORE_MAX_DEV_NAME */ +#define URMA_MAX_DEV_NAME 64 +#define URMA_GUID_SIZE (16) + +#define URMA_IP_ADDR_BYTES 16 /* refer to UBCORE_IP_ADDR_BYTES */ +#define URMA_MAC_BYTES 6 /* refer to UBCORE_MAC_BYTES */ + +#define URMA_JFS_SQE_BASE_ADDR_MASK (1ULL << 0) +#define URMA_JFS_ID_MASK (1ULL << 1) +#define URMA_JFS_DB_ADDR_MASK (1ULL << 2) +#define URMA_JFS_DB_STATUS_MASK (1ULL << 3) +#define URMA_JFS_PI_MASK (1ULL << 4) +#define URMA_JFS_PI_TYPE_MASK (1ULL << 5) +#define URMA_JFS_CI_MASK (1ULL << 6) + +#define URMA_JFR_RQE_BASE_ADDR_MASK (1ULL << 0) +#define URMA_JFR_ID_MASK (1ULL << 1) +#define URMA_JFR_DB_ADDR_MASK (1ULL << 2) +#define URMA_JFR_DB_STATUS_MASK (1ULL << 3) +#define URMA_JFR_PI_MASK (1ULL << 4) +#define URMA_JFR_PI_TYPE_MASK (1ULL << 5) +#define URMA_JFR_CI_MASK (1ULL << 6) + +#define URMA_JFC_CQE_BASE_ADDR_MASK (1ULL << 0) +#define URMA_JFC_ID_MASK (1ULL << 1) +#define URMA_JFC_DB_ADDR_MASK (1ULL << 2) +#define URMA_JFC_DB_STATUS_MASK (1ULL << 3) +#define URMA_JFC_PI_MASK (1ULL << 4) +#define URMA_JFC_PI_TYPE_MASK (1ULL << 5) +#define URMA_JFC_CI_MASK (1ULL << 6) + +typedef struct urma_init_attr { + uint64_t token; /* [Optional] security token */ + uint32_t uasid; /* [Optional] uasid to set and reserve. If the parameter is 0, + the system will randomly assign a non-0 value. */ +} urma_init_attr_t; + +/* device information */ +typedef enum urma_mtu { + URMA_MTU_256 = 1, + URMA_MTU_512, + URMA_MTU_1024, + URMA_MTU_2048, + URMA_MTU_4096, + URMA_MTU_8192, +} urma_mtu_t; + +typedef enum urma_port_state { + URMA_PORT_NOP = 0, + URMA_PORT_DOWN, + URMA_PORT_INIT, + URMA_PORT_ARMED, + URMA_PORT_ACTIVE, + URMA_PORT_ACTIVE_DEFER, +} urma_port_state_t; + +typedef enum urma_speed { + URMA_SP_10M = 0, + URMA_SP_100M, + URMA_SP_1G, + URMA_SP_2_5G, + URMA_SP_5G, + URMA_SP_10G, + URMA_SP_14G, + URMA_SP_25G, + URMA_SP_40G, + URMA_SP_50G, + URMA_SP_100G, + URMA_SP_200G, + URMA_SP_400G, + URMA_SP_800G, +} urma_speed_t; + +typedef enum urma_link_width { + URMA_LINK_X1 = 0x1, + URMA_LINK_X2 = 0x1 << 1, + URMA_LINK_X4 = 0x1 << 2, + URMA_LINK_X8 = 0x1 << 3, + URMA_LINK_X16 = 0x1 << 4, + URMA_LINK_X32 = 0x1 << 5, +} urma_link_width_t; + +typedef union urma_eid { + uint8_t raw[URMA_EID_SIZE]; /* Network Order */ + struct { + uint64_t reserved; /* If IPv4 mapped to IPv6, == 0 */ + uint32_t prefix; /* If IPv4 mapped to IPv6, == 0x0000ffff */ + uint32_t addr; /* If IPv4 mapped to IPv6, == IPv4 addr */ + } in4; + struct { + uint64_t subnet_prefix; + uint64_t interface_id; + } in6; +} urma_eid_t; + +void urma_u32_to_eid(uint32_t ipv4, urma_eid_t *eid); +int urma_str_to_eid(const char *buf, urma_eid_t *eid); + +typedef struct urma_ref { +#ifndef __cplusplus + atomic_ulong atomic_cnt; +#else + std::atomic_ulong atomic_cnt; +#endif +} urma_ref_t; + +typedef struct urma_port_attr { + urma_mtu_t max_mtu; /* [Public] MTU_256, MTU_512, MTU_1024 etc. */ + urma_port_state_t state; /* [Public] PORT_DOWN, PORT_INIT, PORT_ACTIVE */ + urma_link_width_t active_width; /* [Public] link width: X1, X2, X4. */ + urma_speed_t active_speed; /* [Public] bandwidth. */ + urma_mtu_t active_mtu; /* [Public] current effective mtu. */ +} urma_port_attr_t; + +union urma_tp_type_en { + struct { + uint32_t rtp : 1; + uint32_t ctp : 1; + uint32_t utp : 1; + uint32_t reserved : 29; + } bs; + uint32_t value; +}; + +struct urma_sl_info { + uint32_t SL; + union urma_tp_type_en tp_type; +}; + +typedef union urma_device_feature { + struct { + uint32_t oor : 1; /* [Public] URMA_OUT_OF_ORDER_RECEIVING. */ + uint32_t jfc_per_wr : 1; /* [Public] URMA_JFC_PER_WR. */ + uint32_t stride_op : 1; /* [Public] URMA_STRIDE_OP. */ + uint32_t load_store_op : 1; /* [Public] URMA_LOAD_STORE_OP. */ + uint32_t non_pin : 1; /* [Public] URMA_NON_PIN. */ + uint32_t pmem : 1; /* [Public] URMA_PERSISTENCE_MEM. */ + uint32_t jfc_inline : 1; /* [Public] URMA_JFC_INLINE. */ + uint32_t spray_en : 1; /* [Public] URMA_SPRAY_ENABLE for UDP port. */ + uint32_t selective_retrans : 1; /* [Public] URMA_SELECTIVE_RETRANS. */ + uint32_t live_migrate : 1; /* [Public] support live migration. */ + uint32_t dca : 1; /* [Public] for user tp */ + uint32_t jetty_grp : 1; /* [Public] support jetty group. */ + uint32_t error_suspend : 1; /* [Public] support suspend jetty or jfs on error. */ + uint32_t outorder_comp : 1; /* [Public] support out-of-order completion. */ + uint32_t mn : 1; /* [Public] for user tp */ + uint32_t clan : 1; /* [Public] for user tp */ + uint32_t muti_seg_per_token_id : 1; + uint32_t ipourma_en : 1; + uint32_t ctp_en : 1; + uint32_t uboe : 1; + uint32_t reserved : 12; + } bs; + uint32_t value; +} urma_device_feature_t; + +typedef union urma_atomic_feature { + struct { + uint32_t cas : 1; + uint32_t swap : 1; + uint32_t fetch_and_add : 1; + uint32_t fetch_and_sub : 1; + uint32_t fetch_and_and : 1; + uint32_t fetch_and_or : 1; + uint32_t fetch_and_xor : 1; + uint32_t reserved : 25; + } bs; + uint32_t value; +} urma_atomic_feature_t; + +typedef union urma_order_type_cap { + struct { + uint32_t ot : 1; + uint32_t oi : 1; + uint32_t ol : 1; + uint32_t no : 1; + uint32_t reserved : 28; + } bs; + uint32_t value; +} urma_order_type_cap_t; + +typedef union urma_tp_type_cap { + struct { + uint32_t rtp : 1; + uint32_t ctp : 1; + uint32_t utp : 1; + uint32_t reserved : 29; + } bs; + uint32_t value; +} urma_tp_type_cap_t; + +typedef union urma_tp_feature { + struct { + uint32_t rm_multi_path : 1; + uint32_t rc_multi_path : 1; + uint32_t reserved : 30; + } bs; + uint32_t value; +} urma_tp_feature_t; + +typedef struct urma_device_cap { + urma_device_feature_t feature; /* [Public] support feature of device, such as OOO, LS etc. */ + uint32_t max_jfc; /* [Public] max number of jfc supported by the device. */ + uint32_t max_jfs; /* [Public] max number of jfs supported by the device. */ + uint32_t max_jfr; /* [Public] max number of jfr supported by the device. */ + uint32_t max_jetty; /* [Public] max number of jetty supported by the device. */ + uint32_t max_jetty_grp; /* [Public] max number of jetty group supported by the device. */ + uint32_t max_jetty_in_jetty_grp; /* [Public] max number of jetty per jetty group supported by the device. */ + uint32_t max_jfc_depth; /* [Public] max depth of jfc supported by the device. */ + uint32_t max_jfs_depth; /* [Public] max depth of jfs supported by the device. */ + uint32_t max_jfr_depth; /* [Public] max depth of jfr supported by the device. */ + uint32_t max_jfs_inline_len; /* [Public] max inline length(byte) supported by the jfs. */ + uint32_t max_jfs_sge; /* [Public] max number of sge supported by the jfs. */ + uint32_t max_jfs_rsge; /* [Public] max number of remote sge supported by the jfs. */ + uint32_t max_jfr_sge; /* [Public] max number of sge supported by the jfr. */ + uint64_t max_msg_size; /* [Public] max message size supported by the device. */ + uint32_t max_read_size; + uint32_t max_write_size; + uint32_t max_cas_size; + uint32_t max_swap_size; + uint32_t max_fetch_and_add_size; + uint32_t max_fetch_and_sub_size; + uint32_t max_fetch_and_and_size; + uint32_t max_fetch_and_or_size; + uint32_t max_fetch_and_xor_size; + urma_atomic_feature_t atomic_feat; /* [Public] support atomic feature of device */ + uint16_t trans_mode; /* [Public] bit OR of supported transport modes */ + uint16_t reserved; + uint16_t congestion_ctrl_alg; /* [Public] one or more mode from urma_congestion_ctrl_alg_t */ + uint32_t ceq_cnt; /* [Public] ceq_cnt */ + uint32_t max_tp_in_tpg; /* [Public] max tp in tpg */ + uint32_t max_eid_cnt; /* [Public] max eid count */ + uint64_t page_size_cap; /* [Public] page size capability, must include PAGE_SIZE(4k) */ + uint32_t max_oor_cnt; /* [Public] max OOR window size by packet, only for user tp */ + uint32_t mn; /* [Public] only for user tp */ + uint32_t max_netaddr_cnt; /* [Public] only for user tp */ + urma_order_type_cap_t rm_order_cap; + urma_order_type_cap_t rc_order_cap; + urma_tp_type_cap_t rm_tp_cap; + urma_tp_type_cap_t rc_tp_cap; + urma_tp_type_cap_t um_tp_cap; + urma_tp_feature_t tp_feature; + struct urma_sl_info priority_info[URMA_MAX_PRIORITY_CNT]; +} urma_device_cap_t; + +typedef struct urma_guid { + uint8_t raw[URMA_GUID_SIZE]; +} urma_guid_t; + +typedef struct urma_device_attr { + urma_guid_t guid; /* [Public] */ + urma_device_cap_t dev_cap; /* [Public] capabilities of device. */ + uint8_t port_cnt; /* [Public] port number of device. */ + struct urma_port_attr port_attr[MAX_PORT_CNT]; + uint32_t reserved_jetty_id_min; + uint32_t reserved_jetty_id_max; +} urma_device_attr_t; + +/* security information */ +typedef struct urma_token { + uint32_t token; +} urma_token_t; + +struct urma_sysfs_dev; +struct urma_ref; +struct urma_ops; +struct urma_provider_ops; + +typedef enum urma_transport_type { + URMA_TRANSPORT_INVALID = -1, + URMA_TRANSPORT_UB = 0, + URMA_TRANSPORT_IB = 1, + URMA_TRANSPORT_IP = 2, + URMA_TRANSPORT_SOFTUB = 3, + URMA_TRANSPORT_HNS_UB = 5, + URMA_TRANSPORT_MAX +} urma_transport_type_t; + +typedef enum urma_transport_mode { + URMA_TM_RM = 0x1, /* Reliable message */ + URMA_TM_RC = 0x1 << 1, /* Reliable connection */ + URMA_TM_UM = 0x1 << 2, /* Unreliable message */ +} urma_transport_mode_t; + +typedef enum urma_tp_cc_alg { + URMA_TP_CC_NONE = 0, + URMA_TP_CC_DCQCN, + URMA_TP_CC_CAQM, + URMA_TP_CC_LDCP = 3, + URMA_TP_CC_LDCP_L2_HEADER, + URMA_TP_CC_LDCP_TP_HEADER, + URMA_TP_CC_DIP, + URMA_TP_CC_ACC, + URMA_TP_CC_CUSTOM_1, + URMA_TP_CC_CUSTOM_2, + URMA_TP_CC_NUM, +} urma_tp_cc_alg_t; /* larger means better */ + +typedef enum urma_congestion_ctrl_alg { + URMA_CC_NONE = 0x1 << URMA_TP_CC_NONE, + URMA_CC_DCQCN = 0x1 << URMA_TP_CC_DCQCN, + URMA_CC_CAQM = 0x1 << URMA_TP_CC_CAQM, + URMA_CC_LDCP = 0x1 << URMA_TP_CC_LDCP, + URMA_CC_LDCP_L2_HEADER = 0x1 << URMA_TP_CC_LDCP_L2_HEADER, + URMA_CC_LDCP_TP_HEADER = 0x1 << URMA_TP_CC_LDCP_TP_HEADER, + URMA_CC_DIP = 0x1 << URMA_TP_CC_DIP, + URMA_CC_ACC = 0x1 << URMA_TP_CC_ACC, + URMA_CC_CUSTOM_1 = 0x1 << URMA_TP_CC_CUSTOM_1, + URMA_CC_CUSTOM_2 = 0x1 << URMA_TP_CC_CUSTOM_2, +} urma_congestion_ctrl_alg_t; + +typedef struct urma_cc_entry { + urma_tp_cc_alg_t alg; + uint8_t cc_pattern_idx; + uint8_t cc_priority; +} __attribute__((packed)) urma_cc_entry_t; + +typedef struct urma_device { + char name[URMA_MAX_NAME]; /* [Public] urma device's name, the names of devices + in different transport modes are different. */ + char path[URMA_MAX_PATH]; /* [Public] urma device's path in sysfs. */ + urma_transport_type_t type; /* [Public] urma device's transport type. */ + struct urma_provider_ops *ops; /* [Private] urma device driver's ops. */ + struct urma_sysfs_dev *sysfs_dev; /* [Private] internal device corresponding to the urma device */ +} urma_device_t; + +typedef enum urma_context_opt_name { + URMA_OPT_AGGR_MODE, +} urma_opt_name_t; + +typedef enum urma_context_aggr_mode { + URMA_AGGR_MODE_STANDALONE, + URMA_AGGR_MODE_ACTIVE_BACKUP, + URMA_AGGR_MODE_BALANCE, +} urma_context_aggr_mode_t; + +typedef struct urma_context { + struct urma_device *dev; /* [Private] point to the corresponding urma device. */ + struct urma_ops *ops; /* [Private] operation of urma device. */ + int dev_fd; /* [Private] fd of urma device's sysfs file. */ + int async_fd; /* [Private] fd of urma device's async event file. */ + pthread_mutex_t mutex; /* [Private] mutex of urma context. */ + urma_eid_t eid; /* [Public] eid of urma device. */ + uint32_t eid_index; + uint32_t uasid; /* [Public] uasid of current process. */ + struct urma_ref ref; /* [Private] reference count of urma context. */ + urma_context_aggr_mode_t aggr_mode; /* [Public] aggregated mode of urma context. */ +} urma_context_t; + +typedef struct urma_eid_info { + urma_eid_t eid; + uint32_t eid_index; /* 0~UBCORE_MAX_EID_CNT -1 */ +} urma_eid_info_t; + +typedef struct urma_jfce_cfg { + uint32_t depth; + uint64_t user_ctx; +} urma_jfce_cfg_t; + +typedef struct urma_jfce { + urma_context_t *urma_ctx; /* [Private] point to urma context. */ + int fd; /* [Private] fd of completed event. */ + struct urma_ref ref; /* [Private] reference count of urma context. */ +} urma_jfce_t; + +typedef union urma_jfc_flag { + struct { + uint32_t lock_free : 1; + uint32_t jfc_inline : 1; + uint32_t non_blocking : 1; + uint32_t has_drv_ext : 1; + uint32_t reserved : 28; + } bs; + uint32_t value; +} urma_jfc_flag_t; + +typedef struct urma_jfc_cfg { + uint32_t depth; /* [Required] the depth of jfc, no greater than urma_device_cap_t->jfc_depth */ + urma_jfc_flag_t flag; /* [Optional] see urma_jfc_flag_t, set flag.value to be 0 by default */ + uint32_t ceqn; /* [Optional] event queue id, less than urma_device_cap_t->ceq_cnt + set to 0 by default */ + urma_jfce_t *jfce; /* [Required] the event of jfc */ + uint64_t user_ctx; /* [Optional] private data of jfc, set to NULL by default */ +} urma_jfc_cfg_t; + +typedef enum urma_jfc_attr_mask { + JFC_MODERATE_COUNT = 0x1, + JFC_MODERATE_PERIOD = 0x1 << 1 +} urma_jfc_attr_mask_t; + +typedef struct urma_jfc_attr { + uint32_t mask; /* mask value, refer to urma_jfc_attr_mask_t */ + uint16_t moderate_count; + uint16_t moderate_period; /* in micro seconds */ +} urma_jfc_attr_t; + +typedef struct urma_jetty_id { + urma_eid_t eid; + uint32_t uasid; /* maybe zero(stand for kernel) or non-zero(stand for app) */ + uint32_t id; +} urma_jetty_id_t; + +typedef struct urma_jetty_id urma_jfs_id_t; +typedef struct urma_jetty_id urma_jfr_id_t; +typedef struct urma_jetty_id urma_jfc_id_t; + +union urma_jfc_opt_mask { + struct { + uint64_t urma_jfc_cqe_base_addr : 1; + uint64_t urma_jfc_db_addr : 1; + uint64_t urma_jfc_id : 1; + uint64_t urma_jfc_pi : 1; + uint64_t urma_jfc_pi_type : 1; + uint64_t urma_jfc_ci : 1; + uint64_t urma_jfc_db_status : 1; + uint64_t reserved : 57; + } bs; + uint64_t value; +}; + +typedef struct urma_jfc_opt { + union urma_jfc_opt_mask jfc_opt_mask; /* bit0:cqe_base_addr, bit1:db_addr, bit2:id, bit3:pi, bit4:pi_type, + bit5:ci, bit6:db_status */ + bool is_actived; + uint64_t urma_jfc_cqe_base_addr; /* [Optional] CQ Queue Address (VA) */ + uint32_t urma_jfc_id; /* [Optional] the id of jfc */ + uint64_t urma_jfc_db_addr; /* [Optional] CQ Queue Doorbell Address (VA) */ + uint8_t urma_jfc_db_status; /* [Optional] JFC Doorbell status, used for live migration (0 invalid, 1 valid) */ + uint16_t urma_jfc_pi; /* [Optional] PI value of the JFC */ + uint16_t urma_jfc_pi_type; /* [Optional] PI type, 0: absolute value, 1: cumulative value */ + uint16_t urma_jfc_ci; /* [Optional] CI value of the JFC */ + uint64_t reserved[URMA_OPT_REVERSED_NUM]; +} urma_jfc_opt_t; + +typedef struct urma_jfc { + urma_context_t *urma_ctx; /* [Private] point to urma context. */ + urma_jfc_id_t jfc_id; /* [Public] see urma_jetty_id. */ + urma_jfc_cfg_t jfc_cfg; /* [Public] storage jfc config. */ + uint64_t handle; + pthread_mutex_t event_mutex; + pthread_cond_t event_cond; + uint32_t comp_events_acked; + uint32_t async_events_acked; + urma_jfc_opt_t urma_jfc_opt; +} urma_jfc_t; + +typedef enum urma_order_type { + URMA_DEF_ORDER, + URMA_OT, // target ordering + URMA_OI, // initiator ordering + URMA_OL, // low layer ordering + URMA_NO // unreliable non ordering +} urma_order_type_t; + +typedef union urma_jfs_flag { + struct { + uint32_t lock_free : 1; /* default as 0, lock protected */ + uint32_t error_suspend : 1; /* 0: error continue; 1: error suspend */ + uint32_t outorder_comp : 1; /* 0: not support; 1: support out-of-order completion */ + uint32_t order_type : 8; /* (0x0): default, auto config by driver */ + /* (0x1): OT, target ordering */ + /* (0x2): OI, initiator ordering */ + /* (0x3): OL, low layer ordering */ + /* (0x4): UNO, unreliable non ordering */ + uint32_t multi_path : 1; /* 1: multi-path, 0: single path, for ubagg only. */ + uint32_t ctp_rc_mul_path_mode : 1; /* 1: ctp rc mode multi-path */ + uint32_t non_blocking : 1; + uint32_t has_drv_ext : 1; + uint32_t reserved : 17; + } bs; + uint32_t value; +} urma_jfs_flag_t; + +union urma_jfs_opt_mask { + struct { + uint64_t urma_jfs_cqe_base_addr : 1; + uint64_t urma_jfs_db_addr : 1; + uint64_t urma_jfs_id : 1; + uint64_t urma_jfs_pi : 1; + uint64_t urma_jfs_pi_type : 1; + uint64_t urma_jfs_ci : 1; + uint64_t urma_jfs_db_status : 1; + uint64_t reserved : 57; + } bs; + uint64_t value; +}; + +typedef struct urma_jfs_opt { + union urma_jfs_opt_mask jfs_opt_mask; /* bit0:sqe_base_addr, bit1:db_addr, bit2:id, bit3:pi, bit4:pi_type, + bit5:ci, bit6:db_status */ + bool is_actived; + uint64_t urma_jfs_sqe_base_addr; /* [Optional] SQ Queue Address (VA) */ + uint32_t urma_jfs_id; /* [Optional] the id of jfs */ + uint64_t urma_jfs_db_addr; /* [Optional] SQ Queue Doorbell Address (VA) */ + uint8_t urma_jfs_db_status; /* [Optional] JFS Doorbell status, used for live migration (0 invalid, 1 valid) */ + uint16_t urma_jfs_pi; /* [Optional] PI value of the JFS */ + uint16_t urma_jfs_pi_type; /* [Optional] PI type, 0: absolute value, 1: cumulative value */ + uint16_t urma_jfs_ci; /* [Optional] CI value of the JFS */ + uint64_t reserved[URMA_OPT_REVERSED_NUM]; +} urma_jfs_opt_t; + +typedef struct urma_jfs_cfg { + uint32_t depth; /* [Required] the depth of jfs, default urma_device_cap_t->jfs_depth */ + urma_jfs_flag_t flag; /* [Optional] see urma_jfs_flag_t definition */ + urma_transport_mode_t trans_mode; /* [Required] transport mode, must be supported by the device */ + uint8_t priority; /* [Optional] set the priority of JFS, ranging from [0, 15] + Services with low delay need to set high priority. */ + uint8_t max_sge; /* [Optional] max sge count in one wr, default urma_device_cap_t->max_jfs_sge */ + uint8_t max_rsge; /* [Optional] max remote sge count in one wr, default urma_device_cap_t->max_jfs_sge */ + uint32_t max_inline_data; /* [Optional] the max inline data size of JFS. if the parameter is 0, + the system will assign device's max inline data length. */ + uint8_t rnr_retry; /* [Optional] number of times that jfs will resend packets before report error, + when the remote side is not ready to receive (RNR), ranging from [0, 7], + the value 0 means never retry and, + the value 7 means retry infinite number of times for RDMA devices */ + uint8_t err_timeout; /* [Optional] the timeout before report error, ranging from [0, 31], + the actual timeout in usec is caculated by: 4.096*(2^err_timeout) */ + urma_jfc_t *jfc; /* [Required] need to specify jfc */ + uint64_t user_ctx; /* [Optional] private data of jfs */ +} urma_jfs_cfg_t; + +typedef struct urma_jfs { + urma_context_t *urma_ctx; /* [Private] point to urma context. */ + urma_jfs_id_t jfs_id; /* [Public] see urma_jetty_id. */ + urma_jfs_cfg_t jfs_cfg; /* [Public] storage jfs config. */ + uint64_t handle; + pthread_mutex_t event_mutex; + pthread_cond_t event_cond; + uint32_t async_events_acked; + urma_jfs_opt_t urma_jfs_opt; +} urma_jfs_t; + +typedef enum urma_jfs_attr_mask { + JFS_STATE = 0x1 +} urma_jfs_attr_mask_t; + +typedef urma_jetty_state_t urma_jfs_state_t; + +typedef struct urma_jfs_attr { + uint32_t mask; /* mask value refer to urma_jfs_attr_mask_t */ + urma_jfs_state_t state; +} urma_jfs_attr_t; + +typedef union urma_jfr_flag { + struct { + uint32_t token_policy : 3; /* 0: URMA_TOKEN_NONE + 1: URMA_TOKEN_PLAIN_TEXT + 2: URMA_TOKEN_SIGNED + 3: URMA_TOKEN_ALL_ENCRYPTED + 4: URMA_TOKEN_RESERVED */ + uint32_t tag_matching : 1; /* 0: URMA_NO_TAG_MATCHING. + 1: URMA_WITH_TAG_MATCHING. */ + uint32_t lock_free : 1; + uint32_t order_type : 8; /* (0x0): default, auto config by driver */ + /* (0x1): OT, target ordering */ + /* (0x2): OI, initiator ordering */ + /* (0x3): OL, low layer ordering */ + /* (0x4): UNO, unreliable non ordering */ + uint32_t has_drv_ext : 1; /* 0: no extension data. + 1: extension data is appended after urma_rjetty_t. */ + uint32_t non_blocking : 1; + uint32_t reserved : 17; + } bs; + uint32_t value; +} urma_jfr_flag_t; + +union urma_jfr_opt_mask { + struct { + uint64_t urma_jfr_cqe_base_addr : 1; + uint64_t urma_jfr_db_addr : 1; + uint64_t urma_jfr_id : 1; + uint64_t urma_jfr_pi : 1; + uint64_t urma_jfr_pi_type : 1; + uint64_t urma_jfr_ci : 1; + uint64_t urma_jfr_db_status : 1; + uint64_t reserved : 57; + } bs; + uint64_t value; +}; + +typedef struct urma_jfr_opt { + union urma_jfr_opt_mask jfr_opt_mask; /* bit0:rqe_base_addr, bit1:db_addr, bit2:id, bit3:pi, bit4:pi_type, + bit5:ci, bit6:db_status */ + bool is_actived; + uint64_t urma_jfr_rqe_base_addr; /* [Optional] RQ Queue Address (VA) */ + uint32_t urma_jfr_id; /* [Optional] the id of jfr */ + uint64_t urma_jfr_db_addr; /* [Optional] RQ Queue Doorbell Address (VA) */ + uint8_t urma_jfr_db_status; /* [Optional] JFR Doorbell status, used for live migration (0 invalid, 1 valid) */ + uint16_t urma_jfr_pi; /* [Optional] PI value of the JFR */ + uint16_t urma_jfr_pi_type; /* [Optional] PI type, 0: absolute value, 1: cumulative value */ + uint16_t urma_jfr_ci; /* [Optional] CI value of the JFR */ + uint64_t reserved[URMA_OPT_REVERSED_NUM]; +} urma_jfr_opt_t; + +typedef struct urma_jfr_cfg { + uint32_t id; /* [Optional] specify jfr id. If the parameter is 0, + the system will randomly assign a non-0 value. */ + uint32_t depth; /* [Required] total depth, include berth, default urma_device_cap_t->jfr_depth. */ + urma_jfr_flag_t flag; /* [Optional] whether is in TAG_matching, whether is in DC/IDC mode. */ + urma_transport_mode_t trans_mode; /* [Required] transport mode, must be supported by the device */ + uint8_t max_sge; /* [Optional] max sge count in one wr, default urma_device_cap_t->max_jfr_sge. */ + uint8_t min_rnr_timer; /* [Optional] the minimum RNR NACK timer, ranging from [0, 31], i.e. + the time before jfr sends NACK to the sender for the reason of "ready to receive" */ + urma_jfc_t *jfc; /* [Required] need to specify jfc. */ + urma_token_t token_value; /* [Required] specify token_value for jfr. */ + uint64_t user_ctx; /* [Optional] private data of jfr */ +} urma_jfr_cfg_t; + +typedef enum urma_jfr_attr_mask { + JFR_RX_THRESHOLD = 0x1, + JFR_STATE = 0x1 << 1 +} urma_jfr_attr_mask_t; + +typedef struct urma_jfr_attr { + uint32_t mask; // mask value refer to urma_jfr_attr_mask_t + uint32_t rx_threshold; + urma_jfr_state_t state; +} urma_jfr_attr_t; + +typedef struct urma_jfr { + urma_context_t *urma_ctx; /* [Private] point to urma context. */ + urma_jfr_id_t jfr_id; /* [Public] see urma_jetty_id. */ + urma_jfr_cfg_t jfr_cfg; /* [Public] storage jfr config. */ + uint64_t handle; + pthread_mutex_t event_mutex; + pthread_cond_t event_cond; + uint32_t async_events_acked; + urma_jfr_opt_t urma_jfr_opt; +} urma_jfr_t; + +typedef union urma_import_jetty_flag { + struct { + uint32_t token_policy : 3; + uint32_t order_type : 8; /* (0x0): default, auto config by driver */ + /* (0x1): OT, target ordering */ + /* (0x2): OI, initiator ordering */ + /* (0x3): OL, low layer ordering */ + /* (0x4): UNO, unreliable non ordering */ + uint32_t share_tp : 1; /* 1: shared tp; 0: non-shared tp. When rc mode is not ta dst ordering, + this flag can only be set to 0. */ + uint32_t has_drv_ext : 1; /* Driver-defined behavior for import_jetty, such as affinity control. */ + uint32_t has_user_info : 1; /* 0: no extension data. + 1: extension data is appended after urma_rjetty_t. */ + uint32_t reserved : 18; + } bs; + uint32_t value; +} urma_import_jetty_flag_t; + +typedef enum urma_tp_type { + URMA_RTP, + URMA_CTP, + URMA_UTP +} urma_tp_type_t; + +typedef struct urma_rjfr { + urma_jfr_id_t jfr_id; /* see urma_jetty_id */ + urma_transport_mode_t trans_mode; + urma_import_jetty_flag_t flag; + urma_tp_type_t tp_type; +} urma_rjfr_t; + +typedef struct urma_tp { + uint32_t tpn; /* vtpn */ +} urma_tp_t; + +typedef union urma_jetty_flag { + struct { + uint32_t share_jfr : 1; /* 0: URMA_NO_SHARE_JFR. + 1: URMA_SHARE_JFR. */ + uint32_t non_blocking : 1; + uint32_t has_drv_ext : 1; /* Driver-defined behavior for create/import jetty, such as affinity control. */ + uint32_t has_user_info : 1; /* 0: no extension data. + 1: extension data is appended after jetty object. */ + uint32_t reserved : 28; + } bs; + uint32_t value; +} urma_jetty_flag_t; + +typedef struct urma_jetty_grp urma_jetty_grp_t; + +typedef struct urma_jetty_cfg { + uint32_t id; /* [Optional] user specified jetty id. */ + urma_jetty_flag_t flag; /* [Optional] Connection or connection less */ + + /* send configuration */ + urma_jfs_cfg_t jfs_cfg; /* [Required] see urma_jfs_cfg_t */ + + /* recv configuration */ + union { + struct { + urma_jfr_t *jfr; /* [Optional] shared jfr to receive msg */ + urma_jfc_t *jfc; /* [Optional] To replace the jfc related to the above jfr */ + } shared; /* [Required] */ + urma_jfr_cfg_t *jfr_cfg; /* deprecated */ + }; + urma_jetty_grp_t *jetty_grp; /* [Optional] user specified jetty group. */ + uint64_t user_ctx; /* [Optional] private data of jetty */ +} urma_jetty_cfg_t; + +typedef enum urma_jetty_grp_policy { + URMA_JETTY_GRP_POLICY_RR = 0, + URMA_JETTY_GRP_POLICY_HASH_HINT = 1 +} urma_jetty_grp_policy_t; + +typedef enum urma_target_type { + URMA_JFR = 0, + URMA_JETTY, + URMA_JETTY_GROUP +} urma_target_type_t; + +typedef union urma_ext_flag { + struct { + uint32_t enable : 1; + uint32_t reserved : 31; + } bs; + uint32_t value; +} urma_ext_flag_t; + +typedef struct urma_ext { + urma_ext_flag_t flag; + uint32_t length; + char buf[0]; +} urma_ext_t; + +typedef struct urma_rjetty { + urma_jetty_id_t jetty_id; + urma_transport_mode_t trans_mode; + urma_jetty_grp_policy_t policy; + urma_target_type_t type; + urma_import_jetty_flag_t flag; + urma_tp_type_t tp_type; +} urma_rjetty_t; + +typedef struct urma_target_jetty { + urma_context_t *urma_ctx; /* [Private] point to urma context. */ + urma_jetty_id_t id; /* [Private] see urma_jetty_id. */ + uint64_t handle; + urma_transport_mode_t trans_mode; + urma_tp_t tp; + urma_target_type_t type; // todo supplementary target type + urma_import_jetty_flag_t flag; + urma_jetty_grp_policy_t policy; + urma_tp_type_t tp_type; +} urma_target_jetty_t; + +typedef enum urma_jetty_attr_mask { + JETTY_RX_THRESHOLD = 0x1, + JETTY_STATE = 0x1 << 1 +} urma_jetty_attr_mask_t; + +typedef struct urma_jetty_attr { + uint32_t mask; // mask value refer to urma_jetty_attr_mask_t + uint32_t rx_threshold; + urma_jetty_state_t state; +} urma_jetty_attr_t; + +typedef struct urma_jetty_opt { + bool is_actived; + urma_jfs_opt_t jfs_opt; + uint64_t reserved[URMA_OPT_REVERSED_NUM]; +} urma_jetty_opt_t; + +typedef struct urma_jetty { + urma_context_t *urma_ctx; /* [Private] point to urma context. */ + urma_jetty_id_t jetty_id; /* [Public] see urma_jetty_id. */ + urma_target_jetty_t *remote_jetty; /* [Private] Only valid for connection mode Jetty. + After the bind succeeds, the pointer is not null. */ + urma_jetty_cfg_t jetty_cfg; /* [Public] storage jetty config. */ + uint64_t handle; + pthread_mutex_t event_mutex; + pthread_cond_t event_cond; + uint32_t async_events_acked; + urma_jetty_opt_t urma_jetty_opt; +} urma_jetty_t; + +typedef struct urma_notifier { + urma_context_t *urma_ctx; + int fd; + void *incomplete_tjetty_list; +} urma_notifier_t; + +typedef enum urma_notify_type { + URMA_IMPORT_JETTY_NOTIFY = 0, + URMA_BIND_JETTY_NOTIFY +} urma_notify_type_t; + +typedef struct urma_notify { + urma_notify_type_t type; + urma_status_t status; + uint64_t user_ctx; + union { + urma_target_jetty_t *tjetty; /* IMPORT */ + urma_jetty_t *jetty; /* BIND */ + }; +} urma_notify_t; + +typedef union urma_jetty_grp_flag { + struct { + uint32_t token_policy : 3; /* 0: URMA_TOKEN_NONE + 1: URMA_TOKEN_PLAIN_TEXT + 2: URMA_TOKEN_SIGNED + 3: URMA_TOKEN_ALL_ENCRYPTED + 4: URMA_TOKEN_RESERVED */ + uint32_t reserved : 29; + } bs; + uint32_t value; +} urma_jetty_grp_flag_t; + +typedef struct urma_jetty_grp_cfg { + char name[URMA_MAX_NAME]; + urma_jetty_grp_flag_t flag; + urma_token_t token_value; /* [Required] specify token_value for Jetty group. */ + uint32_t id; /* [Optional] specify Jetty group id. + If the parameter is 0, UMDK will assign a non_0 value. */ + urma_jetty_grp_policy_t policy; /* Hash or RR(on default) */ + uint64_t user_ctx; /* [Optional] private data of jetty */ +} urma_jetty_grp_cfg_t; + +struct urma_jetty_grp { + urma_context_t *urma_ctx; + urma_jetty_id_t jetty_grp_id; + urma_jetty_grp_cfg_t cfg; + uint32_t jetty_cnt; + urma_jetty_t **jetty_list; + pthread_mutex_t list_mutex; + uint64_t handle; /* use to quickly get uobj of jetty group in kernel module */ + pthread_mutex_t event_mutex; + pthread_cond_t event_cond; + uint32_t async_events_acked; +}; + +/* memory information */ +typedef struct urma_ubva { + urma_eid_t eid; + uint32_t uasid; // 24 bit for UB + uint64_t va; +} __attribute__((packed)) urma_ubva_t; + + +/* segment definition */ +typedef union urma_reg_seg_flag { + struct { + uint32_t token_policy : 3; /* 0: URMA_TOKEN_NONE. + 1: URMA_TOKEN_PLAIN_TEXT. + 2: URMA_TOKEN_SIGNED. + 3: URMA_TOKEN_ALL_ENCRYPTED. + 4: URMA_TOKEN_RESERVED. */ + uint32_t cacheable : 1; /* 0: URMA_NON_CACHEABLE. + 1: URMA_CACHEABLE. */ + uint32_t dsva : 1; + uint32_t access : 6; /* (0x1): URMA_ACCESS_LOCAL_ONLY. + (0x1 << 1): URMA_ACCESS_READ. + (0x1 << 2): URMA_ACCESS_WRITE. + (0x1 << 3): URMA_ACCESS_ATOMIC. */ + uint32_t non_pin : 1; /* 0: segment pages pinned. + 1: segment pages non-pinned. */ + uint32_t user_iova : 1; /* 0: segment without user iova addr. + 1: segment with user iova addr. */ + uint32_t token_id_valid : 1; /* 0: token id in cfg is invalid. + 1: token id in cfg is valid. */ + uint32_t reserved : 18; + } bs; + uint32_t value; +} urma_reg_seg_flag_t; + +typedef union urma_seg_attr { + struct { + uint32_t token_policy : 3; /* 0: URMA_TOKEN_NONE. + 1: URMA_TOKEN_PLAIN_TEXT. + 2: URMA_TOKEN_SIGNED. + 3: URMA_TOKEN_ALL_ENCRYPTED. + 4: URMA_TOKEN_RESERVED. */ + uint32_t cacheable : 1; /* 0: URMA_NON_CACHEABLE. + 1: URMA_CACHEABLE. */ + uint32_t dsva : 1; + uint32_t access : 6; /* (0x1): URMA_ACCESS_LOCAL_ONLY. + (0x1 << 1): URMA_ACCESS_READ. + (0x1 << 2): URMA_ACCESS_WRITE. + (0x1 << 3): URMA_ACCESS_ATOMIC. */ + uint32_t non_pin : 1; /* 0: segment pages pinned. + 1: segment pages non-pinned. */ + uint32_t user_iova : 1; /* 0: segment without user iova addr. + 1: segment with user iova addr. */ + uint32_t user_token_id : 1; /* 0: token_id is allocated and should be freed by urma. + 1: token_id is allocated by user in urma_seg_cfg. */ + uint32_t has_user_info : 1; /* 0: no extension data. + 1: extension data appended after urma_seg_t. */ + uint32_t reserved : 17; + } bs; + uint32_t value; +} urma_seg_attr_t; + +typedef union urma_import_seg_flag { + struct { + uint32_t cacheable : 1; /* 0: URMA_NON_CACHEABLE. + 1: URMA_CACHEABLE. */ + uint32_t access : 6; /* (0x1): URMA_ACCESS_LOCAL_ONLY. + (0x1 << 1): URMA_ACCESS_READ. + (0x1 << 2): URMA_ACCESS_WRITE. + (0x1 << 3): URMA_ACCESS_ATOMIC. + */ + uint32_t mapping : 1; /* 0: URMA_SEG_NOMAP/ + 1: URMA_SEG_MAPPED. */ + uint32_t reserved : 24; + } bs; + uint32_t value; +} urma_import_seg_flag_t; + +typedef union urma_token_id_flag { + struct { + uint32_t multi_seg : 1; + uint32_t reserved : 31; + } bs; + uint32_t value; +} urma_token_id_flag_t; + +typedef struct urma_token_id { + urma_context_t *urma_ctx; + uint32_t token_id; + uint64_t handle; + urma_ref_t ref; + urma_token_id_flag_t flag; +} urma_token_id_t; + +typedef struct urma_seg_cfg { + uint64_t va; /* specify the address of the segment to be registered */ + uint64_t len; /* specify the length of the segment to be registered */ + urma_token_id_t *token_id; + urma_token_t token_value; /* Security authentication for access */ + urma_reg_seg_flag_t flag; + uint64_t user_ctx; + uint64_t iova; /* user iova, maybe zero-based-address */ +} urma_seg_cfg_t; + +typedef struct urma_seg { + urma_ubva_t ubva; /* [Public] ubva of segment. */ + uint64_t len; /* [Public] length of segment. */ + urma_seg_attr_t attr; /* [Public] include: access flag, token policy, cacheability. */ + uint32_t token_id; /* [Private] match token */ +} urma_seg_t; + +typedef struct urma_target_seg { + urma_seg_t seg; /* [Private] see urma_seg_t. */ + uint64_t user_ctx; /* [Private] private data of segment */ + uint64_t mva; /* [Public] mapping addr when import remote seg. */ + urma_context_t *urma_ctx; /* [Private] point to urma context. */ + urma_token_id_t *token_id; /* When registering seg, it is a valid address; when importing seg, it is NULL */ + uint64_t handle; +} urma_target_seg_t; + +typedef struct urma_user_ctl_in { + uint64_t addr; /* [Required] the address of the input parameter buffer. */ + uint32_t len; /* [Required] the length of the input parameter buffer */ + /* + * Opcode is simultaneously recognized by user and driver. + * User opcode should be distinguished with enum urma_user_ctl_ops_t, which is only used by URMA. + */ + uint32_t opcode; /* [Required] */ +} urma_user_ctl_in_t; + +typedef struct urma_user_ctl_out { + uint64_t addr; /* [Optional] the address of the output parameter buffer. */ + uint32_t len; /* [Optional] the length of the output parameter buffer */ + uint32_t reserved; +} urma_user_ctl_out_t; + +typedef struct urma_user_target_seg { + urma_seg_attr_t attr; + uint32_t token_id; + urma_token_t token_value; +} urma_user_tseg_t; + +typedef struct urma_sge { + uint64_t addr; + uint32_t len; + /* Driver verification + * remote seg: Either tseg or user tseg is not NULL. + * If both of them are not NULL, ignore user_tseg. + * local seg: user_tseg is not supported, tseg must not NULL. + */ + urma_target_seg_t *tseg; + urma_user_tseg_t *user_tseg; /* To support the exemption of import_seg */ +} urma_sge_t; + +typedef struct urma_sg { + urma_sge_t *sge; + uint32_t num_sge; +} urma_sg_t; + +/* wr for batch operations */ +typedef union urma_jfs_wr_flag { + struct { + uint32_t place_order : 2; /* 0: There is no order with other WR + 1: relax order + 2: strong order + 3: reserve */ /* see urma_place_order_t */ + uint32_t comp_order : 1; /* 0: There is no completion order with othwe WR. + 1: Completion order with previous WR. */ + uint32_t fence : 1; /* 0: There is not fence. + 1: Fence with previous read and atomic WR */ + uint32_t solicited_enable : 1; /* 0: There is not solicited. + 1: solicited. It will trigger an event on remote side */ + uint32_t complete_enable : 1; /* 0: Do not notify local process after the task is complete. + 1: Notify local process after the task is completed. */ + uint32_t inline_flag : 1; /* 0: not inline. + 1: inline data. */ + uint32_t db_bypass : 1; + uint32_t udf : 1; + uint32_t has_drv_ext : 1; + uint32_t reserved : 22; + } bs; + uint32_t value; +} urma_jfs_wr_flag_t; + +typedef union urma_jfr_wr_flag { + struct { + uint32_t complete_type : 1; /* 0: Write completion record to jfc. + 1: Write completion record to complete flag (CF) address */ + uint32_t reserved : 31; + } bs; + uint32_t value; +} urma_jfr_wr_flag_t; + +typedef struct urma_rw_wr { + urma_sg_t src; /* including total data length. src is local va for write, and remote va for read. + only support 1 src sge in read operation. */ + urma_sg_t dst; /* dst is remote va for write, and local va for read. + only support 1 dst sge in write operation. */ + uint8_t target_hint; // required when using jetty group + uint64_t notify_data; // notify data or imm data in host byte order; +} urma_rw_wr_t; + +typedef struct urma_send_wr { + urma_sg_t src; // including total data length + uint8_t target_hint; // required when using jetty group + uint64_t imm_data; // imm_data in host byte order; + urma_target_seg_t *tseg; /* tseg used only when send with invalidate */ +} urma_send_wr_t; + +typedef struct urma_cas_wr { + urma_sge_t *dst; // len is the data length of CAS operation + urma_sge_t *src; // local address for destination original value writeback, len represents the buffer length. + union { // Value compared with destination value + uint64_t cmp_data; // When the len <= 8B, it indicates the CMP value. + uint64_t cmp_addr; // When the len > 8B, it indicates the data address. + }; + union { // If destination value is the same as cmp_data, destination value will be changed to swap_data + uint64_t swap_data; // When the len <= 8B, it indicates the swap value. + uint64_t swap_addr; // When the len > 8B, it indicates the data address. + }; +} urma_cas_wr_t; + +typedef struct urma_faa_wr { + urma_sge_t *dst; // len is the data length of FAA operation + urma_sge_t *src; // local address for destination original value writeback, len represents the buffer length. + union { + uint64_t operand; // When the len <= 8B, it indicates the operand value. + uint64_t operand_addr; // When the len > 8B, it indicates the data address. + }; +} urma_faa_wr_t; + +typedef struct urma_jfs_wr { + urma_opcode_t opcode; + urma_jfs_wr_flag_t flag; + urma_target_jetty_t *tjetty; + uint64_t user_ctx; // completion data + union { + urma_rw_wr_t rw; + urma_send_wr_t send; + urma_cas_wr_t cas; + urma_faa_wr_t faa; + }; + struct urma_jfs_wr *next; +} urma_jfs_wr_t; + +typedef struct urma_jfr_wr { + urma_sg_t src; // includeing buffer length + uint64_t user_ctx; // completion data, eg. wr id + struct urma_jfr_wr *next; +} urma_jfr_wr_t; + +typedef union urma_cr_flag { + struct { + uint8_t s_r : 1; // Indicate CR stands for sending or receiving, 0: send, 1: recv. + uint8_t jetty : 1; // Indicate CR stands for jetty or jfs/jfr, 0: jfs/jfr, 1: jetty. + uint8_t suspend_done : 1; // Real CR associated with the WR, user_ctx is valid + uint8_t flush_err_done : 1; // Real CR associated with the WR, user_ctx is valid + uint8_t reserved : 4; + } bs; + uint8_t value; +} urma_cr_flag_t; + +typedef struct urma_cr_token { + uint32_t token_id; + urma_token_t token_value; +} urma_cr_token_t; + +typedef struct urma_cr { + urma_cr_status_t status; + uint64_t user_ctx; // user_ctx related to a work request + urma_cr_opcode_t opcode; // Only for recv + urma_cr_flag_t flag; // indicate notify data or swap data is valid or not + uint32_t completion_len; // The number of bytes transferred + + uint32_t local_id; // Local jetty ID, or JFS ID, or JFR ID, depends on flag + urma_jetty_id_t remote_id; // Valid only for receiving CR. The remote jetty where the + // received msg comes from Jetty ID or JFS ID, depends on flag. + union { + uint64_t imm_data; // Valid only for receiving CR: send/write/read with imm. + urma_cr_token_t invalid_token; // Valid only for receiving CR: send with invalidate. + }; + uint32_t tpn; // TP number or TPG number + uintptr_t user_data; // e.g. use as pointer to local jetty struct. +} urma_cr_t; + +typedef struct urma_async_event { + /* may be SW queue error, may be HW port error */ + const urma_context_t *urma_ctx; + union { + urma_jfc_t *jfc; + urma_jfs_t *jfs; + urma_jfr_t *jfr; + urma_jetty_t *jetty; + urma_jetty_grp_t *jetty_grp; + uint32_t port_id; + uint32_t eid_idx; + } element; + urma_async_event_type_t event_type; + void *priv; +} urma_async_event_t; + +/* URMA region definition */ +typedef union urma_ur_attr { + struct { + uint32_t reserved : 32; + } bs; + uint32_t value; +} urma_ur_attr_t; + +typedef union urma_import_ur_flag { + struct { + uint32_t mapping : 2; /* 0: URMA_SEG_NOMAP + 1: URMA_SEG_MAPPED_MVA + 2: URMA_SEG_MAPPED_DSVA */ + uint32_t reserved : 30; + } bs; + uint32_t value; +} urma_import_ur_flag_t; + +#define UR_NAME_MAX_LEN 256 +#define JFR_NAME_MAX_LEN 256 +#define URMA_MAX_SEGS_PER_UR_OPT 64 // Max number of SEGS per attach/detach ur + +// In parametre for create UR +typedef struct urma_ur { + char name[UR_NAME_MAX_LEN]; // UR url name + uint64_t size; + urma_ur_attr_t attr; // include: access flag, token policy, cacheability, dsva + uint64_t token; + uint64_t user_ctx; +} urma_ur_t; + +// Out parametre for import UR +typedef struct urma_target_ur { + char name[UR_NAME_MAX_LEN]; // UR url name + uint64_t size; + urma_import_ur_flag_t flag; // include: access flag, token policy, cacheability, dsva + urma_target_seg_t **tseg_list; + uint32_t cnt; +} urma_target_ur_t; + +typedef struct urma_seg_info { + urma_seg_t seg; + uint32_t idx_in_ur; +} urma_seg_info_t; + +// Out parametre for lookup UR +typedef struct urma_ur_info { + char name[UR_NAME_MAX_LEN]; // UR url name + uint64_t size; // limit size, by byte + urma_ur_attr_t attr; // include: access flag, token policy, cacheability, dsva + uint32_t cnt; // + urma_seg_info_t seg_list[0]; // cnt * sizeof(urma_seg_info_t) +} urma_ur_info_t; + +typedef struct urma_jfr_info { + char name[JFR_NAME_MAX_LEN]; // jfr url name + urma_eid_t eid; + uint32_t uasid; + uint32_t id; +} urma_jfr_info_t; + +typedef union urma_tp_cfg_flag { + struct { + uint32_t target : 1; /* 0: initiator, 1: target */ + uint32_t loopback : 1; + uint32_t dca_enable : 1; + /* for the bonding case, the hardware selects the port + * ignoring the port of the tp context and + * selects the port based on the hash value + * along with the information in the bonding group table. + */ + uint32_t bonding : 1; + uint32_t reserved : 28; + } bs; + uint32_t value; +} urma_tp_cfg_flag_t; + +typedef struct urma_tp_cfg { + urma_tp_cfg_flag_t flag; /* flag of initial tp */ + /* transport layer attributes */ + urma_transport_mode_t trans_mode; + uint8_t retry_num; + uint8_t retry_factor; /* for calculate the time slot to retry */ + uint8_t ack_timeout; + uint8_t dscp; + uint32_t oor_cnt; /* OOR window size: by packet */ +} urma_tp_cfg_t; + +typedef union urma_tp_attr_mask { + struct { + uint32_t flag : 1; + uint32_t peer_tpn : 1; + uint32_t state : 1; + uint32_t tx_psn : 1; + uint32_t rx_psn : 1; /* modify both rx psn and tx psn when restore tp */ + uint32_t mtu : 1; + uint32_t cc_pattern_idx : 1; + uint32_t oos_cnt : 1; + uint32_t local_net_addr_idx : 1; + uint32_t peer_net_addr : 1; + uint32_t data_udp_start : 1; + uint32_t ack_udp_start : 1; + uint32_t udp_range : 1; + uint32_t hop_limit : 1; + uint32_t flow_label : 1; + uint32_t port_id : 1; + uint32_t mn : 1; + uint32_t peer_trans_type : 1; + uint32_t reserved : 14; + } bs; + uint32_t value; +} urma_tp_attr_mask_t; + +typedef union urma_tp_mod_flag { + struct { + uint32_t oor_en : 1; /* out of order receive, 0: disable 1: enable */ + uint32_t sr_en : 1; /* selective retransmission, 0: disable 1: enable */ + uint32_t cc_en : 1; /* congestion control algorithm, 0: disable 1: enable */ + uint32_t cc_alg : 4; /* The value is ubcore_tp_cc_alg_t */ + uint32_t spray_en : 1; /* spray with src udp port, 0: disable 1: enable */ + uint32_t clan : 1; /* clan domain, 0: disable 1: enable */ + uint32_t reserved : 23; + } bs; + uint32_t value; +} urma_tp_mod_flag_t; + +typedef enum urma_tp_state { + URMA_TP_STATE_RESET = 0, + URMA_TP_STATE_PASSIVE, + URMA_TP_STATE_ACTIVE, + URMA_TP_STATE_BRAKE, + URMA_TP_STATE_ERROR +} urma_tp_state_t; + +typedef struct urma_net_addr { + sa_family_t sin_family; /* AF_INET/AF_INET6 */ + union { + struct in_addr in4; + struct in6_addr in6; + }; + uint64_t vlan; + uint8_t mac[URMA_MAC_BYTES]; + uint32_t prefix_len; +} urma_net_addr_t; + +typedef struct urma_net_addr_info { + urma_net_addr_t netaddr; + uint32_t index; +} urma_net_addr_info_t; + +typedef struct urma_tp_attr { + urma_tp_mod_flag_t flag; + uint32_t peer_tpn; + urma_tp_state_t state; + uint32_t tx_psn; + uint32_t rx_psn; + urma_mtu_t mtu; + uint8_t cc_pattern_idx; + uint32_t oos_cnt; /* out of standing packet cnt */ + uint32_t local_net_addr_idx; + urma_net_addr_t peer_net_addr; + uint16_t data_udp_start; + uint16_t ack_udp_start; + uint8_t udp_range; + uint8_t hop_limit; + uint32_t flow_label; + uint8_t port_id; + uint8_t mn; /* 0~15, a packet contains only one msg if mn is set as 0 */ + urma_transport_type_t peer_trans_type; +} urma_tp_attr_t; + +typedef union urma_get_tp_cfg_flag { + struct { + uint32_t ctp : 1; + uint32_t rtp : 1; + uint32_t utp : 1; + uint32_t uboe : 1; + uint32_t pre_defined : 1; + uint32_t dynamic_defined : 1; + uint32_t udp : 5; + uint32_t group_id : 15; + uint32_t reserved : 6; + } bs; + uint32_t value; +} urma_get_tp_cfg_flag_t; + +typedef struct urma_get_tp_cfg { + urma_get_tp_cfg_flag_t flag; + urma_transport_mode_t trans_mode; + urma_eid_t local_eid; + urma_eid_t peer_eid; +} urma_get_tp_cfg_t; + +typedef struct urma_tp_info { + uint64_t tp_handle; +} urma_tp_info_t; + +typedef struct urma_active_tp_attr { + uint32_t tx_psn; + uint32_t rx_psn; + uint64_t reserved; +} urma_active_tp_attr_t; + +typedef struct urma_active_tp_cfg { + uint64_t tp_handle; + uint64_t peer_tp_handle; + uint64_t tag; + urma_active_tp_attr_t tp_attr; +} urma_active_tp_cfg_t; + +typedef struct urma_active_tp_cfg urma_import_jetty_ex_cfg_t; +typedef struct urma_active_tp_cfg urma_import_jfr_ex_cfg_t; +typedef struct urma_active_tp_cfg urma_bind_jetty_ex_cfg_t; + +#pragma pack(1) +typedef struct urma_tp_attr_value { + uint8_t retry_times_init : 3; + uint8_t at : 5; + uint8_t sip[URMA_IP_ADDR_BYTES]; + uint8_t dip[URMA_IP_ADDR_BYTES]; + uint8_t sma[URMA_MAC_BYTES]; + uint8_t dma[URMA_MAC_BYTES]; + uint16_t vlan_id : 12; + uint8_t vlan_en : 1; + uint8_t dscp : 6; + uint8_t at_times : 5; + uint8_t sl : 4; + uint8_t ttl; + uint16_t ack_udp_srcport; + uint16_t data_udp_srcport; + uint8_t udp_srcport_range : 4; + uint8_t spray_en : 1; + uint8_t udp_global_en : 1; + uint8_t reserve_0 : 2; + uint16_t sl_bitmap; + uint8_t dscp_config_mode : 1; + uint8_t reserve_1 : 7; + uint8_t reserved[70]; +} urma_tp_attr_value_t; +#pragma pack() + +/* callback information */ +typedef void (*urma_async_event_cb)(urma_async_event_t *event, void *cb_arg); + +/* callback function type for urma_advise_jfr/jetty_async. User must define callback function to handle result. + advise_result is the result of advise jfr or jetty */ +typedef void (*urma_advise_async_cb_func)(urma_status_t advise_result, void *cb_arg); + +typedef enum urma_vlog_level { + URMA_VLOG_LEVEL_EMERG = 0, + URMA_VLOG_LEVEL_ALERT = 1, + URMA_VLOG_LEVEL_CRIT = 2, + URMA_VLOG_LEVEL_ERR = 3, + URMA_VLOG_LEVEL_WARNING = 4, + URMA_VLOG_LEVEL_NOTICE = 5, + URMA_VLOG_LEVEL_INFO = 6, + URMA_VLOG_LEVEL_DEBUG = 7, + URMA_VLOG_LEVEL_MAX = 8, +} urma_vlog_level_t; + +typedef void (*urma_log_cb_t)(int level, char *message); + +/* location log callback function definition */ +typedef void (*urma_loc_log_cb)(int level, const char *file, const char *function, int line, char *message); + +#ifdef __cplusplus +} +#endif + +#endif // URMA_TYPES_H diff --git a/include/urma/urma_types_str.h b/include/urma/urma_types_str.h new file mode 100644 index 0000000..13e28e0 --- /dev/null +++ b/include/urma/urma_types_str.h @@ -0,0 +1,248 @@ +/* + * SPDX-License-Identifier: MIT + * Copyright (c) Huawei Technologies Co., Ltd. 2022-2025. All rights reserved. + * Description: URMA type string header file + * Author: Qian Guoxin + * Create: 2022-10-18 + * Note: + * History: 2022-10-18 Create File + */ + +#ifndef URMA_TYPES_STR_H +#define URMA_TYPES_STR_H +#include "urma_types.h" + +static const char *const g_urma_mtu_str[] = { + [URMA_MTU_256] = "MTU_256", // + [URMA_MTU_512] = "MTU_512", // + [URMA_MTU_1024] = "MTU_1024", // + [URMA_MTU_2048] = "MTU_2048", // + [URMA_MTU_4096] = "MTU_4096", // + [URMA_MTU_8192] = "MTU_8192", // +}; + +static inline const char *urma_mtu_to_string(urma_mtu_t mtu) +{ + if (mtu < URMA_MTU_256 || mtu > URMA_MTU_8192) { + return "Invalid Value"; + } + return g_urma_mtu_str[mtu]; +} + +static const char *const g_urma_port_state_str[] = { + [URMA_PORT_NOP] = "NOP", // + [URMA_PORT_DOWN] = "DOWN", // + [URMA_PORT_INIT] = "INIT", // + [URMA_PORT_ARMED] = "ARMED", // + [URMA_PORT_ACTIVE] = "ACTIVE", // + [URMA_PORT_ACTIVE_DEFER] = "ACTIVE_DEFER", // +}; + +static inline const char *urma_port_state_to_string(urma_port_state_t state) +{ + if (state > URMA_PORT_ACTIVE_DEFER) { + return "Invalid Value"; + } + return g_urma_port_state_str[state]; +} + +static const char *const g_urma_speed_str[] = { + [URMA_SP_10M] = "SP_10M", // + [URMA_SP_100M] = "SP_100M", // + [URMA_SP_1G] = "SP_1G", // + [URMA_SP_2_5G] = "SP_2.5G", // + [URMA_SP_5G] = "SP_5G", // + [URMA_SP_10G] = "SP_10G", // + [URMA_SP_14G] = "SP_14G", // + [URMA_SP_25G] = "SP_25G", // + [URMA_SP_40G] = "SP_40G", // + [URMA_SP_50G] = "SP_50G", // + [URMA_SP_100G] = "SP_100G", // + [URMA_SP_200G] = "SP_200G", // + [URMA_SP_400G] = "SP_400G", // + [URMA_SP_800G] = "SP_800G", // +}; + +static inline const char *urma_speed_to_string(urma_speed_t speed) +{ + if (speed > URMA_SP_800G) { + return "Invalid Value"; + } + return g_urma_speed_str[speed]; +} + +static const char *const g_urma_link_width_str[] = { + [0] = "unknow", + [URMA_LINK_X1] = "LINK_X1", + [URMA_LINK_X2] = "LINK_X2", + [URMA_LINK_X4] = "LINK_X4", + [URMA_LINK_X8] = "LINK_X8", + [URMA_LINK_X16] = "LINK_X16", + [URMA_LINK_X32] = "LINK_X32", +}; + +static inline const char *urma_link_width_to_string(urma_link_width_t width) +{ + if (width > URMA_LINK_X32) { + return "Invalid Value"; + } + return g_urma_link_width_str[width]; +} + +static const char * const g_urma_tp_type_en_str[] = { + [URMA_RTP] = "RTP", + [URMA_CTP] = "CTP", + [URMA_UTP] = "UTP", +}; + +static inline const char *urma_tp_type_en_to_string(union urma_tp_type_en tp_type) +{ + if (tp_type.bs.rtp == 1 && tp_type.bs.ctp == 0 && tp_type.bs.utp == 0) { + return g_urma_tp_type_en_str[URMA_RTP]; + } + if (tp_type.bs.rtp == 0 && tp_type.bs.ctp == 1 && tp_type.bs.utp == 0) { + return g_urma_tp_type_en_str[URMA_CTP]; + } + if (tp_type.bs.rtp == 0 && tp_type.bs.ctp == 0 && tp_type.bs.utp == 1) { + return g_urma_tp_type_en_str[URMA_UTP]; + } + return "Invalid Value"; +} + +#define URMA_DEVICE_FEAT_NUM 9 + +static const char *const g_urma_device_feat_str[URMA_DEVICE_FEAT_NUM] = { + "OUT_OF_ORDER", // + "JFC_PER_WR", // + "STRIDE_OP", // + "LOAD_STORE_OP", // + "NON_PIN", // + "PERSISTENCE_MEM", // + "JFC_INLINE", // + "SPRAY_ENABLE", // + "SELECTIVE_RETRANS", // +}; + +static inline const char *urma_device_feat_to_string(uint8_t bit) +{ + if (bit >= URMA_DEVICE_FEAT_NUM) { + return "Invalid Value"; + } + return g_urma_device_feat_str[bit]; +} + +#define URMA_ATOMIC_FEAT_NUM 7 + +static const char *const g_urma_atomic_feat_str[URMA_ATOMIC_FEAT_NUM] = { + "compare_and_swap", // + "swap", // + "fetch_and_add", // + "fetch_and_sub", // + "fetch_and_and", // + "fetch_and_or", // + "fetch_and_xor", // +}; + +static inline const char *urma_atomic_feat_to_string(uint8_t bit) +{ + if (bit >= URMA_ATOMIC_FEAT_NUM) { + return "Invalid Value"; + } + return g_urma_atomic_feat_str[bit]; +} + +static const char *const g_urma_trans_mode_str[] = { + [URMA_TM_RM] = "RM(Reliable message)", + [URMA_TM_RC] = "RC(Reliable connection)", + [URMA_TM_UM] = "UM(Unreliable message)", +}; + +static inline const char *urma_trans_mode_to_string(urma_transport_mode_t mode) +{ + if (mode > URMA_TM_UM) { + return "Invalid Value"; + } + return g_urma_trans_mode_str[mode]; +} + +static const char *const g_urma_tp_type_str[] = { + [URMA_TRANSPORT_UB] = "UB", + [URMA_TRANSPORT_IB] = "IB", + [URMA_TRANSPORT_IP] = "IP", + [URMA_TRANSPORT_SOFTUB] = "SOFTUB", + [URMA_TRANSPORT_HNS_UB] = "HNS_UB", +}; + +static inline const char *urma_tp_type_to_string(urma_transport_type_t type) +{ + if (type <= URMA_TRANSPORT_INVALID || type >= URMA_TRANSPORT_MAX) { + return "Invalid Value"; + } + return g_urma_tp_type_str[type]; +} + +static const char *const g_urma_congestion_ctrl_alg_str[] = { + [URMA_TP_CC_NONE] = "NONE", + [URMA_TP_CC_DCQCN] = "DCQCN", + [URMA_TP_CC_CAQM] = "CAQM", + [URMA_TP_CC_LDCP] = "LDCP", + [URMA_TP_CC_LDCP_L2_HEADER] = "LDCP_L2_HEADER", + [URMA_TP_CC_LDCP_TP_HEADER] = "LDCP_TP_HEADER", + [URMA_TP_CC_DIP] = "DIP", + [URMA_TP_CC_ACC] = "ACC", + [URMA_TP_CC_CUSTOM_1] = "CUSTOM_1", + [URMA_TP_CC_CUSTOM_2] = "CUSTOM_2", +}; + +static inline const char *urma_congestion_ctrl_alg_to_string(uint8_t bit) +{ + if (bit >= URMA_TP_CC_NUM) { + return "Invalid Value"; + } + return g_urma_congestion_ctrl_alg_str[bit]; +} + +static const char *const g_urma_jfc_state[] = { + [URMA_JFC_STATE_INVALID] = "INVALID", + [URMA_JFC_STATE_VALID] = "VALID", + [URMA_JFC_STATE_ERROR] = "ERROR", +}; + +static inline const char *urma_jfc_state_to_string(uint8_t bit) +{ + if (bit > URMA_JFC_STATE_ERROR) { + return "Invalid Value"; + } + return g_urma_jfc_state[bit]; +} + +static const char *const g_urma_jetty_state[] = { + [URMA_JETTY_STATE_RESET] = "RESET", + [URMA_JETTY_STATE_READY] = "READY", + [URMA_JETTY_STATE_SUSPENDED] = "SUSPENDED", + [URMA_JETTY_STATE_ERROR] = "ERROR", +}; + +static inline const char *urma_jetty_state_to_string(uint8_t bit) +{ + if (bit > URMA_JETTY_STATE_ERROR) { + return "Invalid Value"; + } + return g_urma_jetty_state[bit]; +} + +static const char *const g_urma_jfr_state[] = { + [URMA_JFR_STATE_RESET] = "RESET", + [URMA_JFR_STATE_READY] = "READY", + [URMA_JFR_STATE_ERROR] = "ERROR", +}; + +static inline const char *urma_jfr_state_to_string(uint8_t bit) +{ + if (bit > URMA_JFR_STATE_ERROR) { + return "Invalid Value"; + } + return g_urma_jfr_state[bit]; +} + +#endif diff --git a/include/urma/urma_ubagg.h b/include/urma/urma_ubagg.h new file mode 100644 index 0000000..ce38088 --- /dev/null +++ b/include/urma/urma_ubagg.h @@ -0,0 +1,298 @@ +/* + * SPDX-License-Identifier: MIT + * Copyright (c) Huawei Technologies Co., Ltd. 2025-2025. All rights reserved. + * Description: URMA ubagg provider private API header + * Author: Ma Chuan + * Create: 2025-02-05 + * Note: + * History: 2025-02-05 Create File + */ +#ifndef URMA_UBAGG_H +#define URMA_UBAGG_H + +#include "urma_types.h" +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define BOND_CR_RNR_RETRY_CNT_EXC_ERR 99 + +/* For version compatibility */ +#define BONDP_USER_CTL_BONDING BONDP_USER_CTL_BONDING +#define BONDP_USER_CTL_SET_CTX_CFG BONDP_USER_CTL_SET_CTX_CFG + +#define URMA_UBAGG_DEV_MAX_NUM (20) +#define URMA_UBAGG_MAX_CONNECTION (URMA_UBAGG_DEV_MAX_NUM * URMA_UBAGG_DEV_MAX_NUM) +#define URMA_UBAGG_WR_BUF_SIZE (3) +#define URMA_UBAGG_MAX_CR_CNT_PER_DEV (32) +#define URMA_UBAGG_CHIP_LINK_NUM (4) +#define URMA_ACTIVE_PORT_PER_DIE (2) +#define URMA_ACTIVE_PORT_MIN (4) +#define URMA_ACTIVE_PORT_MAX (5) + +#define URMA_FAILOVER_LINK_NUM (IODIE_NUM * URMA_ACTIVE_PORT_PER_DIE) + +typedef enum bondp_user_ctl_opcode { + BONDP_USER_CTL_SET_BONDING_MODE_LEGACY = 4, + BONDP_USER_CTL_ENABLE_SEG_CACHE, + BONDP_USER_CTL_QUERY_PORT, + BONDP_USER_CTL_SET_BONDING_MODE, + BONDP_USER_CTL_GET_JFCE_FD_LIST, + BONDP_USER_CTL_OPCODE_GET_RJETTY, + BONDP_USER_CTL_OPCODE_GET_SEG_CTX, + BONDP_USER_CTL_DISABLE_MSN, + /* port_ids config for this opcode should be the same as the port_ids + config when creating jetty */ + BONDP_USER_CTL_SET_BONDING_PORT, + BONDP_USER_CTL_SET_CTX_CFG, +} bondp_user_ctl_opcode_t; + +typedef enum bondp_ctx_cfg_mask { + BONDP_CTX_CFG_ENABLE_FAILOVER = 1ULL << 0, + BONDP_CTX_CFG_ENABLE_FAILBACK = 1ULL << 1, + BONDP_CTX_CFG_ENABLE_HEALTH_CHECK = 1ULL << 2, + BONDP_CTX_CFG_HEALTH_CHECK_INTERVAL = 1ULL << 3, + BONDP_CTX_CFG_HEALTH_CHECK_BATCH_NUM = 1ULL << 4, + BONDP_CTX_CFG_ENABLE_RNR_RETRY = 1ULL << 5, + BONDP_CTX_CFG_RNR_SLEEP = 1ULL << 6, + BONDP_CTX_CFG_RNR_MAX = 1ULL << 7, + BONDP_CTX_CFG_RNR_JITTER_RATIO = 1ULL << 8, +} bondp_ctx_cfg_mask_t; + +#define BONDP_CTX_CFG_MASK_ALL ((1ULL << 9) - 1) + +typedef struct bondp_set_ctx_cfg_in { + uint64_t mask; + bool enable_failover; + bool enable_failback; + bool enable_health_check; + uint64_t health_check_interval_ms; + uint32_t health_check_batch_node_num; + bool enable_rnr_retry; + uint64_t rnr_retry_sleep_ms; + uint64_t rnr_retry_max; + uint32_t rnr_retry_jitter_ratio; +} bondp_set_ctx_cfg_in_t; + +// URMA_USER_CTL_BOND_SET_BONDING_MODE, +typedef enum bondp_bonding_mode { + BONDP_BONDING_MODE_STANDALONE, + BONDP_BONDING_MODE_ACTIVE_BACKUP, + BONDP_BONDING_MODE_BALANCE, + BONDP_BONDING_MODE_MAX, +} bondp_bonding_mode_t; + +typedef enum bondp_bonding_level { + BONDP_BONDING_LEVEL_IODIE, + BONDP_BONDING_LEVEL_PORT, + BONDP_BONDING_LEVEL_MAX, +} bondp_bonding_level_t; + +/* + * Base segment info without the user-space-only ext field. + * Layout-compatible with kernel struct ubagg_seg_info. + */ +typedef struct urma_seg_base { + urma_ubva_t ubva; + uint64_t len; + urma_seg_attr_t attr; + uint32_t token_id; +} urma_seg_base_t; + +typedef struct bondp_set_bonding_mode_in { + bondp_bonding_mode_t bonding_mode; + bondp_bonding_level_t bonding_level; +} bondp_set_bonding_mode_in_t; + +// URMA_USER_CTL_BOND_QUERY_PORT +typedef struct bondp_query_port_in { + union { + urma_jfr_t *jfr; + urma_jetty_t *jetty; + }; +} bondp_query_port_in_t; + +typedef struct bondp_query_port_out { + uint32_t enabled_indices[URMA_UBAGG_DEV_MAX_NUM]; + uint32_t enabled_count; + uint32_t active_indices[URMA_UBAGG_DEV_MAX_NUM]; + uint32_t active_count; +} bondp_query_port_out_t; + +typedef struct bondp_get_jfce_fd_list_in { + urma_jfce_t *jfce; +} bondp_get_jfce_fd_list_in_t; + +typedef struct bondp_get_jfce_fd_list_out { + int fd_list[URMA_UBAGG_DEV_MAX_NUM]; + uint32_t count; +} bondp_get_jfce_fd_list_out_t; + +typedef union bondp_port_id { + struct { + uint8_t chip_id; + uint8_t die_id; + uint8_t port_idx; // portEID:0~8;primaryEID: UINT8_MAX + uint8_t reserved; + }; + uint64_t value; +} bondp_port_id_t; + +// BONDP_USER_CTL_SET_BONDING_PORT +// The port_ids config for this opcode should be the same as the port_ids +// config when creating jetty. liburma copies the port_ids array internally, +// so the caller's buffer may be released after the call returns. +typedef struct bondp_set_bonding_port_in { + const bondp_port_id_t *port_ids; + uint32_t port_count; +} bondp_set_bonding_port_in_t; + +typedef struct bondp_jfs_cfg { + urma_jfs_cfg_t base; + const bondp_port_id_t *port_ids; + uint32_t port_count; +} bondp_jfs_cfg_t; + +typedef struct bondp_jfc_cfg { + urma_jfc_cfg_t base; + const bondp_port_id_t *port_ids; + uint32_t port_count; +} bondp_jfc_cfg_t; + +typedef struct bondp_jfr_cfg { + urma_jfr_cfg_t base; + const bondp_port_id_t *port_ids; + uint32_t port_count; +} bondp_jfr_cfg_t; + +typedef struct bondp_jetty_cfg { + urma_jetty_cfg_t base; + const bondp_port_id_t *port_ids; + uint32_t port_count; +} bondp_jetty_cfg_t; + +typedef struct urma_bond_jetty_ext { + uint8_t version; + uint64_t mask; + urma_jetty_id_t slave_id[URMA_UBAGG_DEV_MAX_NUM]; + bool is_multipath; + uint8_t enable_indices[URMA_UBAGG_DEV_MAX_NUM]; + uint32_t enable_count; + bool is_health_check_enable; + struct { + urma_seg_base_t slaves[URMA_UBAGG_DEV_MAX_NUM]; + } health_check_seg; +} urma_bond_jetty_ext_t; + +typedef enum bondp_rjetty_ext_version { + BONDP_RJETTY_EXT_VERSION_V0 = 0, +} bondp_rjetty_ext_version_t; + +typedef enum bondp_rjetty_ext_mask { + BONDP_RJETTY_EXT_MASK_MULTI_PATH = 1ULL << 0, + BONDP_RJETTY_EXT_MASK_HEALTH_CHECK = 1ULL << 1, + BONDP_RJETTY_EXT_MASK_LOCAL_CTX = 1ULL << 2, + BONDP_RJETTY_EXT_MASK_TARGET_CTX = 1ULL << 3, +} bondp_rjetty_ext_mask_t; + +/* + * Compact packed target ctx: + * - slave jetty: eid + id (uasid omitted, reuse outer rjetty->jetty_id.uasid) + * - health probe: eid + va + token_id (uasid/len/attr omitted; + * len/attr shared in urma_bond_jetty_ext_v0 when HEALTH_CHECK is set) + */ +#pragma pack(push, 1) +typedef struct bondp_rjetty_target_ctx { + uint8_t target_idx; + urma_eid_t eid; + uint32_t jetty_id; + urma_eid_t health_eid; + uint64_t health_va; + uint32_t health_token_id; +} __attribute__((packed)) bondp_rjetty_target_ctx_t; + +/* + * Compact variable-length rjetty ext layout (version 0): + * data: + * uint8_t local_indices[local_ctx_cnt] + * bondp_rjetty_target_ctx_t target_ctx[target_ctx_cnt] + */ +typedef struct urma_bond_jetty_ext_v0 { + uint8_t version; + uint64_t mask; + bool is_multipath; + bool is_health_check_enable; + /* Number of uint8_t local indices stored in the first variable-length region. */ + uint32_t local_ctx_cnt; + /* Number of bondp_rjetty_target_ctx_t entries stored after local indices. */ + uint32_t target_ctx_cnt; + /* Shared health seg fields (valid when HEALTH_CHECK mask is set). */ + uint64_t health_len; + urma_seg_attr_t health_attr; + char data[0]; +} __attribute__((packed)) urma_bond_jetty_ext_v0_t; +#pragma pack(pop) + +/* + * Compact variable-length seg ext layout (version 0): + * data: bondp_seg_peer_ctx_t entries[peer_cnt] + * Peer entries omit va/len/attr/uasid (reused from outer vseg); only eid+token_id differ. + * Packed to drop alignment padding in the on-wire / user_info buffer. + */ +#pragma pack(push, 1) +typedef struct bondp_seg_peer_ctx { + uint8_t peer_idx; /* absolute device index; import writes back to peer_p_seg[peer_idx] */ + urma_eid_t eid; + uint32_t token_id; +} __attribute__((packed)) bondp_seg_peer_ctx_t; + +typedef struct urma_bond_seg_ext_v0 { + uint8_t version; + uint64_t mask; + uint32_t peer_cnt; + char data[0]; +} __attribute__((packed)) urma_bond_seg_ext_v0_t; +#pragma pack(pop) + +typedef struct bondp_rjetty { + urma_rjetty_t base; + urma_bond_jetty_ext_t ext; + union { + urma_jfs_t *jfs; + urma_jetty_t *jetty; + }; +} bondp_rjetty_t; + +typedef struct bondp_rjfr { + urma_rjfr_t base; + union { + urma_jfs_t *jfs; + urma_jetty_t *jetty; + }; +} bondp_rjfr_t; + +typedef struct bondp_jfs_wr { + urma_jfs_wr_t base; + uint32_t src_chip_id; + uint32_t dst_chip_id; +} bondp_jfs_wr_t; + +typedef struct bondp_path { + uint32_t local_idx; + uint32_t target_idx; + uint32_t least_load; +} bondp_path_t; + +urma_status_t urma_write_affinity(urma_jfs_t *jfs, urma_target_jetty_t *target_jfr, + urma_target_seg_t *dst_tseg, urma_target_seg_t *src_tseg, + uint64_t dst, uint64_t src, uint32_t len, + urma_jfs_wr_flag_t flag, uint64_t user_ctx, + uint32_t src_chip_id, uint32_t dst_chip_id); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/ub_bench.c b/src/ub_bench.c new file mode 100644 index 0000000..f885ff2 --- /dev/null +++ b/src/ub_bench.c @@ -0,0 +1,234 @@ +/* + * SPDX-License-Identifier: MIT + * Copyright (c) Huawei Technologies Co., Ltd. 2026-2026. All rights reserved. + * Description: ub_bench + * Create: 2026-09-16 + * Note: + * History: 2026-09-16 create file + */ + +#include + +#include "urma_api.h" + +#include "ub_bench_mgmt.h" +#include "ub_bench_parameters.h" +#include "ub_bench_resources.h" +#include "ub_bench_run_test.h" +#include "ub_bench_run.h" + +typedef struct context_cfg { + perftest_context_t *ctx; + perftest_config_t *cfg; +} context_cfg_t; + +static int run_test(perftest_context_t *ctx, perftest_config_t *cfg) +{ + int ret = 0; + uint32_t i = 0; + + for (i = 0; i < cfg->pair_num; i++) { + ret = sync_time(cfg, i, "Start test"); + if (ret != 0) { + LOG_ERROR("Failed to sync time, start test.\n"); + return ret; + } + } + + switch (cfg->cmd) { + case PERFTEST_READ_LAT: + ret = run_read_lat(ctx, cfg); + break; + case PERFTEST_WRITE_LAT: + ret = run_write_lat(ctx, cfg); + break; + case PERFTEST_SEND_LAT: + ret = run_send_lat(ctx, cfg); + break; + case PERFTEST_ATOMIC_LAT: + ret = run_atomic_lat(ctx, cfg); + break; + case PERFTEST_READ_BW: + if (cfg->mode == PERFTEST_MODE_SEQUENTIAL) { + ret = bench_run_sequential(ctx, cfg); + } else { + ret = run_read_bw(ctx, cfg); + } + break; + case PERFTEST_WRITE_BW: + if (cfg->mode == PERFTEST_MODE_SEQUENTIAL) { + ret = bench_run_sequential(ctx, cfg); + } else { + ret = run_write_bw(ctx, cfg); + } + break; + case PERFTEST_ATOMIC_BW: + if (cfg->mode == PERFTEST_MODE_SEQUENTIAL) { + ret = bench_run_sequential(ctx, cfg); + } else { + ret = run_atomic_bw(ctx, cfg); + } + break; + case PERFTEST_SEND_BW: + if (cfg->mode == PERFTEST_MODE_SEQUENTIAL) { + ret = bench_run_sequential(ctx, cfg); + } else { + ret = run_send_bw(ctx, cfg); + } + break; + default: + break; + } + + if (cfg->type == PERFTEST_BW && cfg->enable_write_dirty == true) { + cfg->enable_write_dirty = false; /* close the write dirty thread. */ + (void)pthread_join(ctx->write_dirty_thread_id, NULL); + } + + if (ret != 0) { + LOG_ERROR("Failed to run test: %d.\n", (int)cfg->cmd); + return ret; + } + if (!g_exit_flag) { + for (i = 0; i < cfg->pair_num; i++) { + ret = sync_time(cfg, i, "End test"); + if (ret != 0) { + LOG_ERROR("Failed to sync time, End test.\n"); + return ret; + } + } + } + return ret; +} + +int rearm_jfc(perftest_context_t *ctx, const perftest_config_t *cfg) +{ + urma_status_t status; + if (cfg->api_type == PERFTEST_WRITE) { + return -1; + } + for (uint32_t i = 0; i < cfg->jettys; i++) { + status = urma_rearm_jfc(ctx->jfc_s[i], false); + if (status != URMA_SUCCESS) { + LOG_ERROR("Couldn't rearm jfc_s %u\n", i); + return -1; + } + if (cfg->api_type == PERFTEST_SEND) { + status = urma_rearm_jfc(ctx->jfc_r[i], false); + if (status != URMA_SUCCESS) { + LOG_ERROR("Couldn't rearm jfc_r %u\n", i); + return -1; + } + } + if (cfg->pair_flag == false || cfg->type == PERFTEST_BW) { + break; + } + } + return 0; +} + +static void *write_dirty_thread(void *args) +{ + context_cfg_t *ctx_cfg = (context_cfg_t *)args; + perftest_context_t *ctx = ctx_cfg->ctx; + perftest_config_t *cfg = ctx_cfg->cfg; + + while (cfg->enable_write_dirty == true && cfg->write_dirty_period >= PERFTEST_DEF_INF_PERIOD_MS) { + int rand_num = rand() % PERFTEST_CHAR_MAX_VALUE; + if (cfg->seg_pre_jetty == false) { + char *str = (char *)ctx->local_buf[0] + ctx->buf_size * cfg->jettys; + for (size_t i = 0; i < ctx->buf_size * cfg->jettys; i++) { + str[i] = rand_num; + } + } else { + for (uint32_t jetty = 0; jetty < cfg->jettys; jetty++) { + char *str = (char *)ctx->local_buf[jetty] + ctx->buf_size; + for (size_t i = 0; i < ctx->buf_size; i++) { + str[i] = rand_num; + } + } + } + usleep(cfg->write_dirty_period * PERFTEST_MSEC_TO_USEC); + } + return NULL; +} + +static int prepare_test(perftest_context_t *ctx, perftest_config_t *cfg, context_cfg_t *args) +{ + print_cfg(cfg); + if (cfg->use_jfce == true) { + if (rearm_jfc(ctx, cfg) != 0) { + return -1; + } + } + + if (cfg->type == PERFTEST_BW && cfg->enable_write_dirty == true) { + if (pthread_create(&ctx->write_dirty_thread_id, NULL, write_dirty_thread, args) != 0) { + LOG_ERROR("Failed to create write_dirty_thread.\n"); + return -1; + } + } + + return 0; +} + +int main(int argc, char *argv[]) +{ + int ret; + perftest_config_t cfg = {0}; /* cfg.server_ip shoule be initialized as NULL to avoid core dump */ + perftest_context_t ctx; + context_cfg_t args; + + args.cfg = &cfg; + args.ctx = &ctx; + // Parse parameters and check for conflicts + ret = perftest_parse_args(argc, argv, &cfg); + if (ret != 0) { + goto clean_cfg; + } + + ret = check_local_cfg(&cfg); + if (ret != 0) { + goto clean_cfg; + } + + // Establish connection between client and server + ret = establish_connection(&cfg); + if (ret != 0) { + goto clean_cfg; + } + + // Exchange configuration information and check + ret = check_remote_cfg(&cfg); + if (ret != 0) { + goto close_connect; + } + + // Create resource for test + ret = create_ctx(&ctx, &cfg); + if (ret != 0) { + goto close_connect; + } + + // Prepare the operation before the test. For example: print test information, create wr_ list. + ret = prepare_test(&ctx, &cfg, &args); + if (ret != 0) { + goto destroy_ctx; + } + // Flush print from flowbuffer to output before starting test + (void)fflush(stdout); + + // Run test for each cmd + ret = run_test(&ctx, &cfg); + if (ret != 0) { + goto destroy_ctx; + } + +destroy_ctx: + destroy_ctx(&ctx, &cfg); +close_connect: + close_connection(&cfg); +clean_cfg: + destroy_cfg(&cfg); + return ret; +} diff --git a/src/ub_bench_hist.c b/src/ub_bench_hist.c new file mode 100644 index 0000000..266480a --- /dev/null +++ b/src/ub_bench_hist.c @@ -0,0 +1,47 @@ +/* + * SPDX-License-Identifier: MIT + * Copyright (c) Huawei Technologies Co., Ltd. 2026-2026. All rights reserved. + * Description: log2 histogram implementation for ub_bench + * Create: 2026-09-16 + */ + +#include "ub_bench_hist.h" + +uint64_t hist_percentile(const latency_hist_t *h, double pct) +{ + if (h->total_count == 0) { + return 0; + } + uint64_t threshold = (uint64_t)(h->total_count * (1.0 - pct)); + uint64_t count = 0; + for (int i = HIST_BUCKET_NUM - 1; i >= 0; i--) { + count += h->buckets[i]; + if (count > threshold) { + return hist_bucket_to_value(i); + } + } + return h->max_delta; +} + +void hist_merge(latency_hist_t *dst, const latency_hist_t *src) +{ + for (int i = 0; i < HIST_BUCKET_NUM; i++) { + dst->buckets[i] += src->buckets[i]; + } + dst->total_count += src->total_count; + dst->sum_delta += src->sum_delta; + if (src->min_delta < dst->min_delta) { + dst->min_delta = src->min_delta; + } + if (src->max_delta > dst->max_delta) { + dst->max_delta = src->max_delta; + } +} + +double hist_avg(const latency_hist_t *h) +{ + if (h->total_count == 0) { + return 0; + } + return (double)h->sum_delta / (double)h->total_count; +} diff --git a/src/ub_bench_hist.h b/src/ub_bench_hist.h new file mode 100644 index 0000000..1d03866 --- /dev/null +++ b/src/ub_bench_hist.h @@ -0,0 +1,91 @@ +/* + * SPDX-License-Identifier: MIT + * Copyright (c) Huawei Technologies Co., Ltd. 2026-2026. All rights reserved. + * Description: log2 histogram for ub_bench latency collection + * Create: 2026-09-16 + */ + +#ifndef UB_BENCH_HIST_H +#define UB_BENCH_HIST_H + +#include +#include +#include + +#define HIST_SUB_BITS 9 +#define HIST_MAX_MAG 28 // max 2^28 cycles (~111ms @2.4GHz), covers 8MB packets + tail spikes +#define HIST_SUB_NUM (1 << HIST_SUB_BITS) +#define HIST_BUCKET_NUM (HIST_MAX_MAG * HIST_SUB_NUM) + +typedef struct { + uint32_t buckets[HIST_BUCKET_NUM]; + uint64_t total_count; + uint64_t sum_delta; + uint64_t min_delta; + uint64_t max_delta; +} latency_hist_t; + +static inline void hist_init(latency_hist_t *h) +{ + memset(h, 0, sizeof(*h)); + h->min_delta = (uint64_t)-1; + h->max_delta = 0; +} + +static inline void hist_reset(latency_hist_t *h) +{ + memset(h->buckets, 0, sizeof(h->buckets)); + h->total_count = 0; + h->sum_delta = 0; + h->min_delta = (uint64_t)-1; + h->max_delta = 0; +} + +static inline void hist_add(latency_hist_t *h, uint64_t delta) +{ + if (delta == 0) { + h->buckets[0]++; + h->total_count++; + h->sum_delta += delta; + h->min_delta = 0; + return; + } + int mag = delta ? (63 - __builtin_clzll(delta)) : 0; + if (mag >= HIST_MAX_MAG) { + mag = HIST_MAX_MAG - 1; + } + uint32_t sub_size = (1U << mag) >> HIST_SUB_BITS; + if (sub_size == 0) { + sub_size = 1; + } + int sub = (int)((delta - (1ULL << mag)) / sub_size); + if (sub >= HIST_SUB_NUM) { + sub = HIST_SUB_NUM - 1; + } + h->buckets[mag * HIST_SUB_NUM + sub]++; + h->total_count++; + h->sum_delta += delta; + if (delta < h->min_delta) { + h->min_delta = delta; + } + if (delta > h->max_delta) { + h->max_delta = delta; + } +} + +static inline uint64_t hist_bucket_to_value(int bucket_idx) +{ + int mag = bucket_idx >> HIST_SUB_BITS; + int sub = bucket_idx & (HIST_SUB_NUM - 1); + uint32_t sub_size = (1U << mag) >> HIST_SUB_BITS; + if (sub_size == 0) { + sub_size = 1; + } + return (1ULL << mag) + (uint64_t)sub * sub_size; +} + +uint64_t hist_percentile(const latency_hist_t *h, double pct); +void hist_merge(latency_hist_t *dst, const latency_hist_t *src); +double hist_avg(const latency_hist_t *h); + +#endif diff --git a/src/ub_bench_log.c b/src/ub_bench_log.c new file mode 100644 index 0000000..61622a0 --- /dev/null +++ b/src/ub_bench_log.c @@ -0,0 +1,12 @@ +/* + * SPDX-License-Identifier: MIT + * Copyright (c) Huawei Technologies Co., Ltd. 2026-2026. All rights reserved. + * Description: ub_bench log implementation file + * Create: 2026-09-16 + * Note: + * History: 2026-09-16 Create file + */ + +#include "ub_bench_log.h" + +perftest_vlog_level_t verbose_level = VLOG_LEVEL_INFO; diff --git a/src/ub_bench_log.h b/src/ub_bench_log.h new file mode 100644 index 0000000..7ec79b2 --- /dev/null +++ b/src/ub_bench_log.h @@ -0,0 +1,54 @@ +/* + * SPDX-License-Identifier: MIT + * Copyright (c) Huawei Technologies Co., Ltd. 2026-2026. All rights reserved. + * Description: ub_bench log head file + * Create: 2026-09-16 + * Note: + * History: 2026-09-16 Create file + */ + +#ifndef UB_BENCH_LOG_H +#define UB_BENCH_LOG_H + +#include +#include + +typedef enum perftest_vlog_level { + VLOG_LEVEL_QUIET = 0, + VLOG_LEVEL_INFO = 1, + VLOG_LEVEL_VERBOSE = 2, + VLOG_LEVEL_VVERBOSE = 3, +} perftest_vlog_level_t; + +extern perftest_vlog_level_t verbose_level; + +static inline void verbose_set_level(perftest_vlog_level_t level) +{ + verbose_level = level; +} + +static inline perftest_vlog_level_t verbose_get_level(void) +{ + return verbose_level; +} + +static inline void verbose_print(FILE *stream, perftest_vlog_level_t level, + const char *fmt, ...) +{ + if (verbose_level < level) { + return; + } + + va_list va; + va_start(va, fmt); + (void)vfprintf(stream, fmt, va); + va_end(va); +} + +#define LOG_QUIET(...) verbose_print(stdout, VLOG_LEVEL_QUIET, __VA_ARGS__) +#define LOG_INFO(...) verbose_print(stdout, VLOG_LEVEL_INFO, __VA_ARGS__) +#define LOG_VERBOSE(...) verbose_print(stdout, VLOG_LEVEL_VERBOSE, __VA_ARGS__) +#define LOG_VVERBOSE(...) verbose_print(stdout, VLOG_LEVEL_VVERBOSE, __VA_ARGS__) +#define LOG_ERROR(...) verbose_print(stderr, VLOG_LEVEL_QUIET, __VA_ARGS__) + +#endif diff --git a/src/ub_bench_mgmt.c b/src/ub_bench_mgmt.c new file mode 100644 index 0000000..9f6259e --- /dev/null +++ b/src/ub_bench_mgmt.c @@ -0,0 +1,128 @@ +/* + * SPDX-License-Identifier: MIT + * Copyright (c) Huawei Technologies Co., Ltd. 2026-2026. All rights reserved. + * Description: management for ub_bench + * Create: 2026-09-16 + * Note: + * History: 2026-09-16 create file + */ + +#include + +#include "ub_bench_mgmt_tcp.h" +#include "ub_bench_mgmt_ub.h" +#include "ub_bench_parameters.h" + +#include "ub_bench_mgmt.h" + +int establish_connection(const perftest_config_t *cfg) +{ + switch (cfg->mgmt_type) { + case PERFTEST_MGMT_TCP: { + comm_tcp_cfg_t tcp_cfg = { + .server_ip = cfg->server_ip, + .bind_ip = cfg->bind_ip, + .enable_ipv6 = cfg->enable_ipv6, + .port = cfg->port, + .sock_num = cfg->pair_num, + }; + return tcp_establish_connection(&tcp_cfg); + } + case PERFTEST_MGMT_UB: { + const bool port_specified = cfg->port != PERFTEST_DEF_PORT; + comm_ub_cfg_t ub_cfg = { + .src_eid = cfg->mgmt_addr, + .dst_eid = cfg->server_ip, + .dst_jetty_id = port_specified ? cfg->port : 0, + }; + return ub_establish_connection(&ub_cfg); + } + default: + LOG_ERROR("Invalid management channel type: %d.\n", (int)cfg->mgmt_type); + return -1; + } +} + +void close_connection(perftest_config_t *cfg) +{ + switch (cfg->mgmt_type) { + case PERFTEST_MGMT_TCP: + tcp_close_connection(); + break; + case PERFTEST_MGMT_UB: + ub_close_connection(); + break; + default: + break; + } + free(cfg->server_ip); + cfg->server_ip = NULL; + if (cfg->bind_ip != NULL) { + free(cfg->bind_ip); + cfg->bind_ip = NULL; + } + if (cfg->mgmt_addr != NULL) { + free(cfg->mgmt_addr); + cfg->mgmt_addr = NULL; + } +} + +int sync_data(const perftest_config_t *cfg, uint32_t index, int size, char *local_data, char *remote_data) +{ + switch (cfg->mgmt_type) { + case PERFTEST_MGMT_TCP: + return tcp_sync_data(index, size, local_data, remote_data); + case PERFTEST_MGMT_UB: + return ub_sync_data(index, size, local_data, remote_data); + default: + return -1; + } +} + +int sync_time(const perftest_config_t *cfg, uint32_t index, const char *a) +{ + switch (cfg->mgmt_type) { + case PERFTEST_MGMT_TCP: + return tcp_sync_time(index, a); + case PERFTEST_MGMT_UB: + return ub_sync_time(index, a); + default: + return -1; + } +} + +ssize_t comm_send(const perftest_config_t *cfg, uint32_t index, const void *buf, size_t size) +{ + switch (cfg->mgmt_type) { + case PERFTEST_MGMT_TCP: + return tcp_comm_send(index, buf, size); + case PERFTEST_MGMT_UB: + return ub_comm_send(index, buf, size); + default: + return -1; + } +} + +ssize_t comm_recv(const perftest_config_t *cfg, uint32_t index, void *buf, size_t size) +{ + switch (cfg->mgmt_type) { + case PERFTEST_MGMT_TCP: + return tcp_comm_recv(index, buf, size); + case PERFTEST_MGMT_UB: + return ub_comm_recv(index, buf, size); + default: + return -1; + } +} + +int comm_poll(const perftest_config_t *cfg, uint32_t index, int timeout_ms) +{ + switch (cfg->mgmt_type) { + case PERFTEST_MGMT_TCP: + return tcp_comm_poll(index, timeout_ms); + case PERFTEST_MGMT_UB: + return ub_comm_poll(index, timeout_ms); + default: + return -1; + } +} diff --git a/src/ub_bench_mgmt.h b/src/ub_bench_mgmt.h new file mode 100644 index 0000000..1bc3242 --- /dev/null +++ b/src/ub_bench_mgmt.h @@ -0,0 +1,34 @@ +/* + * SPDX-License-Identifier: MIT + * Copyright (c) Huawei Technologies Co., Ltd. 2026-2026. All rights reserved. + * Description: management header file for ub_bench + * Create: 2026-09-16 + * Note: + * History: 2026-09-16 create file + */ + +#ifndef UB_BENCH_MGMT_H +#define UB_BENCH_MGMT_H + +#include +#include +#include + +typedef struct perftest_config perftest_config_t; + +typedef enum perftest_mgmt_type { + PERFTEST_MGMT_TCP = 0, + PERFTEST_MGMT_UB, + PERFTEST_MGMT_TYPE_NUM +} perftest_mgmt_type_t; + +int establish_connection(const perftest_config_t *cfg); +void close_connection(perftest_config_t *cfg); + +int sync_data(const perftest_config_t *cfg, uint32_t index, int size, char *local_data, char *remote_data); +int sync_time(const perftest_config_t *cfg, uint32_t index, const char *a); +ssize_t comm_send(const perftest_config_t *cfg, uint32_t index, const void *buf, size_t size); +ssize_t comm_recv(const perftest_config_t *cfg, uint32_t index, void *buf, size_t size); +int comm_poll(const perftest_config_t *cfg, uint32_t index, int timeout_ms); + +#endif diff --git a/src/ub_bench_mgmt_tcp.c b/src/ub_bench_mgmt_tcp.c new file mode 100644 index 0000000..fb7e818 --- /dev/null +++ b/src/ub_bench_mgmt_tcp.c @@ -0,0 +1,485 @@ +/* + * SPDX-License-Identifier: MIT + * Copyright (c) Huawei Technologies Co., Ltd. 2026-2026. All rights reserved. + * Description: tcp management for ub_bench + * Create: 2026-09-16 + * Note: + * History: 2026-09-16 create file + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ub_bench_log.h" +#include "ub_bench_parameters.h" + +#include "ub_bench_mgmt_tcp.h" + +#define PERFTEST_MAX_CONNECTIONS (10) +#define PERFTEST_CONNECT_COUNT (5) +#define ERFTEST_SLEEP_TIME (100 * 1000) /* Sleep for 100 ms */ + +typedef struct comm_tcp_ctx { + int listen_fd; + int *sock_fd; + uint32_t sock_num; +} comm_tcp_ctx_t; + +static comm_tcp_ctx_t comm_ctx = { + .listen_fd = -1, + .sock_fd = NULL, + .sock_num = 0, +}; + +static int send_all(int sock_fd, const char *buf, int size) +{ + ssize_t send_bytes; + int total_send_bytes = 0; + + while (total_send_bytes < size) { + send_bytes = send(sock_fd, buf + total_send_bytes, (size_t)(size - total_send_bytes), MSG_NOSIGNAL); + if (send_bytes <= 0) { + if (send_bytes < 0 && errno == EINTR) { + continue; + } + LOG_ERROR("Failed to send data, errno: [%d]%s, total_size:%d, expect_size:%d.\n", + errno, strerror(errno), total_send_bytes, size); + return -1; + } + total_send_bytes += (int)send_bytes; + } + + return 0; +} + +static int recv_all(int sock_fd, char *buf, int size) +{ + ssize_t recv_bytes; + int total_recv_bytes = 0; + + while (total_recv_bytes < size) { + recv_bytes = recv(sock_fd, buf + total_recv_bytes, (size_t)(size - total_recv_bytes), 0); + if (recv_bytes == 0) { + LOG_ERROR("Peer closed connection, total_size:%d, expect_size:%d.\n", total_recv_bytes, size); + return -1; + } + if (recv_bytes < 0) { + if (errno == EINTR) { + continue; + } + LOG_ERROR("Failed to recv data, errno: [%d]%s, total_size:%d, expect_size:%d.\n", + errno, strerror(errno), total_recv_bytes, size); + return -1; + } + total_recv_bytes += (int)recv_bytes; + } + + return 0; +} + +static int alloc_comm_sock(uint32_t sock_num) +{ + if (comm_ctx.listen_fd >= 0 || comm_ctx.sock_fd != NULL) { + errno = EBUSY; + return -1; + } + + comm_ctx.listen_fd = -1; + comm_ctx.sock_fd = (int *)calloc(sock_num, sizeof(int)); + if (comm_ctx.sock_fd == NULL) { + comm_ctx.sock_num = 0; + return -1; + } + + comm_ctx.sock_num = sock_num; + for (uint32_t i = 0; i < sock_num; i++) { + comm_ctx.sock_fd[i] = -1; + } + return 0; +} + +static void cleanup_comm_ctx(void) +{ + if (comm_ctx.listen_fd >= 0) { + (void)close(comm_ctx.listen_fd); + comm_ctx.listen_fd = -1; + } + if (comm_ctx.sock_fd != NULL) { + for (uint32_t i = 0; i < comm_ctx.sock_num; i++) { + if (comm_ctx.sock_fd[i] >= 0) { + (void)close(comm_ctx.sock_fd[i]); + comm_ctx.sock_fd[i] = -1; + } + } + free(comm_ctx.sock_fd); + } + comm_ctx.listen_fd = -1; + comm_ctx.sock_fd = NULL; + comm_ctx.sock_num = 0; +} + +static int ip_set_sockopts(int sockfd) +{ + int ret; + int enable_reuse = 1; + int enable_nodelay = 1; + + /* Set socket reuse. When the server is restarted, + * the problem of the connection failure of the client is solved */ + ret = setsockopt(sockfd, SOL_SOCKET, SO_REUSEPORT, &enable_reuse, sizeof(enable_reuse)); + if (ret < 0) { + LOG_ERROR("socket set_opt failed. enable_reuse:%d, ret: %d, err: [%d]%s.\n", + SO_REUSEPORT, ret, errno, strerror(errno)); + return ret; + } + + // Close Nagle algorithm, and fix 42ms delay problem. + ret = setsockopt(sockfd, SOL_TCP, TCP_NODELAY, &enable_nodelay, sizeof(enable_nodelay)); + if (ret < 0) { + LOG_ERROR("socket set_opt failed. opt:%d, ret: %d, err: [%d]%s.\n", + TCP_NODELAY, ret, errno, strerror(errno)); + return ret; + } + + return 0; +} + +#define PERFTEST_PORT_LEN_MAX 32 +static int check_add_port(int port, const char *server_ip, struct addrinfo *hints, struct addrinfo **res) +{ + int num; + char service[PERFTEST_PORT_LEN_MAX] = {0}; + + if (port < 0 || port > UINT16_MAX) { + LOG_ERROR("Invalid port: %d.\n", port); + return -1; + } + + if (snprintf(service, sizeof(service), "%d", port) <= 0) { + return -1; + } + + num = getaddrinfo(server_ip, service, hints, res); + if (num < 0) { + LOG_ERROR("%s for %s:%d\n", gai_strerror(num), server_ip, port); + return -1; + } + + return 0; +} + +static int connect_retry(int sockfd, struct sockaddr *addr, uint32_t size) +{ + uint32_t times = 0; + for (int i = 1; i <= PERFTEST_CONNECT_COUNT; i++) { + if (connect(sockfd, addr, size) != 0) { + times += i * (uint32_t)ERFTEST_SLEEP_TIME; + (void)usleep(times); + continue; + } + return 0; + } + return -1; +} + +static int client_connect(const comm_tcp_cfg_t *comm) +{ + struct addrinfo *res = NULL, *tmp = NULL, *client_res = NULL, *client_tmp = NULL; + struct addrinfo hints = {0}, client_hints = {0}; + uint32_t i = 0; + + if (alloc_comm_sock(comm->sock_num) != 0) { + return -1; + } + hints.ai_family = comm->enable_ipv6 ? AF_INET6 : AF_INET; + hints.ai_socktype = SOCK_STREAM; + + if (comm->bind_ip != NULL) { + int err, bound = 0; + client_hints.ai_family = hints.ai_family; + client_hints.ai_socktype = SOCK_STREAM; + err = getaddrinfo(comm->bind_ip, NULL, &client_hints, &client_res); + if (err != 0) { + LOG_ERROR("Problem in resolving bind IP '%s': %s\n", + comm->bind_ip, gai_strerror(err)); + goto bind_client_error; + } + for (client_tmp = client_res; client_tmp != NULL; client_tmp = client_tmp->ai_next) { + if (client_tmp->ai_family == hints.ai_family) { + bound = 1; + break; + } + } + if (!bound) { + LOG_ERROR("Bind IP not found : %s\n", comm->bind_ip); + goto create_client_error; + } + } + + for (i = 0; i < comm->sock_num; i++) { + if (check_add_port((comm->port + i), comm->server_ip, &hints, &res)) { + LOG_ERROR("Problem in resolving basic address and port\n"); + goto create_client_error; + } + + for (tmp = res; tmp != NULL; tmp = tmp->ai_next) { + bool try_connect = true; + comm_ctx.sock_fd[i] = socket(tmp->ai_family, tmp->ai_socktype, tmp->ai_protocol); + if (comm_ctx.sock_fd[i] < 0) { + continue; + } + if (comm->bind_ip != NULL) { + if (bind(comm_ctx.sock_fd[i], client_tmp->ai_addr, client_tmp->ai_addrlen) != 0) { + try_connect = false; + LOG_ERROR("Failed to bind ip: %s\n", comm->bind_ip); + } + } + if (try_connect && connect_retry(comm_ctx.sock_fd[i], tmp->ai_addr, tmp->ai_addrlen) == 0) { + break; + } + close(comm_ctx.sock_fd[i]); + comm_ctx.sock_fd[i] = -1; + } + + if (res != NULL) { + freeaddrinfo(res); + res = NULL; + } + + if (comm_ctx.sock_fd[i] < 0) { + LOG_ERROR("Failed to connect %s:%d\n\n", comm->server_ip, (comm->port + i)); + goto create_client_error; + } + + if (ip_set_sockopts(comm_ctx.sock_fd[i]) != 0) { + LOG_ERROR("Failed to set_sockopts, sockfd:%d, errno: %s\n", comm_ctx.sock_fd[i], strerror(errno)); + (void)close(comm_ctx.sock_fd[i]); + comm_ctx.sock_fd[i] = -1; + goto create_client_error; + } + } + + if (comm->bind_ip != NULL) { + if (client_res != NULL) { + freeaddrinfo(client_res); + } + } + + return 0; +create_client_error: + cleanup_comm_ctx(); + if (client_res != NULL) { + freeaddrinfo(client_res); + } + return -1; +bind_client_error: + cleanup_comm_ctx(); + return -1; +} + +static int server_connect(const comm_tcp_cfg_t *comm) +{ + struct addrinfo *res = NULL, *tmp = NULL; + struct addrinfo hints = {0}; + uint32_t accept_num = 0; + + if (alloc_comm_sock(comm->sock_num) != 0) { + return -1; + } + hints.ai_flags = AI_PASSIVE; + hints.ai_family = comm->enable_ipv6 ? AF_INET6 : AF_INET; + hints.ai_socktype = SOCK_STREAM; + + if (check_add_port(comm->port, comm->bind_ip, &hints, &res)) { + LOG_ERROR("Problem in resolving basic address and port\n"); + goto free_sock; + } + + for (tmp = res; tmp != NULL; tmp = tmp->ai_next) { + if (tmp->ai_family != hints.ai_family) { + continue; + } + + comm_ctx.listen_fd = socket(tmp->ai_family, tmp->ai_socktype, tmp->ai_protocol); + if (comm_ctx.listen_fd >= 0) { + if (ip_set_sockopts(comm_ctx.listen_fd) != 0) { + LOG_ERROR("Failed to set_sockopts, sockfd:%d, errno: %s\n", + comm_ctx.listen_fd, strerror(errno)); + goto free_res; + } + if (bind(comm_ctx.listen_fd, tmp->ai_addr, tmp->ai_addrlen) == 0) { + break; + } + (void)close(comm_ctx.listen_fd); + comm_ctx.listen_fd = -1; + } + } + + if (comm_ctx.listen_fd < 0) { + LOG_ERROR("Failed to bind, port:%d.\n", comm->port); + goto free_res; + } + + if (listen(comm_ctx.listen_fd, PERFTEST_MAX_CONNECTIONS) != 0) { + LOG_ERROR("Failed to listen, listenfd:%d, errno: [%d]%s\n", + comm_ctx.listen_fd, errno, strerror(errno)); + goto free_res; + } + + while (accept_num < comm->sock_num) { + comm_ctx.sock_fd[accept_num] = accept(comm_ctx.listen_fd, NULL, 0); + if (comm_ctx.sock_fd[accept_num] < 0) { + LOG_ERROR("Failed to accept, listenfd:%d, errno: [%d]%s\n", + comm_ctx.listen_fd, errno, strerror(errno)); + goto free_res; + } + + if (ip_set_sockopts(comm_ctx.sock_fd[accept_num]) != 0) { + LOG_ERROR("Failed to set_sockopts, sockfd:%d, errno: [%d]%s\n", + comm_ctx.sock_fd[accept_num], errno, strerror(errno)); + (void)close(comm_ctx.sock_fd[accept_num]); + comm_ctx.sock_fd[accept_num] = -1; + goto free_res; + } + accept_num++; + } + + freeaddrinfo(res); + (void)close(comm_ctx.listen_fd); // No other connections need to be accepted. + comm_ctx.listen_fd = -1; + return 0; + +free_res: + if (res != NULL) { + freeaddrinfo(res); + } +free_sock: + cleanup_comm_ctx(); + return -1; +} + +int tcp_establish_connection(const comm_tcp_cfg_t *cfg) +{ + int ret; + + if (cfg->server_ip != NULL) { + /* client side */ + ret = client_connect(cfg); + } else { + /* server side */ + LOG_INFO(PERFTEST_RESULT_LINE); + LOG_INFO(" Waiting for client to connect...\n"); + ret = server_connect(cfg); + } + + return ret; +} + +void tcp_close_connection(void) +{ + cleanup_comm_ctx(); +} + +int tcp_sync_data(uint32_t index, int size, char *local_data, char *remote_data) +{ + int sock_fd; + + if (comm_ctx.sock_fd == NULL || index >= comm_ctx.sock_num) { + errno = EINVAL; + return -1; + } + sock_fd = comm_ctx.sock_fd[index]; + if (sock_fd < 0) { + errno = EINVAL; + return -1; + } + + if (send_all(sock_fd, local_data, size) != 0) { + LOG_ERROR("Failed to send data during tcp_sync_data.\n"); + return -1; + } + + if (recv_all(sock_fd, remote_data, size) != 0) { + LOG_ERROR("Failed to recv data during tcp_sync_data.\n"); + return -1; + } + + return 0; +} + +int tcp_sync_time(uint32_t index, const char *a) +{ + if (a == NULL) { + LOG_ERROR("Invalid parameter with a nullptr.\n"); + return -1; + } + int len = (int)strlen(a); + char *b = calloc(1, (unsigned long)len + 1); + int ret = 0; + if (b == NULL) { + return -ENOMEM; + } + ret = tcp_sync_data(index, len, (char *)a, b); + if (ret != 0) { + LOG_ERROR("sync time error, %s, ret: %d.\n", a, ret); + goto sync_ret; + } + ret = memcmp(a, b, (unsigned long)len); + if (ret != 0) { + b[len] = '\0'; + LOG_ERROR("sync time error, %s != %s.\n", a, b); + goto sync_ret; + } + +sync_ret: + free(b); + return ret; +} + +ssize_t tcp_comm_send(uint32_t index, const void *buf, size_t size) +{ + if (comm_ctx.sock_fd == NULL || index >= comm_ctx.sock_num || comm_ctx.sock_fd[index] < 0) { + errno = EINVAL; + return -1; + } + return send(comm_ctx.sock_fd[index], buf, size, MSG_NOSIGNAL); +} + +ssize_t tcp_comm_recv(uint32_t index, void *buf, size_t size) +{ + if (comm_ctx.sock_fd == NULL || index >= comm_ctx.sock_num || comm_ctx.sock_fd[index] < 0) { + errno = EINVAL; + return -1; + } + return recv(comm_ctx.sock_fd[index], buf, size, MSG_PEEK); +} + +int tcp_comm_poll(uint32_t index, int timeout_ms) +{ + if (comm_ctx.sock_fd == NULL || index >= comm_ctx.sock_num || comm_ctx.sock_fd[index] < 0) { + errno = EINVAL; + return -1; + } + + struct pollfd pfd = { + .fd = comm_ctx.sock_fd[index], + .events = POLLIN, + .revents = 0, + }; + int ret = poll(&pfd, 1, timeout_ms); + if (ret > 0 && (pfd.revents & (POLLIN | POLLHUP | POLLERR)) == 0) { + errno = EIO; + return -1; + } + return ret; +} diff --git a/src/ub_bench_mgmt_tcp.h b/src/ub_bench_mgmt_tcp.h new file mode 100644 index 0000000..756fe8e --- /dev/null +++ b/src/ub_bench_mgmt_tcp.h @@ -0,0 +1,35 @@ +/* + * SPDX-License-Identifier: MIT + * Copyright (c) Huawei Technologies Co., Ltd. 2026-2026. All rights reserved. + * Description: tcp management header file for ub_bench + * Create: 2026-09-16 + * Note: + * History: 2026-09-16 create file + */ + +#ifndef UB_BENCH_MGMT_TCP_H +#define UB_BENCH_MGMT_TCP_H + +#include +#include +#include +#include + +typedef struct comm_tcp_cfg { + char *server_ip; + char *bind_ip; + bool enable_ipv6; + uint16_t port; /* Server port for bind or connect, default 21115. */ + uint32_t sock_num; +} comm_tcp_cfg_t; + +int tcp_establish_connection(const comm_tcp_cfg_t *cfg); +void tcp_close_connection(void); + +int tcp_sync_data(uint32_t index, int size, char *local_data, char *remote_data); +int tcp_sync_time(uint32_t index, const char *a); +ssize_t tcp_comm_send(uint32_t index, const void *buf, size_t size); +ssize_t tcp_comm_recv(uint32_t index, void *buf, size_t size); +int tcp_comm_poll(uint32_t index, int timeout_ms); + +#endif diff --git a/src/ub_bench_mgmt_ub.c b/src/ub_bench_mgmt_ub.c new file mode 100644 index 0000000..ed9bf68 --- /dev/null +++ b/src/ub_bench_mgmt_ub.c @@ -0,0 +1,880 @@ +/* + * SPDX-License-Identifier: MIT + * Copyright (c) Huawei Technologies Co., Ltd. 2026-2026. All rights reserved. + * Description: ub management channel implementation for ub_bench + * Create: 2026-09-16 + * Note: UB mgmt channel over URMA RM. Local EID from --mgmt_addr. + * Single pair only. Server must start before client. + * History: 2026-09-16 create file + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "urma_api.h" +#include "ub_bench_log.h" +#include "ub_bench_parameters.h" +#include "ub_bench_run_test.h" + +#include "ub_bench_mgmt_ub.h" + +#define UB_MGMT_TOKEN_VALUE (0xABCDEF) /* same as g_perftest_token in perftest_resources.c */ +#define UB_MGMT_HANDSHAKE_SIZE (1) +#define UB_MGMT_SEG_ALIGN (4096) /* UMMU table mode requires 4K-aligned VA */ +#define UB_MGMT_BONDING_DEV_PREFIX "bonding_dev" +#define UB_MGMT_BONDING_DEV_PREFIX_LEN (11) + +static urma_token_t g_ub_mgmt_token = { + .token = UB_MGMT_TOKEN_VALUE, +}; + +typedef struct ub_jpair { + urma_jetty_t *jetty; /* local mgmt jetty */ + urma_target_jetty_t *tjetty; /* peer mgmt jetty (after handshake) */ + /* comm_poll/comm_recv coordination: UB has no kernel-buffered "readable" + * state; poll posts a 1B probe recv, the CQE+data remain for comm_recv. */ + bool have_pending_recv; /* probe recv posted, not yet completed */ + bool have_pending_data; /* probe recv completed, recv_buf has data */ + uint32_t pending_data_len; /* valid when have_pending_data == true */ +} ub_jpair_t; + +typedef struct ub_mgmt_ctx { + urma_context_t *urma_ctx; + urma_device_t *dev; + urma_jfc_t *jfc; /* shared jfc for both send and recv CQE */ + urma_jfr_t *jfr; /* shared jfr (UB requires share_jfr) */ + char *send_buf; /* shared 4KB buffer for SEND */ + char *recv_buf; /* shared 4KB buffer for data RECV */ + char *recv_buf_hs; /* dedicated 4KB buffer for handshake RECV (server only) */ + urma_target_seg_t *tseg_send; /* registered seg covering send_buf */ + urma_target_seg_t *tseg_recv; /* registered seg covering recv_buf */ + urma_target_seg_t *tseg_recv_hs; /* registered seg covering recv_buf_hs (server only) */ + bool is_server; + ub_jpair_t pair; /* single pair (UB mgmt does not support multi-pair) */ +} ub_mgmt_ctx_t; + +static ub_mgmt_ctx_t *g_ub_ctx = NULL; + +/* ========================================================================== */ +/* internal helpers */ +/* ========================================================================== */ + +/* Build rjetty descriptor for importing peer mgmt jetty. tp_type=CTP. */ +static void fill_rjetty(urma_eid_t peer_eid, uint32_t jetty_id, urma_rjetty_t *rjetty) +{ + (void)memset(rjetty, 0, sizeof(*rjetty)); + rjetty->jetty_id.eid = peer_eid; + rjetty->jetty_id.id = jetty_id; + rjetty->trans_mode = URMA_TM_RM; + rjetty->type = URMA_JETTY; + rjetty->tp_type = URMA_CTP; +} + +static int poll_one_cqe(urma_jfc_t *jfc, urma_cr_t *cr, bool interruptible) +{ + while (true) { + if (interruptible && g_exit_flag) { + return -EINTR; + } + int n = urma_poll_jfc(jfc, 1, cr); + if (n < 0) { + LOG_ERROR("Failed to poll jfc.\n"); + return -1; + } + if (n == 1) { + if (cr->status != URMA_CR_SUCCESS) { + LOG_ERROR("mgmt CR status %d (s_r=%u).\n", (int)cr->status, cr->flag.bs.s_r); + return -1; + } + return 0; + } + } +} + +/* Post one max-size RECV WR. Used for pre-post at handshake and refill in sync_data. */ +static int ub_post_one_recv(ub_mgmt_ctx_t *ctx) +{ + urma_sge_t sge = {0}; + urma_jfr_wr_t wr = {0}; + urma_jfr_wr_t *bad = NULL; + sge.addr = (uint64_t)ctx->recv_buf; + sge.len = UB_MGMT_MSG_MAX_SIZE; + sge.tseg = ctx->tseg_recv; + wr.src.sge = &sge; + wr.src.num_sge = 1; + wr.next = NULL; + return (urma_post_jetty_recv_wr(ctx->pair.jetty, &wr, &bad) == URMA_SUCCESS) ? 0 : -1; +} + +/* Resolve (dev, eid_index) from src EID string. Mirrors ping_run.c:init_urma_resource. */ +static int ub_resolve_dev_and_eid_idx(const char *src_eid_str, urma_device_t **dev_out, uint32_t *eid_idx_out) +{ + urma_eid_t src_eid = {0}; + urma_device_t *dev = NULL; + urma_eid_info_t *eid_list = NULL; + uint32_t eid_cnt = 0; + uint32_t i = 0; + bool found = false; + + if (urma_str_to_eid(src_eid_str, &src_eid) != 0) { + LOG_ERROR("Failed to parse src eid: %s\n", src_eid_str); + return -1; + } + + dev = urma_get_device_by_eid(src_eid, URMA_TRANSPORT_UB); + if (dev == NULL) { + LOG_ERROR("Failed to find UB device for src eid: %s\n", src_eid_str); + return -1; + } + + /* Reject bonding (aggregation) devices: mgmt channel needs a bare UB device. */ + if (strncmp(dev->name, UB_MGMT_BONDING_DEV_PREFIX, UB_MGMT_BONDING_DEV_PREFIX_LEN) == 0) { + LOG_ERROR("UB mgmt channel does not support bonding device: %s\n", dev->name); + return -1; + } + + eid_list = urma_get_eid_list(dev, &eid_cnt); + if (eid_list == NULL) { + LOG_ERROR("Failed to get eid list from device: %s\n", dev->name); + return -1; + } + for (i = 0; i < eid_cnt; i++) { + if (memcmp(&src_eid, &eid_list[i].eid, sizeof(urma_eid_t)) == 0) { + *eid_idx_out = eid_list[i].eid_index; + found = true; + break; + } + } + urma_free_eid_list(eid_list); + if (!found) { + LOG_ERROR("Src eid not found in device eid list: dev=%s, eid=%s\n", dev->name, src_eid_str); + return -1; + } + + *dev_out = dev; + return 0; +} + +/* ========================================================================== */ +/* establish / close */ +/* ========================================================================== */ + +static int ub_create_local_resources(const comm_ub_cfg_t *cfg, ub_mgmt_ctx_t **ctx_out) +{ + urma_device_t *dev = NULL; + urma_context_t *urma_ctx = NULL; + urma_jfc_t *jfc = NULL; + urma_jfr_t *jfr = NULL; + urma_target_seg_t *tseg_send = NULL; + urma_target_seg_t *tseg_recv = NULL; + urma_target_seg_t *tseg_recv_hs = NULL; + char *send_buf = NULL; + char *recv_buf = NULL; + char *recv_buf_hs = NULL; + urma_jfc_cfg_t jfc_cfg = {0}; + urma_seg_cfg_t seg_cfg = {0}; + urma_jfs_cfg_t jfs_cfg = {0}; + urma_jfr_cfg_t jfr_cfg = {0}; + urma_jetty_cfg_t jetty_cfg = {0}; + ub_mgmt_ctx_t *ctx = NULL; + uint32_t local_jetty_id = 0; + uint32_t eid_idx = 0; + + if (ub_resolve_dev_and_eid_idx(cfg->src_eid, &dev, &eid_idx) != 0) { + return -1; + } + + urma_ctx = urma_create_context(dev, eid_idx); + if (urma_ctx == NULL) { + LOG_ERROR("Failed to create urma context.\n"); + return -1; + } + + jfc_cfg.depth = UB_MGMT_JFC_DEPTH; + jfc_cfg.flag.value = 0; + jfc_cfg.jfce = NULL; + jfc_cfg.user_ctx = (uint64_t)NULL; + /* urma_create_jfc (not alloc_jfc) initializes the CQ buffer; alloc_jfc leaves it NULL. */ + jfc = urma_create_jfc(urma_ctx, &jfc_cfg); + if (jfc == NULL) { + LOG_ERROR("Failed to create mgmt jfc.\n"); + goto delete_ctx; + } + + send_buf = (char *)memalign(UB_MGMT_SEG_ALIGN, UB_MGMT_MSG_MAX_SIZE); + recv_buf = (char *)memalign(UB_MGMT_SEG_ALIGN, UB_MGMT_MSG_MAX_SIZE); + recv_buf_hs = (char *)memalign(UB_MGMT_SEG_ALIGN, UB_MGMT_MSG_MAX_SIZE); + if (send_buf == NULL || recv_buf == NULL || recv_buf_hs == NULL) { + LOG_ERROR("Failed to alloc mgmt buffers.\n"); + goto free_jfc; + } + memset(send_buf, 0, UB_MGMT_MSG_MAX_SIZE); + memset(recv_buf, 0, UB_MGMT_MSG_MAX_SIZE); + memset(recv_buf_hs, 0, UB_MGMT_MSG_MAX_SIZE); + + seg_cfg.len = UB_MGMT_MSG_MAX_SIZE; + seg_cfg.token_id = NULL; + seg_cfg.token_value = g_ub_mgmt_token; + seg_cfg.flag.value = 0; + seg_cfg.flag.bs.access = URMA_ACCESS_LOCAL_ONLY; + seg_cfg.user_ctx = (uint64_t)NULL; + seg_cfg.iova = 0; + + seg_cfg.va = (uint64_t)send_buf; + tseg_send = urma_register_seg(urma_ctx, &seg_cfg); + if (tseg_send == NULL) { + LOG_ERROR("Failed to register mgmt send seg.\n"); + goto free_bufs; + } + + seg_cfg.va = (uint64_t)recv_buf; + tseg_recv = urma_register_seg(urma_ctx, &seg_cfg); + if (tseg_recv == NULL) { + LOG_ERROR("Failed to register mgmt recv seg.\n"); + goto unregister_send; + } + + /* + * Dedicated handshake recv seg. Server posts 2 recvs at handshake entry: + * WQE[0] = handshake (1B) on recv_buf_hs + * WQE[1] = data (4KB) on recv_buf + * Both stay outstanding before peer's first send arrives, eliminating the + * race where peer's sync_data SEND reaches our RQ before stage 6.5's + * post_recv runs (RNR in UB+RM, no kernel buffering). + * + * recv_buf_hs is unused on client; allocated unconditionally to keep the + * ctx layout symmetric and simplify rollback/cleanup paths. + */ + seg_cfg.va = (uint64_t)recv_buf_hs; + tseg_recv_hs = urma_register_seg(urma_ctx, &seg_cfg); + if (tseg_recv_hs == NULL) { + LOG_ERROR("Failed to register mgmt handshake recv seg.\n"); + goto unregister_recv; + } + + jfs_cfg.depth = UB_MGMT_JFS_DEPTH; + jfs_cfg.flag.value = 0; + jfs_cfg.trans_mode = URMA_TM_RM; + jfs_cfg.priority = 0; + jfs_cfg.max_sge = 1; + jfs_cfg.max_rsge = 1; + jfs_cfg.max_inline_data = 0; /* mgmt uses registered seg, no inline needed */ + jfs_cfg.rnr_retry = URMA_TYPICAL_RNR_RETRY; + jfs_cfg.err_timeout = URMA_TYPICAL_ERR_TIMEOUT; + jfs_cfg.jfc = jfc; + jfs_cfg.user_ctx = (uint64_t)NULL; + + jfr_cfg.id = 0; + jfr_cfg.depth = UB_MGMT_JFR_DEPTH; + jfr_cfg.flag.value = 0; + jfr_cfg.trans_mode = URMA_TM_RM; + jfr_cfg.max_sge = 1; + jfr_cfg.min_rnr_timer = URMA_TYPICAL_MIN_RNR_TIMER; + jfr_cfg.jfc = jfc; + jfr_cfg.token_value = g_ub_mgmt_token; + jfr_cfg.user_ctx = (uint64_t)NULL; + + /* UB dev requires share_jfr (urma_cp_api.c:1563). Create 1 shared jfr + * here, then attach it to the mgmt jetty via jetty_cfg.shared.jfr. */ + jfr = urma_create_jfr(urma_ctx, &jfr_cfg); + if (jfr == NULL) { + LOG_ERROR("Failed to create mgmt shared jfr.\n"); + goto unregister_recv_hs; + } + + ctx = (ub_mgmt_ctx_t *)calloc(1, sizeof(ub_mgmt_ctx_t)); + if (ctx == NULL) { + LOG_ERROR("Failed to alloc mgmt ctx.\n"); + goto delete_jfr; + } + ctx->urma_ctx = urma_ctx; + ctx->dev = dev; + ctx->jfc = jfc; + ctx->jfr = jfr; + ctx->send_buf = send_buf; + ctx->recv_buf = recv_buf; + ctx->recv_buf_hs = recv_buf_hs; + ctx->tseg_send = tseg_send; + ctx->tseg_recv = tseg_recv; + ctx->tseg_recv_hs = tseg_recv_hs; + ctx->is_server = (cfg->dst_eid == NULL); + + if (ctx->is_server) { + local_jetty_id = cfg->dst_jetty_id; + } else { + local_jetty_id = 0; + } + + jetty_cfg.id = local_jetty_id; + jetty_cfg.flag.value = 0; + jetty_cfg.flag.bs.share_jfr = URMA_SHARE_JFR; + jetty_cfg.jfs_cfg = jfs_cfg; + jetty_cfg.shared.jfr = jfr; + jetty_cfg.shared.jfc = jfc; + jetty_cfg.jetty_grp = NULL; + jetty_cfg.user_ctx = (uint64_t)NULL; + + ctx->pair.jetty = urma_create_jetty(urma_ctx, &jetty_cfg); + if (ctx->pair.jetty == NULL) { + LOG_ERROR("Failed to create mgmt jetty.\n"); + goto free_ctx; + } + ctx->pair.tjetty = NULL; + + *ctx_out = ctx; + return 0; + +free_ctx: + free(ctx); +delete_jfr: + (void)urma_delete_jfr(jfr); +unregister_recv_hs: + (void)urma_unregister_seg(tseg_recv_hs); +unregister_recv: + (void)urma_unregister_seg(tseg_recv); +unregister_send: + (void)urma_unregister_seg(tseg_send); +free_bufs: + free(send_buf); + free(recv_buf); + free(recv_buf_hs); +free_jfc: + (void)urma_delete_jfc(jfc); +delete_ctx: + (void)urma_delete_context(urma_ctx); + return -1; +} + +/* + * Server handshake: post [handshake recv (1B), data recv (4KB)] in FIFO order, + * poll handshake CQE, then import peer jetty via cr.remote_id (HW-filled). + * Data recv stays outstanding across handshake to avoid RNR race with the + * first sync_data send. Dedicated handshake buffer avoids overwriting by data. + */ +static int ub_server_handshake(ub_mgmt_ctx_t *ctx) +{ + urma_sge_t sge = {0}; + urma_jfr_wr_t wr = {0}; + urma_jfr_wr_t *bad = NULL; + urma_cr_t cr = {0}; + urma_rjetty_t rjetty = {0}; + + LOG_INFO(PERFTEST_RESULT_LINE); + LOG_INFO(" Waiting for client to connect...\n"); + + /* WQE[0]: handshake recv (1B). */ + sge.addr = (uint64_t)ctx->recv_buf_hs; + sge.len = UB_MGMT_HANDSHAKE_SIZE; + sge.tseg = ctx->tseg_recv_hs; + wr.src.sge = &sge; + wr.src.num_sge = 1; + wr.user_ctx = 0; + wr.next = NULL; + if (urma_post_jetty_recv_wr(ctx->pair.jetty, &wr, &bad) != URMA_SUCCESS) { + LOG_ERROR("Failed to post handshake recv.\n"); + return -1; + } + + /* WQE[1]: data recv (4KB), stays in RQ across handshake. */ + sge.addr = (uint64_t)ctx->recv_buf; + sge.len = UB_MGMT_MSG_MAX_SIZE; + sge.tseg = ctx->tseg_recv; + wr.src.sge = &sge; + wr.src.num_sge = 1; + wr.user_ctx = 0; + wr.next = NULL; + if (urma_post_jetty_recv_wr(ctx->pair.jetty, &wr, &bad) != URMA_SUCCESS) { + LOG_ERROR("Failed to pre-post data recv.\n"); + return -1; + } + + if (poll_one_cqe(ctx->jfc, &cr, true) != 0) { + return -1; + } + + /* cr.remote_id (eid + id) is filled by HW on RECV. */ + fill_rjetty(cr.remote_id.eid, cr.remote_id.id, &rjetty); + ctx->pair.tjetty = urma_import_jetty(ctx->urma_ctx, &rjetty, &g_ub_mgmt_token); + if (ctx->pair.tjetty == NULL) { + LOG_ERROR("Failed to import peer mgmt jetty (handshake).\n"); + return -1; + } + return 0; +} + +/* Client handshake: parse server EID, import server jetty, post 1B send, poll CQE. */ +static int ub_client_handshake(ub_mgmt_ctx_t *ctx, const char *peer_eid_str, uint32_t peer_jetty_id) +{ + urma_eid_t peer_eid = {0}; + urma_rjetty_t rjetty = {0}; + urma_sge_t sge = {0}; + urma_jfs_wr_t wr = {0}; + urma_jfs_wr_t *bad = NULL; + urma_cr_t cr = {0}; + + if (urma_str_to_eid(peer_eid_str, &peer_eid) != 0) { + LOG_ERROR("Failed to parse peer eid: %s\n", peer_eid_str); + return -1; + } + + fill_rjetty(peer_eid, peer_jetty_id, &rjetty); + ctx->pair.tjetty = urma_import_jetty(ctx->urma_ctx, &rjetty, &g_ub_mgmt_token); + if (ctx->pair.tjetty == NULL) { + LOG_ERROR("Failed to import peer mgmt jetty.\n"); + return -1; + } + + ctx->send_buf[0] = 'H'; + sge.addr = (uint64_t)ctx->send_buf; + sge.len = UB_MGMT_HANDSHAKE_SIZE; + sge.tseg = ctx->tseg_send; + wr.opcode = URMA_OPC_SEND; + wr.flag.value = 0; + wr.flag.bs.complete_enable = 1; + wr.tjetty = ctx->pair.tjetty; + wr.user_ctx = 0; + wr.send.src.sge = &sge; + wr.send.src.num_sge = 1; + wr.send.imm_data = 0; + wr.next = NULL; + + if (urma_post_jetty_send_wr(ctx->pair.jetty, &wr, &bad) != URMA_SUCCESS) { + LOG_ERROR("Failed to post handshake send.\n"); + return -1; + } + + if (poll_one_cqe(ctx->jfc, &cr, true) != 0) { + return -1; + } + return 0; +} + +int ub_establish_connection(const comm_ub_cfg_t *cfg) +{ + ub_mgmt_ctx_t *ctx = NULL; + urma_init_attr_t init_attr = { .token = 0, .uasid = 0 }; + urma_status_t status; + + if (cfg == NULL) { + return -EINVAL; + } + + /* mgmt channel runs before init_device; must urma_init here. Tolerate EEXIST. */ + status = urma_init(&init_attr); + if (status != URMA_SUCCESS && status != URMA_EEXIST) { + LOG_ERROR("Failed to urma_init for mgmt channel, status: %d.\n", (int)status); + return -1; + } + + if (cfg->src_eid == NULL || cfg->src_eid[0] == '\0') { + LOG_ERROR("Invalid mgmt ub cfg: src_eid missing.\n"); + return -EINVAL; + } + if (cfg->dst_eid != NULL && cfg->dst_eid[0] == '\0') { + LOG_ERROR("Invalid mgmt ub cfg: empty dst_eid.\n"); + return -EINVAL; + } + if (g_ub_ctx != NULL) { + LOG_ERROR("mgmt ub ctx already initialized.\n"); + return -EEXIST; + } + + if (cfg->dst_eid == NULL && cfg->dst_jetty_id == 0) { + LOG_ERROR("UB mgmt server requires -P for jetty id.\n"); + return -EINVAL; + } + + if (ub_create_local_resources(cfg, &ctx) != 0) { + return -1; + } + + if (ctx->is_server) { + if (ub_server_handshake(ctx) != 0) { + goto rollback_handshake; + } + } else { + if (ub_client_handshake(ctx, cfg->dst_eid, cfg->dst_jetty_id) != 0) { + goto rollback_handshake; + } + } + + /* + * Pre-post one data RECV on client before any sync_data send. Server + * already has data recv pre-posted inside ub_server_handshake (WQE[1]). + * Without this, peer's SEND arriving at an empty RQ exhausts rnr_retry + * in RM mode (UB has no kernel buffering). Mirrors ping_run.c:682. + */ + if (!ctx->is_server) { + if (ub_post_one_recv(ctx) != 0) { + LOG_ERROR("Failed to pre-post mgmt recv.\n"); + goto rollback_handshake; + } + } + ctx->pair.have_pending_recv = !ctx->is_server; + + g_ub_ctx = ctx; + return 0; + +rollback_handshake: + if (ctx->pair.tjetty != NULL) { + (void)urma_unimport_jetty(ctx->pair.tjetty); + ctx->pair.tjetty = NULL; + } + if (ctx->pair.jetty != NULL) { + (void)urma_delete_jetty(ctx->pair.jetty); + } + (void)urma_delete_jfr(ctx->jfr); + (void)urma_unregister_seg(ctx->tseg_recv_hs); + (void)urma_unregister_seg(ctx->tseg_recv); + (void)urma_unregister_seg(ctx->tseg_send); + free(ctx->send_buf); + free(ctx->recv_buf); + free(ctx->recv_buf_hs); + (void)urma_delete_jfc(ctx->jfc); + (void)urma_delete_context(ctx->urma_ctx); + free(ctx); + return -1; +} + +void ub_close_connection(void) +{ + if (g_ub_ctx == NULL) { + return; + } + + /* Caller (destroy_*_ctx) must invoke close_connection BEFORE uninit_device: + * urma_uninit dlclose()'s provider .so, after which ctx->ops dangles. */ + if (g_ub_ctx->pair.tjetty != NULL) { + (void)urma_unimport_jetty(g_ub_ctx->pair.tjetty); + g_ub_ctx->pair.tjetty = NULL; + } + if (g_ub_ctx->pair.jetty != NULL) { + (void)urma_delete_jetty(g_ub_ctx->pair.jetty); + g_ub_ctx->pair.jetty = NULL; + } + if (g_ub_ctx->jfr != NULL) { + (void)urma_delete_jfr(g_ub_ctx->jfr); + g_ub_ctx->jfr = NULL; + } + if (g_ub_ctx->tseg_recv != NULL) { + (void)urma_unregister_seg(g_ub_ctx->tseg_recv); + g_ub_ctx->tseg_recv = NULL; + } + if (g_ub_ctx->tseg_recv_hs != NULL) { + (void)urma_unregister_seg(g_ub_ctx->tseg_recv_hs); + g_ub_ctx->tseg_recv_hs = NULL; + } + if (g_ub_ctx->tseg_send != NULL) { + (void)urma_unregister_seg(g_ub_ctx->tseg_send); + g_ub_ctx->tseg_send = NULL; + } + if (g_ub_ctx->jfc != NULL) { + (void)urma_delete_jfc(g_ub_ctx->jfc); + g_ub_ctx->jfc = NULL; + } + if (g_ub_ctx->urma_ctx != NULL) { + (void)urma_delete_context(g_ub_ctx->urma_ctx); + g_ub_ctx->urma_ctx = NULL; + } + free(g_ub_ctx->send_buf); + g_ub_ctx->send_buf = NULL; + free(g_ub_ctx->recv_buf); + g_ub_ctx->recv_buf = NULL; + free(g_ub_ctx->recv_buf_hs); + g_ub_ctx->recv_buf_hs = NULL; + free(g_ub_ctx); + g_ub_ctx = NULL; +} + +/* ========================================================================== */ +/* sync_data / sync_time */ +/* ========================================================================== */ + +int ub_sync_data(uint32_t index, int size, char *local_data, char *remote_data) +{ + urma_sge_t send_sge = {0}; + urma_jfs_wr_t send_wr = {0}; + urma_jfs_wr_t *send_bad = NULL; + urma_cr_t cr = {0}; + int pending = 2; /* expect 1 send CQE + 1 recv CQE */ + + (void)index; /* single pair; index ignored */ + + if (g_ub_ctx == NULL || size <= 0 || size > UB_MGMT_MSG_MAX_SIZE || + local_data == NULL || remote_data == NULL) { + LOG_ERROR("Invalid ub_sync_data args: ctx=%p, size=%d\n", (void *)g_ub_ctx, size); + return -EINVAL; + } + + /* + * RECV is already pre-posted (ub_establish_connection) and refilled + * after each consumption below. DO NOT post recv here: posting recv + * synchronously with peer's post_send races in UB+RM. UB has no kernel + * buffering (unlike TCP), so the brief window where peer's SEND arrives + * before our post_recv is processed by HW exhausts rnr_retry=7 in RM + * mode. Same idiom as ping_run.c:682 (pre-post before send) and + * urma_sample.c:624 (pre-post RECV_BATCH_CNT before accept loop). + */ + + /* copy local_data into registered send_buf */ + (void)memcpy(g_ub_ctx->send_buf, local_data, (size_t)size); + + /* post send (buffer=send_buf) */ + send_sge.addr = (uint64_t)g_ub_ctx->send_buf; + send_sge.len = (uint32_t)size; + send_sge.tseg = g_ub_ctx->tseg_send; + send_wr.opcode = URMA_OPC_SEND; + send_wr.flag.value = 0; + send_wr.flag.bs.complete_enable = 1; + send_wr.tjetty = g_ub_ctx->pair.tjetty; + send_wr.user_ctx = 0; + send_wr.send.src.sge = &send_sge; + send_wr.send.src.num_sge = 1; + send_wr.send.imm_data = 0; + send_wr.next = NULL; + if (urma_post_jetty_send_wr(g_ub_ctx->pair.jetty, &send_wr, &send_bad) != URMA_SUCCESS) { + LOG_ERROR("Failed to post mgmt send wr.\n"); + return -1; + } + + /* poll for 2 CQEs (send + recv); refill recv immediately on recv CQE. */ + while (pending > 0) { + if (g_exit_flag) { + return -EINTR; + } + int n = urma_poll_jfc(g_ub_ctx->jfc, 1, &cr); + if (n < 0) { + LOG_ERROR("Failed to poll jfc.\n"); + return -1; + } + if (n == 1) { + if (cr.status != URMA_CR_SUCCESS) { + LOG_ERROR("mgmt CR status %d (s_r=%u).\n", (int)cr.status, cr.flag.bs.s_r); + return -1; + } + if (cr.flag.bs.s_r == 1) { /* recv CQE: refill */ + if (ub_post_one_recv(g_ub_ctx) != 0) { + LOG_ERROR("Failed to refill mgmt recv.\n"); + return -1; + } + } + pending--; + } + } + + /* copy recv_buf into remote_data. After this call RQ has 1 recv (the + * refill above), have_pending_recv=false (not a probe). Caller may + * immediately call comm_poll, which will skip posting a duplicate probe. */ + (void)memcpy(remote_data, g_ub_ctx->recv_buf, (size_t)size); + return 0; +} + +int ub_sync_time(uint32_t index, const char *tag) +{ + int len; + char *b = NULL; + int ret; + + if (tag == NULL) { + LOG_ERROR("Invalid parameter: tag is nullptr.\n"); + return -EINVAL; + } + len = (int)strlen(tag); + if (len >= UB_MGMT_MSG_MAX_SIZE) { + LOG_ERROR("sync_time tag too long: %d.\n", len); + return -EINVAL; + } + b = (char *)calloc(1, (size_t)len + 1); + if (b == NULL) { + return -ENOMEM; + } + ret = ub_sync_data(index, len, (char *)tag, b); + if (ret != 0) { + LOG_ERROR("sync_time ub error, tag: %s, ret: %d.\n", tag, ret); + free(b); + return ret; + } + ret = (memcmp(tag, b, (size_t)len) == 0) ? 0 : -1; + if (ret != 0) { + b[len] = '\0'; + LOG_ERROR("sync_time ub mismatch: %s != %s.\n", tag, b); + } + free(b); + return ret; +} + +/* ========================================================================== */ +/* comm_send / comm_recv / comm_poll (infinite BW mode control flow) */ +/* ========================================================================== */ + +ssize_t ub_comm_send(uint32_t index, const void *buf, size_t size) +{ + urma_sge_t sge = {0}; + urma_jfs_wr_t wr = {0}; + urma_jfs_wr_t *bad = NULL; + urma_cr_t cr = {0}; + + (void)index; /* single pair; index ignored */ + + if (g_ub_ctx == NULL || buf == NULL || size == 0 || size > UB_MGMT_MSG_MAX_SIZE) { + return -EINVAL; + } + (void)memcpy(g_ub_ctx->send_buf, buf, size); + + sge.addr = (uint64_t)g_ub_ctx->send_buf; + sge.len = (uint32_t)size; + sge.tseg = g_ub_ctx->tseg_send; + wr.opcode = URMA_OPC_SEND; + wr.flag.bs.complete_enable = 1; + wr.tjetty = g_ub_ctx->pair.tjetty; + wr.send.src.sge = &sge; + wr.send.src.num_sge = 1; + wr.next = NULL; + + if (urma_post_jetty_send_wr(g_ub_ctx->pair.jetty, &wr, &bad) != URMA_SUCCESS) { + LOG_ERROR("Failed to post comm_send wr.\n"); + return -1; + } + + if (poll_one_cqe(g_ub_ctx->jfc, &cr, false) != 0) { + return -1; + } + return (ssize_t)size; +} + +ssize_t ub_comm_recv(uint32_t index, void *buf, size_t size) +{ + urma_sge_t sge = {0}; + urma_jfr_wr_t wr = {0}; + urma_jfr_wr_t *bad = NULL; + urma_cr_t cr = {0}; + + (void)index; /* single pair; index ignored */ + + if (g_ub_ctx == NULL || buf == NULL || size == 0 || size > UB_MGMT_MSG_MAX_SIZE) { + return -EINVAL; + } + + /* If comm_poll already captured probe data, return it directly. + * perftest's comm_recv is only for 1B PERFTEST_EXIT_CMD. */ + if (g_ub_ctx->pair.have_pending_data) { + if (size > 1) { + LOG_ERROR("comm_recv: size=%zu but pending probe data is 1B only.\n", size); + return -EINVAL; + } + (void)memcpy(buf, g_ub_ctx->recv_buf, 1); + g_ub_ctx->pair.have_pending_data = false; + g_ub_ctx->pair.pending_data_len = 0; + return 1; + } + + if (!g_ub_ctx->pair.have_pending_recv) { + /* Fresh recv: post with caller's size. */ + sge.addr = (uint64_t)g_ub_ctx->recv_buf; + sge.len = (uint32_t)size; + sge.tseg = g_ub_ctx->tseg_recv; + wr.src.sge = &sge; + wr.src.num_sge = 1; + wr.next = NULL; + if (urma_post_jetty_recv_wr(g_ub_ctx->pair.jetty, &wr, &bad) != URMA_SUCCESS) { + LOG_ERROR("Failed to post comm_recv wr.\n"); + return -1; + } + } else { + /* Probe recv in flight; just wait for its CQE. */ + g_ub_ctx->pair.have_pending_recv = false; + } + + if (poll_one_cqe(g_ub_ctx->jfc, &cr, true) != 0) { + return -1; + } + uint32_t got = cr.completion_len; + if (got > size) { + got = (uint32_t)size; + } + (void)memcpy(buf, g_ub_ctx->recv_buf, got); + return (ssize_t)got; +} + +/* + * UB equivalent of TCP poll(fd, POLLIN, timeout_ms). UB has no kernel + * buffering, so poll posts a 1B probe recv and non-blocking polls jfc + * until CQE arrives or timeout. Returns >0 if data ready, 0 on timeout. + */ +int ub_comm_poll(uint32_t index, int timeout_ms) +{ + urma_sge_t sge = {0}; + urma_jfr_wr_t wr = {0}; + urma_jfr_wr_t *bad = NULL; + + (void)index; /* single pair; index ignored */ + + if (g_ub_ctx == NULL) { + errno = EINVAL; + return -1; + } + if (timeout_ms < 0) { + timeout_ms = 0; + } + + /* If a previous poll already got data, return immediately. */ + if (g_ub_ctx->pair.have_pending_data) { + return 1; + } + + /* Post probe recv if not already in flight. */ + if (!g_ub_ctx->pair.have_pending_recv) { + sge.addr = (uint64_t)g_ub_ctx->recv_buf; + sge.len = 1; /* probe: just 1B to detect peer exit signal */ + sge.tseg = g_ub_ctx->tseg_recv; + wr.src.sge = &sge; + wr.src.num_sge = 1; + wr.next = NULL; + if (urma_post_jetty_recv_wr(g_ub_ctx->pair.jetty, &wr, &bad) != URMA_SUCCESS) { + LOG_ERROR("Failed to post comm_poll probe recv.\n"); + errno = EIO; + return -1; + } + g_ub_ctx->pair.have_pending_recv = true; + } + + /* Non-blocking poll loop with 1ms sleep, up to timeout_ms iterations. */ + struct timespec ts_start = {0}; + (void)clock_gettime(CLOCK_MONOTONIC, &ts_start); + uint64_t start_ms = (uint64_t)ts_start.tv_sec * 1000 + (uint64_t)ts_start.tv_nsec / 1000000; + + while (true) { + urma_cr_t cr = {0}; + int n = urma_poll_jfc(g_ub_ctx->jfc, 1, &cr); + if (n < 0) { + LOG_ERROR("Failed to poll jfc in comm_poll.\n"); + errno = EIO; + return -1; + } + if (n == 1) { + if (cr.status != URMA_CR_SUCCESS) { + LOG_ERROR("comm_poll CR status %d.\n", (int)cr.status); + errno = EIO; + return -1; + } + /* Probe completed: data is in recv_buf. Keep it for comm_recv. */ + g_ub_ctx->pair.have_pending_recv = false; + g_ub_ctx->pair.have_pending_data = true; + g_ub_ctx->pair.pending_data_len = cr.completion_len; + return 1; + } + + struct timespec ts_now = {0}; + (void)clock_gettime(CLOCK_MONOTONIC, &ts_now); + uint64_t now_ms = (uint64_t)ts_now.tv_sec * 1000 + (uint64_t)ts_now.tv_nsec / 1000000; + if (now_ms - start_ms >= (uint64_t)timeout_ms) { + return 0; /* timeout, probe recv still pending */ + } + (void)usleep(1000); /* 1ms backoff to avoid burning CPU */ + } +} diff --git a/src/ub_bench_mgmt_ub.h b/src/ub_bench_mgmt_ub.h new file mode 100644 index 0000000..6dc6b3d --- /dev/null +++ b/src/ub_bench_mgmt_ub.h @@ -0,0 +1,37 @@ +/* + * SPDX-License-Identifier: MIT + * Copyright (c) Huawei Technologies Co., Ltd. 2026-2026. All rights reserved. + * Description: ub management header file for ub_bench + * Create: 2026-09-16 + * Note: + * History: 2026-09-16 create file + */ + +#ifndef UB_BENCH_MGMT_UB_H +#define UB_BENCH_MGMT_UB_H + +#include +#include +#include + +#define UB_MGMT_JFC_DEPTH (64) +#define UB_MGMT_JFS_DEPTH (8) +#define UB_MGMT_JFR_DEPTH (8) +#define UB_MGMT_MSG_MAX_SIZE (4096) + +typedef struct comm_ub_cfg { + char *src_eid; /* Local mgmt EID. Required. */ + char *dst_eid; /* Server mgmt EID, NULL on server side. */ + uint32_t dst_jetty_id; /* Server mgmt jetty id, 0 on client (driver auto-assigns). */ +} comm_ub_cfg_t; + +int ub_establish_connection(const comm_ub_cfg_t *cfg); +void ub_close_connection(void); + +int ub_sync_data(uint32_t index, int size, char *local_data, char *remote_data); +int ub_sync_time(uint32_t index, const char *tag); +ssize_t ub_comm_send(uint32_t index, const void *buf, size_t size); +ssize_t ub_comm_recv(uint32_t index, void *buf, size_t size); +int ub_comm_poll(uint32_t index, int timeout_ms); + +#endif diff --git a/src/ub_bench_parameters.c b/src/ub_bench_parameters.c new file mode 100644 index 0000000..056793d --- /dev/null +++ b/src/ub_bench_parameters.c @@ -0,0 +1,2000 @@ +/* + * SPDX-License-Identifier: MIT + * Copyright (c) Huawei Technologies Co., Ltd. 2026-2026. All rights reserved. + * Description: parse parameters for ub_bench + * Create: 2026-09-16 + * Note: + * History: 2026-09-16 create file + */ + +#include +#include +#include +#include +#include +#include + +#include + +#include "ub_get_clock.h" +#include "ub_util.h" +#include "urma_types.h" +#include "urma_types_str.h" +#include "urma_ubagg.h" + +#include "ub_bench_parameters.h" + +#define PERFTEST_CACHE_LINE_FILE_SIZE (10) +#define PERFTEST_JFC_MUL_THRESHOLD (4) +#define PERFTEST_DEFAULT_DURATION (5) + +#define PERFTEST_RTP_MAX_SEND_SIZE (65536) +#define PERFTEST_CTP_MAX_SEND_SIZE (4096) +#define PERFTEST_RTP_MAX_ORDER (16) +#define PERFTEST_CTP_MAX_ORDER (12) + +typedef struct perftest_cmd { + char *cmd; + perftest_cmd_type_t type; +} perftest_cmd_t; + +static const char *g_atomic_types_str[] = { + [PERFTEST_CAS] = "cas", + [PERFTEST_FAA] = "faa", +}; +static const char *g_print_test_str[] = { + [PERFTEST_READ] = "URMA_READ", + [PERFTEST_WRITE] = "URMA_WRITE", + [PERFTEST_SEND] = "URMA_SEND", + [PERFTEST_ATOMIC] = "URMA_ATOMIC", +}; +static const char *g_trans_mode_str[] = { + [URMA_TM_RM] = "URMA_TM_RM", + [URMA_TM_RC] = "URMA_TM_RC", + [URMA_TM_UM] = "URMA_TM_UM", +}; +static const char *g_jetty_mode_str[] = { + [PERFTEST_JETTY_SIMPLEX] = "SIMPLEX", + [PERFTEST_JETTY_DUPLEX] = "DUPLEX", +}; +static const char *g_bond_mode_str[] = { + [BONDP_BONDING_MODE_STANDALONE] = "standalone", + [BONDP_BONDING_MODE_ACTIVE_BACKUP] = "active_backup", + [BONDP_BONDING_MODE_BALANCE] = "balance", +}; +static const char *g_bond_level_str[] = { + [BONDP_BONDING_LEVEL_IODIE] = "iodie", + [BONDP_BONDING_LEVEL_PORT] = "port", +}; + +#define PERFTEST_BOOL_TO_STR(val) ((val) == true ? "true" : "false") + +static const perftest_cmd_t g_cmd[] = { + {"read_lat", PERFTEST_READ_LAT}, + {"write_lat", PERFTEST_WRITE_LAT}, + {"send_lat", PERFTEST_SEND_LAT}, + {"atomic_lat", PERFTEST_ATOMIC_LAT}, + {"read_bw", PERFTEST_READ_BW}, + {"write_bw", PERFTEST_WRITE_BW}, + {"send_bw", PERFTEST_SEND_BW}, + {"atomic_bw", PERFTEST_ATOMIC_BW}, +}; + +static void command_usage(const char *argv0) +{ + LOG_QUIET( + "Usage: %s command [command options]\n" + " %s UB benchmark tool\n" + "Command syntax:\n" + " read_lat Test for read latency.\n" + " write_lat Test for write latency.\n" + " send_lat Test for send latency.\n" + " atomic_lat Test for atomic latency.\n" + " read_bw Test for read bandwidth.\n" + " write_bw Test for write bandwidth.\n" + " send_bw Test for send bandwidth.\n" + " atomic_bw Test for atomic bandwidth.\n", + argv0, argv0); +} + +static void usage(const char *argv0) +{ + command_usage(argv0); + LOG_QUIET( + "Options:\n" + " -a, --all[order] Run sizes from 2 till 2^23,\n" + " default 2^12 for send, 2^16 for others, order: exponent of 2.\n" + " -A, --atomic_type Specify atomic type, {cas|faa}.\n" + " -b, --simplex_mode Run with simplex mode(jfs/jfr), duplex jetty mode for reserved.\n" + " -B, --bidirection Measure bidirectional bandwidth (default unidirectional).\n" + " -c, --jfc_inline Enable jfc_inline to upgrade latency performance.\n" + " -C, --jfc_depth Size of jfc depth (default 4096 for bw, 1024 for ip bw, 1 for lat.\n" + " -d, --dev The name of ubep device.\n" + " -D, --duration Run test for a customized period of seconds, this cfg covers iters.\n" + " -e, --use_jfce use jfc event.\n" + " --eid_idx Specified eid index of device.\n" + " -E, --err_timeout