summaryrefslogtreecommitdiffstats
path: root/src/seastar/dpdk/examples/ethtool
diff options
context:
space:
mode:
Diffstat (limited to 'src/seastar/dpdk/examples/ethtool')
-rw-r--r--src/seastar/dpdk/examples/ethtool/Makefile23
-rw-r--r--src/seastar/dpdk/examples/ethtool/ethtool-app/Makefile31
-rw-r--r--src/seastar/dpdk/examples/ethtool/ethtool-app/ethapp.c910
-rw-r--r--src/seastar/dpdk/examples/ethtool/ethtool-app/ethapp.h12
-rw-r--r--src/seastar/dpdk/examples/ethtool/ethtool-app/main.c282
-rw-r--r--src/seastar/dpdk/examples/ethtool/lib/Makefile37
-rw-r--r--src/seastar/dpdk/examples/ethtool/lib/rte_ethtool.c453
-rw-r--r--src/seastar/dpdk/examples/ethtool/lib/rte_ethtool.h415
-rw-r--r--src/seastar/dpdk/examples/ethtool/meson.build10
9 files changed, 2173 insertions, 0 deletions
diff --git a/src/seastar/dpdk/examples/ethtool/Makefile b/src/seastar/dpdk/examples/ethtool/Makefile
new file mode 100644
index 000000000..d3b97bb50
--- /dev/null
+++ b/src/seastar/dpdk/examples/ethtool/Makefile
@@ -0,0 +1,23 @@
+# SPDX-License-Identifier: BSD-3-Clause
+# Copyright(c) 2015 Intel Corporation
+
+ifeq ($(RTE_SDK),)
+$(error "Please define RTE_SDK environment variable")
+endif
+
+# Default target, detect a build directory, by looking for a path with a .config
+RTE_TARGET ?= $(notdir $(abspath $(dir $(firstword $(wildcard $(RTE_SDK)/*/.config)))))
+
+include $(RTE_SDK)/mk/rte.vars.mk
+
+ifneq ($(CONFIG_RTE_EXEC_ENV_LINUX),y)
+$(info This application can only operate in a linux environment, \
+please change the definition of the RTE_TARGET environment variable)
+else
+
+DIRS-y += lib ethtool-app
+endif
+
+DEPDIRS-ethtool-app := lib
+
+include $(RTE_SDK)/mk/rte.extsubdir.mk
diff --git a/src/seastar/dpdk/examples/ethtool/ethtool-app/Makefile b/src/seastar/dpdk/examples/ethtool/ethtool-app/Makefile
new file mode 100644
index 000000000..3543bdee0
--- /dev/null
+++ b/src/seastar/dpdk/examples/ethtool/ethtool-app/Makefile
@@ -0,0 +1,31 @@
+# SPDX-License-Identifier: BSD-3-Clause
+# Copyright(c) 2010-2014 Intel Corporation
+
+ifeq ($(RTE_SDK),)
+$(error "Please define RTE_SDK environment variable")
+endif
+
+# Default target, detect a build directory, by looking for a path with a .config
+RTE_TARGET ?= $(notdir $(abspath $(dir $(firstword $(wildcard $(RTE_SDK)/*/.config)))))
+
+include $(RTE_SDK)/mk/rte.vars.mk
+
+# binary name
+APP = ethtool
+
+# all source are stored in SRCS-y
+SRCS-y := main.c ethapp.c
+
+CFLAGS += -O3 -pthread -I$(SRCDIR)/../lib
+CFLAGS += $(WERROR_FLAGS)
+
+LDLIBS += -L$(subst ethtool-app,lib,$(RTE_OUTPUT))/lib
+LDLIBS += -lrte_ethtool
+
+ifeq ($(CONFIG_RTE_BUILD_SHARED_LIB),y)
+ifeq ($(CONFIG_RTE_LIBRTE_IXGBE_PMD),y)
+LDLIBS += -lrte_pmd_ixgbe
+endif
+endif
+
+include $(RTE_SDK)/mk/rte.extapp.mk
diff --git a/src/seastar/dpdk/examples/ethtool/ethtool-app/ethapp.c b/src/seastar/dpdk/examples/ethtool/ethtool-app/ethapp.c
new file mode 100644
index 000000000..a4e64b354
--- /dev/null
+++ b/src/seastar/dpdk/examples/ethtool/ethtool-app/ethapp.c
@@ -0,0 +1,910 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2015 Intel Corporation
+ */
+
+#include <cmdline_parse.h>
+#include <cmdline_parse_num.h>
+#include <cmdline_parse_string.h>
+#include <cmdline_parse_etheraddr.h>
+#include <cmdline_socket.h>
+#include <cmdline.h>
+
+#include "rte_ethtool.h"
+#include "ethapp.h"
+
+#define EEPROM_DUMP_CHUNKSIZE 1024
+
+
+struct pcmd_get_params {
+ cmdline_fixed_string_t cmd;
+};
+struct pcmd_int_params {
+ cmdline_fixed_string_t cmd;
+ uint16_t port;
+};
+struct pcmd_intstr_params {
+ cmdline_fixed_string_t cmd;
+ uint16_t port;
+ cmdline_fixed_string_t opt;
+};
+struct pcmd_intmac_params {
+ cmdline_fixed_string_t cmd;
+ uint16_t port;
+ struct ether_addr mac;
+};
+struct pcmd_str_params {
+ cmdline_fixed_string_t cmd;
+ cmdline_fixed_string_t opt;
+};
+struct pcmd_vlan_params {
+ cmdline_fixed_string_t cmd;
+ uint16_t port;
+ cmdline_fixed_string_t mode;
+ uint16_t vid;
+};
+struct pcmd_intintint_params {
+ cmdline_fixed_string_t cmd;
+ uint16_t port;
+ uint16_t tx;
+ uint16_t rx;
+};
+
+
+/* Parameter-less commands */
+cmdline_parse_token_string_t pcmd_quit_token_cmd =
+ TOKEN_STRING_INITIALIZER(struct pcmd_get_params, cmd, "quit");
+cmdline_parse_token_string_t pcmd_stats_token_cmd =
+ TOKEN_STRING_INITIALIZER(struct pcmd_get_params, cmd, "stats");
+cmdline_parse_token_string_t pcmd_drvinfo_token_cmd =
+ TOKEN_STRING_INITIALIZER(struct pcmd_get_params, cmd, "drvinfo");
+cmdline_parse_token_string_t pcmd_link_token_cmd =
+ TOKEN_STRING_INITIALIZER(struct pcmd_get_params, cmd, "link");
+
+/* Commands taking just port id */
+cmdline_parse_token_string_t pcmd_open_token_cmd =
+ TOKEN_STRING_INITIALIZER(struct pcmd_int_params, cmd, "open");
+cmdline_parse_token_string_t pcmd_stop_token_cmd =
+ TOKEN_STRING_INITIALIZER(struct pcmd_int_params, cmd, "stop");
+cmdline_parse_token_string_t pcmd_rxmode_token_cmd =
+ TOKEN_STRING_INITIALIZER(struct pcmd_int_params, cmd, "rxmode");
+cmdline_parse_token_string_t pcmd_portstats_token_cmd =
+ TOKEN_STRING_INITIALIZER(struct pcmd_int_params, cmd, "portstats");
+cmdline_parse_token_num_t pcmd_int_token_port =
+ TOKEN_NUM_INITIALIZER(struct pcmd_int_params, port, UINT16);
+
+/* Commands taking port id and string */
+cmdline_parse_token_string_t pcmd_eeprom_token_cmd =
+ TOKEN_STRING_INITIALIZER(struct pcmd_intstr_params, cmd, "eeprom");
+cmdline_parse_token_string_t pcmd_module_eeprom_token_cmd =
+ TOKEN_STRING_INITIALIZER(struct pcmd_intstr_params, cmd,
+ "module-eeprom");
+cmdline_parse_token_string_t pcmd_mtu_token_cmd =
+ TOKEN_STRING_INITIALIZER(struct pcmd_intstr_params, cmd, "mtu");
+cmdline_parse_token_string_t pcmd_regs_token_cmd =
+ TOKEN_STRING_INITIALIZER(struct pcmd_intstr_params, cmd, "regs");
+
+cmdline_parse_token_num_t pcmd_intstr_token_port =
+ TOKEN_NUM_INITIALIZER(struct pcmd_intstr_params, port, UINT16);
+cmdline_parse_token_string_t pcmd_intstr_token_opt =
+ TOKEN_STRING_INITIALIZER(struct pcmd_intstr_params, opt, NULL);
+
+/* Commands taking port id and a MAC address string */
+cmdline_parse_token_string_t pcmd_macaddr_token_cmd =
+ TOKEN_STRING_INITIALIZER(struct pcmd_intmac_params, cmd, "macaddr");
+cmdline_parse_token_num_t pcmd_intmac_token_port =
+ TOKEN_NUM_INITIALIZER(struct pcmd_intmac_params, port, UINT16);
+cmdline_parse_token_etheraddr_t pcmd_intmac_token_mac =
+ TOKEN_ETHERADDR_INITIALIZER(struct pcmd_intmac_params, mac);
+
+/* Command taking just a MAC address */
+cmdline_parse_token_string_t pcmd_validate_token_cmd =
+ TOKEN_STRING_INITIALIZER(struct pcmd_intmac_params, cmd, "validate");
+
+
+/* Commands taking port id and two integers */
+cmdline_parse_token_string_t pcmd_ringparam_token_cmd =
+ TOKEN_STRING_INITIALIZER(struct pcmd_intintint_params, cmd,
+ "ringparam");
+cmdline_parse_token_num_t pcmd_intintint_token_port =
+ TOKEN_NUM_INITIALIZER(struct pcmd_intintint_params, port, UINT16);
+cmdline_parse_token_num_t pcmd_intintint_token_tx =
+ TOKEN_NUM_INITIALIZER(struct pcmd_intintint_params, tx, UINT16);
+cmdline_parse_token_num_t pcmd_intintint_token_rx =
+ TOKEN_NUM_INITIALIZER(struct pcmd_intintint_params, rx, UINT16);
+
+
+/* Pause commands */
+cmdline_parse_token_string_t pcmd_pause_token_cmd =
+ TOKEN_STRING_INITIALIZER(struct pcmd_intstr_params, cmd, "pause");
+cmdline_parse_token_num_t pcmd_pause_token_port =
+ TOKEN_NUM_INITIALIZER(struct pcmd_intstr_params, port, UINT16);
+cmdline_parse_token_string_t pcmd_pause_token_opt =
+ TOKEN_STRING_INITIALIZER(struct pcmd_intstr_params,
+ opt, "all#tx#rx#none");
+
+/* VLAN commands */
+cmdline_parse_token_string_t pcmd_vlan_token_cmd =
+ TOKEN_STRING_INITIALIZER(struct pcmd_vlan_params, cmd, "vlan");
+cmdline_parse_token_num_t pcmd_vlan_token_port =
+ TOKEN_NUM_INITIALIZER(struct pcmd_vlan_params, port, UINT16);
+cmdline_parse_token_string_t pcmd_vlan_token_mode =
+ TOKEN_STRING_INITIALIZER(struct pcmd_vlan_params, mode, "add#del");
+cmdline_parse_token_num_t pcmd_vlan_token_vid =
+ TOKEN_NUM_INITIALIZER(struct pcmd_vlan_params, vid, UINT16);
+
+
+static void
+pcmd_quit_callback(__rte_unused void *ptr_params,
+ struct cmdline *ctx,
+ __rte_unused void *ptr_data)
+{
+ cmdline_quit(ctx);
+}
+
+
+static void
+pcmd_drvinfo_callback(__rte_unused void *ptr_params,
+ __rte_unused struct cmdline *ctx,
+ __rte_unused void *ptr_data)
+{
+ struct ethtool_drvinfo info;
+ uint16_t id_port;
+
+ RTE_ETH_FOREACH_DEV(id_port) {
+ memset(&info, 0, sizeof(info));
+ if (rte_ethtool_get_drvinfo(id_port, &info)) {
+ printf("Error getting info for port %i\n", id_port);
+ return;
+ }
+ printf("Port %i driver: %s (ver: %s)\n",
+ id_port, info.driver, info.version
+ );
+ printf("firmware-version: %s\n", info.fw_version);
+ printf("bus-info: %s\n", info.bus_info);
+ }
+}
+
+
+static void
+pcmd_link_callback(__rte_unused void *ptr_params,
+ __rte_unused struct cmdline *ctx,
+ __rte_unused void *ptr_data)
+{
+ uint16_t id_port;
+ int stat_port;
+
+ RTE_ETH_FOREACH_DEV(id_port) {
+ if (!rte_eth_dev_is_valid_port(id_port))
+ continue;
+ stat_port = rte_ethtool_get_link(id_port);
+ switch (stat_port) {
+ case 0:
+ printf("Port %i: Down\n", id_port);
+ break;
+ case 1:
+ printf("Port %i: Up\n", id_port);
+ break;
+ default:
+ printf("Port %i: Error getting link status\n",
+ id_port
+ );
+ break;
+ }
+ }
+ printf("\n");
+}
+
+
+static void
+pcmd_regs_callback(void *ptr_params,
+ __rte_unused struct cmdline *ctx,
+ __rte_unused void *ptr_data)
+{
+ struct pcmd_intstr_params *params = ptr_params;
+ int len_regs;
+ struct ethtool_regs regs;
+ unsigned char *buf_data;
+ FILE *fp_regs;
+
+ if (!rte_eth_dev_is_valid_port(params->port)) {
+ printf("Error: Invalid port number %i\n", params->port);
+ return;
+ }
+ len_regs = rte_ethtool_get_regs_len(params->port);
+ if (len_regs > 0) {
+ printf("Port %i: %i bytes\n", params->port, len_regs);
+ buf_data = malloc(len_regs);
+ if (buf_data == NULL) {
+ printf("Error allocating %i bytes for buffer\n",
+ len_regs);
+ return;
+ }
+ if (!rte_ethtool_get_regs(params->port, &regs, buf_data)) {
+ fp_regs = fopen(params->opt, "wb");
+ if (fp_regs == NULL) {
+ printf("Error opening '%s' for writing\n",
+ params->opt);
+ } else {
+ if ((int)fwrite(buf_data,
+ 1, len_regs,
+ fp_regs) != len_regs)
+ printf("Error writing '%s'\n",
+ params->opt);
+ fclose(fp_regs);
+ }
+ }
+ free(buf_data);
+ } else if (len_regs == -ENOTSUP)
+ printf("Port %i: Operation not supported\n", params->port);
+ else
+ printf("Port %i: Error getting registers\n", params->port);
+}
+
+
+static void
+pcmd_eeprom_callback(void *ptr_params,
+ __rte_unused struct cmdline *ctx,
+ __rte_unused void *ptr_data)
+{
+ struct pcmd_intstr_params *params = ptr_params;
+ struct ethtool_eeprom info_eeprom;
+ int len_eeprom;
+ int pos_eeprom;
+ int stat;
+ unsigned char bytes_eeprom[EEPROM_DUMP_CHUNKSIZE];
+ FILE *fp_eeprom;
+
+ if (!rte_eth_dev_is_valid_port(params->port)) {
+ printf("Error: Invalid port number %i\n", params->port);
+ return;
+ }
+ len_eeprom = rte_ethtool_get_eeprom_len(params->port);
+ if (len_eeprom > 0) {
+ fp_eeprom = fopen(params->opt, "wb");
+ if (fp_eeprom == NULL) {
+ printf("Error opening '%s' for writing\n",
+ params->opt);
+ return;
+ }
+ printf("Total EEPROM length: %i bytes\n", len_eeprom);
+ info_eeprom.len = EEPROM_DUMP_CHUNKSIZE;
+ for (pos_eeprom = 0;
+ pos_eeprom < len_eeprom;
+ pos_eeprom += EEPROM_DUMP_CHUNKSIZE) {
+ info_eeprom.offset = pos_eeprom;
+ if (pos_eeprom + EEPROM_DUMP_CHUNKSIZE > len_eeprom)
+ info_eeprom.len = len_eeprom - pos_eeprom;
+ else
+ info_eeprom.len = EEPROM_DUMP_CHUNKSIZE;
+ stat = rte_ethtool_get_eeprom(
+ params->port, &info_eeprom, bytes_eeprom
+ );
+ if (stat != 0) {
+ printf("EEPROM read error %i\n", stat);
+ break;
+ }
+ if (fwrite(bytes_eeprom,
+ 1, info_eeprom.len,
+ fp_eeprom) != info_eeprom.len) {
+ printf("Error writing '%s'\n", params->opt);
+ break;
+ }
+ }
+ fclose(fp_eeprom);
+ } else if (len_eeprom == 0)
+ printf("Port %i: Device does not have EEPROM\n", params->port);
+ else if (len_eeprom == -ENOTSUP)
+ printf("Port %i: Operation not supported\n", params->port);
+ else
+ printf("Port %i: Error getting EEPROM\n", params->port);
+}
+
+
+static void
+pcmd_module_eeprom_callback(void *ptr_params,
+ __rte_unused struct cmdline *ctx,
+ __rte_unused void *ptr_data)
+{
+ struct pcmd_intstr_params *params = ptr_params;
+ struct ethtool_eeprom info_eeprom;
+ uint32_t module_info[2];
+ int stat;
+ unsigned char bytes_eeprom[EEPROM_DUMP_CHUNKSIZE];
+ FILE *fp_eeprom;
+
+ if (!rte_eth_dev_is_valid_port(params->port)) {
+ printf("Error: Invalid port number %i\n", params->port);
+ return;
+ }
+
+ stat = rte_ethtool_get_module_info(params->port, module_info);
+ if (stat != 0) {
+ printf("Module EEPROM information read error %i\n", stat);
+ return;
+ }
+
+ info_eeprom.len = module_info[1];
+ info_eeprom.offset = 0;
+
+ stat = rte_ethtool_get_module_eeprom(params->port,
+ &info_eeprom, bytes_eeprom);
+ if (stat != 0) {
+ printf("Module EEPROM read error %i\n", stat);
+ return;
+ }
+
+ fp_eeprom = fopen(params->opt, "wb");
+ if (fp_eeprom == NULL) {
+ printf("Error opening '%s' for writing\n", params->opt);
+ return;
+ }
+ printf("Total plugin module EEPROM length: %i bytes\n",
+ info_eeprom.len);
+ if (fwrite(bytes_eeprom, 1, info_eeprom.len,
+ fp_eeprom) != info_eeprom.len) {
+ printf("Error writing '%s'\n", params->opt);
+ }
+ fclose(fp_eeprom);
+}
+
+
+static void
+pcmd_pause_callback(void *ptr_params,
+ __rte_unused struct cmdline *ctx,
+ void *ptr_data)
+{
+ struct pcmd_intstr_params *params = ptr_params;
+ struct ethtool_pauseparam info;
+ int stat;
+
+ if (!rte_eth_dev_is_valid_port(params->port)) {
+ printf("Error: Invalid port number %i\n", params->port);
+ return;
+ }
+ if (ptr_data != NULL) {
+ stat = rte_ethtool_get_pauseparam(params->port, &info);
+ } else {
+ memset(&info, 0, sizeof(info));
+ if (strcasecmp("all", params->opt) == 0) {
+ info.tx_pause = 1;
+ info.rx_pause = 1;
+ } else if (strcasecmp("tx", params->opt) == 0) {
+ info.tx_pause = 1;
+ info.rx_pause = 0;
+ } else if (strcasecmp("rx", params->opt) == 0) {
+ info.tx_pause = 0;
+ info.rx_pause = 1;
+ } else {
+ info.tx_pause = 0;
+ info.rx_pause = 0;
+ }
+ /* Assume auto-negotiation wanted */
+ info.autoneg = 1;
+ stat = rte_ethtool_set_pauseparam(params->port, &info);
+ }
+ if (stat == 0) {
+ if (info.rx_pause && info.tx_pause)
+ printf("Port %i: Tx & Rx Paused\n", params->port);
+ else if (info.rx_pause)
+ printf("Port %i: Rx Paused\n", params->port);
+ else if (info.tx_pause)
+ printf("Port %i: Tx Paused\n", params->port);
+ else
+ printf("Port %i: Tx & Rx not paused\n", params->port);
+ } else if (stat == -ENOTSUP)
+ printf("Port %i: Operation not supported\n", params->port);
+ else
+ printf("Port %i: Error %i\n", params->port, stat);
+}
+
+
+static void
+pcmd_open_callback(__rte_unused void *ptr_params,
+ __rte_unused struct cmdline *ctx,
+ __rte_unused void *ptr_data)
+{
+ struct pcmd_int_params *params = ptr_params;
+ int stat;
+
+ if (!rte_eth_dev_is_valid_port(params->port)) {
+ printf("Error: Invalid port number %i\n", params->port);
+ return;
+ }
+ lock_port(params->port);
+ stat = rte_ethtool_net_open(params->port);
+ mark_port_active(params->port);
+ unlock_port(params->port);
+ if (stat == 0)
+ return;
+ else if (stat == -ENOTSUP)
+ printf("Port %i: Operation not supported\n", params->port);
+ else
+ printf("Port %i: Error opening device\n", params->port);
+}
+
+static void
+pcmd_stop_callback(__rte_unused void *ptr_params,
+ __rte_unused struct cmdline *ctx,
+ __rte_unused void *ptr_data)
+{
+ struct pcmd_int_params *params = ptr_params;
+ int stat;
+
+ if (!rte_eth_dev_is_valid_port(params->port)) {
+ printf("Error: Invalid port number %i\n", params->port);
+ return;
+ }
+ lock_port(params->port);
+ stat = rte_ethtool_net_stop(params->port);
+ mark_port_inactive(params->port);
+ unlock_port(params->port);
+ if (stat == 0)
+ return;
+ else if (stat == -ENOTSUP)
+ printf("Port %i: Operation not supported\n", params->port);
+ else
+ printf("Port %i: Error stopping device\n", params->port);
+}
+
+
+static void
+pcmd_rxmode_callback(void *ptr_params,
+ __rte_unused struct cmdline *ctx,
+ __rte_unused void *ptr_data)
+{
+ struct pcmd_intstr_params *params = ptr_params;
+ int stat;
+
+ if (!rte_eth_dev_is_valid_port(params->port)) {
+ printf("Error: Invalid port number %i\n", params->port);
+ return;
+ }
+ stat = rte_ethtool_net_set_rx_mode(params->port);
+ if (stat == 0)
+ return;
+ else if (stat == -ENOTSUP)
+ printf("Port %i: Operation not supported\n", params->port);
+ else
+ printf("Port %i: Error setting rx mode\n", params->port);
+}
+
+
+static void
+pcmd_macaddr_callback(void *ptr_params,
+ __rte_unused struct cmdline *ctx,
+ void *ptr_data)
+{
+ struct pcmd_intmac_params *params = ptr_params;
+ struct ether_addr mac_addr;
+ int stat;
+
+ stat = 0;
+ if (!rte_eth_dev_is_valid_port(params->port)) {
+ printf("Error: Invalid port number %i\n", params->port);
+ return;
+ }
+ if (ptr_data != NULL) {
+ lock_port(params->port);
+ stat = rte_ethtool_net_set_mac_addr(params->port,
+ &params->mac);
+ mark_port_newmac(params->port);
+ unlock_port(params->port);
+ if (stat == 0) {
+ printf("MAC address changed\n");
+ return;
+ }
+ } else {
+ stat = rte_ethtool_net_get_mac_addr(params->port, &mac_addr);
+ if (stat == 0) {
+ printf(
+ "Port %i MAC Address: %02x:%02x:%02x:%02x:%02x:%02x\n",
+ params->port,
+ mac_addr.addr_bytes[0],
+ mac_addr.addr_bytes[1],
+ mac_addr.addr_bytes[2],
+ mac_addr.addr_bytes[3],
+ mac_addr.addr_bytes[4],
+ mac_addr.addr_bytes[5]);
+ return;
+ }
+ }
+
+ printf("Port %i: Error %s\n", params->port,
+ strerror(-stat));
+}
+
+static void
+pcmd_mtu_callback(void *ptr_params,
+ __rte_unused struct cmdline *ctx,
+ __rte_unused void *ptr_data)
+{
+ struct pcmd_intstr_params *params = ptr_params;
+ int stat;
+ int new_mtu;
+ char *ptr_parse_end;
+
+ if (!rte_eth_dev_is_valid_port(params->port)) {
+ printf("Error: Invalid port number %i\n", params->port);
+ return;
+ }
+ new_mtu = atoi(params->opt);
+ new_mtu = strtoul(params->opt, &ptr_parse_end, 10);
+ if (*ptr_parse_end != '\0' ||
+ new_mtu < ETHER_MIN_MTU ||
+ new_mtu > ETHER_MAX_JUMBO_FRAME_LEN) {
+ printf("Port %i: Invalid MTU value\n", params->port);
+ return;
+ }
+ stat = rte_ethtool_net_change_mtu(params->port, new_mtu);
+ if (stat == 0)
+ printf("Port %i: MTU set to %i\n", params->port, new_mtu);
+ else if (stat == -ENOTSUP)
+ printf("Port %i: Operation not supported\n", params->port);
+ else
+ printf("Port %i: Error setting MTU\n", params->port);
+}
+
+
+
+static void pcmd_portstats_callback(__rte_unused void *ptr_params,
+ __rte_unused struct cmdline *ctx,
+ __rte_unused void *ptr_data)
+{
+ struct pcmd_int_params *params = ptr_params;
+ struct rte_eth_stats stat_info;
+ int stat;
+
+ if (!rte_eth_dev_is_valid_port(params->port)) {
+ printf("Error: Invalid port number %i\n", params->port);
+ return;
+ }
+ stat = rte_ethtool_net_get_stats64(params->port, &stat_info);
+ if (stat == 0) {
+ printf("Port %i stats\n", params->port);
+ printf(" In: %" PRIu64 " (%" PRIu64 " bytes)\n"
+ " Out: %"PRIu64" (%"PRIu64 " bytes)\n"
+ " Err: %"PRIu64"\n",
+ stat_info.ipackets,
+ stat_info.ibytes,
+ stat_info.opackets,
+ stat_info.obytes,
+ stat_info.ierrors+stat_info.oerrors
+ );
+ } else if (stat == -ENOTSUP)
+ printf("Port %i: Operation not supported\n", params->port);
+ else
+ printf("Port %i: Error fetching statistics\n", params->port);
+}
+
+static void pcmd_ringparam_callback(__rte_unused void *ptr_params,
+ __rte_unused struct cmdline *ctx,
+ void *ptr_data)
+{
+ struct pcmd_intintint_params *params = ptr_params;
+ struct ethtool_ringparam ring_data;
+ struct ethtool_ringparam ring_params;
+ int stat;
+
+ if (!rte_eth_dev_is_valid_port(params->port)) {
+ printf("Error: Invalid port number %i\n", params->port);
+ return;
+ }
+ if (ptr_data == NULL) {
+ stat = rte_ethtool_get_ringparam(params->port, &ring_data);
+ if (stat == 0) {
+ printf("Port %i ring parameters\n"
+ " Rx Pending: %i (%i max)\n"
+ " Tx Pending: %i (%i max)\n",
+ params->port,
+ ring_data.rx_pending,
+ ring_data.rx_max_pending,
+ ring_data.tx_pending,
+ ring_data.tx_max_pending);
+ }
+ } else {
+ if (params->tx < 1 || params->rx < 1) {
+ printf("Error: Invalid parameters\n");
+ return;
+ }
+ memset(&ring_params, 0, sizeof(struct ethtool_ringparam));
+ ring_params.tx_pending = params->tx;
+ ring_params.rx_pending = params->rx;
+ lock_port(params->port);
+ stat = rte_ethtool_set_ringparam(params->port, &ring_params);
+ unlock_port(params->port);
+ }
+ if (stat == 0)
+ return;
+ else if (stat == -ENOTSUP)
+ printf("Port %i: Operation not supported\n", params->port);
+ else
+ printf("Port %i: Error fetching statistics\n", params->port);
+}
+
+static void pcmd_validate_callback(void *ptr_params,
+ __rte_unused struct cmdline *ctx,
+ __rte_unused void *ptr_data)
+{
+ struct pcmd_intmac_params *params = ptr_params;
+
+ if (rte_ethtool_net_validate_addr(0, &params->mac))
+ printf("Address is unicast\n");
+ else
+ printf("Address is not unicast\n");
+}
+
+
+static void pcmd_vlan_callback(__rte_unused void *ptr_params,
+ __rte_unused struct cmdline *ctx,
+ __rte_unused void *ptr_data)
+{
+ struct pcmd_vlan_params *params = ptr_params;
+ int stat;
+
+ if (!rte_eth_dev_is_valid_port(params->port)) {
+ printf("Error: Invalid port number %i\n", params->port);
+ return;
+ }
+ stat = 0;
+
+ if (strcasecmp("add", params->mode) == 0) {
+ stat = rte_ethtool_net_vlan_rx_add_vid(
+ params->port, params->vid
+ );
+ if (stat == 0)
+ printf("VLAN vid %i added\n", params->vid);
+
+ } else if (strcasecmp("del", params->mode) == 0) {
+ stat = rte_ethtool_net_vlan_rx_kill_vid(
+ params->port, params->vid
+ );
+ if (stat == 0)
+ printf("VLAN vid %i removed\n", params->vid);
+ } else {
+ /* Should not happen! */
+ printf("Error: Bad mode %s\n", params->mode);
+ }
+ if (stat == -ENOTSUP)
+ printf("Port %i: Operation not supported\n", params->port);
+ else if (stat == -ENOSYS)
+ printf("Port %i: VLAN filtering disabled\n", params->port);
+ else if (stat != 0)
+ printf("Port %i: Error changing VLAN setup (code %i)\n",
+ params->port, -stat);
+}
+
+
+cmdline_parse_inst_t pcmd_quit = {
+ .f = pcmd_quit_callback,
+ .data = NULL,
+ .help_str = "quit\n Exit program",
+ .tokens = {(void *)&pcmd_quit_token_cmd, NULL},
+};
+cmdline_parse_inst_t pcmd_drvinfo = {
+ .f = pcmd_drvinfo_callback,
+ .data = NULL,
+ .help_str = "drvinfo\n Print driver info",
+ .tokens = {(void *)&pcmd_drvinfo_token_cmd, NULL},
+};
+cmdline_parse_inst_t pcmd_link = {
+ .f = pcmd_link_callback,
+ .data = NULL,
+ .help_str = "link\n Print port link states",
+ .tokens = {(void *)&pcmd_link_token_cmd, NULL},
+};
+cmdline_parse_inst_t pcmd_regs = {
+ .f = pcmd_regs_callback,
+ .data = NULL,
+ .help_str = "regs <port_id> <filename>\n"
+ " Dump port register(s) to file",
+ .tokens = {
+ (void *)&pcmd_regs_token_cmd,
+ (void *)&pcmd_intstr_token_port,
+ (void *)&pcmd_intstr_token_opt,
+ NULL
+ },
+};
+cmdline_parse_inst_t pcmd_eeprom = {
+ .f = pcmd_eeprom_callback,
+ .data = NULL,
+ .help_str = "eeprom <port_id> <filename>\n Dump EEPROM to file",
+ .tokens = {
+ (void *)&pcmd_eeprom_token_cmd,
+ (void *)&pcmd_intstr_token_port,
+ (void *)&pcmd_intstr_token_opt,
+ NULL
+ },
+};
+cmdline_parse_inst_t pcmd_module_eeprom = {
+ .f = pcmd_module_eeprom_callback,
+ .data = NULL,
+ .help_str = "module-eeprom <port_id> <filename>\n"
+ " Dump plugin module EEPROM to file",
+ .tokens = {
+ (void *)&pcmd_module_eeprom_token_cmd,
+ (void *)&pcmd_intstr_token_port,
+ (void *)&pcmd_intstr_token_opt,
+ NULL
+ },
+};
+cmdline_parse_inst_t pcmd_pause_noopt = {
+ .f = pcmd_pause_callback,
+ .data = (void *)0x01,
+ .help_str = "pause <port_id>\n Print port pause state",
+ .tokens = {
+ (void *)&pcmd_pause_token_cmd,
+ (void *)&pcmd_pause_token_port,
+ NULL
+ },
+};
+cmdline_parse_inst_t pcmd_pause = {
+ .f = pcmd_pause_callback,
+ .data = NULL,
+ .help_str =
+ "pause <port_id> <all|tx|rx|none>\n Pause/unpause port",
+ .tokens = {
+ (void *)&pcmd_pause_token_cmd,
+ (void *)&pcmd_pause_token_port,
+ (void *)&pcmd_pause_token_opt,
+ NULL
+ },
+};
+cmdline_parse_inst_t pcmd_open = {
+ .f = pcmd_open_callback,
+ .data = NULL,
+ .help_str = "open <port_id>\n Open port",
+ .tokens = {
+ (void *)&pcmd_open_token_cmd,
+ (void *)&pcmd_int_token_port,
+ NULL
+ },
+};
+cmdline_parse_inst_t pcmd_stop = {
+ .f = pcmd_stop_callback,
+ .data = NULL,
+ .help_str = "stop <port_id>\n Stop port",
+ .tokens = {
+ (void *)&pcmd_stop_token_cmd,
+ (void *)&pcmd_int_token_port,
+ NULL
+ },
+};
+cmdline_parse_inst_t pcmd_rxmode = {
+ .f = pcmd_rxmode_callback,
+ .data = NULL,
+ .help_str = "rxmode <port_id>\n Toggle port Rx mode",
+ .tokens = {
+ (void *)&pcmd_rxmode_token_cmd,
+ (void *)&pcmd_int_token_port,
+ NULL
+ },
+};
+cmdline_parse_inst_t pcmd_macaddr_get = {
+ .f = pcmd_macaddr_callback,
+ .data = NULL,
+ .help_str = "macaddr <port_id>\n"
+ " Get MAC address",
+ .tokens = {
+ (void *)&pcmd_macaddr_token_cmd,
+ (void *)&pcmd_intstr_token_port,
+ NULL
+ },
+};
+cmdline_parse_inst_t pcmd_macaddr = {
+ .f = pcmd_macaddr_callback,
+ .data = (void *)0x01,
+ .help_str =
+ "macaddr <port_id> <mac_addr>\n"
+ " Set MAC address",
+ .tokens = {
+ (void *)&pcmd_macaddr_token_cmd,
+ (void *)&pcmd_intmac_token_port,
+ (void *)&pcmd_intmac_token_mac,
+ NULL
+ },
+};
+cmdline_parse_inst_t pcmd_mtu = {
+ .f = pcmd_mtu_callback,
+ .data = NULL,
+ .help_str = "mtu <port_id> <mtu_value>\n"
+ " Change MTU",
+ .tokens = {
+ (void *)&pcmd_mtu_token_cmd,
+ (void *)&pcmd_intstr_token_port,
+ (void *)&pcmd_intstr_token_opt,
+ NULL
+ },
+};
+cmdline_parse_inst_t pcmd_portstats = {
+ .f = pcmd_portstats_callback,
+ .data = NULL,
+ .help_str = "portstats <port_id>\n"
+ " Print port eth statistics",
+ .tokens = {
+ (void *)&pcmd_portstats_token_cmd,
+ (void *)&pcmd_int_token_port,
+ NULL
+ },
+};
+cmdline_parse_inst_t pcmd_ringparam = {
+ .f = pcmd_ringparam_callback,
+ .data = NULL,
+ .help_str = "ringparam <port_id>\n"
+ " Print ring parameters",
+ .tokens = {
+ (void *)&pcmd_ringparam_token_cmd,
+ (void *)&pcmd_intintint_token_port,
+ NULL
+ },
+};
+cmdline_parse_inst_t pcmd_ringparam_set = {
+ .f = pcmd_ringparam_callback,
+ .data = (void *)1,
+ .help_str = "ringparam <port_id> <tx_param> <rx_param>\n"
+ " Set ring parameters",
+ .tokens = {
+ (void *)&pcmd_ringparam_token_cmd,
+ (void *)&pcmd_intintint_token_port,
+ (void *)&pcmd_intintint_token_tx,
+ (void *)&pcmd_intintint_token_rx,
+ NULL
+ },
+};
+cmdline_parse_inst_t pcmd_validate = {
+ .f = pcmd_validate_callback,
+ .data = NULL,
+ .help_str = "validate <mac_addr>\n"
+ " Check that MAC address is valid unicast address",
+ .tokens = {
+ (void *)&pcmd_validate_token_cmd,
+ (void *)&pcmd_intmac_token_mac,
+ NULL
+ },
+};
+cmdline_parse_inst_t pcmd_vlan = {
+ .f = pcmd_vlan_callback,
+ .data = NULL,
+ .help_str = "vlan <port_id> <add|del> <vlan_id>\n"
+ " Add/remove VLAN id",
+ .tokens = {
+ (void *)&pcmd_vlan_token_cmd,
+ (void *)&pcmd_vlan_token_port,
+ (void *)&pcmd_vlan_token_mode,
+ (void *)&pcmd_vlan_token_vid,
+ NULL
+ },
+};
+
+
+cmdline_parse_ctx_t list_prompt_commands[] = {
+ (cmdline_parse_inst_t *)&pcmd_drvinfo,
+ (cmdline_parse_inst_t *)&pcmd_eeprom,
+ (cmdline_parse_inst_t *)&pcmd_module_eeprom,
+ (cmdline_parse_inst_t *)&pcmd_link,
+ (cmdline_parse_inst_t *)&pcmd_macaddr_get,
+ (cmdline_parse_inst_t *)&pcmd_macaddr,
+ (cmdline_parse_inst_t *)&pcmd_mtu,
+ (cmdline_parse_inst_t *)&pcmd_open,
+ (cmdline_parse_inst_t *)&pcmd_pause_noopt,
+ (cmdline_parse_inst_t *)&pcmd_pause,
+ (cmdline_parse_inst_t *)&pcmd_portstats,
+ (cmdline_parse_inst_t *)&pcmd_regs,
+ (cmdline_parse_inst_t *)&pcmd_ringparam,
+ (cmdline_parse_inst_t *)&pcmd_ringparam_set,
+ (cmdline_parse_inst_t *)&pcmd_rxmode,
+ (cmdline_parse_inst_t *)&pcmd_stop,
+ (cmdline_parse_inst_t *)&pcmd_validate,
+ (cmdline_parse_inst_t *)&pcmd_vlan,
+ (cmdline_parse_inst_t *)&pcmd_quit,
+ NULL
+};
+
+
+void ethapp_main(void)
+{
+ struct cmdline *ctx_cmdline;
+
+ ctx_cmdline = cmdline_stdin_new(list_prompt_commands, "EthApp> ");
+ cmdline_interact(ctx_cmdline);
+ cmdline_stdin_exit(ctx_cmdline);
+}
diff --git a/src/seastar/dpdk/examples/ethtool/ethtool-app/ethapp.h b/src/seastar/dpdk/examples/ethtool/ethtool-app/ethapp.h
new file mode 100644
index 000000000..7a70480c8
--- /dev/null
+++ b/src/seastar/dpdk/examples/ethtool/ethtool-app/ethapp.h
@@ -0,0 +1,12 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2015 Intel Corporation
+ */
+
+
+void ethapp_main(void);
+void print_stats(void);
+void lock_port(int idx_port);
+void unlock_port(int idx_port);
+void mark_port_inactive(int idx_port);
+void mark_port_active(int idx_port);
+void mark_port_newmac(int idx_port);
diff --git a/src/seastar/dpdk/examples/ethtool/ethtool-app/main.c b/src/seastar/dpdk/examples/ethtool/ethtool-app/main.c
new file mode 100644
index 000000000..e23d3afd2
--- /dev/null
+++ b/src/seastar/dpdk/examples/ethtool/ethtool-app/main.c
@@ -0,0 +1,282 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2015 Intel Corporation
+ */
+
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <rte_common.h>
+#include <rte_spinlock.h>
+#include <rte_eal.h>
+#include <rte_ethdev.h>
+#include <rte_ether.h>
+#include <rte_ip.h>
+#include <rte_memory.h>
+#include <rte_mempool.h>
+#include <rte_mbuf.h>
+
+#include "ethapp.h"
+
+#define MAX_PORTS RTE_MAX_ETHPORTS
+#define MAX_BURST_LENGTH 32
+#define PORT_RX_QUEUE_SIZE 1024
+#define PORT_TX_QUEUE_SIZE 1024
+#define PKTPOOL_EXTRA_SIZE 512
+#define PKTPOOL_CACHE 32
+
+
+struct txq_port {
+ uint16_t cnt_unsent;
+ struct rte_mbuf *buf_frames[MAX_BURST_LENGTH];
+};
+
+struct app_port {
+ struct ether_addr mac_addr;
+ struct txq_port txq;
+ rte_spinlock_t lock;
+ int port_active;
+ int port_dirty;
+ int idx_port;
+ struct rte_mempool *pkt_pool;
+};
+
+struct app_config {
+ struct app_port ports[MAX_PORTS];
+ int cnt_ports;
+ int exit_now;
+};
+
+
+struct app_config app_cfg;
+
+
+void lock_port(int idx_port)
+{
+ struct app_port *ptr_port = &app_cfg.ports[idx_port];
+
+ rte_spinlock_lock(&ptr_port->lock);
+}
+
+void unlock_port(int idx_port)
+{
+ struct app_port *ptr_port = &app_cfg.ports[idx_port];
+
+ rte_spinlock_unlock(&ptr_port->lock);
+}
+
+void mark_port_active(int idx_port)
+{
+ struct app_port *ptr_port = &app_cfg.ports[idx_port];
+
+ ptr_port->port_active = 1;
+}
+
+void mark_port_inactive(int idx_port)
+{
+ struct app_port *ptr_port = &app_cfg.ports[idx_port];
+
+ ptr_port->port_active = 0;
+}
+
+void mark_port_newmac(int idx_port)
+{
+ struct app_port *ptr_port = &app_cfg.ports[idx_port];
+
+ ptr_port->port_dirty = 1;
+}
+
+static void setup_ports(struct app_config *app_cfg, int cnt_ports)
+{
+ int idx_port;
+ int size_pktpool;
+ struct rte_eth_conf cfg_port;
+ struct rte_eth_dev_info dev_info;
+ char str_name[16];
+ uint16_t nb_rxd = PORT_RX_QUEUE_SIZE;
+ uint16_t nb_txd = PORT_TX_QUEUE_SIZE;
+
+ memset(&cfg_port, 0, sizeof(cfg_port));
+ cfg_port.txmode.mq_mode = ETH_MQ_TX_NONE;
+
+ for (idx_port = 0; idx_port < cnt_ports; idx_port++) {
+ struct app_port *ptr_port = &app_cfg->ports[idx_port];
+
+ rte_eth_dev_info_get(idx_port, &dev_info);
+ size_pktpool = dev_info.rx_desc_lim.nb_max +
+ dev_info.tx_desc_lim.nb_max + PKTPOOL_EXTRA_SIZE;
+
+ snprintf(str_name, 16, "pkt_pool%i", idx_port);
+ ptr_port->pkt_pool = rte_pktmbuf_pool_create(
+ str_name,
+ size_pktpool, PKTPOOL_CACHE,
+ 0,
+ RTE_MBUF_DEFAULT_BUF_SIZE,
+ rte_socket_id()
+ );
+ if (ptr_port->pkt_pool == NULL)
+ rte_exit(EXIT_FAILURE,
+ "rte_pktmbuf_pool_create failed"
+ );
+
+ printf("Init port %i..\n", idx_port);
+ ptr_port->port_active = 1;
+ ptr_port->port_dirty = 0;
+ ptr_port->idx_port = idx_port;
+
+ if (rte_eth_dev_configure(idx_port, 1, 1, &cfg_port) < 0)
+ rte_exit(EXIT_FAILURE,
+ "rte_eth_dev_configure failed");
+ if (rte_eth_dev_adjust_nb_rx_tx_desc(idx_port, &nb_rxd,
+ &nb_txd) < 0)
+ rte_exit(EXIT_FAILURE,
+ "rte_eth_dev_adjust_nb_rx_tx_desc failed");
+
+ if (rte_eth_rx_queue_setup(
+ idx_port, 0, nb_rxd,
+ rte_eth_dev_socket_id(idx_port), NULL,
+ ptr_port->pkt_pool) < 0)
+ rte_exit(EXIT_FAILURE,
+ "rte_eth_rx_queue_setup failed"
+ );
+ if (rte_eth_tx_queue_setup(
+ idx_port, 0, nb_txd,
+ rte_eth_dev_socket_id(idx_port), NULL) < 0)
+ rte_exit(EXIT_FAILURE,
+ "rte_eth_tx_queue_setup failed"
+ );
+ if (rte_eth_dev_start(idx_port) < 0)
+ rte_exit(EXIT_FAILURE,
+ "%s:%i: rte_eth_dev_start failed",
+ __FILE__, __LINE__
+ );
+ rte_eth_macaddr_get(idx_port, &ptr_port->mac_addr);
+ rte_spinlock_init(&ptr_port->lock);
+ }
+}
+
+static void process_frame(struct app_port *ptr_port,
+ struct rte_mbuf *ptr_frame)
+{
+ struct ether_hdr *ptr_mac_hdr;
+
+ ptr_mac_hdr = rte_pktmbuf_mtod(ptr_frame, struct ether_hdr *);
+ ether_addr_copy(&ptr_mac_hdr->s_addr, &ptr_mac_hdr->d_addr);
+ ether_addr_copy(&ptr_port->mac_addr, &ptr_mac_hdr->s_addr);
+}
+
+static int slave_main(__attribute__((unused)) void *ptr_data)
+{
+ struct app_port *ptr_port;
+ struct rte_mbuf *ptr_frame;
+ struct txq_port *txq;
+
+ uint16_t cnt_recv_frames;
+ uint16_t idx_frame;
+ uint16_t cnt_sent;
+ uint16_t idx_port;
+ uint16_t lock_result;
+
+ while (app_cfg.exit_now == 0) {
+ for (idx_port = 0; idx_port < app_cfg.cnt_ports; idx_port++) {
+ /* Check that port is active and unlocked */
+ ptr_port = &app_cfg.ports[idx_port];
+ lock_result = rte_spinlock_trylock(&ptr_port->lock);
+ if (lock_result == 0)
+ continue;
+ if (ptr_port->port_active == 0) {
+ rte_spinlock_unlock(&ptr_port->lock);
+ continue;
+ }
+ txq = &ptr_port->txq;
+
+ /* MAC address was updated */
+ if (ptr_port->port_dirty == 1) {
+ rte_eth_macaddr_get(ptr_port->idx_port,
+ &ptr_port->mac_addr);
+ ptr_port->port_dirty = 0;
+ }
+
+ /* Incoming frames */
+ cnt_recv_frames = rte_eth_rx_burst(
+ ptr_port->idx_port, 0,
+ &txq->buf_frames[txq->cnt_unsent],
+ RTE_DIM(txq->buf_frames) - txq->cnt_unsent
+ );
+ if (cnt_recv_frames > 0) {
+ for (idx_frame = 0;
+ idx_frame < cnt_recv_frames;
+ idx_frame++) {
+ ptr_frame = txq->buf_frames[
+ idx_frame + txq->cnt_unsent];
+ process_frame(ptr_port, ptr_frame);
+ }
+ txq->cnt_unsent += cnt_recv_frames;
+ }
+
+ /* Outgoing frames */
+ if (txq->cnt_unsent > 0) {
+ cnt_sent = rte_eth_tx_burst(
+ ptr_port->idx_port, 0,
+ txq->buf_frames,
+ txq->cnt_unsent
+ );
+ /* Shuffle up unsent frame pointers */
+ for (idx_frame = cnt_sent;
+ idx_frame < txq->cnt_unsent;
+ idx_frame++)
+ txq->buf_frames[idx_frame - cnt_sent] =
+ txq->buf_frames[idx_frame];
+ txq->cnt_unsent -= cnt_sent;
+ }
+ rte_spinlock_unlock(&ptr_port->lock);
+ } /* end for( idx_port ) */
+ } /* end for(;;) */
+
+ return 0;
+}
+
+int main(int argc, char **argv)
+{
+ int cnt_args_parsed;
+ uint32_t id_core;
+ uint32_t cnt_ports;
+
+ /* Init runtime environment */
+ cnt_args_parsed = rte_eal_init(argc, argv);
+ if (cnt_args_parsed < 0)
+ rte_exit(EXIT_FAILURE, "rte_eal_init(): Failed");
+
+ cnt_ports = rte_eth_dev_count_avail();
+ printf("Number of NICs: %i\n", cnt_ports);
+ if (cnt_ports == 0)
+ rte_exit(EXIT_FAILURE, "No available NIC ports!\n");
+ if (cnt_ports > MAX_PORTS) {
+ printf("Info: Using only %i of %i ports\n",
+ cnt_ports, MAX_PORTS
+ );
+ cnt_ports = MAX_PORTS;
+ }
+
+ setup_ports(&app_cfg, cnt_ports);
+
+ app_cfg.exit_now = 0;
+ app_cfg.cnt_ports = cnt_ports;
+
+ if (rte_lcore_count() < 2)
+ rte_exit(EXIT_FAILURE, "No available slave core!\n");
+ /* Assume there is an available slave.. */
+ id_core = rte_lcore_id();
+ id_core = rte_get_next_lcore(id_core, 1, 1);
+ rte_eal_remote_launch(slave_main, NULL, id_core);
+
+ ethapp_main();
+
+ app_cfg.exit_now = 1;
+ RTE_LCORE_FOREACH_SLAVE(id_core) {
+ if (rte_eal_wait_lcore(id_core) < 0)
+ return -1;
+ }
+
+ return 0;
+}
diff --git a/src/seastar/dpdk/examples/ethtool/lib/Makefile b/src/seastar/dpdk/examples/ethtool/lib/Makefile
new file mode 100644
index 000000000..9da7dc3ba
--- /dev/null
+++ b/src/seastar/dpdk/examples/ethtool/lib/Makefile
@@ -0,0 +1,37 @@
+# SPDX-License-Identifier: BSD-3-Clause
+# Copyright(c) 2015 Intel Corporation
+
+ifeq ($(RTE_SDK),)
+$(error "Please define RTE_SDK environment variable")
+endif
+
+# Default target, detect a build directory, by looking for a path with a .config
+RTE_TARGET ?= $(notdir $(abspath $(dir $(firstword $(wildcard $(RTE_SDK)/*/.config)))))
+
+include $(RTE_SDK)/mk/rte.vars.mk
+
+ifneq ($(CONFIG_RTE_EXEC_ENV_LINUX),y)
+$(error This application can only operate in a linux environment, \
+please change the definition of the RTE_TARGET environment variable)
+endif
+
+# library name
+LIB = librte_ethtool.a
+
+LIBABIVER := 1
+
+# all source are stored in SRC-Y
+SRCS-y := rte_ethtool.c
+
+CFLAGS += -O3
+CFLAGS += $(WERROR_FLAGS)
+CFLAGS += -DALLOW_EXPERIMENTAL_API
+
+ifeq ($(CONFIG_RTE_BUILD_SHARED_LIB),y)
+ifeq ($(CONFIG_RTE_LIBRTE_IXGBE_PMD),y)
+LDLIBS += -lrte_pmd_ixgbe
+endif
+endif
+LDLIBS += -lrte_eal -lrte_ethdev
+
+include $(RTE_SDK)/mk/rte.extlib.mk
diff --git a/src/seastar/dpdk/examples/ethtool/lib/rte_ethtool.c b/src/seastar/dpdk/examples/ethtool/lib/rte_ethtool.c
new file mode 100644
index 000000000..bf10139e7
--- /dev/null
+++ b/src/seastar/dpdk/examples/ethtool/lib/rte_ethtool.c
@@ -0,0 +1,453 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2010-2016 Intel Corporation
+ */
+#include <stdio.h>
+#include <string.h>
+#include <stdint.h>
+#include <rte_string_fns.h>
+#include <rte_version.h>
+#include <rte_ethdev.h>
+#include <rte_ether.h>
+#include <rte_bus_pci.h>
+#ifdef RTE_LIBRTE_IXGBE_PMD
+#include <rte_pmd_ixgbe.h>
+#endif
+#include "rte_ethtool.h"
+
+#define PKTPOOL_SIZE 512
+#define PKTPOOL_CACHE 32
+
+
+int
+rte_ethtool_get_drvinfo(uint16_t port_id, struct ethtool_drvinfo *drvinfo)
+{
+ struct rte_eth_dev_info dev_info;
+ struct rte_dev_reg_info reg_info;
+ const struct rte_pci_device *pci_dev;
+ const struct rte_bus *bus = NULL;
+ int n;
+ int ret;
+
+ if (drvinfo == NULL)
+ return -EINVAL;
+
+ RTE_ETH_VALID_PORTID_OR_ERR_RET(port_id, -ENODEV);
+
+ ret = rte_eth_dev_fw_version_get(port_id, drvinfo->fw_version,
+ sizeof(drvinfo->fw_version));
+ if (ret < 0)
+ printf("firmware version get error: (%s)\n", strerror(-ret));
+ else if (ret > 0)
+ printf("Insufficient fw version buffer size, "
+ "the minimum size should be %d\n", ret);
+
+ memset(&dev_info, 0, sizeof(dev_info));
+ rte_eth_dev_info_get(port_id, &dev_info);
+
+ strlcpy(drvinfo->driver, dev_info.driver_name,
+ sizeof(drvinfo->driver));
+ strlcpy(drvinfo->version, rte_version(), sizeof(drvinfo->version));
+ /* TODO: replace bus_info by rte_devargs.name */
+ if (dev_info.device)
+ bus = rte_bus_find_by_device(dev_info.device);
+ if (bus && !strcmp(bus->name, "pci")) {
+ pci_dev = RTE_DEV_TO_PCI(dev_info.device);
+ snprintf(drvinfo->bus_info, sizeof(drvinfo->bus_info),
+ "%04x:%02x:%02x.%x",
+ pci_dev->addr.domain, pci_dev->addr.bus,
+ pci_dev->addr.devid, pci_dev->addr.function);
+ } else {
+ snprintf(drvinfo->bus_info, sizeof(drvinfo->bus_info), "N/A");
+ }
+
+ memset(&reg_info, 0, sizeof(reg_info));
+ rte_eth_dev_get_reg_info(port_id, &reg_info);
+ n = reg_info.length;
+ if (n > 0)
+ drvinfo->regdump_len = n;
+ else
+ drvinfo->regdump_len = 0;
+
+ n = rte_eth_dev_get_eeprom_length(port_id);
+ if (n > 0)
+ drvinfo->eedump_len = n;
+ else
+ drvinfo->eedump_len = 0;
+
+ drvinfo->n_stats = sizeof(struct rte_eth_stats) / sizeof(uint64_t);
+ drvinfo->testinfo_len = 0;
+
+ return 0;
+}
+
+int
+rte_ethtool_get_regs_len(uint16_t port_id)
+{
+ struct rte_dev_reg_info reg_info;
+ int ret;
+
+ memset(&reg_info, 0, sizeof(reg_info));
+
+ ret = rte_eth_dev_get_reg_info(port_id, &reg_info);
+ if (ret)
+ return ret;
+
+ return reg_info.length * reg_info.width;
+}
+
+int
+rte_ethtool_get_regs(uint16_t port_id, struct ethtool_regs *regs, void *data)
+{
+ struct rte_dev_reg_info reg_info;
+ int status;
+
+ if (regs == NULL || data == NULL)
+ return -EINVAL;
+
+ reg_info.data = data;
+ reg_info.length = 0;
+
+ status = rte_eth_dev_get_reg_info(port_id, &reg_info);
+ if (status)
+ return status;
+ regs->version = reg_info.version;
+
+ return 0;
+}
+
+int
+rte_ethtool_get_link(uint16_t port_id)
+{
+ struct rte_eth_link link;
+
+ RTE_ETH_VALID_PORTID_OR_ERR_RET(port_id, -ENODEV);
+ rte_eth_link_get(port_id, &link);
+ return link.link_status;
+}
+
+int
+rte_ethtool_get_eeprom_len(uint16_t port_id)
+{
+ return rte_eth_dev_get_eeprom_length(port_id);
+}
+
+int
+rte_ethtool_get_eeprom(uint16_t port_id, struct ethtool_eeprom *eeprom,
+ void *words)
+{
+ struct rte_dev_eeprom_info eeprom_info;
+ int status;
+
+ if (eeprom == NULL || words == NULL)
+ return -EINVAL;
+
+ eeprom_info.offset = eeprom->offset;
+ eeprom_info.length = eeprom->len;
+ eeprom_info.data = words;
+
+ status = rte_eth_dev_get_eeprom(port_id, &eeprom_info);
+ if (status)
+ return status;
+
+ eeprom->magic = eeprom_info.magic;
+
+ return 0;
+}
+
+int
+rte_ethtool_set_eeprom(uint16_t port_id, struct ethtool_eeprom *eeprom,
+ void *words)
+{
+ struct rte_dev_eeprom_info eeprom_info;
+ int status;
+
+ if (eeprom == NULL || words == NULL || eeprom->offset >= eeprom->len)
+ return -EINVAL;
+
+ eeprom_info.offset = eeprom->offset;
+ eeprom_info.length = eeprom->len;
+ eeprom_info.data = words;
+
+ status = rte_eth_dev_set_eeprom(port_id, &eeprom_info);
+ if (status)
+ return status;
+
+ eeprom->magic = eeprom_info.magic;
+
+ return 0;
+}
+
+int
+rte_ethtool_get_module_info(uint16_t port_id, uint32_t *modinfo)
+{
+ struct rte_eth_dev_module_info *info;
+
+ info = (struct rte_eth_dev_module_info *)modinfo;
+ return rte_eth_dev_get_module_info(port_id, info);
+}
+
+int
+rte_ethtool_get_module_eeprom(uint16_t port_id, struct ethtool_eeprom *eeprom,
+ void *words)
+{
+ struct rte_dev_eeprom_info eeprom_info;
+ int status;
+
+ if (eeprom == NULL || words == NULL)
+ return -EINVAL;
+
+ eeprom_info.offset = eeprom->offset;
+ eeprom_info.length = eeprom->len;
+ eeprom_info.data = words;
+
+ status = rte_eth_dev_get_module_eeprom(port_id, &eeprom_info);
+ if (status)
+ return status;
+
+ return 0;
+}
+
+int
+rte_ethtool_get_pauseparam(uint16_t port_id,
+ struct ethtool_pauseparam *pause_param)
+{
+ struct rte_eth_fc_conf fc_conf;
+ int status;
+
+ if (pause_param == NULL)
+ return -EINVAL;
+
+ status = rte_eth_dev_flow_ctrl_get(port_id, &fc_conf);
+ if (status)
+ return status;
+
+ pause_param->tx_pause = 0;
+ pause_param->rx_pause = 0;
+ switch (fc_conf.mode) {
+ case RTE_FC_RX_PAUSE:
+ pause_param->rx_pause = 1;
+ break;
+ case RTE_FC_TX_PAUSE:
+ pause_param->tx_pause = 1;
+ break;
+ case RTE_FC_FULL:
+ pause_param->rx_pause = 1;
+ pause_param->tx_pause = 1;
+ default:
+ /* dummy block to avoid compiler warning */
+ break;
+ }
+ pause_param->autoneg = (uint32_t)fc_conf.autoneg;
+
+ return 0;
+}
+
+int
+rte_ethtool_set_pauseparam(uint16_t port_id,
+ struct ethtool_pauseparam *pause_param)
+{
+ struct rte_eth_fc_conf fc_conf;
+ int status;
+
+ if (pause_param == NULL)
+ return -EINVAL;
+
+ /*
+ * Read device flow control parameter first since
+ * ethtool set_pauseparam op doesn't have all the information.
+ * as defined in struct rte_eth_fc_conf.
+ * This API requires the device to support both
+ * rte_eth_dev_flow_ctrl_get and rte_eth_dev_flow_ctrl_set, otherwise
+ * return -ENOTSUP
+ */
+ status = rte_eth_dev_flow_ctrl_get(port_id, &fc_conf);
+ if (status)
+ return status;
+
+ fc_conf.autoneg = (uint8_t)pause_param->autoneg;
+
+ if (pause_param->tx_pause) {
+ if (pause_param->rx_pause)
+ fc_conf.mode = RTE_FC_FULL;
+ else
+ fc_conf.mode = RTE_FC_TX_PAUSE;
+ } else {
+ if (pause_param->rx_pause)
+ fc_conf.mode = RTE_FC_RX_PAUSE;
+ else
+ fc_conf.mode = RTE_FC_NONE;
+ }
+
+ status = rte_eth_dev_flow_ctrl_set(port_id, &fc_conf);
+ if (status)
+ return status;
+
+ return 0;
+}
+
+int
+rte_ethtool_net_open(uint16_t port_id)
+{
+ rte_eth_dev_stop(port_id);
+
+ return rte_eth_dev_start(port_id);
+}
+
+int
+rte_ethtool_net_stop(uint16_t port_id)
+{
+ RTE_ETH_VALID_PORTID_OR_ERR_RET(port_id, -ENODEV);
+ rte_eth_dev_stop(port_id);
+
+ return 0;
+}
+
+int
+rte_ethtool_net_get_mac_addr(uint16_t port_id, struct ether_addr *addr)
+{
+ RTE_ETH_VALID_PORTID_OR_ERR_RET(port_id, -ENODEV);
+ if (addr == NULL)
+ return -EINVAL;
+ rte_eth_macaddr_get(port_id, addr);
+
+ return 0;
+}
+
+int
+rte_ethtool_net_set_mac_addr(uint16_t port_id, struct ether_addr *addr)
+{
+ if (addr == NULL)
+ return -EINVAL;
+ return rte_eth_dev_default_mac_addr_set(port_id, addr);
+}
+
+int
+rte_ethtool_net_validate_addr(uint16_t port_id __rte_unused,
+ struct ether_addr *addr)
+{
+ if (addr == NULL)
+ return -EINVAL;
+ return is_valid_assigned_ether_addr(addr);
+}
+
+int
+rte_ethtool_net_change_mtu(uint16_t port_id, int mtu)
+{
+ if (mtu < 0 || mtu > UINT16_MAX)
+ return -EINVAL;
+ return rte_eth_dev_set_mtu(port_id, (uint16_t)mtu);
+}
+
+int
+rte_ethtool_net_get_stats64(uint16_t port_id, struct rte_eth_stats *stats)
+{
+ if (stats == NULL)
+ return -EINVAL;
+ return rte_eth_stats_get(port_id, stats);
+}
+
+int
+rte_ethtool_net_vlan_rx_add_vid(uint16_t port_id, uint16_t vid)
+{
+ return rte_eth_dev_vlan_filter(port_id, vid, 1);
+}
+
+int
+rte_ethtool_net_vlan_rx_kill_vid(uint16_t port_id, uint16_t vid)
+{
+ return rte_eth_dev_vlan_filter(port_id, vid, 0);
+}
+
+/*
+ * The set_rx_mode provides driver-specific rx mode setting.
+ * This implementation implements rx mode setting based upon
+ * ixgbe/igb drivers. Further improvement is to provide a
+ * callback op field over struct rte_eth_dev::dev_ops so each
+ * driver can register device-specific implementation
+ */
+int
+rte_ethtool_net_set_rx_mode(uint16_t port_id)
+{
+ uint16_t num_vfs;
+ struct rte_eth_dev_info dev_info;
+ uint16_t vf;
+
+ memset(&dev_info, 0, sizeof(dev_info));
+ rte_eth_dev_info_get(port_id, &dev_info);
+ num_vfs = dev_info.max_vfs;
+
+ /* Set VF vf_rx_mode, VF unsupport status is discard */
+ for (vf = 0; vf < num_vfs; vf++) {
+#ifdef RTE_LIBRTE_IXGBE_PMD
+ rte_pmd_ixgbe_set_vf_rxmode(port_id, vf,
+ ETH_VMDQ_ACCEPT_UNTAG, 0);
+#endif
+ }
+
+ /* Enable Rx vlan filter, VF unspport status is discard */
+ rte_eth_dev_set_vlan_offload(port_id, ETH_VLAN_FILTER_MASK);
+
+ return 0;
+}
+
+
+int
+rte_ethtool_get_ringparam(uint16_t port_id,
+ struct ethtool_ringparam *ring_param)
+{
+ struct rte_eth_dev_info dev_info;
+ struct rte_eth_rxq_info rx_qinfo;
+ struct rte_eth_txq_info tx_qinfo;
+ int stat;
+
+ if (ring_param == NULL)
+ return -EINVAL;
+
+ rte_eth_dev_info_get(port_id, &dev_info);
+
+ stat = rte_eth_rx_queue_info_get(port_id, 0, &rx_qinfo);
+ if (stat != 0)
+ return stat;
+
+ stat = rte_eth_tx_queue_info_get(port_id, 0, &tx_qinfo);
+ if (stat != 0)
+ return stat;
+
+ memset(ring_param, 0, sizeof(*ring_param));
+ ring_param->rx_pending = rx_qinfo.nb_desc;
+ ring_param->rx_max_pending = dev_info.rx_desc_lim.nb_max;
+ ring_param->tx_pending = tx_qinfo.nb_desc;
+ ring_param->tx_max_pending = dev_info.tx_desc_lim.nb_max;
+
+ return 0;
+}
+
+
+int
+rte_ethtool_set_ringparam(uint16_t port_id,
+ struct ethtool_ringparam *ring_param)
+{
+ struct rte_eth_rxq_info rx_qinfo;
+ int stat;
+
+ if (ring_param == NULL)
+ return -EINVAL;
+
+ stat = rte_eth_rx_queue_info_get(port_id, 0, &rx_qinfo);
+ if (stat != 0)
+ return stat;
+
+ rte_eth_dev_stop(port_id);
+
+ stat = rte_eth_tx_queue_setup(port_id, 0, ring_param->tx_pending,
+ rte_socket_id(), NULL);
+ if (stat != 0)
+ return stat;
+
+ stat = rte_eth_rx_queue_setup(port_id, 0, ring_param->rx_pending,
+ rte_socket_id(), NULL, rx_qinfo.mp);
+ if (stat != 0)
+ return stat;
+
+ return rte_eth_dev_start(port_id);
+}
diff --git a/src/seastar/dpdk/examples/ethtool/lib/rte_ethtool.h b/src/seastar/dpdk/examples/ethtool/lib/rte_ethtool.h
new file mode 100644
index 000000000..31cd5ae4e
--- /dev/null
+++ b/src/seastar/dpdk/examples/ethtool/lib/rte_ethtool.h
@@ -0,0 +1,415 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2010-2015 Intel Corporation
+ */
+
+#ifndef _RTE_ETHTOOL_H_
+#define _RTE_ETHTOOL_H_
+
+/*
+ * This new interface is designed to provide a user-space shim layer for
+ * Ethtool and Netdevice op API.
+ *
+ * rte_ethtool_get_driver: ethtool_ops::get_drvinfo
+ * rte_ethtool_get_link: ethtool_ops::get_link
+ * rte_ethtool_get_regs_len: ethtool_ops::get_regs_len
+ * rte_ethtool_get_regs: ethtool_ops::get_regs
+ * rte_ethtool_get_eeprom_len: ethtool_ops::get_eeprom_len
+ * rte_ethtool_get_eeprom: ethtool_ops::get_eeprom
+ * rte_ethtool_set_eeprom: ethtool_ops::set_eeprom
+ * rte_ethtool_get_pauseparam: ethtool_ops::get_pauseparam
+ * rte_ethtool_set_pauseparam: ethtool_ops::set_pauseparam
+ *
+ * rte_ethtool_net_open: net_device_ops::ndo_open
+ * rte_ethtool_net_stop: net_device_ops::ndo_stop
+ * rte_ethtool_net_set_mac_addr: net_device_ops::ndo_set_mac_address
+ * rte_ethtool_net_validate_addr: net_device_ops::ndo_validate_addr
+ * rte_ethtool_net_change_mtu: net_device_ops::ndo_change_mtu
+ * rte_ethtool_net_get_stats64: net_device_ops::ndo_get_stats64
+ * rte_ethtool_net_vlan_rx_add_vid net_device_ops::ndo_vlan_rx_add_vid
+ * rte_ethtool_net_vlan_rx_kill_vid net_device_ops::ndo_vlan_rx_kill_vid
+ * rte_ethtool_net_set_rx_mode net_device_ops::ndo_set_rx_mode
+ *
+ */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdint.h>
+#include <rte_ethdev.h>
+#include <linux/ethtool.h>
+
+/**
+ * Retrieve the Ethernet device driver information according to
+ * attributes described by ethtool data structure, ethtool_drvinfo.
+ *
+ * @param port_id
+ * The port identifier of the Ethernet device.
+ * @param drvinfo
+ * A pointer to get driver information
+ * @return
+ * - (0) if successful.
+ * - (-ENODEV) if *port_id* invalid.
+ */
+int rte_ethtool_get_drvinfo(uint16_t port_id, struct ethtool_drvinfo *drvinfo);
+
+/**
+ * Retrieve the Ethernet device register length in bytes.
+ *
+ * @param port_id
+ * The port identifier of the Ethernet device.
+ * @return
+ * - (> 0) # of device registers (in bytes) available for dump
+ * - (0) no registers available for dump.
+ * - (-ENOTSUP) if hardware doesn't support.
+ * - (-ENODEV) if *port_id* invalid.
+ * - others depends on the specific operations implementation.
+ */
+int rte_ethtool_get_regs_len(uint16_t port_id);
+
+/**
+ * Retrieve the Ethernet device register information according to
+ * attributes described by ethtool data structure, ethtool_regs
+ *
+ * @param port_id
+ * The port identifier of the Ethernet device.
+ * @param reg
+ * A pointer to ethtool_regs that has register information
+ * @param data
+ * A pointer to a buffer that is used to retrieve device register content
+ * @return
+ * - (0) if successful.
+ * - (-ENOTSUP) if hardware doesn't support.
+ * - (-ENODEV) if *port_id* invalid.
+ * - others depends on the specific operations implementation.
+ */
+int rte_ethtool_get_regs(uint16_t port_id, struct ethtool_regs *regs,
+ void *data);
+
+/**
+ * Retrieve the Ethernet device link status
+ *
+ * @param port_id
+ * The port identifier of the Ethernet device.
+ * @return
+ * - (1) if link up.
+ * - (0) if link down.
+ * - (-ENOTSUP) if hardware doesn't support.
+ * - (-ENODEV) if *port_id* invalid.
+ * - (-EINVAL) if parameters invalid.
+ * - others depends on the specific operations implementation.
+ */
+int rte_ethtool_get_link(uint16_t port_id);
+
+/**
+ * Retrieve the Ethernet device EEPROM size
+ *
+ * @param port_id
+ * The port identifier of the Ethernet device.
+ * @return
+ * - (> 0) device EEPROM size in bytes
+ * - (0) device has NO EEPROM
+ * - (-ENOTSUP) if hardware doesn't support.
+ * - (-ENODEV) if *port_id* invalid.
+ * - others depends on the specific operations implementation.
+ */
+int rte_ethtool_get_eeprom_len(uint16_t port_id);
+
+/**
+ * Retrieve EEPROM content based upon eeprom range described in ethtool
+ * data structure, ethtool_eeprom
+ *
+ * @param port_id
+ * The port identifier of the Ethernet device.
+ * @param eeprom
+ * The pointer of ethtool_eeprom that provides eeprom range
+ * @param words
+ * A buffer that holds data read from eeprom
+ * @return
+ * - (0) if successful.
+ * - (-ENOTSUP) if hardware doesn't support.
+ * - (-ENODEV) if *port_id* invalid.
+ * - others depends on the specific operations implementation.
+ */
+int rte_ethtool_get_eeprom(uint16_t port_id, struct ethtool_eeprom *eeprom,
+ void *words);
+
+/**
+ * Setting EEPROM content based upon eeprom range described in ethtool
+ * data structure, ethtool_eeprom
+ *
+ * @param port_id
+ * The port identifier of the Ethernet device.
+ * @param eeprom
+ * The pointer of ethtool_eeprom that provides eeprom range
+ * @param words
+ * A buffer that holds data to be written into eeprom
+ * @return
+ * - (0) if successful.
+ * - (-ENOTSUP) if hardware doesn't support.
+ * - (-ENODEV) if *port_id* invalid.
+ * - (-EINVAL) if parameters invalid.
+ * - others depends on the specific operations implementation.
+ */
+int rte_ethtool_set_eeprom(uint16_t port_id, struct ethtool_eeprom *eeprom,
+ void *words);
+
+/**
+ * Retrieve the type and size of plugin module EEPROM
+ *
+ * @param port_id
+ * The port identifier of the Ethernet device.
+ * @param modinfo
+ * The pointer that provides the type and size of plugin module EEPROM.
+ * @return
+ * - (0) if successful.
+ * - (-ENOTSUP) if hardware doesn't support.
+ * - (-ENODEV) if *port_id* invalid.
+ * - others depends on the specific operations implementation.
+ */
+int rte_ethtool_get_module_info(uint16_t port_id, uint32_t *modinfo);
+
+/**
+ * Retrieve the data of plugin module EEPROM
+ *
+ * @param port_id
+ * The port identifier of the Ethernet device.
+ * @param eeprom
+ * The pointer of ethtool_eeprom that provides plugin module eeprom
+ * offset and length
+ * @param words
+ * A buffer that holds data read from plugin module eeprom
+ * @return
+ * - (0) if successful.
+ * - (-ENOTSUP) if hardware doesn't support.
+ * - (-ENODEV) if *port_id* invalid.
+ * - others depends on the specific operations implementation.
+ */
+int rte_ethtool_get_module_eeprom(uint16_t port_id,
+ struct ethtool_eeprom *eeprom, void *words);
+
+/**
+ * Retrieve the Ethernet device pause frame configuration according to
+ * parameter attributes desribed by ethtool data structure,
+ * ethtool_pauseparam.
+ *
+ * @param port_id
+ * The port identifier of the Ethernet device.
+ * @param pause_param
+ * The pointer of ethtool_coalesce that gets pause frame
+ * configuration parameters
+ * @return
+ * - (0) if successful.
+ * - (-ENOTSUP) if hardware doesn't support.
+ * - (-ENODEV) if *port_id* invalid.
+ * - (-EINVAL) if parameters invalid.
+ * - others depends on the specific operations implementation.
+ */
+int rte_ethtool_get_pauseparam(uint16_t port_id,
+ struct ethtool_pauseparam *pause_param);
+
+/**
+ * Setting the Ethernet device pause frame configuration according to
+ * parameter attributes desribed by ethtool data structure, ethtool_pauseparam.
+ *
+ * @param port_id
+ * The port identifier of the Ethernet device.
+ * @param pause_param
+ * The pointer of ethtool_coalesce that gets ring configuration parameters
+ * @return
+ * - (0) if successful.
+ * - (-ENOTSUP) if hardware doesn't support.
+ * - (-ENODEV) if *port_id* invalid.
+ * - (-EINVAL) if parameters invalid.
+ * - others depends on the specific operations implementation.
+ */
+int rte_ethtool_set_pauseparam(uint16_t port_id,
+ struct ethtool_pauseparam *param);
+
+/**
+ * Start the Ethernet device.
+ *
+ * @param port_id
+ * The port identifier of the Ethernet device.
+ * @return
+ * - (0) if successful.
+ * - (-ENOTSUP) if hardware doesn't support.
+ * - (-ENODEV) if *port_id* invalid.
+ * - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_open(uint16_t port_id);
+
+/**
+ * Stop the Ethernet device.
+ *
+ * @param port_id
+ * The port identifier of the Ethernet device.
+ * @return
+ * - (0) if successful.
+ * - (-ENODEV) if *port_id* invalid.
+ */
+int rte_ethtool_net_stop(uint16_t port_id);
+
+/**
+ * Get the Ethernet device MAC address.
+ *
+ * @param port_id
+ * The port identifier of the Ethernet device.
+ * @param addr
+ * MAC address of the Ethernet device.
+ * @return
+ * - (0) if successful.
+ * - (-ENODEV) if *port_id* invalid.
+ */
+int rte_ethtool_net_get_mac_addr(uint16_t port_id, struct ether_addr *addr);
+
+/**
+ * Setting the Ethernet device MAC address.
+ *
+ * @param port_id
+ * The port identifier of the Ethernet device.
+ * @param addr
+ * The new MAC addr.
+ * @return
+ * - (0) if successful.
+ * - (-ENOTSUP) if hardware doesn't support.
+ * - (-ENODEV) if *port_id* invalid.
+ * - (-EINVAL) if parameters invalid.
+ * - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_set_mac_addr(uint16_t port_id, struct ether_addr *addr);
+
+/**
+ * Validate if the provided MAC address is valid unicast address
+ *
+ * @param port_id
+ * The port identifier of the Ethernet device.
+ * @param addr
+ * A pointer to a buffer (6-byte, 48bit) for the target MAC address
+ * @return
+ * - (0) if successful.
+ * - (-ENOTSUP) if hardware doesn't support.
+ * - (-ENODEV) if *port_id* invalid.
+ * - (-EINVAL) if parameters invalid.
+ * - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_validate_addr(uint16_t port_id, struct ether_addr *addr);
+
+/**
+ * Setting the Ethernet device maximum Tx unit.
+ *
+ * @param port_id
+ * The port identifier of the Ethernet device.
+ * @param mtu
+ * New MTU
+ * @return
+ * - (0) if successful.
+ * - (-ENOTSUP) if hardware doesn't support.
+ * - (-ENODEV) if *port_id* invalid.
+ * - (-EINVAL) if parameters invalid.
+ * - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_change_mtu(uint16_t port_id, int mtu);
+
+/**
+ * Retrieve the Ethernet device traffic statistics
+ *
+ * @param port_id
+ * The port identifier of the Ethernet device.
+ * @param stats
+ * A pointer to struct rte_eth_stats for statistics parameters
+ * @return
+ * - (0) if successful.
+ * - (-ENOTSUP) if hardware doesn't support.
+ * - (-ENODEV) if *port_id* invalid.
+ * - (-EINVAL) if parameters invalid.
+ * - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_get_stats64(uint16_t port_id, struct rte_eth_stats *stats);
+
+/**
+ * Update the Ethernet device VLAN filter with new vid
+ *
+ * @param port_id
+ * The port identifier of the Ethernet device.
+ * @param vid
+ * A new VLAN id
+ * @return
+ * - (0) if successful.
+ * - (-ENOTSUP) if hardware doesn't support.
+ * - (-ENODEV) if *port_id* invalid.
+ * - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_vlan_rx_add_vid(uint16_t port_id, uint16_t vid);
+
+/**
+ * Remove VLAN id from Ethernet device.
+ *
+ * @param port_id
+ * The port identifier of the Ethernet device.
+ * @param vid
+ * A new VLAN id
+ * @return
+ * - (0) if successful.
+ * - (-ENOTSUP) if hardware doesn't support.
+ * - (-ENODEV) if *port_id* invalid.
+ * - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_vlan_rx_kill_vid(uint16_t port_id, uint16_t vid);
+
+/**
+ * Setting the Ethernet device rx mode.
+ *
+ * @param port_id
+ * The port identifier of the Ethernet device.
+ * @return
+ * - (0) if successful.
+ * - (-ENOTSUP) if hardware doesn't support.
+ * - (-ENODEV) if *port_id* invalid.
+ * - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_set_rx_mode(uint16_t port_id);
+
+/**
+ * Getting ring parameters for Ethernet device.
+ *
+ * @param port_id
+ * The port identifier of the Ethernet device.
+ * @param ring_param
+ * Pointer to struct ethrool_ringparam to receive parameters.
+ * @return
+ * - (0) if successful.
+ * - (-ENOTSUP) if hardware doesn't support.
+ * - (-ENODEV) if *port_id* invalid.
+ * - others depends on the specific operations implementation.
+ * @note
+ * Only the tx_pending and rx_pending fields of struct ethtool_ringparam
+ * are used, and the function only gets parameters for queue 0.
+ */
+int rte_ethtool_get_ringparam(uint16_t port_id,
+ struct ethtool_ringparam *ring_param);
+
+/**
+ * Setting ring parameters for Ethernet device.
+ *
+ * @param port_id
+ * The port identifier of the Ethernet device.
+ * @param ring_param
+ * Pointer to struct ethrool_ringparam with parameters to set.
+ * @return
+ * - (0) if successful.
+ * - (-ENOTSUP) if hardware doesn't support.
+ * - (-ENODEV) if *port_id* invalid.
+ * - others depends on the specific operations implementation.
+ * @note
+ * Only the tx_pending and rx_pending fields of struct ethtool_ringparam
+ * are used, and the function only sets parameters for queue 0.
+ */
+int rte_ethtool_set_ringparam(uint16_t port_id,
+ struct ethtool_ringparam *ring_param);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _RTE_ETHTOOL_H_ */
diff --git a/src/seastar/dpdk/examples/ethtool/meson.build b/src/seastar/dpdk/examples/ethtool/meson.build
new file mode 100644
index 000000000..c370d7476
--- /dev/null
+++ b/src/seastar/dpdk/examples/ethtool/meson.build
@@ -0,0 +1,10 @@
+# SPDX-License-Identifier: BSD-3-Clause
+# Copyright(c) 2018 Intel Corporation
+
+# meson file, for building this example as part of a main DPDK build.
+#
+# To build this example as a standalone application with an already-installed
+# DPDK instance, use 'make'
+
+# Example app currently unsupported by meson build
+build = false