diff options
Diffstat (limited to 'platform/linux-generic')
27 files changed, 539 insertions, 69 deletions
diff --git a/platform/linux-generic/Makefile.am b/platform/linux-generic/Makefile.am index 2986e08e8..267d02a7d 100644 --- a/platform/linux-generic/Makefile.am +++ b/platform/linux-generic/Makefile.am @@ -2,6 +2,7 @@ #export CUSTOM_STR=https://github.com/OpenDataPlane/odp.git include $(top_srcdir)/platform/Makefile.inc +lib_LTLIBRARIES += $(LIB)/libodp-linux.la AM_CPPFLAGS = $(ODP_INCLUDES) AM_CPPFLAGS += -I$(top_srcdir)/platform/$(with_platform)/include @@ -17,7 +18,7 @@ AM_CFLAGS += $(DPDK_CFLAGS) AM_CFLAGS += $(LIBCONFIG_CFLAGS) DISTCLEANFILES = include/odp_libconfig_config.h -include/odp_libconfig_config.h: $(top_srcdir)/config/odp-$(with_platform).conf $(top_builddir)/config.status +include/odp_libconfig_config.h: $(top_builddir)/$(rel_default_config_path) $(top_builddir)/config.status cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ odpapiabiarchincludedir = $(archincludedir)/odp/api/abi @@ -57,7 +58,9 @@ odpapiabiarchinclude_HEADERS += \ include-abi/odp/api/abi/cpumask.h \ include-abi/odp/api/abi/crypto.h \ include-abi/odp/api/abi/debug.h \ + include-abi/odp/api/abi/errno.h \ include-abi/odp/api/abi/event.h \ + include-abi/odp/api/abi/hash.h \ include-abi/odp/api/abi/init.h \ include-abi/odp/api/abi/ipsec.h \ include-abi/odp/api/abi/packet.h \ @@ -148,7 +151,7 @@ noinst_HEADERS = \ include/protocols/tcp.h \ include/protocols/thash.h \ include/protocols/udp.h -nodist_noinst_HEADERS = \ +BUILT_SOURCES = \ include/odp_libconfig_config.h __LIB__libodp_linux_la_SOURCES = \ diff --git a/platform/linux-generic/include-abi/odp/api/abi/errno.h b/platform/linux-generic/include-abi/odp/api/abi/errno.h new file mode 100644 index 000000000..6215a0676 --- /dev/null +++ b/platform/linux-generic/include-abi/odp/api/abi/errno.h @@ -0,0 +1,18 @@ +/* Copyright (c) 2020, Marvell + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/** + * @file + * + * ODP errno + */ + +#ifndef ODP_API_ABI_ERRNO_H_ +#define ODP_API_ABI_ERRNO_H_ + +#include <odp/api/abi-default/errno.h> + +#endif diff --git a/platform/linux-generic/include-abi/odp/api/abi/hash.h b/platform/linux-generic/include-abi/odp/api/abi/hash.h new file mode 100644 index 000000000..fc81dcc91 --- /dev/null +++ b/platform/linux-generic/include-abi/odp/api/abi/hash.h @@ -0,0 +1,18 @@ +/* Copyright (c) 2020, Marvell + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/** + * @file + * + * ODP hash + */ + +#ifndef ODP_API_ABI_HASH_H_ +#define ODP_API_ABI_HASH_H_ + +#include <odp/api/abi-default/hash.h> + +#endif diff --git a/platform/linux-generic/include/odp/api/plat/time_inlines.h b/platform/linux-generic/include/odp/api/plat/time_inlines.h index 527490e3d..0b05aa4f7 100644 --- a/platform/linux-generic/include/odp/api/plat/time_inlines.h +++ b/platform/linux-generic/include/odp/api/plat/time_inlines.h @@ -1,4 +1,5 @@ /* Copyright (c) 2018, Linaro Limited + * Copyright (c) 2020, Nokia * All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause @@ -16,6 +17,7 @@ /** @cond _ODP_HIDE_FROM_DOXYGEN_ */ #define _ODP_TIMESPEC_SIZE 16 +#define _ODP_TIME_GIGA_HZ 1000000000ULL typedef struct _odp_time_global_t { /* Storage space for struct timespec. Posix headers are not included @@ -44,14 +46,42 @@ static inline odp_time_t _odp_time_cur(void) return _odp_timespec_cur(); } +static inline uint64_t _odp_time_hw_to_ns(odp_time_t time) +{ + uint64_t nsec; + uint64_t freq_hz = _odp_time_glob.hw_freq_hz; + uint64_t count = time.count; + uint64_t sec = 0; + + if (count >= freq_hz) { + sec = count / freq_hz; + count = count - sec * freq_hz; + } + + nsec = (_ODP_TIME_GIGA_HZ * count) / freq_hz; + + return (sec * _ODP_TIME_GIGA_HZ) + nsec; +} + +static inline uint64_t _odp_time_convert_to_ns(odp_time_t time) +{ + if (_odp_time_glob.use_hw) + return _odp_time_hw_to_ns(time); + + return time.nsec; +} + #ifndef _ODP_NO_INLINE /* Inline functions by default */ #define _ODP_INLINE static inline - #define odp_time_local __odp_time_local - #define odp_time_global __odp_time_global - #define odp_time_cmp __odp_time_cmp - #define odp_time_diff __odp_time_diff - #define odp_time_sum __odp_time_sum + #define odp_time_local __odp_time_local + #define odp_time_global __odp_time_global + #define odp_time_to_ns __odp_time_to_ns + #define odp_time_local_ns __odp_time_local_ns + #define odp_time_global_ns __odp_time_global_ns + #define odp_time_cmp __odp_time_cmp + #define odp_time_diff __odp_time_diff + #define odp_time_sum __odp_time_sum #else #define _ODP_INLINE @@ -67,6 +97,21 @@ _ODP_INLINE odp_time_t odp_time_global(void) return _odp_time_cur(); } +_ODP_INLINE uint64_t odp_time_to_ns(odp_time_t time) +{ + return _odp_time_convert_to_ns(time); +} + +_ODP_INLINE uint64_t odp_time_local_ns(void) +{ + return _odp_time_convert_to_ns(_odp_time_cur()); +} + +_ODP_INLINE uint64_t odp_time_global_ns(void) +{ + return _odp_time_convert_to_ns(_odp_time_cur()); +} + _ODP_INLINE int odp_time_cmp(odp_time_t t2, odp_time_t t1) { if (odp_likely(t2.u64 > t1.u64)) diff --git a/platform/linux-generic/include/odp_packet_io_internal.h b/platform/linux-generic/include/odp_packet_io_internal.h index 0e6a8a335..4219ff114 100644 --- a/platform/linux-generic/include/odp_packet_io_internal.h +++ b/platform/linux-generic/include/odp_packet_io_internal.h @@ -180,6 +180,7 @@ typedef struct pktio_if_ops { int (*mac_get)(pktio_entry_t *pktio_entry, void *mac_addr); int (*mac_set)(pktio_entry_t *pktio_entry, const void *mac_addr); int (*link_status)(pktio_entry_t *pktio_entry); + int (*link_info)(pktio_entry_t *pktio_entry, odp_pktio_link_info_t *info); int (*capability)(pktio_entry_t *pktio_entry, odp_pktio_capability_t *capa); int (*config)(pktio_entry_t *pktio_entry, diff --git a/platform/linux-generic/include/odp_socket_common.h b/platform/linux-generic/include/odp_socket_common.h index afce0f55d..0a9704076 100644 --- a/platform/linux-generic/include/odp_socket_common.h +++ b/platform/linux-generic/include/odp_socket_common.h @@ -12,6 +12,8 @@ extern "C" { #endif +#include <odp/api/packet_io.h> + #include <string.h> #include <linux/if_ether.h> @@ -57,6 +59,11 @@ int promisc_mode_get_fd(int fd, const char *name); */ int link_status_fd(int fd, const char *name); +/** + * Read link information from a packet socket + */ +int link_info_fd(int fd, const char *name, odp_pktio_link_info_t *info); + #ifdef __cplusplus } #endif diff --git a/platform/linux-generic/libodp-linux.pc.in b/platform/linux-generic/libodp-linux.pc.in index 5fe806435..df92e9345 100644 --- a/platform/linux-generic/libodp-linux.pc.in +++ b/platform/linux-generic/libodp-linux.pc.in @@ -3,10 +3,10 @@ exec_prefix=@exec_prefix@ libdir=@libdir@ includedir=@includedir@ -Name: libodp-linux +Name: lib@ODP_LIB_NAME@ Description: The ODP packet processing engine Version: @PKGCONFIG_VERSION@ Requires.private: libconfig@DPDK_PKG@ -Libs: -L${libdir} -lodp-linux +Libs: -L${libdir} -l@ODP_LIB_NAME@ Libs.private: @OPENSSL_STATIC_LIBS@ @DPDK_LIBS@ @PCAP_LIBS@ @PTHREAD_LIBS@ @TIMER_LIBS@ -lpthread @ATOMIC_LIBS@ Cflags: -I${includedir} diff --git a/platform/linux-generic/m4/configure.m4 b/platform/linux-generic/m4/configure.m4 index bcd55b7c5..06bff0669 100644 --- a/platform/linux-generic/m4/configure.m4 +++ b/platform/linux-generic/m4/configure.m4 @@ -1,4 +1,5 @@ ODP_IMPLEMENTATION_NAME="odp-linux" +ODP_LIB_NAME="odp-linux" ODP_VISIBILITY ODP_ATOMIC diff --git a/platform/linux-generic/m4/odp_libconfig.m4 b/platform/linux-generic/m4/odp_libconfig.m4 index f042d65d7..d13fcf274 100644 --- a/platform/linux-generic/m4/odp_libconfig.m4 +++ b/platform/linux-generic/m4/odp_libconfig.m4 @@ -20,9 +20,16 @@ AC_SUBST(_ODP_CONFIG_VERSION_MINOR) ########################################################################## default_config_path="${srcdir}/config/odp-$with_platform.conf" +AC_CHECK_PROGS([REALPATH], [realpath]) +AS_IF([test -z "$REALPATH"], [AC_MSG_ERROR([Could not find 'realpath'])]) + AC_ARG_WITH([config-file], AS_HELP_STRING([--with-config-file=FILE path to the default configuration file], [(this file must include all configuration options).]), [default_config_path=$withval], []) -ODP_LIBCONFIG([$with_platform], [$default_config_path]) +rel_default_config_path=`realpath --relative-to=$(pwd) ${default_config_path}` +AC_SUBST(default_config_path) +AC_SUBST(rel_default_config_path) + +ODP_LIBCONFIG([$with_platform], [$rel_default_config_path]) diff --git a/platform/linux-generic/odp_crypto_openssl.c b/platform/linux-generic/odp_crypto_openssl.c index 98a13ce4a..2a8d4fb9b 100644 --- a/platform/linux-generic/odp_crypto_openssl.c +++ b/platform/linux-generic/odp_crypto_openssl.c @@ -285,6 +285,9 @@ odp_crypto_generic_session_t *alloc_session(void) } odp_spinlock_unlock(&global->lock); + if (!session) + return NULL; + session->idx = session - global->sessions; for (i = 0; i < ODP_THREAD_COUNT_MAX; i++) diff --git a/platform/linux-generic/odp_packet_io.c b/platform/linux-generic/odp_packet_io.c index 1cd5745aa..d57c21a9e 100644 --- a/platform/linux-generic/odp_packet_io.c +++ b/platform/linux-generic/odp_packet_io.c @@ -1,5 +1,5 @@ /* Copyright (c) 2013-2018, Linaro Limited - * Copyright (c) 2019, Nokia + * Copyright (c) 2019-2020, Nokia * All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause @@ -1168,15 +1168,15 @@ int odp_pktio_mac_addr_set(odp_pktio_t hdl, const void *mac_addr, int addr_size) return ret; } -int odp_pktio_link_status(odp_pktio_t hdl) +odp_pktio_link_status_t odp_pktio_link_status(odp_pktio_t hdl) { pktio_entry_t *entry; - int ret = -1; + int ret = ODP_PKTIO_LINK_STATUS_UNKNOWN; entry = get_pktio_entry(hdl); if (entry == NULL) { ODP_DBG("pktio entry %d does not exist\n", hdl); - return -1; + return ODP_PKTIO_LINK_STATUS_UNKNOWN; } lock_entry(entry); @@ -1184,7 +1184,7 @@ int odp_pktio_link_status(odp_pktio_t hdl) if (odp_unlikely(is_free(entry))) { unlock_entry(entry); ODP_DBG("already freed pktio\n"); - return -1; + return ODP_PKTIO_LINK_STATUS_UNKNOWN; } if (entry->s.ops->link_status) @@ -1244,6 +1244,23 @@ int odp_pktio_info(odp_pktio_t hdl, odp_pktio_info_t *info) return 0; } +int odp_pktio_link_info(odp_pktio_t hdl, odp_pktio_link_info_t *info) +{ + pktio_entry_t *entry; + + entry = get_pktio_entry(hdl); + + if (entry == NULL) { + ODP_DBG("pktio entry %d does not exist\n", hdl); + return -1; + } + + if (entry->s.ops->link_info) + return entry->s.ops->link_info(entry, info); + + return -1; +} + uint64_t odp_pktin_ts_res(odp_pktio_t hdl) { pktio_entry_t *entry; diff --git a/platform/linux-generic/odp_pool.c b/platform/linux-generic/odp_pool.c index d31f210e7..913e71f5a 100644 --- a/platform/linux-generic/odp_pool.c +++ b/platform/linux-generic/odp_pool.c @@ -666,9 +666,9 @@ static odp_pool_t pool_create(const char *name, const odp_pool_param_t *params, /* Allocate extra memory for skipping packet buffers which cross huge * page boundaries. */ if (params->type == ODP_POOL_PACKET) { - num_extra = (((uint64_t)(num * block_size) + + num_extra = ((((uint64_t)num * block_size) + FIRST_HP_SIZE - 1) / FIRST_HP_SIZE); - num_extra += (((uint64_t)(num_extra * block_size) + + num_extra += ((((uint64_t)num_extra * block_size) + FIRST_HP_SIZE - 1) / FIRST_HP_SIZE); } diff --git a/platform/linux-generic/odp_time.c b/platform/linux-generic/odp_time.c index b033a733c..aea823eb6 100644 --- a/platform/linux-generic/odp_time.c +++ b/platform/linux-generic/odp_time.c @@ -78,11 +78,6 @@ static inline uint64_t time_spec_res(void) return ODP_TIME_SEC_IN_NS / (uint64_t)tres.tv_nsec; } -static inline uint64_t time_spec_to_ns(odp_time_t time) -{ - return time.nsec; -} - static inline odp_time_t time_spec_from_ns(uint64_t ns) { odp_time_t time; @@ -101,23 +96,6 @@ static inline uint64_t time_hw_res(void) return _odp_time_glob.hw_freq_hz; } -static inline uint64_t time_hw_to_ns(odp_time_t time) -{ - uint64_t nsec; - uint64_t freq_hz = _odp_time_glob.hw_freq_hz; - uint64_t count = time.count; - uint64_t sec = 0; - - if (count >= freq_hz) { - sec = count / freq_hz; - count = count - sec * freq_hz; - } - - nsec = (ODP_TIME_SEC_IN_NS * count) / freq_hz; - - return (sec * ODP_TIME_SEC_IN_NS) + nsec; -} - static inline odp_time_t time_hw_from_ns(uint64_t ns) { odp_time_t time; @@ -150,14 +128,6 @@ static inline uint64_t time_res(void) return time_spec_res(); } -static inline uint64_t time_to_ns(odp_time_t time) -{ - if (_odp_time_glob.use_hw) - return time_hw_to_ns(time); - - return time_spec_to_ns(time); -} - static inline odp_time_t time_from_ns(uint64_t ns) { if (_odp_time_glob.use_hw) @@ -181,12 +151,7 @@ uint64_t odp_time_diff_ns(odp_time_t t2, odp_time_t t1) time.u64 = t2.u64 - t1.u64; - return time_to_ns(time); -} - -uint64_t odp_time_to_ns(odp_time_t time) -{ - return time_to_ns(time); + return odp_time_to_ns(time); } odp_time_t odp_time_local_from_ns(uint64_t ns) diff --git a/platform/linux-generic/odp_timer.c b/platform/linux-generic/odp_timer.c index 5fa020118..e7c0d4e51 100644 --- a/platform/linux-generic/odp_timer.c +++ b/platform/linux-generic/odp_timer.c @@ -1,5 +1,5 @@ /* Copyright (c) 2013-2018, Linaro Limited - * Copyright (c) 2019, Nokia + * Copyright (c) 2019-2020, Nokia * All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause @@ -54,6 +54,9 @@ /* Inlined API functions */ #include <odp/api/plat/event_inlines.h> +/* One divided by one nanosecond in Hz */ +#define GIGA_HZ 1000000000 + #define TMO_UNUSED ((uint64_t)0xFFFFFFFFFFFFFFFF) /* TMO_INACTIVE is or-ed with the expiration tick to indicate an expired timer. * The original expiration tick (63 bits) is still available so it can be used @@ -148,6 +151,7 @@ typedef struct timer_global_t { odp_shm_t shm; /* Max timer resolution in nanoseconds */ uint64_t highest_res_ns; + uint64_t highest_res_hz; uint64_t poll_interval_nsec; int num_timer_pools; uint8_t timer_pool_used[MAX_TIMER_POOLS]; @@ -324,7 +328,10 @@ static odp_timer_pool_t timer_pool_new(const char *name, memset(tp, 0, tp_size); - res_ns = param->res_ns; + if (param->res_ns) + res_ns = param->res_ns; + else + res_ns = GIGA_HZ / param->res_hz; /* Scan timer pool twice during resolution interval */ if (res_ns > ODP_TIME_USEC_IN_NS) @@ -344,6 +351,7 @@ static odp_timer_pool_t timer_pool_new(const char *name, } tp->shm = shm; tp->param = *param; + tp->param.res_ns = res_ns; tp->min_rel_tck = odp_timer_ns_to_tick(timer_pool_to_hdl(tp), param->min_tmo); tp->max_rel_tck = odp_timer_ns_to_tick(timer_pool_to_hdl(tp), @@ -1239,9 +1247,11 @@ int odp_timer_capability(odp_timer_clk_src_t clk_src, capa->max_timers = 0; capa->highest_res_ns = timer_global->highest_res_ns; capa->max_res.res_ns = timer_global->highest_res_ns; + capa->max_res.res_hz = timer_global->highest_res_hz; capa->max_res.min_tmo = 0; capa->max_res.max_tmo = MAX_TMO_NSEC; capa->max_tmo.res_ns = timer_global->highest_res_ns; + capa->max_tmo.res_hz = timer_global->highest_res_hz; capa->max_tmo.min_tmo = 0; capa->max_tmo.max_tmo = MAX_TMO_NSEC; @@ -1261,12 +1271,13 @@ int odp_timer_res_capability(odp_timer_clk_src_t clk_src, return -1; } - if (res_capa->res_ns) { + if (res_capa->res_ns || res_capa->res_hz) { res_capa->min_tmo = 0; res_capa->max_tmo = MAX_TMO_NSEC; } else { /* max_tmo */ res_capa->min_tmo = 0; res_capa->res_ns = timer_global->highest_res_ns; + res_capa->res_hz = timer_global->highest_res_hz; } return 0; @@ -1280,7 +1291,20 @@ odp_timer_pool_t odp_timer_pool_create(const char *name, return ODP_TIMER_POOL_INVALID; } - if (param->res_ns < timer_global->highest_res_ns) { + if ((param->res_ns && param->res_hz) || + (param->res_ns == 0 && param->res_hz == 0)) { + __odp_errno = EINVAL; + return ODP_TIMER_POOL_INVALID; + } + + if (param->res_hz == 0 && + param->res_ns < timer_global->highest_res_ns) { + __odp_errno = EINVAL; + return ODP_TIMER_POOL_INVALID; + } + + if (param->res_ns == 0 && + param->res_hz > timer_global->highest_res_hz) { __odp_errno = EINVAL; return ODP_TIMER_POOL_INVALID; } @@ -1561,6 +1585,9 @@ int _odp_timer_init_global(const odp_init_t *params) block_sigalarm(); } + /* timer_res_init() may update highest_res_ns */ + timer_global->highest_res_hz = GIGA_HZ / timer_global->highest_res_ns; + return 0; error: diff --git a/platform/linux-generic/odp_traffic_mngr.c b/platform/linux-generic/odp_traffic_mngr.c index de9cbfb73..1b6ca2ec2 100644 --- a/platform/linux-generic/odp_traffic_mngr.c +++ b/platform/linux-generic/odp_traffic_mngr.c @@ -4575,7 +4575,8 @@ static int tm_query_info_copy(tm_queue_info_t *queue_info, uint32_t query_flags, odp_tm_query_info_t *info) { - tm_queue_thresholds_t *threshold_params; + if ((query_flags & ODP_TM_QUERY_THRESHOLDS) && !queue_info->threshold_params) + return -1; memset(info, 0, sizeof(odp_tm_query_info_t)); info->total_pkt_cnt = @@ -4587,9 +4588,7 @@ static int tm_query_info_copy(tm_queue_info_t *queue_info, info->approx_byte_cnt = 0; if (query_flags & ODP_TM_QUERY_THRESHOLDS) { - threshold_params = queue_info->threshold_params; - if (!threshold_params) - return -1; + tm_queue_thresholds_t *threshold_params = queue_info->threshold_params; info->max_pkt_cnt = threshold_params->max_pkts; info->max_byte_cnt = threshold_params->max_bytes; @@ -4722,6 +4721,41 @@ void odp_tm_stats_print(odp_tm_t odp_tm) } } +uint64_t odp_tm_to_u64(odp_tm_t hdl) +{ + return _odp_pri(hdl); +} + +uint64_t odp_tm_queue_to_u64(odp_tm_queue_t hdl) +{ + return _odp_pri(hdl); +} + +uint64_t odp_tm_node_to_u64(odp_tm_node_t hdl) +{ + return _odp_pri(hdl); +} + +uint64_t odp_tm_shaper_to_u64(odp_tm_shaper_t hdl) +{ + return _odp_pri(hdl); +} + +uint64_t odp_tm_sched_to_u64(odp_tm_sched_t hdl) +{ + return _odp_pri(hdl); +} + +uint64_t odp_tm_threshold_to_u64(odp_tm_threshold_t hdl) +{ + return _odp_pri(hdl); +} + +uint64_t odp_tm_wred_to_u64(odp_tm_wred_t hdl) +{ + return _odp_pri(hdl); +} + int _odp_tm_init_global(void) { odp_shm_t shm; diff --git a/platform/linux-generic/pktio/dpdk.c b/platform/linux-generic/pktio/dpdk.c index 18f583a65..7aee73dc1 100644 --- a/platform/linux-generic/pktio/dpdk.c +++ b/platform/linux-generic/pktio/dpdk.c @@ -1,5 +1,5 @@ /* Copyright (c) 2016-2018, Linaro Limited - * Copyright (c) 2019, Nokia + * Copyright (c) 2019-2020, Nokia * All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause @@ -2056,8 +2056,63 @@ static int dpdk_link_status(pktio_entry_t *pktio_entry) memset(&link, 0, sizeof(struct rte_eth_link)); rte_eth_link_get_nowait(pkt_priv(pktio_entry)->port_id, &link); + if (link.link_status) + return ODP_PKTIO_LINK_STATUS_UP; + return ODP_PKTIO_LINK_STATUS_DOWN; +} + +static int dpdk_link_info(pktio_entry_t *pktio_entry, odp_pktio_link_info_t *info) +{ + struct rte_eth_link link; + struct rte_eth_fc_conf fc_conf; + uint16_t port_id = pkt_priv(pktio_entry)->port_id; + int ret; - return link.link_status; + memset(&fc_conf, 0, sizeof(struct rte_eth_fc_conf)); + memset(&link, 0, sizeof(struct rte_eth_link)); + + ret = rte_eth_dev_flow_ctrl_get(port_id, &fc_conf); + if (ret && ret != -ENOTSUP) { + ODP_ERR("rte_eth_dev_flow_ctrl_get() failed\n"); + return -1; + } + + memset(info, 0, sizeof(odp_pktio_link_info_t)); + info->pause_rx = ODP_PKTIO_LINK_PAUSE_OFF; + info->pause_tx = ODP_PKTIO_LINK_PAUSE_OFF; + if (fc_conf.mode == RTE_FC_RX_PAUSE) { + info->pause_rx = ODP_PKTIO_LINK_PAUSE_ON; + } else if (fc_conf.mode == RTE_FC_TX_PAUSE) { + info->pause_tx = ODP_PKTIO_LINK_PAUSE_ON; + } else if (fc_conf.mode == RTE_FC_FULL) { + info->pause_rx = ODP_PKTIO_LINK_PAUSE_ON; + info->pause_tx = ODP_PKTIO_LINK_PAUSE_ON; + } + + rte_eth_link_get_nowait(port_id, &link); + if (link.link_autoneg == ETH_LINK_AUTONEG) + info->autoneg = ODP_PKTIO_LINK_AUTONEG_ON; + else + info->autoneg = ODP_PKTIO_LINK_AUTONEG_OFF; + + if (link.link_duplex == ETH_LINK_FULL_DUPLEX) + info->duplex = ODP_PKTIO_LINK_DUPLEX_FULL; + else + info->duplex = ODP_PKTIO_LINK_DUPLEX_HALF; + + if (link.link_speed == ETH_SPEED_NUM_NONE) + info->speed = ODP_PKTIO_LINK_SPEED_UNKNOWN; + else + info->speed = link.link_speed; + + if (link.link_status == ETH_LINK_UP) + info->status = ODP_PKTIO_LINK_STATUS_UP; + else + info->status = ODP_PKTIO_LINK_STATUS_DOWN; + + info->media = "unknown"; + + return 0; } static void stats_convert(const struct rte_eth_stats *rte_stats, @@ -2106,6 +2161,7 @@ const pktio_if_ops_t dpdk_pktio_ops = { .recv = dpdk_recv, .send = dpdk_send, .link_status = dpdk_link_status, + .link_info = dpdk_link_info, .mtu_get = dpdk_frame_maxlen, .promisc_mode_set = dpdk_promisc_mode_set, .promisc_mode_get = dpdk_promisc_mode_get, diff --git a/platform/linux-generic/pktio/ipc.c b/platform/linux-generic/pktio/ipc.c index d63a77b74..34b32ae2c 100644 --- a/platform/linux-generic/pktio/ipc.c +++ b/platform/linux-generic/pktio/ipc.c @@ -900,6 +900,35 @@ static int ipc_stop(pktio_entry_t *pktio_entry) return 0; } +static int ipc_link_status(pktio_entry_t *pktio_entry) +{ + pkt_ipc_t *pktio_ipc = pkt_priv(pktio_entry); + + if (odp_atomic_load_u32(&pktio_ipc->ready)) + return ODP_PKTIO_LINK_STATUS_UP; + return ODP_PKTIO_LINK_STATUS_DOWN; +} + +static int ipc_link_info(pktio_entry_t *pktio_entry, odp_pktio_link_info_t *info) +{ + pkt_ipc_t *pktio_ipc = pkt_priv(pktio_entry); + + memset(info, 0, sizeof(odp_pktio_link_info_t)); + + info->autoneg = ODP_PKTIO_LINK_AUTONEG_OFF; + info->duplex = ODP_PKTIO_LINK_DUPLEX_FULL; + info->media = "virtual"; + info->pause_rx = ODP_PKTIO_LINK_PAUSE_OFF; + info->pause_tx = ODP_PKTIO_LINK_PAUSE_OFF; + info->speed = ODP_PKTIO_LINK_SPEED_UNKNOWN; + if (odp_atomic_load_u32(&pktio_ipc->ready)) + info->status = ODP_PKTIO_LINK_STATUS_UP; + else + info->status = ODP_PKTIO_LINK_STATUS_DOWN; + + return 0; +} + static int ipc_close(pktio_entry_t *pktio_entry) { pkt_ipc_t *pktio_ipc = pkt_priv(pktio_entry); @@ -947,6 +976,8 @@ const pktio_if_ops_t ipc_pktio_ops = { .send = ipc_pktio_send, .start = ipc_start, .stop = ipc_stop, + .link_status = ipc_link_status, + .link_info = ipc_link_info, .mtu_get = ipc_mtu_get, .promisc_mode_set = NULL, .promisc_mode_get = NULL, diff --git a/platform/linux-generic/pktio/loop.c b/platform/linux-generic/pktio/loop.c index e6d004d43..3de096139 100644 --- a/platform/linux-generic/pktio/loop.c +++ b/platform/linux-generic/pktio/loop.c @@ -1,5 +1,5 @@ /* Copyright (c) 2013-2018, Linaro Limited - * Copyright (c) 2013, Nokia Solutions and Networks + * Copyright (c) 2013-2020, Nokia Solutions and Networks * All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause @@ -367,7 +367,22 @@ static int loopback_mac_addr_get(pktio_entry_t *pktio_entry ODP_UNUSED, static int loopback_link_status(pktio_entry_t *pktio_entry ODP_UNUSED) { /* loopback interfaces are always up */ - return 1; + return ODP_PKTIO_LINK_STATUS_UP; +} + +static int loopback_link_info(pktio_entry_t *pktio_entry ODP_UNUSED, odp_pktio_link_info_t *info) +{ + memset(info, 0, sizeof(odp_pktio_link_info_t)); + + info->autoneg = ODP_PKTIO_LINK_AUTONEG_OFF; + info->duplex = ODP_PKTIO_LINK_DUPLEX_FULL; + info->media = "virtual"; + info->pause_rx = ODP_PKTIO_LINK_PAUSE_OFF; + info->pause_tx = ODP_PKTIO_LINK_PAUSE_OFF; + info->speed = ODP_PKTIO_LINK_SPEED_UNKNOWN; + info->status = ODP_PKTIO_LINK_STATUS_UP; + + return 0; } static int loopback_init_capability(pktio_entry_t *pktio_entry) @@ -467,6 +482,7 @@ const pktio_if_ops_t loopback_pktio_ops = { .mac_get = loopback_mac_addr_get, .mac_set = NULL, .link_status = loopback_link_status, + .link_info = loopback_link_info, .capability = loopback_capability, .pktin_ts_res = NULL, .pktin_ts_from_ns = NULL, diff --git a/platform/linux-generic/pktio/netmap.c b/platform/linux-generic/pktio/netmap.c index e1a5da773..0f608c6f6 100644 --- a/platform/linux-generic/pktio/netmap.c +++ b/platform/linux-generic/pktio/netmap.c @@ -1,5 +1,5 @@ /* Copyright (c) 2015-2018, Linaro Limited - * Copyright (c) 2019, Nokia + * Copyright (c) 2019-2020, Nokia * All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause @@ -355,12 +355,33 @@ static int netmap_close(pktio_entry_t *pktio_entry) static int netmap_link_status(pktio_entry_t *pktio_entry) { if (pkt_priv(pktio_entry)->is_virtual) - return 1; + return ODP_PKTIO_LINK_STATUS_UP; return link_status_fd(pkt_priv(pktio_entry)->sockfd, pkt_priv(pktio_entry)->if_name); } +static int netmap_link_info(pktio_entry_t *pktio_entry, odp_pktio_link_info_t *info) +{ + pkt_netmap_t *pkt_nm = pkt_priv(pktio_entry); + + if (pkt_nm->is_virtual) { + memset(info, 0, sizeof(odp_pktio_link_info_t)); + + info->autoneg = ODP_PKTIO_LINK_AUTONEG_OFF; + info->duplex = ODP_PKTIO_LINK_DUPLEX_FULL; + info->media = "virtual"; + info->pause_rx = ODP_PKTIO_LINK_PAUSE_OFF; + info->pause_tx = ODP_PKTIO_LINK_PAUSE_OFF; + info->speed = ODP_PKTIO_LINK_SPEED_UNKNOWN; + info->status = ODP_PKTIO_LINK_STATUS_UP; + + return 0; + } + + return link_info_fd(pkt_nm->sockfd, pkt_nm->if_name, info); +} + /** * Wait for netmap link to come up * @@ -1225,6 +1246,7 @@ const pktio_if_ops_t netmap_pktio_ops = { .start = netmap_start, .stop = netmap_stop, .link_status = netmap_link_status, + .link_info = netmap_link_info, .stats = netmap_stats, .stats_reset = netmap_stats_reset, .mtu_get = netmap_mtu_get, diff --git a/platform/linux-generic/pktio/null.c b/platform/linux-generic/pktio/null.c index bb7f85c9b..d739ccafe 100644 --- a/platform/linux-generic/pktio/null.c +++ b/platform/linux-generic/pktio/null.c @@ -154,6 +154,26 @@ static int null_init_global(void) return 0; } +static int null_link_status(pktio_entry_t *pktio_entry ODP_UNUSED) +{ + return ODP_PKTIO_LINK_STATUS_UP; +} + +static int null_link_info(pktio_entry_t *pktio_entry ODP_UNUSED, odp_pktio_link_info_t *info) +{ + memset(info, 0, sizeof(odp_pktio_link_info_t)); + + info->autoneg = ODP_PKTIO_LINK_AUTONEG_OFF; + info->duplex = ODP_PKTIO_LINK_DUPLEX_FULL; + info->media = "virtual"; + info->pause_rx = ODP_PKTIO_LINK_PAUSE_OFF; + info->pause_tx = ODP_PKTIO_LINK_PAUSE_OFF; + info->speed = ODP_PKTIO_LINK_SPEED_UNKNOWN; + info->status = ODP_PKTIO_LINK_STATUS_UP; + + return 0; +} + const pktio_if_ops_t null_pktio_ops = { .name = "null", .print = NULL, @@ -179,4 +199,6 @@ const pktio_if_ops_t null_pktio_ops = { .config = NULL, .input_queues_config = null_inqueues_config, .output_queues_config = null_outqueues_config, + .link_status = null_link_status, + .link_info = null_link_info }; diff --git a/platform/linux-generic/pktio/pcap.c b/platform/linux-generic/pktio/pcap.c index 6ef998717..262528abc 100644 --- a/platform/linux-generic/pktio/pcap.c +++ b/platform/linux-generic/pktio/pcap.c @@ -444,6 +444,26 @@ static int pcapif_init_global(void) return 0; } +static int pcapif_link_status(pktio_entry_t *pktio_entry ODP_UNUSED) +{ + return ODP_PKTIO_LINK_STATUS_UP; +} + +static int pcapif_link_info(pktio_entry_t *pktio_entry ODP_UNUSED, odp_pktio_link_info_t *info) +{ + memset(info, 0, sizeof(odp_pktio_link_info_t)); + + info->autoneg = ODP_PKTIO_LINK_AUTONEG_OFF; + info->duplex = ODP_PKTIO_LINK_DUPLEX_FULL; + info->media = "virtual"; + info->pause_rx = ODP_PKTIO_LINK_PAUSE_OFF; + info->pause_tx = ODP_PKTIO_LINK_PAUSE_OFF; + info->speed = ODP_PKTIO_LINK_SPEED_UNKNOWN; + info->status = ODP_PKTIO_LINK_STATUS_UP; + + return 0; +} + const pktio_if_ops_t pcap_pktio_ops = { .name = "pcap", .print = NULL, @@ -466,4 +486,6 @@ const pktio_if_ops_t pcap_pktio_ops = { .config = NULL, .input_queues_config = NULL, .output_queues_config = NULL, + .link_status = pcapif_link_status, + .link_info = pcapif_link_info }; diff --git a/platform/linux-generic/pktio/socket.c b/platform/linux-generic/pktio/socket.c index d148edf03..4776b83f9 100644 --- a/platform/linux-generic/pktio/socket.c +++ b/platform/linux-generic/pktio/socket.c @@ -493,6 +493,11 @@ static int sock_link_status(pktio_entry_t *pktio_entry) pktio_entry->s.name); } +static int sock_link_info(pktio_entry_t *pktio_entry, odp_pktio_link_info_t *info) +{ + return link_info_fd(pkt_priv(pktio_entry)->sockfd, pktio_entry->s.name, info); +} + static int sock_capability(pktio_entry_t *pktio_entry ODP_UNUSED, odp_pktio_capability_t *capa) { @@ -566,6 +571,7 @@ const pktio_if_ops_t sock_mmsg_pktio_ops = { .mac_get = sock_mac_addr_get, .mac_set = NULL, .link_status = sock_link_status, + .link_info = sock_link_info, .capability = sock_capability, .pktin_ts_res = NULL, .pktin_ts_from_ns = NULL, diff --git a/platform/linux-generic/pktio/socket_common.c b/platform/linux-generic/pktio/socket_common.c index 4fbf2f041..2eb3b4001 100644 --- a/platform/linux-generic/pktio/socket_common.c +++ b/platform/linux-generic/pktio/socket_common.c @@ -1,5 +1,5 @@ /* Copyright (c) 2018, Linaro Limited - * Copyright (c) 2019, Nokia + * Copyright (c) 2019-2020, Nokia * All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause @@ -14,7 +14,9 @@ #include <sys/types.h> #include <sys/ioctl.h> #include <net/if.h> +#include <linux/ethtool.h> #include <linux/if_packet.h> +#include <linux/sockios.h> #include <errno.h> #include <odp_debug_internal.h> #include <odp_errno_define.h> @@ -155,8 +157,141 @@ int link_status_fd(int fd, const char *name) __odp_errno = errno; ODP_DBG("ioctl(SIOCGIFFLAGS): %s: \"%s\".\n", strerror(errno), ifr.ifr_name); + return ODP_PKTIO_LINK_STATUS_UNKNOWN; + } + + if (ifr.ifr_flags & IFF_RUNNING) + return ODP_PKTIO_LINK_STATUS_UP; + return ODP_PKTIO_LINK_STATUS_DOWN; +} + +int link_info_fd(int fd, const char *name, odp_pktio_link_info_t *info) +{ + struct ethtool_link_settings hcmd = {.cmd = ETHTOOL_GLINKSETTINGS}; + struct ethtool_link_settings *ecmd; + struct ethtool_pauseparam pcmd = {.cmd = ETHTOOL_GPAUSEPARAM}; + struct ifreq ifr; + int status; + + status = link_status_fd(fd, name); + if (status < 0) + return -1; + + snprintf(ifr.ifr_name, IF_NAMESIZE, "%s", name); + + /* Link pause status */ + ifr.ifr_data = (void *)&pcmd; + if (ioctl(fd, SIOCETHTOOL, &ifr) && errno != EOPNOTSUPP) { + __odp_errno = errno; + ODP_ERR("ioctl(SIOCETHTOOL): %s: \"%s\".\n", strerror(errno), + ifr.ifr_name); + return -1; + } + + /* Try to perform handshake and fall back to old API if failed */ + ifr.ifr_data = (void *)&hcmd; + if (ioctl(fd, SIOCETHTOOL, &ifr) < 0) { + struct ethtool_cmd ecmd_old = {.cmd = ETHTOOL_GSET}; + + ifr.ifr_data = (void *)&ecmd_old; + if (ioctl(fd, SIOCETHTOOL, &ifr) < 0) { + __odp_errno = errno; + ODP_ERR("ioctl(SIOCETHTOOL): %s: \"%s\".\n", strerror(errno), ifr.ifr_name); + return -1; + } + + memset(info, 0, sizeof(odp_pktio_link_info_t)); + info->speed = ethtool_cmd_speed(&ecmd_old); + if (info->speed == (uint32_t)SPEED_UNKNOWN) + info->speed = ODP_PKTIO_LINK_SPEED_UNKNOWN; + + if (ecmd_old.autoneg == AUTONEG_ENABLE) + info->autoneg = ODP_PKTIO_LINK_AUTONEG_ON; + else if (ecmd_old.autoneg == AUTONEG_DISABLE) + info->autoneg = ODP_PKTIO_LINK_AUTONEG_OFF; + else + info->autoneg = ODP_PKTIO_LINK_AUTONEG_UNKNOWN; + + if (ecmd_old.duplex == DUPLEX_HALF) + info->duplex = ODP_PKTIO_LINK_DUPLEX_HALF; + else if (ecmd_old.duplex == DUPLEX_FULL) + info->duplex = ODP_PKTIO_LINK_DUPLEX_FULL; + else + info->duplex = ODP_PKTIO_LINK_DUPLEX_UNKNOWN; + + info->pause_rx = pcmd.rx_pause ? ODP_PKTIO_LINK_PAUSE_ON : ODP_PKTIO_LINK_PAUSE_OFF; + info->pause_tx = pcmd.tx_pause ? ODP_PKTIO_LINK_PAUSE_ON : ODP_PKTIO_LINK_PAUSE_OFF; + + if (ecmd_old.port == PORT_TP) + info->media = "copper"; + else if (ecmd_old.port == PORT_FIBRE) + info->media = "fiber"; + else if (ecmd_old.port == PORT_OTHER) + info->media = "other"; + else + info->media = "unknown"; + + info->status = status; + + return 0; + } + + if (hcmd.link_mode_masks_nwords >= 0 || hcmd.cmd != ETHTOOL_GLINKSETTINGS) { + ODP_ERR("ETHTOOL_GLINKSETTINGS handshake failed\n"); + return -1; + } + /* Absolute value indicates kernel recommended 'link_mode_masks_nwords' value. */ + hcmd.link_mode_masks_nwords = -hcmd.link_mode_masks_nwords; + + /* Reserve space for the three bitmasks (map_supported, map_advertising, map_lp_advertising) + * at the end of struct ethtool_link_settings. 'link_mode_masks_nwords' defines the bitmask + * length in 32-bit words. */ + uint8_t ODP_ALIGNED_CACHE data[offsetof(struct ethtool_link_settings, link_mode_masks) + + (3 * sizeof(uint32_t) * hcmd.link_mode_masks_nwords)]; + + ecmd = (void *)data; + *ecmd = hcmd; + ifr.ifr_data = (void *)ecmd; + if (ioctl(fd, SIOCETHTOOL, &ifr) < 0) { + __odp_errno = errno; + ODP_ERR("ioctl(SIOCETHTOOL): %s: \"%s\".\n", strerror(errno), + ifr.ifr_name); return -1; } - return !!(ifr.ifr_flags & IFF_RUNNING); + memset(info, 0, sizeof(odp_pktio_link_info_t)); + if (ecmd->speed == (uint32_t)SPEED_UNKNOWN) + info->speed = ODP_PKTIO_LINK_SPEED_UNKNOWN; + else + info->speed = ecmd->speed; + + if (ecmd->autoneg == AUTONEG_ENABLE) + info->autoneg = ODP_PKTIO_LINK_AUTONEG_ON; + else if (ecmd->autoneg == AUTONEG_DISABLE) + info->autoneg = ODP_PKTIO_LINK_AUTONEG_OFF; + else + info->autoneg = ODP_PKTIO_LINK_AUTONEG_UNKNOWN; + + if (ecmd->duplex == DUPLEX_HALF) + info->duplex = ODP_PKTIO_LINK_DUPLEX_HALF; + else if (ecmd->duplex == DUPLEX_FULL) + info->duplex = ODP_PKTIO_LINK_DUPLEX_FULL; + else + info->duplex = ODP_PKTIO_LINK_DUPLEX_UNKNOWN; + + info->pause_rx = pcmd.rx_pause ? ODP_PKTIO_LINK_PAUSE_ON : ODP_PKTIO_LINK_PAUSE_OFF; + info->pause_tx = pcmd.tx_pause ? ODP_PKTIO_LINK_PAUSE_ON : ODP_PKTIO_LINK_PAUSE_OFF; + + if (ecmd->port == PORT_TP) + info->media = "copper"; + else if (ecmd->port == PORT_FIBRE) + info->media = "fiber"; + else if (ecmd->port == PORT_OTHER) + info->media = "other"; + else + info->media = "unknown"; + + info->status = status; + + return 0; } diff --git a/platform/linux-generic/pktio/socket_mmap.c b/platform/linux-generic/pktio/socket_mmap.c index bf1cbad81..d0d37636d 100644 --- a/platform/linux-generic/pktio/socket_mmap.c +++ b/platform/linux-generic/pktio/socket_mmap.c @@ -784,6 +784,11 @@ static int sock_mmap_link_status(pktio_entry_t *pktio_entry) pktio_entry->s.name); } +static int sock_mmap_link_info(pktio_entry_t *pktio_entry, odp_pktio_link_info_t *info) +{ + return link_info_fd(pkt_priv(pktio_entry)->sockfd, pktio_entry->s.name, info); +} + static int sock_mmap_capability(pktio_entry_t *pktio_entry ODP_UNUSED, odp_pktio_capability_t *capa) { @@ -860,6 +865,7 @@ const pktio_if_ops_t sock_mmap_pktio_ops = { .mac_get = sock_mmap_mac_addr_get, .mac_set = NULL, .link_status = sock_mmap_link_status, + .link_info = sock_mmap_link_info, .capability = sock_mmap_capability, .pktin_ts_res = NULL, .pktin_ts_from_ns = NULL, diff --git a/platform/linux-generic/pktio/tap.c b/platform/linux-generic/pktio/tap.c index db5c701b2..13a9feaf8 100644 --- a/platform/linux-generic/pktio/tap.c +++ b/platform/linux-generic/pktio/tap.c @@ -467,6 +467,11 @@ static int tap_link_status(pktio_entry_t *pktio_entry) pktio_entry->s.name + 4); } +static int tap_link_info(pktio_entry_t *pktio_entry, odp_pktio_link_info_t *info) +{ + return link_info_fd(pkt_priv(pktio_entry)->skfd, pktio_entry->s.name + 4, info); +} + static int tap_capability(pktio_entry_t *pktio_entry ODP_UNUSED, odp_pktio_capability_t *capa) { @@ -501,6 +506,7 @@ const pktio_if_ops_t tap_pktio_ops = { .mac_get = tap_mac_addr_get, .mac_set = tap_mac_addr_set, .link_status = tap_link_status, + .link_info = tap_link_info, .capability = tap_capability, .pktin_ts_res = NULL, .pktin_ts_from_ns = NULL, diff --git a/platform/linux-generic/test/pktio_ipc/ipc_common.c b/platform/linux-generic/test/pktio_ipc/ipc_common.c index b064177bc..655cd80d5 100644 --- a/platform/linux-generic/test/pktio_ipc/ipc_common.c +++ b/platform/linux-generic/test/pktio_ipc/ipc_common.c @@ -22,6 +22,7 @@ int ipc_odp_packet_send_or_free(odp_pktio_t pktio, odp_pktout_queue_t pktout; int i; + memset(&pktout, 0, sizeof(pktout)); start_time = odp_time_local(); wait = odp_time_local_from_ns(ODP_TIME_SEC_IN_NS); end_time = odp_time_sum(start_time, wait); diff --git a/platform/linux-generic/test/pktio_ipc/pktio_ipc2.c b/platform/linux-generic/test/pktio_ipc/pktio_ipc2.c index 0d64e94ba..9d4f91341 100644 --- a/platform/linux-generic/test/pktio_ipc/pktio_ipc2.c +++ b/platform/linux-generic/test/pktio_ipc/pktio_ipc2.c @@ -73,6 +73,7 @@ static int ipc_second_process(int master_pid) return -1; } + memset(&pktin, 0, sizeof(pktin)); /* not needed but makes GCC happy */ if (odp_pktin_queue(ipc_pktio, &pktin, 1) != 1) { odp_pool_destroy(pool); ODPH_ERR("no input queue\n"); |