* [dpdk-dev] [PATCH] User-space Ethool example
@ 2015-07-20 14:12 Liang-Min Larry Wang
2015-07-20 14:12 ` [dpdk-dev] [PATCH] examples: new example: l2fwd-ethtool Liang-Min Larry Wang
0 siblings, 1 reply; 10+ messages in thread
From: Liang-Min Larry Wang @ 2015-07-20 14:12 UTC (permalink / raw)
To: dev; +Cc: Liang-Min Larry Wang
This implementation is designed to provide an example illlustrating how to create a
user-space ethtool library from existing ethdev APIs. This example only implements
19 popular used Ethtool and Netdevice ops as described in examples/l2fwd-ethtool/lib/rte_ethtool.h
Liang-Min Larry Wang (1):
examples: new example: l2fwd-ethtool
examples/Makefile | 1 +
examples/l2fwd-ethtool/Makefile | 48 +
examples/l2fwd-ethtool/l2fwd-app/Makefile | 58 ++
examples/l2fwd-ethtool/l2fwd-app/main.c | 1025 ++++++++++++++++++++++
examples/l2fwd-ethtool/l2fwd-app/netdev_api.h | 770 ++++++++++++++++
examples/l2fwd-ethtool/l2fwd-app/shared_fifo.h | 159 ++++
examples/l2fwd-ethtool/lib/Makefile | 57 ++
examples/l2fwd-ethtool/lib/rte_ethtool.c | 336 +++++++
examples/l2fwd-ethtool/lib/rte_ethtool.h | 385 ++++++++
examples/l2fwd-ethtool/nic-control/Makefile | 55 ++
examples/l2fwd-ethtool/nic-control/nic_control.c | 614 +++++++++++++
mk/rte.lib.mk | 2 +
12 files changed, 3510 insertions(+)
create mode 100644 examples/l2fwd-ethtool/Makefile
create mode 100644 examples/l2fwd-ethtool/l2fwd-app/Makefile
create mode 100644 examples/l2fwd-ethtool/l2fwd-app/main.c
create mode 100644 examples/l2fwd-ethtool/l2fwd-app/netdev_api.h
create mode 100644 examples/l2fwd-ethtool/l2fwd-app/shared_fifo.h
create mode 100644 examples/l2fwd-ethtool/lib/Makefile
create mode 100644 examples/l2fwd-ethtool/lib/rte_ethtool.c
create mode 100644 examples/l2fwd-ethtool/lib/rte_ethtool.h
create mode 100644 examples/l2fwd-ethtool/nic-control/Makefile
create mode 100644 examples/l2fwd-ethtool/nic-control/nic_control.c
--
2.1.4
^ permalink raw reply [flat|nested] 10+ messages in thread
* [dpdk-dev] [PATCH] examples: new example: l2fwd-ethtool
2015-07-20 14:12 [dpdk-dev] [PATCH] User-space Ethool example Liang-Min Larry Wang
@ 2015-07-20 14:12 ` Liang-Min Larry Wang
2015-07-23 15:00 ` [dpdk-dev] [PATCH v2 0/2] Example: l2fwd-ethtool Liang-Min Larry Wang
0 siblings, 1 reply; 10+ messages in thread
From: Liang-Min Larry Wang @ 2015-07-20 14:12 UTC (permalink / raw)
To: dev; +Cc: Liang-Min Larry Wang
The example includes an ethtool library and two applications:
one application is a non- DPDK process (nic-control)
and the other is a DPDK l2fwd applicaiton (l2fwd-app).
The nic-control process sends ethtool alike device management
requests to l2fwd-app through a named pipe IPC. This example
is designed to show how to build a ethtool shim library and
how to use ethtool apis to manage device parameters.
Signed-off-by: Liang-Min Larry Wang <liang-min.wang@intel.com>
---
examples/Makefile | 1 +
examples/l2fwd-ethtool/Makefile | 48 +
examples/l2fwd-ethtool/l2fwd-app/Makefile | 58 ++
examples/l2fwd-ethtool/l2fwd-app/main.c | 1025 ++++++++++++++++++++++
examples/l2fwd-ethtool/l2fwd-app/netdev_api.h | 770 ++++++++++++++++
examples/l2fwd-ethtool/l2fwd-app/shared_fifo.h | 159 ++++
examples/l2fwd-ethtool/lib/Makefile | 57 ++
examples/l2fwd-ethtool/lib/rte_ethtool.c | 336 +++++++
examples/l2fwd-ethtool/lib/rte_ethtool.h | 385 ++++++++
examples/l2fwd-ethtool/nic-control/Makefile | 55 ++
examples/l2fwd-ethtool/nic-control/nic_control.c | 614 +++++++++++++
mk/rte.lib.mk | 2 +
12 files changed, 3510 insertions(+)
create mode 100644 examples/l2fwd-ethtool/Makefile
create mode 100644 examples/l2fwd-ethtool/l2fwd-app/Makefile
create mode 100644 examples/l2fwd-ethtool/l2fwd-app/main.c
create mode 100644 examples/l2fwd-ethtool/l2fwd-app/netdev_api.h
create mode 100644 examples/l2fwd-ethtool/l2fwd-app/shared_fifo.h
create mode 100644 examples/l2fwd-ethtool/lib/Makefile
create mode 100644 examples/l2fwd-ethtool/lib/rte_ethtool.c
create mode 100644 examples/l2fwd-ethtool/lib/rte_ethtool.h
create mode 100644 examples/l2fwd-ethtool/nic-control/Makefile
create mode 100644 examples/l2fwd-ethtool/nic-control/nic_control.c
diff --git a/examples/Makefile b/examples/Makefile
index b4eddbd..3dc049c 100644
--- a/examples/Makefile
+++ b/examples/Makefile
@@ -53,6 +53,7 @@ DIRS-$(CONFIG_RTE_LIBRTE_KNI) += kni
DIRS-y += l2fwd
DIRS-$(CONFIG_RTE_LIBRTE_IVSHMEM) += l2fwd-ivshmem
DIRS-$(CONFIG_RTE_LIBRTE_JOBSTATS) += l2fwd-jobstats
+DIRS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += l2fwd-ethtool
DIRS-y += l3fwd
DIRS-$(CONFIG_RTE_LIBRTE_ACL) += l3fwd-acl
DIRS-$(CONFIG_RTE_LIBRTE_POWER) += l3fwd-power
diff --git a/examples/l2fwd-ethtool/Makefile b/examples/l2fwd-ethtool/Makefile
new file mode 100644
index 0000000..d9ad439
--- /dev/null
+++ b/examples/l2fwd-ethtool/Makefile
@@ -0,0 +1,48 @@
+# BSD LICENSE
+#
+# Copyright(c) 2015 Intel Corporation. All rights reserved.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in
+# the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Intel Corporation nor the names of its
+# contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ifeq ($(RTE_SDK),)
+$(error "Please define RTE_SDK environment variable")
+endif
+
+# Default target, can be overwritten by command line or environment
+RTE_TARGET ?= x86_64-native-linuxapp-gcc
+
+include $(RTE_SDK)/mk/rte.vars.mk
+
+ifneq ($(CONFIG_RTE_EXEC_ENV),"linuxapp")
+$(error This application can only operate in a linuxapp environment, \
+please change the definition of the RTE_TARGET environment variable)
+endif
+
+DIRS-y += lib nic-control l2fwd-app
+
+include $(RTE_SDK)/mk/rte.extsubdir.mk
diff --git a/examples/l2fwd-ethtool/l2fwd-app/Makefile b/examples/l2fwd-ethtool/l2fwd-app/Makefile
new file mode 100644
index 0000000..69405f2
--- /dev/null
+++ b/examples/l2fwd-ethtool/l2fwd-app/Makefile
@@ -0,0 +1,58 @@
+# BSD LICENSE
+#
+# Copyright(c) 2015 Intel Corporation. All rights reserved.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in
+# the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Intel Corporation nor the names of its
+# contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ifeq ($(RTE_SDK),)
+$(error "Please define RTE_SDK environment variable")
+endif
+
+# Default target, can be overwritten by command line or environment
+RTE_TARGET ?= x86_64-native-linuxapp-gcc
+
+include $(RTE_SDK)/mk/rte.vars.mk
+
+ifneq ($(CONFIG_RTE_EXEC_ENV),"linuxapp")
+$(error This application can only operate in a linuxapp environment, \
+please change the definition of the RTE_TARGET environment variable)
+endif
+
+# binary name
+APP = l2fwd-app
+
+# all source are stored in SRCS-y
+SRCS-y := main.c
+
+CFLAGS += -O3 -D_GNU_SOURCE -pthread -I$(SRCDIR)/../lib
+CFLAGS += $(WERROR_FLAGS)
+
+LDLIBS += -L$(subst l2fwd-app,lib,$(RTE_OUTPUT))/lib
+LDLIBS += -lrte_ethtool
+
+include $(RTE_SDK)/mk/rte.extapp.mk
diff --git a/examples/l2fwd-ethtool/l2fwd-app/main.c b/examples/l2fwd-ethtool/l2fwd-app/main.c
new file mode 100644
index 0000000..73c29e3
--- /dev/null
+++ b/examples/l2fwd-ethtool/l2fwd-app/main.c
@@ -0,0 +1,1025 @@
+/*-
+ * BSD LICENSE
+ *
+ * Copyright(c) 2015 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+#include <inttypes.h>
+#include <sys/types.h>
+#include <sys/queue.h>
+#include <netinet/in.h>
+#include <setjmp.h>
+#include <stdarg.h>
+#include <ctype.h>
+#include <errno.h>
+#include <getopt.h>
+#include <pthread.h>
+#include <unistd.h>
+
+#include <rte_common.h>
+#include <rte_log.h>
+#include <rte_memory.h>
+#include <rte_memcpy.h>
+#include <rte_memzone.h>
+#include <rte_tailq.h>
+#include <rte_eal.h>
+#include <rte_per_lcore.h>
+#include <rte_launch.h>
+#include <rte_atomic.h>
+#include <rte_cycles.h>
+#include <rte_prefetch.h>
+#include <rte_lcore.h>
+#include <rte_per_lcore.h>
+#include <rte_branch_prediction.h>
+#include <rte_interrupts.h>
+#include <rte_pci.h>
+#include <rte_random.h>
+#include <rte_debug.h>
+#include <rte_ether.h>
+#include <rte_ethdev.h>
+#include <rte_ring.h>
+#include <rte_mempool.h>
+#include <rte_mbuf.h>
+#include "rte_ethtool.h"
+#define NETDEV_OP_REPLY 1
+#include "netdev_api.h"
+
+#define RTE_LOGTYPE_L2FWD RTE_LOGTYPE_USER1
+
+#define MBUF_SIZE (2048 + sizeof(struct rte_mbuf) + RTE_PKTMBUF_HEADROOM)
+#define NB_MBUF 8192
+
+#define MAX_PKT_BURST 32
+#define BURST_TX_DRAIN_US 100 /* TX drain every ~100us */
+
+#define is_vf_port(vf_mask, port_id) ((vf_mask & (1 << port_id)) > 0)
+#define is_port_enabled(port_mask, port_id) ((port_mask & (1 << port_id)) > 0)
+#define TX_PTHRESH 32
+#define TX_HTHRESH 0
+#define TX_WTHRESH 0
+/*
+ * Configurable number of RX/TX ring descriptors
+ */
+#define RTE_TEST_RX_DESC_DEFAULT 128
+#define RTE_TEST_TX_DESC_DEFAULT 512
+static uint16_t nb_rxd = RTE_TEST_RX_DESC_DEFAULT;
+static uint16_t nb_txd = RTE_TEST_TX_DESC_DEFAULT;
+
+/* ethernet addresses of ports */
+static struct ether_addr l2fwd_ports_eth_addr[RTE_MAX_ETHPORTS];
+
+/* mask of enabled ports */
+static uint32_t l2fwd_enabled_port_mask;
+
+/* virtio setup enable */
+static int virtio_setup;
+
+/* list of enabled ports */
+static uint32_t l2fwd_dst_ports[RTE_MAX_ETHPORTS];
+
+static unsigned int l2fwd_rx_queue_per_lcore = 1;
+
+struct mbuf_table {
+ unsigned len;
+ struct rte_mbuf *m_table[MAX_PKT_BURST];
+};
+
+#define MAX_RX_QUEUE_PER_LCORE 16
+#define MAX_TX_QUEUE_PER_PORT 16
+struct lcore_queue_conf {
+ unsigned n_rx_port;
+ unsigned rx_port_list[MAX_RX_QUEUE_PER_LCORE];
+ struct mbuf_table tx_mbufs[RTE_MAX_ETHPORTS];
+
+} __rte_cache_aligned;
+struct lcore_queue_conf lcore_queue_conf[RTE_MAX_LCORE];
+
+static struct rte_eth_conf port_conf = {
+ .rxmode = {
+ .split_hdr_size = 0,
+ .header_split = 0, /**< Header Split disabled */
+ .hw_ip_checksum = 0, /**< IP checksum offload disabled */
+ .hw_vlan_filter = 0, /**< VLAN filtering disabled */
+ .jumbo_frame = 0, /**< Jumbo Frame Support disabled */
+ .hw_strip_crc = 0, /**< CRC stripped by hardware */
+ },
+ .txmode = {
+ .mq_mode = ETH_MQ_TX_NONE,
+ },
+};
+
+static struct rte_eth_txconf tx_conf = {
+ .tx_thresh = {
+ .pthresh = TX_PTHRESH,
+ .hthresh = TX_HTHRESH,
+ .wthresh = TX_WTHRESH,
+ },
+ .tx_free_thresh = 32,
+ .tx_rs_thresh = 32,
+ .txq_flags = 0xf00,
+};
+
+struct rte_mempool *l2fwd_pktmbuf_pool;
+
+/* Per-port statistics struct */
+struct l2fwd_port_statistics {
+ uint64_t tx;
+ uint64_t rx;
+ uint64_t dropped;
+} __rte_cache_aligned;
+struct l2fwd_port_statistics port_statistics[RTE_MAX_ETHPORTS];
+
+/* A tsc-based timer responsible for triggering statistics printout */
+#define TIMER_MILLISECOND 2000000ULL /* around 1ms at 2 Ghz */
+#define MAX_TIMER_PERIOD 86400 /* 1 day max */
+/* default period is 10 seconds */
+static int64_t timer_period = 10 * TIMER_MILLISECOND * 1000;
+
+/* IPC done checking utility function */
+/* status of ipc completed */
+static rte_atomic64_t ipc_done;
+
+static inline void init_ipc_done(void)
+{
+ rte_atomic64_init(&ipc_done);
+}
+
+static inline int is_ipc_done(void)
+{
+ return rte_atomic64_read(&ipc_done) > 0;
+}
+
+static inline void set_ipc_done(void)
+{
+ rte_atomic64_inc(&ipc_done);
+}
+
+/* Print out statistics on packets dropped */
+static void
+print_stats(void)
+{
+ uint64_t total_packets_dropped, total_packets_tx, total_packets_rx;
+ unsigned portid;
+
+ total_packets_dropped = 0;
+ total_packets_tx = 0;
+ total_packets_rx = 0;
+
+ const char clr[] = { 27, '[', '2', 'J', '\0' };
+ const char topLeft[] = { 27, '[', '1', ';', '1', 'H', '\0' };
+
+ /* Clear screen and move to top left */
+ printf("%s%s", clr, topLeft);
+
+ printf("\nPort statistics ====================================");
+
+ for (portid = 0; portid < RTE_MAX_ETHPORTS; portid++) {
+ /* skip disabled ports */
+ if ((l2fwd_enabled_port_mask & (1 << portid)) == 0)
+ continue;
+ printf("\nStatistics for port %u ----------------------------",
+ portid);
+ printf("\nPackets sent: %24"PRIu64, port_statistics[portid].tx);
+ printf("\nPackets received: %20"PRIu64,
+ port_statistics[portid].rx);
+ printf("\nPackets dropped: %21"PRIu64,
+ port_statistics[portid].dropped);
+
+ total_packets_dropped += port_statistics[portid].dropped;
+ total_packets_tx += port_statistics[portid].tx;
+ total_packets_rx += port_statistics[portid].rx;
+ }
+ printf("\nAggregate statistics ===============================");
+ printf("\nTotal packets sent: %18"PRIu64, total_packets_tx);
+ printf("\nTotal packets received: %14"PRIu64, total_packets_rx);
+ printf("\nTotal packets dropped: %15"PRIu64, total_packets_dropped);
+ printf("\n====================================================\n");
+}
+
+/* Send the burst of packets on an output interface */
+static int
+l2fwd_send_burst(struct lcore_queue_conf *qconf, unsigned n, uint8_t port)
+{
+ struct rte_mbuf **m_table;
+ unsigned ret;
+ unsigned queueid = 0;
+
+ m_table = (struct rte_mbuf **)qconf->tx_mbufs[port].m_table;
+
+ ret = rte_eth_tx_burst(port, (uint16_t) queueid, m_table, (uint16_t) n);
+ port_statistics[port].tx += ret;
+ if (unlikely(ret < n)) {
+ port_statistics[port].dropped += (n - ret);
+ do {
+ rte_pktmbuf_free(m_table[ret]);
+ } while (++ret < n);
+ }
+
+ return 0;
+}
+
+/* Enqueue packets for TX and prepare them to be sent */
+static int
+l2fwd_send_packet(struct rte_mbuf *m, uint8_t port)
+{
+ unsigned lcore_id, len;
+ struct lcore_queue_conf *qconf;
+
+ lcore_id = rte_lcore_id();
+
+ qconf = &lcore_queue_conf[lcore_id];
+ len = qconf->tx_mbufs[port].len;
+ qconf->tx_mbufs[port].m_table[len] = m;
+ len++;
+
+ /* enough pkts to be sent */
+ if (unlikely(len == MAX_PKT_BURST)) {
+ l2fwd_send_burst(qconf, MAX_PKT_BURST, port);
+ len = 0;
+ }
+
+ qconf->tx_mbufs[port].len = len;
+ return 0;
+}
+
+static void
+l2fwd_simple_forward(struct rte_mbuf *m, unsigned portid)
+{
+ struct ether_hdr *eth;
+ void *tmp;
+ unsigned dst_port;
+
+ dst_port = l2fwd_dst_ports[portid];
+ eth = rte_pktmbuf_mtod(m, struct ether_hdr *);
+
+ /* 02:00:00:00:00:xx */
+ tmp = ð->d_addr.addr_bytes[0];
+ *((uint64_t *)tmp) = 0x000000000002 + ((uint64_t)dst_port << 40);
+
+ /* src addr */
+ ether_addr_copy(&l2fwd_ports_eth_addr[dst_port], ð->s_addr);
+
+ l2fwd_send_packet(m, (uint8_t) dst_port);
+}
+
+/* main processing loop */
+static void
+l2fwd_main_loop(void)
+{
+ struct rte_mbuf *pkts_burst[MAX_PKT_BURST];
+ struct rte_mbuf *m;
+ unsigned lcore_id;
+ uint64_t prev_tsc, diff_tsc, cur_tsc, timer_tsc;
+ unsigned i, j, portid, nb_rx;
+ struct lcore_queue_conf *qconf;
+ const uint64_t drain_tsc = (rte_get_tsc_hz() + US_PER_S - 1) /
+ US_PER_S * BURST_TX_DRAIN_US;
+
+ prev_tsc = 0;
+ timer_tsc = 0;
+
+ lcore_id = rte_lcore_id();
+ qconf = &lcore_queue_conf[lcore_id];
+
+ if (qconf->n_rx_port == 0) {
+ RTE_LOG(INFO, L2FWD, "lcore %u has nothing to do\n", lcore_id);
+ return;
+ }
+
+ RTE_LOG(INFO, L2FWD, "entering main loop on lcore %u\n", lcore_id);
+
+ for (i = 0; i < qconf->n_rx_port; i++) {
+
+ portid = qconf->rx_port_list[i];
+ RTE_LOG(INFO, L2FWD, " -- lcoreid=%u portid=%u\n", lcore_id,
+ portid);
+ }
+
+ if (virtio_setup) {
+ while (is_ipc_done() == 0)
+ usleep(50);
+ }
+
+ while (1) {
+ cur_tsc = rte_rdtsc();
+
+ /* TX burst queue drain */
+ diff_tsc = cur_tsc - prev_tsc;
+ if (unlikely(diff_tsc > drain_tsc)) {
+
+ for (portid = 0; portid < RTE_MAX_ETHPORTS; portid++) {
+ if (qconf->tx_mbufs[portid].len == 0)
+ continue;
+ l2fwd_send_burst(&lcore_queue_conf[lcore_id],
+ qconf->tx_mbufs[portid].len,
+ (uint8_t) portid);
+ qconf->tx_mbufs[portid].len = 0;
+ }
+
+ /* if timer is enabled */
+ if (timer_period > 0) {
+
+ /* advance the timer */
+ timer_tsc += diff_tsc;
+
+ /* if timer has reached its timeout */
+ if (unlikely(timer_tsc >=
+ (uint64_t) timer_period)) {
+
+ /* do this only on master core */
+ if (lcore_id ==
+ rte_get_master_lcore()) {
+ print_stats();
+ /* reset the timer */
+ timer_tsc = 0;
+ }
+ }
+ }
+
+ prev_tsc = cur_tsc;
+ }
+
+ /*
+ * Read packet from RX queues
+ */
+ for (i = 0; i < qconf->n_rx_port; i++) {
+
+ portid = qconf->rx_port_list[i];
+ nb_rx = rte_eth_rx_burst((uint8_t) portid, 0,
+ pkts_burst, MAX_PKT_BURST);
+
+ port_statistics[portid].rx += nb_rx;
+
+ for (j = 0; j < nb_rx; j++) {
+ m = pkts_burst[j];
+ rte_prefetch0(rte_pktmbuf_mtod(m, void *));
+ l2fwd_simple_forward(m, portid);
+ }
+ }
+ }
+}
+
+static int
+l2fwd_launch_one_lcore(__attribute__((unused)) void *dummy)
+{
+ l2fwd_main_loop();
+ return 0;
+}
+
+/* display usage */
+static void
+l2fwd_usage(const char *prgname)
+{
+ printf("%s [EAL options] -- -p PORTMASK [-q NQ]\n"
+ " -p PORTMASK: hexadecimal bitmask of ports to configure\n"
+ " -q NQ: number of queue (=ports) per lcore (default is 1)\n"
+ " -V : setting rx/tx mode to enable virtio\n"
+ " -T PERIOD: statistics will be refreshed each PERIOD seconds",
+ prgname);
+ printf("(0 to disable, 10 default, 86400 maximum)\n");
+}
+
+static int
+l2fwd_parse_portmask(const char *portmask)
+{
+ char *end = NULL;
+ unsigned long pm;
+
+ /* parse hexadecimal string */
+ pm = strtoul(portmask, &end, 16);
+ if ((portmask[0] == '\0') || (end == NULL) || (*end != '\0'))
+ return -1;
+
+ if (pm == 0)
+ return -1;
+
+ return pm;
+}
+
+static unsigned int
+l2fwd_parse_nqueue(const char *q_arg)
+{
+ char *end = NULL;
+ unsigned long n;
+
+ /* parse hexadecimal string */
+ n = strtoul(q_arg, &end, 10);
+ if ((q_arg[0] == '\0') || (end == NULL) || (*end != '\0'))
+ return 0;
+ if (n == 0)
+ return 0;
+ if (n >= MAX_RX_QUEUE_PER_LCORE)
+ return 0;
+
+ return n;
+}
+
+static int
+l2fwd_parse_timer_period(const char *q_arg)
+{
+ char *end = NULL;
+ int n;
+
+ /* parse number string */
+ n = strtol(q_arg, &end, 10);
+ if ((q_arg[0] == '\0') || (end == NULL) || (*end != '\0'))
+ return -1;
+ if (n >= MAX_TIMER_PERIOD)
+ return -1;
+
+ return n;
+}
+
+static int
+l2fwd_parse_virtio_setup(const char *q_arg)
+{
+ char *end = NULL;
+ int n;
+
+ /* parse number string */
+ n = strtol(q_arg, &end, 10);
+ if ((q_arg[0] == '\0') || (end == NULL) || (*end != '\0'))
+ return -1;
+ if (n >= MAX_TIMER_PERIOD)
+ return -1;
+
+ return n;
+}
+
+/* Parse the argument given in the command line of the application */
+static int
+l2fwd_parse_args(int argc, char **argv)
+{
+ int opt, ret;
+ char **argvopt;
+ int option_index;
+ char *prgname = argv[0];
+ static struct option lgopts[] = {
+ {NULL, 0, 0, 0}
+ };
+
+ argvopt = argv;
+
+ while ((opt = getopt_long(argc, argvopt, "p:q:T:V:",
+ lgopts, &option_index)) != EOF) {
+
+ switch (opt) {
+ /* portmask */
+ case 'p':
+ l2fwd_enabled_port_mask = l2fwd_parse_portmask(optarg);
+ if (l2fwd_enabled_port_mask == 0) {
+ printf("invalid portmask\n");
+ l2fwd_usage(prgname);
+ return -1;
+ }
+ break;
+
+ /* nqueue */
+ case 'q':
+ l2fwd_rx_queue_per_lcore = l2fwd_parse_nqueue(optarg);
+ if (l2fwd_rx_queue_per_lcore == 0) {
+ printf("invalid queue number\n");
+ l2fwd_usage(prgname);
+ return -1;
+ }
+ break;
+
+ /* timer period */
+ case 'T':
+ timer_period = l2fwd_parse_timer_period(optarg) *
+ 1000 * TIMER_MILLISECOND;
+ if (timer_period < 0) {
+ printf("invalid timer period\n");
+ l2fwd_usage(prgname);
+ return -1;
+ }
+ break;
+
+ /* virtio setup */
+ case 'V':
+ /* get option as the pf mac addr */
+ virtio_setup = l2fwd_parse_virtio_setup(optarg);
+ if (virtio_setup) {
+ port_conf.rxmode.hw_vlan_strip = 0;
+ port_conf.rxmode.hw_vlan_extend = 0;
+ }
+ break;
+
+ /* long options */
+ case 0:
+ l2fwd_usage(prgname);
+ return -1;
+
+ default:
+ l2fwd_usage(prgname);
+ return -1;
+ }
+ }
+
+ if (optind >= 0)
+ argv[optind-1] = prgname;
+
+ ret = optind-1;
+ optind = 0; /* reset getopt lib */
+ return ret;
+}
+
+/* Check the link status of all ports in up to 9s, and print them finally */
+static void
+check_all_ports_link_status(uint8_t port_num, uint32_t port_mask)
+{
+#define CHECK_INTERVAL 100 /* 100ms */
+#define MAX_CHECK_TIME 90 /* 9s (90 * 100ms) in total */
+ uint8_t portid, count, all_ports_up, print_flag = 0;
+ struct rte_eth_link link;
+
+ printf("\nChecking link status!!!");
+ fflush(stdout);
+ for (count = 0; count <= MAX_CHECK_TIME; count++) {
+ all_ports_up = 1;
+ for (portid = 0; portid < port_num; portid++) {
+ if ((port_mask & (1 << portid)) == 0)
+ continue;
+ memset(&link, 0, sizeof(link));
+ rte_eth_link_get_nowait(portid, &link);
+ /* print link status if flag set */
+ if (print_flag == 1) {
+ if (link.link_status) {
+ printf("Port %d Link Up - speed %u "
+ , (uint8_t)portid,
+ (unsigned)link.link_speed);
+ printf("Mbps - %s\n", (link.link_duplex
+ == ETH_LINK_FULL_DUPLEX) ?
+ ("full-duplex") :
+ ("half-duplex\n"));
+ } else
+ printf("Port %d Link Down\n",
+ (uint8_t)portid);
+ continue;
+ }
+ /* clear all_ports_up flag if any link down */
+ if (link.link_status == 0) {
+ all_ports_up = 0;
+ break;
+ }
+ }
+ /* after finally printing all link status, get out */
+ if (print_flag == 1)
+ break;
+
+ if (all_ports_up == 0) {
+ printf(".");
+ fflush(stdout);
+ rte_delay_ms(CHECK_INTERVAL);
+ }
+
+ /* set the print_flag if all ports up or timeout */
+ if (all_ports_up == 1 || count == (MAX_CHECK_TIME - 1)) {
+ print_flag = 1;
+ printf("done\n");
+ }
+ }
+}
+
+static inline char*
+mac_addr_str(unsigned char *mac_addr)
+{
+#define MAC_STR_SIZE (3*MAC_ADDR_SIZE+1)
+ static char addr_string[MAC_STR_SIZE];
+
+ snprintf(addr_string, MAC_STR_SIZE, "%02x:%02x:%02x:%02x:%02x:%02x",
+ mac_addr[0], mac_addr[1], mac_addr[2],
+ mac_addr[3], mac_addr[4], mac_addr[5]);
+ return addr_string;
+}
+
+static int
+proc_ipc_begin(struct nic_info *info, uint16_t req_id)
+{
+ struct ethtool_drvinfo drvinfo;
+ uint8_t mac_addr[MAC_ADDR_SIZE];
+ uint8_t param[4], port_id, num_of_ports = info->num_of_ports;
+ uint32_t param2[2];
+ int status;
+
+ param[0] = num_of_ports;
+ info->vf_port_mask = 0;
+ for (port_id = 0; port_id < num_of_ports; port_id++) {
+ status = rte_ethtool_get_drvinfo(port_id, &drvinfo);
+ if (status) {
+ printf("get_drvinfo from port #%d fails\n", port_id);
+ return -1;
+ }
+ info->vf_port_mask |= (drvinfo.eedump_len == 0?1:0) << port_id;
+ rte_ethtool_net_stop(port_id);
+ }
+ param2[0] = info->port_mask;
+ param2[1] = info->vf_port_mask;
+
+ for (port_id = 0; port_id < num_of_ports; port_id++) {
+ rte_ethtool_net_open(port_id);
+ if (!is_vf_port(info->vf_port_mask, port_id)) {
+ struct rte_eth_dev *dev = &rte_eth_devices[port_id];
+ struct rte_eth_dev_data *dev_data =
+ (struct rte_eth_dev_data *)dev->data;
+
+ dev_data->promiscuous = 1;
+ rte_ethtool_net_set_rx_mode(port_id);
+ }
+ rte_ethtool_net_get_mac_addr(port_id, (void *)mac_addr);
+ printf("Port #%d init mac address is", port_id);
+ printf(" %s", mac_addr_str(mac_addr));
+
+ }
+
+ send_reply2(req_id, 1, param, (uint16_t)(sizeof(uint32_t)*2), param2);
+ return 0;
+}
+
+static inline void
+proc_no_action(uint16_t req_id)
+{
+ send_reply(req_id, 0, NULL);
+}
+
+static inline void
+proc_invalid(uint16_t req_id)
+{
+ send_reply(req_id, BAD_RETURN(0), NULL);
+}
+
+static void*
+ethtool(void *ctx)
+{
+ struct nic_info *info = ctx;
+ int keep_req = 1;
+ int reg_count, eeprom_size;
+ uint16_t req_id, param1_size, param2_size;
+ uint8_t req_type, port_id;
+ int status;
+ uint8_t param1[MAXI_PARA];
+ uint8_t param2[MAXI_PARA];
+ uint8_t reply1[MAXI_DATA];
+ void *first_param = FIRST_PARAM(param1);
+
+ init_rep_pipe();
+ while (1) {
+ read_request(&req_id, &req_type, ¶m1_size, param1,
+ ¶m2_size, param2);
+ if (req_type != (enum req_t)ipc_begin)
+ proc_invalid(req_id);
+ else
+ break;
+ }
+ proc_ipc_begin(info, req_id);
+
+ set_ipc_done();
+ reg_count = eeprom_size = 0;
+
+ while (keep_req) {
+ status = NETDEV_INVALID;
+ read_request(&req_id, &req_type, ¶m1_size, param1,
+ ¶m2_size, param2);
+ port_id = param1[0];
+
+ switch ((enum req_t)req_type) {
+ case get_drvinfo:
+ status = proc_ethtool_get_drvinfo(port_id, req_id,
+ first_param);
+ break;
+
+ case get_regs_len:
+ status = reg_count = proc_ethtool_get_regs_len(
+ port_id, req_id);
+ break;
+
+ case get_regs:
+ if (reg_count == 0)
+ reg_count = rte_ethtool_get_regs_len(port_id);
+ if (reg_count)
+ status = proc_ethtool_get_regs(port_id, req_id,
+ first_param, reply1);
+ break;
+
+ case get_link:
+ status = proc_ethtool_get_link(port_id, req_id);
+ break;
+
+ case get_eeprom_len:
+ if (eeprom_size == 0)
+ eeprom_size = rte_ethtool_get_eeprom_len(
+ port_id);
+ status = proc_ethtool_get_eeprom_len(port_id, req_id);
+ break;
+
+ case get_eeprom:
+ status = proc_ethtool_get_eeprom(port_id, req_id,
+ first_param, reply1);
+ break;
+
+ case set_eeprom:
+ status = proc_ethtool_set_eeprom(port_id, req_id,
+ first_param, param2);
+ break;
+
+ case get_pauseparam:
+ status = proc_ethtool_get_pauseparam(port_id,
+ req_id,
+ cast_ptr(reply1, struct ethtool_pauseparam *));
+ break;
+
+ case set_pauseparam:
+ status = proc_ethtool_set_pauseparam(port_id,
+ req_id,
+ cast_ptr(reply1, struct ethtool_pauseparam *));
+ break;
+
+ case dev_open:
+ status = proc_net_open(port_id, req_id);
+ break;
+
+ case dev_stop:
+ status = proc_net_stop(port_id, req_id);
+ break;
+
+ case set_rx_mode:
+ status = proc_net_set_rx_mode(port_id, req_id);
+ break;
+
+ case get_mac_addr:
+ status = proc_net_get_mac_addr(port_id,
+ req_id, first_param);
+ break;
+
+ case set_mac_addr:
+ status = proc_net_set_mac_addr(port_id,
+ req_id, first_param);
+ break;
+
+ case validate_addr:
+ status = proc_net_validate_addr(port_id,
+ req_id, first_param);
+ break;
+
+ case set_config:
+ status = proc_net_set_config(port_id,
+ req_id, first_param);
+ break;
+
+ case change_mtu:
+ status = proc_net_change_mtu(port_id,
+ req_id, first_param);
+ break;
+
+ case get_stats64:
+ status = proc_net_get_stats64(port_id,
+ req_id, reply1);
+ break;
+
+ case vlan_rx_add_vid:
+ status = proc_net_vlan_rx_add_vid(port_id,
+ req_id, first_param);
+ break;
+
+ case vlan_rx_kill_vid:
+ status = proc_net_vlan_rx_kill_vid(port_id,
+ req_id, first_param);
+ break;
+
+ case ipc_end:
+ keep_req = 0;
+ proc_no_action(req_id);
+ status = 0;
+ break;
+
+ default:
+ proc_invalid(req_id);
+ printf("unsupported service request type:");
+ printf(" %d\n", req_type);
+ break;
+ }
+ if (status < 0)
+ printf("Request type (=%d) failed\n", (int)req_type);
+ /* check if termination flag is set */
+ }
+ printf("IPC session is over\n");
+ return NULL;
+}
+
+int
+main(int argc, char **argv)
+{
+ struct lcore_queue_conf *qconf;
+ struct rte_eth_dev_info dev_info;
+ int ret;
+ uint8_t nb_ports;
+ uint8_t nb_ports_available;
+ uint8_t portid, last_port;
+ unsigned lcore_id, rx_lcore_id;
+ unsigned nb_ports_in_mask = 0;
+
+ init_ipc_done();
+ /* init EAL */
+ ret = rte_eal_init(argc, argv);
+ if (ret < 0)
+ rte_exit(EXIT_FAILURE, "Invalid EAL arguments\n");
+ argc -= ret;
+ argv += ret;
+
+ /* parse application arguments (after the EAL ones) */
+ ret = l2fwd_parse_args(argc, argv);
+ if (ret < 0)
+ rte_exit(EXIT_FAILURE, "Invalid L2FWD arguments\n");
+
+ /* create the mbuf pool */
+ l2fwd_pktmbuf_pool =
+ rte_mempool_create("mbuf_pool", NB_MBUF,
+ MBUF_SIZE, 32,
+ sizeof(struct rte_pktmbuf_pool_private),
+ rte_pktmbuf_pool_init, NULL,
+ rte_pktmbuf_init, NULL,
+ rte_socket_id(), 0);
+ if (l2fwd_pktmbuf_pool == NULL)
+ rte_exit(EXIT_FAILURE, "Cannot init mbuf pool\n");
+
+ nb_ports = rte_eth_dev_count();
+ if (nb_ports == 0)
+ rte_exit(EXIT_FAILURE, "No Ethernet ports - bye\n");
+
+ if (nb_ports > RTE_MAX_ETHPORTS)
+ nb_ports = RTE_MAX_ETHPORTS;
+
+ /* reset l2fwd_dst_ports */
+ for (portid = 0; portid < RTE_MAX_ETHPORTS; portid++)
+ l2fwd_dst_ports[portid] = 0;
+ last_port = 0;
+
+ /*
+ * Each logical core is assigned a dedicated TX queue on each port.
+ */
+ for (portid = 0; portid < nb_ports; portid++) {
+ /* skip ports that are not enabled */
+ if ((l2fwd_enabled_port_mask & (1 << portid)) == 0)
+ continue;
+
+ if (nb_ports_in_mask % 2) {
+ l2fwd_dst_ports[portid] = last_port;
+ l2fwd_dst_ports[last_port] = portid;
+ } else
+ last_port = portid;
+
+ nb_ports_in_mask++;
+
+ rte_eth_dev_info_get(portid, &dev_info);
+ }
+ if (nb_ports_in_mask % 2) {
+ printf("Notice: odd number of ports in portmask.\n");
+ l2fwd_dst_ports[last_port] = last_port;
+ }
+
+ rx_lcore_id = 0;
+ qconf = NULL;
+
+ /* Initialize the port/queue configuration of each logical core */
+ for (portid = 0; portid < nb_ports; portid++) {
+ /* skip ports that are not enabled */
+ if ((l2fwd_enabled_port_mask & (1 << portid)) == 0)
+ continue;
+
+ /* get the lcore_id for this port */
+ while (rte_lcore_is_enabled(rx_lcore_id) == 0 ||
+ lcore_queue_conf[rx_lcore_id].n_rx_port ==
+ l2fwd_rx_queue_per_lcore) {
+ rx_lcore_id++;
+ if (rx_lcore_id >= RTE_MAX_LCORE)
+ rte_exit(EXIT_FAILURE, "Not enough cores\n");
+ }
+
+ if (qconf != &lcore_queue_conf[rx_lcore_id])
+ /* Assigned a new logical core in the loop above. */
+ qconf = &lcore_queue_conf[rx_lcore_id];
+
+ qconf->rx_port_list[qconf->n_rx_port] = portid;
+ qconf->n_rx_port++;
+ printf("Lcore %u: RX port %u\n", rx_lcore_id,
+ (unsigned) portid);
+ }
+
+ nb_ports_available = nb_ports;
+
+ /* Initialise each port */
+ for (portid = 0; portid < nb_ports; portid++) {
+ /* skip ports that are not enabled */
+ if ((l2fwd_enabled_port_mask & (1 << portid)) == 0) {
+ printf("Skipping disabled port %u\n",
+ (unsigned) portid);
+ nb_ports_available--;
+ continue;
+ }
+ /* init port */
+ printf("Initializing port %u... ", (unsigned) portid);
+ fflush(stdout);
+ ret = rte_eth_dev_configure(portid, 1, 1, &port_conf);
+ if (ret < 0)
+ rte_exit(EXIT_FAILURE,
+ "Cannot configure device: err=%d, port=%u\n",
+ ret, (unsigned) portid);
+
+ rte_eth_macaddr_get(portid, &l2fwd_ports_eth_addr[portid]);
+
+ /* init one RX queue */
+ fflush(stdout);
+ ret = rte_eth_rx_queue_setup(portid, 0, nb_rxd,
+ rte_eth_dev_socket_id(portid),
+ NULL,
+ l2fwd_pktmbuf_pool);
+ if (ret < 0)
+ rte_exit(EXIT_FAILURE,
+ "rte_eth_rx_queue_setup:err=%d, port=%u\n",
+ ret, (unsigned) portid);
+
+ /* init one TX queue on each port */
+ fflush(stdout);
+ if (virtio_setup) {
+ ret = rte_eth_tx_queue_setup(portid, 0, nb_txd,
+ rte_eth_dev_socket_id(portid), &tx_conf);
+ } else {
+ ret = rte_eth_tx_queue_setup(portid, 0, nb_txd,
+ rte_eth_dev_socket_id(portid),
+ NULL);
+ }
+ if (ret < 0)
+ rte_exit(EXIT_FAILURE,
+ "rte_eth_tx_queue_setup:err=%d, port=%u\n",
+ ret, (unsigned) portid);
+ }
+
+ /* create a ethtool proxy thread */
+ pthread_attr_t attr;
+ cpu_set_t cpus;
+ pthread_t ethtool_thread;
+ struct nic_info info;
+
+ /* set core affinity to core 1 */
+ CPU_ZERO(&cpus);
+ CPU_SET(2, &cpus);
+ pthread_attr_init(&attr);
+ pthread_attr_setaffinity_np(&attr, sizeof(cpu_set_t), &cpus);
+ /* Since the register size is more than 4K (1147*4) */
+ pthread_attr_setstacksize(&attr, 4*PAGE_SIZE);
+
+ info.num_of_ports = nb_ports;
+ info.port_mask = l2fwd_enabled_port_mask;
+ if (pthread_create(ðtool_thread, NULL, ðtool, &info)) {
+ rte_exit(EXIT_FAILURE,
+ "Fail to create a pthread for ethtool task!!!\n");
+ }
+ memset(&port_statistics, 0, sizeof(port_statistics));
+
+ if (!nb_ports_available) {
+ rte_exit(EXIT_FAILURE,
+ "All available ports are disabled. Please set portmask.\n");
+ }
+
+ check_all_ports_link_status(nb_ports, l2fwd_enabled_port_mask);
+
+ /* launch per-lcore init on every lcore */
+ rte_eal_mp_remote_launch(l2fwd_launch_one_lcore, NULL, CALL_MASTER);
+ RTE_LCORE_FOREACH_SLAVE(lcore_id) {
+ if (rte_eal_wait_lcore(lcore_id) < 0)
+ return -1;
+ }
+
+ return 0;
+}
diff --git a/examples/l2fwd-ethtool/l2fwd-app/netdev_api.h b/examples/l2fwd-ethtool/l2fwd-app/netdev_api.h
new file mode 100644
index 0000000..2e93e9a
--- /dev/null
+++ b/examples/l2fwd-ethtool/l2fwd-app/netdev_api.h
@@ -0,0 +1,770 @@
+/*-
+ * BSD LICENSE
+ *
+ * Copyright(c) 2015 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _NETDEV_API_H_
+#define _NETDEV_API_H_
+
+#include <linux/ethtool.h>
+#include <string.h>
+#include "shared_fifo.h"
+
+#define MAC_ADDR_SIZE 6
+#define quad_aligned_size(x) ((x & 0x7) ? ((x+7)&0x7) : x)
+
+#define size16(data_type) (uint16_t)(sizeof(data_type))
+
+/* NETDEV_STATUS = 0 if successful */
+#define NETDEV_UNSUPPORTED -1
+#define NETDEV_INVALID -1
+#define NETDEV_STATUS(data_size) (GOOD_RETURN(data_size) \
+ ? 0 : NETDEV_INVALID)
+#define UNUSED(x) (void)(x)
+
+#ifdef NETDEV_OP_REQUEST
+static uint16_t
+next_reqid(void) {
+ static uint16_t request_id;
+
+ return request_id++;
+}
+
+/*
+ * send request (with one or two variables) to request-pipe
+ * (invoked by non- DPDK process)
+ */
+static int
+send_request(uint16_t req_id, uint8_t req_type, uint16_t param_size,
+ void *param_data)
+{
+ int fd;
+ uint32_t req[2];
+
+ req[0] = REQ_DWORD_LO(req_id, 0, req_type);
+ req[1] = REQ_DWORD_HI(param_size, 0);
+
+ fd = open(REQ_PIPE, O_WRONLY);
+ write(fd, req, PIPE_CTL_BYTE_COUNT);
+ if (param_size)
+ write(fd, param_data, param_size);
+ close(fd);
+
+ return 0;
+}
+
+/*
+ * send request (with more than two variables) to request-pipe
+ * (invoked by non- DPDK process)
+ */
+static int
+send_request2(uint16_t req_id, uint8_t req_type, uint16_t param1_size,
+ void *param1_data, int param2_size, void *param2_data)
+{
+ int fd;
+ uint32_t req[2];
+
+ req[0] = REQ_DWORD_LO(req_id, 1, req_type);
+ req[1] = REQ_DWORD_HI(param1_size, param2_size);
+
+ fd = open(REQ_PIPE, O_WRONLY);
+ write(fd, req, PIPE_CTL_BYTE_COUNT);
+
+ if (param1_size)
+ write(fd, param1_data, param1_size);
+ if (param2_size)
+ write(fd, param2_data, param2_size);
+ close(fd);
+
+ return 0;
+}
+
+/* read return variables from the reply-pipe (invoked by non- DPDK process) */
+static int
+read_reply(uint16_t expected_id, uint16_t *byte_count, void *reply_data1,
+ void *reply_data2)
+{
+ int fd;
+ uint32_t req[2];
+ uint16_t rx_id, data1_size;
+
+ /* block on read if reply is not available */
+ fd = open(REP_PIPE, O_RDONLY);
+ read(fd, req, PIPE_CTL_BYTE_COUNT);
+
+ *byte_count = REP_DATA1_COUNT(req);
+ rx_id = REP_ID(req);
+
+ if (!GOOD_RETURN(*byte_count)) {
+ close(fd);
+ return -1;
+ }
+ data1_size = BYTE_COUNT((*byte_count));
+ read(fd, reply_data1, data1_size);
+ if (MULTIPLE_DATA(*byte_count)) {
+ assert(reply_data2);
+ read(fd, reply_data2, REP_DATA2_COUNT(req));
+ }
+ close(fd);
+
+ if (expected_id != rx_id)
+ return -1;
+ return 0;
+}
+
+/* definition of netdev op request */
+
+static int
+netdev_ethtool_get_drvinfo(uint8_t port_id, struct ethtool_drvinfo *drvinfo)
+{
+ uint16_t req_id = next_reqid();
+ uint16_t data_size;
+
+ send_request(req_id, get_drvinfo, 1, &port_id);
+ read_reply(req_id, &data_size, drvinfo, NULL);
+
+ return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_ethtool_get_regs_len(uint8_t port_id)
+{
+ uint16_t req_id = next_reqid();
+ uint16_t data_size;
+ int length;
+
+ send_request(req_id, get_regs_len, 1, &port_id);
+ read_reply(req_id, &data_size, &length, NULL);
+
+ if (GOOD_RETURN(data_size))
+ return length;
+ return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_ethtool_get_regs(uint8_t port_id, struct ethtool_regs *regs, void *buf)
+{
+ uint16_t req_id = next_reqid();
+ uint16_t data_size;
+ uint8_t param_data[PARAM_SIZE(struct ethtool_regs)];
+
+ param_data[0] = port_id;
+ memcpy(FIRST_PARAM(param_data), regs, sizeof(struct ethtool_regs));
+
+ send_request(req_id, get_regs, PARAM_SIZE(struct ethtool_regs),
+ param_data);
+ read_reply(req_id, &data_size, regs, buf);
+
+ return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_ethtool_get_link(uint8_t port_id)
+{
+ uint16_t req_id = next_reqid();
+ uint16_t data_size;
+ int link_status;
+
+ send_request(req_id, get_link, 1, &port_id);
+ read_reply(req_id, &data_size, &link_status, NULL);
+ if (GOOD_RETURN(data_size))
+ return link_status;
+ return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_ethtool_get_eeprom_len(uint8_t port_id)
+{
+ uint16_t req_id = next_reqid();
+ uint16_t data_size;
+ int length;
+
+ send_request(req_id, get_eeprom_len, 1, &port_id);
+ read_reply(req_id, &data_size, &length, NULL);
+
+ if (GOOD_RETURN(data_size))
+ return length;
+ return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_ethtool_get_eeprom(uint8_t port_id, struct ethtool_eeprom *eeprom,
+ void *words)
+{
+ uint16_t req_id = next_reqid();
+ uint16_t data_size;
+ uint8_t param_data[PARAM_SIZE(struct ethtool_eeprom)];
+
+ param_data[0] = port_id;
+ memcpy(FIRST_PARAM(param_data), eeprom, sizeof(struct ethtool_eeprom));
+
+ send_request(req_id, get_eeprom, PARAM_SIZE(struct ethtool_eeprom),
+ param_data);
+ read_reply(req_id, &data_size, eeprom, words);
+
+ return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_ethtool_set_eeprom(uint8_t port_id, struct ethtool_eeprom *eeprom,
+ void *words)
+{
+ uint16_t req_id = next_reqid();
+ uint16_t data_size;
+ uint8_t param_data[PARAM_SIZE(struct ethtool_eeprom)];
+
+ param_data[0] = port_id;
+ memcpy(FIRST_PARAM(param_data), eeprom, sizeof(struct ethtool_eeprom));
+
+ send_request2(req_id, set_eeprom, PARAM_SIZE(struct ethtool_eeprom),
+ param_data, eeprom->len, words);
+ read_reply(req_id, &data_size, eeprom, NULL);
+
+ return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_ethtool_get_pauseparam(uint8_t port_id, struct ethtool_pauseparam *param)
+{
+ uint16_t req_id = next_reqid();
+ uint16_t data_size;
+
+ send_request(req_id, get_pauseparam, 1, &port_id);
+ read_reply(req_id, &data_size, param, NULL);
+
+ return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_ethtool_set_pauseparam(uint8_t port_id, struct ethtool_pauseparam *param)
+{
+ uint16_t req_id = next_reqid();
+ uint16_t data_size;
+
+ send_request(req_id, set_pauseparam, 1, &port_id);
+ read_reply(req_id, &data_size, param, NULL);
+
+ return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_net_open(uint8_t port_id) {
+ uint16_t req_id = next_reqid();
+ uint16_t data_size;
+
+ send_request(req_id, dev_open, 1, &port_id);
+ read_reply(req_id, &data_size, NULL, NULL);
+
+ return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_net_stop(uint8_t port_id) {
+ uint16_t req_id = next_reqid();
+ uint16_t data_size;
+
+ send_request(req_id, dev_stop, 1, &port_id);
+ read_reply(req_id, &data_size, NULL, NULL);
+
+ return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_net_set_rx_mode(uint8_t port_id)
+{
+ uint16_t req_id = next_reqid();
+ uint16_t data_size;
+
+ send_request(req_id, set_rx_mode, 1, &port_id);
+ read_reply(req_id, &data_size, NULL, NULL);
+
+ return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_net_get_mac_addr(uint8_t port_id, void *addr)
+{
+ uint16_t req_id = next_reqid();
+ uint16_t data_size;
+
+ send_request(req_id, get_mac_addr, 1, &port_id);
+ read_reply(req_id, &data_size, addr, NULL);
+
+ return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_net_set_mac_addr(uint8_t port_id, void *addr)
+{
+ uint16_t req_id = next_reqid();
+ uint16_t data_size;
+ uint8_t param_data[FIRST_DATA_OFFSET+MAC_ADDR_SIZE];
+
+ param_data[0] = port_id;
+ memcpy(FIRST_PARAM(param_data), addr, MAC_ADDR_SIZE);
+ send_request(req_id, set_mac_addr,
+ (FIRST_DATA_OFFSET+MAC_ADDR_SIZE), param_data);
+ read_reply(req_id, &data_size, NULL, NULL);
+
+ return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_net_validate_addr(uint8_t port_id, void *addr)
+{
+ uint16_t req_id = next_reqid();
+ uint16_t data_size;
+ uint8_t param_data[FIRST_DATA_OFFSET+MAC_ADDR_SIZE];
+ int valid;
+
+ param_data[0] = port_id;
+ memcpy(FIRST_PARAM(param_data), addr, MAC_ADDR_SIZE);
+ send_request(req_id, validate_addr,
+ (FIRST_DATA_OFFSET+MAC_ADDR_SIZE), param_data);
+ read_reply(req_id, &data_size, &valid, NULL);
+
+ if (GOOD_RETURN(data_size))
+ return valid;
+ return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_net_change_mtu(uint8_t port_id, int mtu)
+{
+ uint16_t req_id = next_reqid();
+ uint16_t data_size;
+ uint8_t param_data[PARAM_SIZE(int)];
+
+ param_data[0] = port_id;
+ memcpy(FIRST_PARAM(param_data), &mtu, sizeof(int));
+ send_request(req_id, change_mtu, PARAM_SIZE(int), param_data);
+ read_reply(req_id, &data_size, NULL, NULL);
+
+ return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_net_get_stats64(uint8_t port_id, void *stats)
+{
+ uint16_t req_id = next_reqid();
+ uint16_t data_size;
+
+ send_request(req_id, get_stats64, 1, &port_id);
+ read_reply(req_id, &data_size, stats, NULL);
+
+ return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_net_vlan_rx_add_vid(uint8_t port_id, uint16_t vid)
+{
+ uint16_t req_id = next_reqid();
+ uint16_t data_size;
+ uint8_t param_data[PARAM_SIZE(int)];
+
+ param_data[0] = port_id;
+ memcpy(FIRST_PARAM(param_data), &vid, sizeof(uint16_t));
+ send_request(req_id, vlan_rx_add_vid, FIRST_DATA_OFFSET+sizeof(int),
+ param_data);
+ read_reply(req_id, &data_size, NULL, NULL);
+
+ return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_net_vlan_rx_kill_vid(uint8_t port_id, uint16_t vid)
+{
+ uint16_t req_id = next_reqid();
+ uint16_t data_size;
+ uint8_t param_data[PARAM_SIZE(int)];
+
+ param_data[0] = port_id;
+ memcpy(FIRST_PARAM(param_data), &vid, sizeof(uint16_t));
+ send_request(req_id, vlan_rx_kill_vid, FIRST_DATA_OFFSET+sizeof(int),
+ param_data);
+ read_reply(req_id, &data_size, NULL, NULL);
+
+ return NETDEV_STATUS(data_size);
+};
+
+#endif /* NETDEV_OP_REQUEST */
+
+#ifdef NETDEV_OP_REPLY
+/* read request from request-pipe (invoked by rte-api server thread) */
+static int
+read_request(uint16_t *req_id, uint8_t *req_type, uint16_t *param1_size,
+ uint8_t *param1_data, uint16_t *param2_size, void *param2_data)
+{
+ int fd;
+ uint32_t req[2];
+
+ /* block on read if request is not sent ... */
+ fd = open(REQ_PIPE, O_RDONLY);
+ read(fd, req, PIPE_CTL_BYTE_COUNT);
+
+ *req_id = REQ_ID(req);
+ *req_type = REQ_TYPE(req);
+ *param1_size = REQ_PARAM1_SIZE(req);
+
+ if (*param1_size > 0) {
+ read(fd, param1_data, *param1_size);
+ if (REQ_IDTYPE(req)) {
+ *param2_size = REQ_PARAM2_SIZE(req);
+ read(fd, param2_data, *param2_size);
+ } else
+ *param2_size = 0;
+ }
+ close(fd);
+
+ return 0;
+}
+
+/* definition of netdev op service */
+/*
+ * rep[1:0]: request id
+ * rep[3:2]: data byte count; bit[15]: error status bit[14]: multiple return
+ * variables are requested
+ *
+ * send reply with one return variable to reply-pipe
+ * (invoked by rte-api server thread)
+ */
+static int
+send_reply(uint16_t rx_id, uint16_t byte_count, void *reply_data)
+{
+ int fd;
+ uint32_t req[2];
+
+ req[0] = REP_DWORD_LO(rx_id, byte_count);
+ req[1] = REP_DWORD_HI(0);
+
+ fd = open(REP_PIPE, O_WRONLY);
+ write(fd, req, PIPE_CTL_BYTE_COUNT);
+
+ if (GOOD_RETURN(byte_count) && (byte_count > 0))
+ write(fd, reply_data, byte_count);
+ close(fd);
+
+ return 0;
+}
+
+/*
+ * send reply with two or more variables to reply-pipe
+ * (invoked by rte-api server thread)
+ */
+static int
+send_reply2(uint16_t rx_id, uint16_t byte_count1, void *reply_data1,
+ uint16_t byte_count2, void *reply_data2)
+{
+ int fd;
+ uint32_t req[2];
+
+ req[0] = REP_DWORD_LO(rx_id, REP_MUTILPLE_DATA(byte_count1));
+ req[1] = REP_DWORD_HI(byte_count2);
+
+ fd = open(REP_PIPE, O_WRONLY);
+ write(fd, req, PIPE_CTL_BYTE_COUNT);
+
+ if (GOOD_RETURN(byte_count1) && (byte_count2 > 0)) {
+ write(fd, reply_data1, byte_count1);
+ write(fd, reply_data2, byte_count2);
+ }
+ close(fd);
+
+ return 0;
+}
+
+/* Functions for netdev service thread */
+static int
+proc_ethtool_get_drvinfo(uint8_t port_id, uint16_t req_id, void *param_data)
+{
+ struct ethtool_drvinfo *drvinfo = param_data;
+ uint16_t data_size;
+
+ if (rte_ethtool_get_drvinfo(port_id, drvinfo))
+ data_size = STATUS_MASK;
+ else
+ data_size = size16(struct ethtool_drvinfo);
+ return send_reply(req_id, data_size, param_data);
+};
+
+static int
+proc_ethtool_get_regs_len(uint8_t port_id, uint16_t req_id)
+{
+ int reg_len;
+ uint16_t data_size;
+
+ reg_len = rte_ethtool_get_regs_len(port_id);
+ if (reg_len == 0)
+ data_size = STATUS_MASK;
+ else
+ data_size = size16(int);
+ return send_reply(req_id, data_size, ®_len);
+};
+
+static int
+proc_ethtool_get_regs(uint8_t port_id, uint16_t req_id, void *param_data,
+ void *reply_data2)
+{
+ struct ethtool_regs *reg_info = param_data;
+ void *buf = reply_data2;
+ uint16_t data_size;
+
+ if (rte_ethtool_get_regs(port_id, reg_info, buf))
+ data_size = STATUS_MASK;
+ else
+ data_size = sizeof(struct ethtool_regs);
+ return send_reply2(req_id, data_size, reg_info,
+ rte_ethtool_get_regs_len(port_id)*sizeof(int), reply_data2);
+};
+
+static int
+proc_ethtool_get_link(uint8_t port_id, uint16_t req_id)
+{
+ int link_status;
+
+ link_status = rte_ethtool_get_link(port_id);
+ return send_reply(req_id, (uint16_t)sizeof(int), &link_status);
+};
+
+static int
+proc_ethtool_get_eeprom_len(uint8_t port_id, uint16_t req_id)
+{
+ int eeprom_length;
+ uint16_t data_size;
+
+ eeprom_length = rte_ethtool_get_eeprom_len(port_id);
+ if (eeprom_length == 0)
+ data_size = STATUS_MASK;
+ else
+ data_size = size16(int);
+ return send_reply(req_id, data_size, &eeprom_length);
+};
+
+static int
+proc_ethtool_get_eeprom(uint8_t port_id, uint16_t req_id, void *param_data,
+ void *reply_data2)
+{
+ struct ethtool_eeprom *eeprom_ptr = param_data;
+ uint16_t data_size;
+
+ if (rte_ethtool_get_eeprom(port_id, eeprom_ptr, reply_data2))
+ data_size = STATUS_MASK;
+ else
+ data_size = sizeof(struct ethtool_eeprom);
+ return send_reply2(req_id, data_size, eeprom_ptr,
+ eeprom_ptr->len & ~1, reply_data2);
+};
+
+static int
+proc_ethtool_set_eeprom(uint8_t port_id, uint16_t req_id, void *param_data,
+ void *param2_data)
+{
+ struct ethtool_eeprom *eeprom_ptr = param_data;
+ uint16_t data_size;
+
+ if (rte_ethtool_set_eeprom(port_id, eeprom_ptr, param2_data))
+ data_size = STATUS_MASK;
+ else
+ data_size = sizeof(struct ethtool_eeprom);
+ return send_reply(req_id, data_size, eeprom_ptr);
+};
+
+static int
+proc_ethtool_get_pauseparam(uint8_t port_id, uint16_t req_id, void *reply_data)
+{
+ uint16_t data_size;
+
+ if (rte_ethtool_get_pauseparam(port_id,
+ (struct ethtool_pauseparam *)reply_data))
+ data_size = STATUS_MASK;
+ else
+ data_size = (uint16_t)(sizeof(struct ethtool_pauseparam));
+ return send_reply(req_id, data_size, reply_data);
+};
+
+static int
+proc_ethtool_set_pauseparam(uint8_t port_id, uint16_t req_id, void *set_data)
+{
+ uint16_t data_size;
+
+ if (rte_ethtool_set_pauseparam(port_id,
+ (struct ethtool_pauseparam *)set_data))
+ data_size = STATUS_MASK;
+ else
+ data_size = (uint16_t)(sizeof(struct ethtool_pauseparam));
+ return send_reply(req_id, data_size, set_data);
+};
+
+static int
+proc_net_open(uint8_t port_id, uint16_t req_id)
+{
+ uint16_t data_size;
+
+ if (rte_ethtool_net_open(port_id))
+ data_size = STATUS_MASK;
+ else
+ data_size = 0;
+
+ return send_reply(req_id, data_size, &data_size);
+};
+
+static int
+proc_net_stop(uint8_t port_id, uint16_t req_id)
+{
+ uint16_t data_size;
+
+ rte_ethtool_net_stop(port_id);
+ data_size = 0;
+
+ return send_reply(req_id, data_size, &data_size);
+};
+
+static int
+proc_net_set_rx_mode(uint8_t port_id, uint16_t req_id)
+{
+ uint16_t data_size;
+
+ if (rte_ethtool_net_set_rx_mode(port_id))
+ data_size = STATUS_MASK;
+ else
+ data_size = 0;
+
+ return send_reply(req_id, data_size, &data_size);
+};
+
+static int
+proc_net_get_mac_addr(uint8_t port_id, uint16_t req_id, void *param_data)
+{
+ uint16_t data_size;
+
+ if (rte_ethtool_net_get_mac_addr(port_id, param_data))
+ data_size = STATUS_MASK;
+ else
+ data_size = MAC_ADDR_SIZE;
+
+ return send_reply(req_id, data_size, param_data);
+};
+
+static int
+proc_net_set_mac_addr(uint8_t port_id, uint16_t req_id, void *param_data)
+{
+ uint16_t data_size;
+
+ if (rte_ethtool_net_set_mac_addr(port_id, param_data))
+ data_size = STATUS_MASK;
+ else
+ data_size = 0;
+
+ return send_reply(req_id, data_size, &data_size);
+};
+
+static int
+proc_net_validate_addr(uint8_t port_id, uint16_t req_id, void *param_data)
+{
+ int status;
+
+ status = rte_ethtool_net_validate_addr(port_id, param_data);
+
+ return send_reply(req_id, (uint16_t)sizeof(int), &status);
+};
+
+static int
+proc_net_set_config(uint8_t port_id, uint16_t req_id, void *param_data)
+{
+ uint16_t data_size;
+
+ if (rte_ethtool_net_set_config(port_id, param_data))
+ data_size = STATUS_MASK;
+ else
+ data_size = 0;
+
+ return send_reply(req_id, data_size, &data_size);
+};
+
+static int
+proc_net_change_mtu(uint8_t port_id, uint16_t req_id, void *param_data)
+{
+ uint16_t data_size;
+ int mtu = *(int *)(param_data);
+
+ if (rte_ethtool_net_change_mtu(port_id, mtu))
+ data_size = STATUS_MASK;
+ else
+ data_size = 0;
+
+ return send_reply(req_id, data_size, &data_size);
+};
+
+static int
+proc_net_get_stats64(uint8_t port_id, uint16_t req_id, void *reply_data)
+{
+ uint16_t data_size;
+
+ if (rte_ethtool_net_get_stats64(port_id, reply_data))
+ data_size = STATUS_MASK;
+ else
+ data_size = size16(struct rte_eth_stats);
+
+ return send_reply(req_id, data_size, reply_data);
+};
+
+static int
+proc_net_vlan_rx_add_vid(uint8_t port_id, uint16_t req_id,
+ void *param_data)
+{
+ uint16_t data_size;
+ int *vid_ptr = (int *)param_data;
+
+ if (rte_ethtool_net_vlan_rx_add_vid(port_id, *vid_ptr))
+ data_size = STATUS_MASK;
+ else
+ data_size = 0;
+
+ return send_reply(req_id, data_size, &data_size);
+};
+
+static int
+proc_net_vlan_rx_kill_vid(uint8_t port_id, uint16_t req_id,
+ void *param_data)
+{
+ uint16_t data_size;
+ int *vid_ptr = (int *)param_data;
+
+ if (rte_ethtool_net_vlan_rx_kill_vid(port_id, *vid_ptr))
+ data_size = STATUS_MASK;
+ else
+ data_size = 0;
+
+ return send_reply(req_id, data_size, &data_size);
+};
+
+#endif /* NETDEV_OP_REPLY */
+#endif /* _NETDEV_API_H_ */
diff --git a/examples/l2fwd-ethtool/l2fwd-app/shared_fifo.h b/examples/l2fwd-ethtool/l2fwd-app/shared_fifo.h
new file mode 100644
index 0000000..be528b8
--- /dev/null
+++ b/examples/l2fwd-ethtool/l2fwd-app/shared_fifo.h
@@ -0,0 +1,159 @@
+/*-
+ * BSD LICENSE
+ *
+ * Copyright(c) 2015 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _SHARED_FIFO_H_
+#define _SHARED_FIFO_H_
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <assert.h>
+
+#define REQ_PIPE "/tmp/nic_request"
+#define REP_PIPE "/tmp/nic_reply"
+#define PAGE_SIZE (4*1024)
+#define STACK_SIZE (4*PAGE_SIZE)
+#define MAXI_DATA (1024*6)
+#define MAXI_PARA 1024
+#define STATUS_MASK 0x8000
+#define MULTIPLE_DATA_MASK 0x4000
+#define MAXI_REQ_TYPE 16
+#define FIRST_DATA_OFFSET 8
+#define cast_ptr(x, new_type) (new_type)(void *)(x)
+#define to_ptr(new_ptr_type, data, offset) \
+ (new_ptr_type)(&((unsigned char *)(void *)data)[offset])
+#define u8ptr(x) cast_ptr(x, uint8_t *)
+#define to_mac_type(x) cast_ptr(x, struct ether_addr *)
+
+/*
+ * req[1:0]: request-id
+ * req[2]: request-id type
+ * req[3]: request type
+ * req[4:5]: param1-size
+ * req[7:6]: param2-size
+ *
+ * rep[1:0] reply-id
+ * rep[3:2]: data1-size // bit[15]: status bit[14]: two return data
+ * rep[7:4]: data2-size
+ */
+#define PIPE_CTL_BYTE_COUNT (sizeof(uint32_t)*2)
+#define REQ_DWORD_LO(req_id, id_type, req_tye) \
+ (((uint32_t)req_type << 24) | ((uint32_t)id_type << 16) | req_id)
+#define REQ_DWORD_HI(param1_size, param2_size) \
+ (((uint32_t)param2_size << 16) | param1_size)
+
+#define REP_DWORD_LO(rep_id, data_bytes) \
+ (((uint32_t)data_bytes << 16) | (uint32_t)rep_id)
+#define REP_DWORD_HI(data2_bytes) (data2_bytes)
+
+#define REP_MUTILPLE_DATA(data1_size) (data1_size | MULTIPLE_DATA_MASK)
+#define REQ_ID(dword_ptr) (dword_ptr[0] & 0xFFFF)
+#define REQ_IDTYPE(dword_ptr) ((dword_ptr[0] >> 16) & 0xFF)
+#define REQ_TYPE(dword_ptr) ((dword_ptr[0] >> 24) & 0xFF)
+#define REQ_PARAM1_SIZE(dword_ptr) (dword_ptr[1] & 0xFFFF)
+#define REQ_PARAM2_SIZE(dword_ptr) ((dword_ptr[1]>>16) & 0xFFFF)
+#define REP_ID(dword_ptr) (dword_ptr[0] & 0xFFFF)
+#define REP_DATA1_COUNT(dword_ptr) ((dword_ptr[0] >> 16) & 0xFFFF)
+#define REP_DATA2_COUNT(dword_ptr) (dword_ptr[1])
+
+#define BAD_RETURN(data_size) (data_size | STATUS_MASK)
+#define GOOD_RETURN(data_size) ((data_size & STATUS_MASK) == 0)
+#define MULTIPLE_DATA(data_size) (data_size & MULTIPLE_DATA_MASK)
+#define BYTE_COUNT(data_size) \
+ (data_size & ~(STATUS_MASK|MULTIPLE_DATA_MASK))
+
+#define PARAM_SIZE(type) \
+ ((uint16_t)(FIRST_DATA_OFFSET+sizeof(type)))
+#define FIRST_PARAM(param_data) (void *)(&(param_data[FIRST_DATA_OFFSET]))
+#define FIRST_PARAM_TYPE(param_data, ptr_type) \
+ (ptr_type)(FIRST_PARAM(param_data))
+
+void init_req_pipe(void);
+void init_rep_pipe(void);
+
+struct nic_info {
+ uint8_t num_of_ports;
+ uint32_t port_mask;
+ uint32_t vf_port_mask;
+ uint32_t flag;
+} nic_info;
+
+enum req_t {
+ get_drvinfo = 0,
+ get_setting,
+ set_setting,
+ get_regs_len,
+ get_regs,
+ get_link,
+ get_eeprom_len,
+ get_eeprom,
+ set_eeprom,
+ get_coalesce,
+ set_coalesce,
+ get_pauseparam,
+ set_pauseparam,
+ dump_data,
+
+ dev_open,
+ dev_stop,
+ set_rx_mode,
+ get_mac_addr,
+ set_mac_addr,
+ validate_addr,
+ set_config,
+ change_mtu,
+ get_stats64,
+ get_stats,
+ vlan_rx_add_vid,
+ vlan_rx_kill_vid,
+ ipc_begin, /* request to start ipc, and get nic info ... */
+ ipc_end, /* request to stop ipc ... */
+ invalid_req,
+};
+
+void
+init_req_pipe(void)
+{
+ mkfifo(REQ_PIPE, 0666);
+}
+
+void
+init_rep_pipe(void)
+{
+ mkfifo(REP_PIPE, 0666);
+}
+
+#endif /* _SHARED_FIFO_H_ */
diff --git a/examples/l2fwd-ethtool/lib/Makefile b/examples/l2fwd-ethtool/lib/Makefile
new file mode 100644
index 0000000..d7ee955
--- /dev/null
+++ b/examples/l2fwd-ethtool/lib/Makefile
@@ -0,0 +1,57 @@
+# BSD LICENSE
+#
+# Copyright(c) 2015 Intel Corporation. All rights reserved.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in
+# the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Intel Corporation nor the names of its
+# contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ifeq ($(RTE_SDK),)
+$(error "Please define RTE_SDK environment variable")
+endif
+
+# Default target, can be overwritten by command line or environment
+RTE_TARGET ?= x86_64-native-linuxapp-gcc
+
+include $(RTE_SDK)/mk/rte.vars.mk
+
+ifneq ($(CONFIG_RTE_EXEC_ENV),"linuxapp")
+$(error This application can only operate in a linuxapp 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)
+
+include $(RTE_SDK)/mk/rte.extlib.mk
diff --git a/examples/l2fwd-ethtool/lib/rte_ethtool.c b/examples/l2fwd-ethtool/lib/rte_ethtool.c
new file mode 100644
index 0000000..2ef78f1
--- /dev/null
+++ b/examples/l2fwd-ethtool/lib/rte_ethtool.c
@@ -0,0 +1,336 @@
+/*-
+ * BSD LICENSE
+ *
+ * Copyright(c) 2010-2015 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include <stdio.h>
+#include <string.h>
+#include <stdint.h>
+#include <rte_version.h>
+#include <rte_ethdev.h>
+#include "rte_ethtool.h"
+
+int
+rte_ethtool_get_drvinfo(uint8_t port_id, struct ethtool_drvinfo *drvinfo)
+{
+ struct rte_eth_dev_info dev_info;
+ int n;
+
+ memset(&dev_info, 0, sizeof(dev_info));
+ rte_eth_dev_info_get(port_id, &dev_info);
+
+ snprintf(drvinfo->driver, sizeof(drvinfo->driver), "%s",
+ dev_info.driver_name);
+ snprintf(drvinfo->version, sizeof(drvinfo->version), "%s",
+ rte_version());
+ snprintf(drvinfo->bus_info, sizeof(drvinfo->bus_info),
+ "%04x:%02x:%02x.%x",
+ dev_info.pci_dev->addr.domain, dev_info.pci_dev->addr.bus,
+ dev_info.pci_dev->addr.devid, dev_info.pci_dev->addr.function);
+
+ n = rte_eth_dev_get_reg_length(port_id);
+ 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(uint8_t port_id)
+{
+ return rte_eth_dev_get_reg_length(port_id);
+}
+
+int
+rte_ethtool_get_regs(uint8_t port_id, struct ethtool_regs *regs, void *data)
+{
+ struct rte_dev_reg_info reg_info;
+ int status;
+
+ reg_info.data = data;
+ reg_info.length = 0;
+
+ status = rte_eth_dev_get_reg_info(port_id, ®_info);
+ if (status)
+ return status;
+ regs->version = reg_info.version;
+
+ return 0;
+}
+
+int
+rte_ethtool_get_link(uint8_t port_id)
+{
+ struct rte_eth_link link;
+
+ rte_eth_link_get(port_id, &link);
+ return link.link_status;
+}
+
+int
+rte_ethtool_get_eeprom_len(uint8_t port_id)
+{
+ return rte_eth_dev_get_eeprom_length(port_id);
+}
+
+int
+rte_ethtool_get_eeprom(uint8_t port_id, struct ethtool_eeprom *eeprom,
+ void *words)
+{
+ struct rte_dev_eeprom_info eeprom_info;
+ int status;
+
+ 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(uint8_t port_id, struct ethtool_eeprom *eeprom,
+ void *words)
+{
+ struct rte_dev_eeprom_info eeprom_info;
+ int status;
+
+ 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_pauseparam(uint8_t port_id,
+ struct ethtool_pauseparam *pause_param)
+{
+ struct rte_eth_fc_conf fc_conf;
+ int status;
+
+ 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_NONE:
+ /* dummy block to avoid compiler warning */
+ break;
+ 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;
+ }
+ pause_param->autoneg = (uint32_t)fc_conf.autoneg;
+
+ return 0;
+}
+
+int
+rte_ethtool_set_pauseparam(uint8_t port_id,
+ struct ethtool_pauseparam *pause_param)
+{
+ struct rte_eth_fc_conf fc_conf;
+ int status;
+ /*
+ * 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(uint8_t port_id)
+{
+ rte_eth_dev_stop(port_id);
+
+ return rte_eth_dev_start(port_id);
+}
+
+int
+rte_ethtool_net_stop(uint8_t port_id)
+{
+ rte_eth_dev_stop(port_id);
+
+ return 0;
+}
+
+int
+rte_ethtool_net_get_mac_addr(uint8_t port_id, struct ether_addr *addr)
+{
+ rte_eth_macaddr_get(port_id, addr);
+
+ return 0;
+}
+
+int
+rte_ethtool_net_set_mac_addr(uint8_t port_id, struct ether_addr *addr)
+{
+ return rte_eth_dev_default_mac_addr_set(port_id, addr);
+}
+
+int
+rte_ethtool_net_validate_addr(uint8_t port_id __rte_unused,
+ struct ether_addr *addr)
+{
+ return is_valid_assigned_ether_addr(addr);
+}
+
+int
+rte_ethtool_net_set_config(uint8_t port_id, void *config __rte_unused)
+{
+ struct rte_eth_link link;
+
+ memset(&link, 0, sizeof(link));
+ rte_eth_link_get(port_id, &link);
+ if (link.link_status == 1)
+ return -EINVAL;
+ return 0;
+}
+
+int
+rte_ethtool_net_change_mtu(uint8_t port_id, int mtu)
+{
+ return rte_eth_dev_set_mtu(port_id, (uint16_t)mtu);
+}
+
+int
+rte_ethtool_net_get_stats64(uint8_t port_id, struct rte_eth_stats *stats)
+{
+ return rte_eth_stats_get(port_id, stats);
+}
+
+int
+rte_ethtool_net_vlan_rx_add_vid(uint8_t port_id, uint16_t vid)
+{
+ return rte_eth_dev_vlan_filter(port_id, vid, 1);
+}
+
+int
+rte_ethtool_net_vlan_rx_kill_vid(uint8_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(uint8_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;
+
+ /* Setting single cast promiscuous mode */
+ if (rte_eth_promiscuous_get(port_id) == 1)
+ rte_eth_promiscuous_enable(port_id);
+ else if (rte_eth_promiscuous_get(port_id) == 0)
+ rte_eth_promiscuous_disable(port_id);
+
+ /* Setting multi-cast promiscuous mode */
+ if (rte_eth_allmulticast_get(port_id) == 1)
+ rte_eth_allmulticast_enable(port_id);
+ else if (rte_eth_allmulticast_get(port_id) == 0)
+ rte_eth_allmulticast_disable(port_id);
+
+ /* Set VF vf_rx_mode, VF unsupport status is discard */
+ for (vf = 0; vf < num_vfs; vf++)
+ rte_eth_dev_set_vf_rxmode(port_id, vf, 1, 1);
+
+ /* Enable Rx vlan filter, VF unspport status is discard */
+ rte_eth_dev_set_vlan_offload(port_id, ETH_VLAN_FILTER_MASK);
+
+ return 0;
+}
diff --git a/examples/l2fwd-ethtool/lib/rte_ethtool.h b/examples/l2fwd-ethtool/lib/rte_ethtool.h
new file mode 100644
index 0000000..5d48b0d
--- /dev/null
+++ b/examples/l2fwd-ethtool/lib/rte_ethtool.h
@@ -0,0 +1,385 @@
+/*-
+ * BSD LICENSE
+ *
+ * Copyright(c) 2010-2015 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _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_driverinfo
+ * 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_set_config: net_device_ops::ndo_set_config
+ * rte_ethtool_net_change_mtu: net_device_ops::rte_net_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.
+ * - (-ENOTSUP) if hardware doesn't support.
+ * - (-ENODEV) if *port_id* invalid.
+ * - others depends on the specific operations implementation.
+ */
+int rte_ethtool_get_drvinfo(uint8_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(uint8_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(uint8_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.
+ * - others depends on the specific operations implementation.
+ */
+int rte_ethtool_get_link(uint8_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(uint8_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(uint8_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.
+ * - others depends on the specific operations implementation.
+ */
+int rte_ethtool_set_eeprom(uint8_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.
+ * - others depends on the specific operations implementation.
+ */
+int rte_ethtool_get_pauseparam(uint8_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.
+ * - others depends on the specific operations implementation.
+ */
+int rte_ethtool_set_pauseparam(uint8_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(uint8_t port_id);
+
+/**
+ * Stop 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_stop(uint8_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.
+ * - (-ENOTSUP) if hardware doesn't support.
+ * - (-ENODEV) if *port_id* invalid.
+ * - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_get_mac_addr(uint8_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.
+ * - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_set_mac_addr(uint8_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.
+ * - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_validate_addr(uint8_t port_id, struct ether_addr *addr);
+
+/**
+ * Setting the Ethernet device configuration.
+ *
+ * @param port_id
+ * The port identifier of the Ethernet device.
+ * @param config
+ * A opintr to a configuration parameter.
+ * @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_config(uint8_t port_id, void *config);
+
+/**
+ * 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.
+ * - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_change_mtu(uint8_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.
+ * - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_get_stats64(uint8_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(uint8_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(uint8_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(uint8_t port_id);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _RTE_ETHTOOL_H_ */
diff --git a/examples/l2fwd-ethtool/nic-control/Makefile b/examples/l2fwd-ethtool/nic-control/Makefile
new file mode 100644
index 0000000..17ab4a3
--- /dev/null
+++ b/examples/l2fwd-ethtool/nic-control/Makefile
@@ -0,0 +1,55 @@
+# BSD LICENSE
+#
+# Copyright(c) 2015 Intel Corporation. All rights reserved.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in
+# the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Intel Corporation nor the names of its
+# contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ifeq ($(RTE_SDK),)
+$(error "Please define RTE_SDK environment variable")
+endif
+
+# Default target, can be overwritten by command line or environment
+RTE_TARGET ?= x86_64-native-linuxapp-gcc
+
+include $(RTE_SDK)/mk/rte.vars.mk
+
+ifneq ($(CONFIG_RTE_EXEC_ENV),"linuxapp")
+$(error This application can only operate in a linuxapp environment, \
+please change the definition of the RTE_TARGET environment variable)
+endif
+
+# binary name
+APP = nic-control
+
+# all source are stored in SRCS-y
+SRCS-y := nic_control.c
+
+CFLAGS += -O3 -I$(SRCDIR)/../l2fwd-app -I$(SRCDIR)/../lib
+CFLAGS += $(WERROR_FLAGS)
+
+include $(RTE_SDK)/mk/rte.extapp.mk
diff --git a/examples/l2fwd-ethtool/nic-control/nic_control.c b/examples/l2fwd-ethtool/nic-control/nic_control.c
new file mode 100644
index 0000000..32769cb
--- /dev/null
+++ b/examples/l2fwd-ethtool/nic-control/nic_control.c
@@ -0,0 +1,614 @@
+/*-
+* BSD LICENSE
+*
+* Copyright(c) 2015 Intel Corporation. All rights reserved.
+* All rights reserved.
+*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions
+* are met:
+*
+* * Redistributions of source code must retain the above copyright
+* notice, this list of conditions and the following disclaimer.
+* * Redistributions in binary form must reproduce the above copyright
+* notice, this list of conditions and the following disclaimer in
+* the documentation and/or other materials provided with the
+* distribution.
+* * Neither the name of Intel Corporation nor the names of its
+* contributors may be used to endorse or promote products derived
+* from this software without specific prior written permission.
+*
+* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*
+ * This is a non- DPDK application that sends NIC device management request
+ * through named pipe to a DPDK data plan process.
+ *
+ */
+#define USE_NEW_TYPE
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <sys/resource.h>
+
+#include "rte_ethtool.h"
+#define NETDEV_OP_REQUEST 1
+#include "netdev_api.h"
+
+#define ITER_LIMIT 30
+#define CPU_CYCLES (double)(2400.0*1000000)
+#define TEST_FAIL -1
+#define TEST_PASS 0
+#define TEST_READ_SIZE 16
+#define STATS_PERIOD 10
+
+#define PACKET_RATE(before_value, after_value, before_ts, after_ts) \
+ ((double)(after_value - before_value) * \
+ CPU_CYCLES/(after_ts - before_ts))
+
+#define BYTE2BIT_RATE(before_value, after_value, before_ts, after_ts) \
+ ((double)(after_value - before_value) * \
+ CPU_CYCLES*8/(after_ts - before_ts))
+
+#define check(cond) (cond?"match":"miss-match")
+#define MAC_STR_SIZE (3*MAC_ADDR_SIZE+1)
+
+struct time_stamp {
+ uint32_t hi;
+ uint32_t lo;
+};
+
+enum test_type {
+ test_eeprom = 0,
+ test_regs,
+ test_mtu,
+ test_vlan_rx,
+ test_pauseparam,
+ test_counts,
+};
+
+struct api_test {
+ const char *test_name;
+ int mask_bit;
+ int (*test_task)(int port_id);
+};
+
+static inline unsigned long long
+rdtsc(void)
+{
+ unsigned hi, lo;
+
+ __asm__ __volatile__ ("rdtsc" : "=a"(lo), "=d"(hi));
+ return ((unsigned long long)lo) | (((unsigned long long)hi) << 32);
+}
+
+static uint32_t port_mask;
+static uint32_t vf_port_mask;
+static uint8_t num_of_ports;
+static char addr_string[MAC_STR_SIZE];
+
+static inline int
+is_port_enabled(uint8_t port_id)
+{
+ return (port_mask & (1 << port_id)) > 0;
+}
+
+static inline int
+is_vf_port(uint8_t port_id)
+{
+ return (vf_port_mask & (1 << port_id)) > 0;
+}
+
+static int
+netdev_ipc_begin(void)
+{
+ uint8_t reply_data[sizeof(double)];
+ uint16_t req_id = next_reqid();
+ uint16_t data_size;
+ uint32_t reply_data2[2];
+ uint8_t param_data[FIRST_DATA_OFFSET];
+
+ param_data[0] = 0;
+ send_request(req_id, ipc_begin,
+ FIRST_DATA_OFFSET, param_data);
+ read_reply(req_id, &data_size, reply_data, reply_data2);
+ num_of_ports = reply_data[0];
+ port_mask = reply_data2[0];
+ vf_port_mask = reply_data2[1];
+
+ return reply_data[0];
+}
+
+static int
+netdev_ipc_end(void)
+{
+ uint8_t reply_data[sizeof(double)];
+ uint16_t req_id = next_reqid();
+ uint16_t data_size;
+
+ send_request(req_id, ipc_end, 0, NULL);
+ read_reply(req_id, &data_size, reply_data, NULL);
+
+ return NETDEV_STATUS(data_size);
+}
+
+static uint8_t
+get_port(void)
+{
+ uint8_t port_id;
+ /* assume maximum of 32 ports */
+ port_id = rand() & 0x1F;
+ while (!is_port_enabled(port_id))
+ port_id = rand() & 0x1F;
+
+ return port_id;
+}
+
+static inline char*
+mac_addr_str(void *mac_addr_in)
+{
+ unsigned char *mac_addr = mac_addr_in;
+
+ snprintf(addr_string, MAC_STR_SIZE, "%02x:%02x:%02x:%02x:%02x:%02x",
+ mac_addr[0], mac_addr[1], mac_addr[2],
+ mac_addr[3], mac_addr[4], mac_addr[5]);
+ return addr_string;
+}
+
+static int
+test_eeprom_get(int port_id)
+{
+ int count, i;
+ void *data;
+ uint16_t *word;
+ struct ethtool_eeprom eeprom;
+
+ count = netdev_ethtool_get_eeprom_len(port_id);
+ if (count <= 0) {
+ printf("fail to retrieve eeprom");
+ printf("count from port #%d\n", port_id);
+ return TEST_FAIL;
+ }
+
+ printf("eeprom size is %d bytes\n", count);
+ eeprom.offset = 0;
+ eeprom.len = TEST_READ_SIZE;
+ data = malloc(TEST_READ_SIZE);
+ if (data == NULL) {
+ printf("Fail to allocate memory, bailed out !!!\n");
+ return TEST_FAIL;
+ }
+
+ if (netdev_ethtool_get_eeprom(port_id, &eeprom, data)) {
+ printf("Fail to read eeprom from port #%d\n", port_id);
+ free(data);
+ return TEST_FAIL;
+ }
+
+ word = data;
+ printf("eeprom-magic: %x;", eeprom.magic);
+ printf("eeprom data[0:%d]:\n", TEST_READ_SIZE-1);
+ for (i = 0; i < (int)(eeprom.len >> 1); i++)
+ printf("%4x ", word[i]);
+ printf("\n");
+ free(data);
+ return TEST_PASS;
+}
+
+/*
+ * Testing eeprom get/set by getting eeprom data and write-back
+ * the same data
+ */
+static int
+test_eeprom_t(int port_id)
+{
+ int i, ind;
+ void *data_in, *data_out;
+ struct ethtool_eeprom eeprom;
+
+ eeprom.offset = 0;
+ eeprom.len = TEST_READ_SIZE;
+ data_in = malloc(eeprom.len);
+ if (data_in == NULL) {
+ printf("Fail to allocate memory, bailed out !!!\n");
+ return TEST_FAIL;
+ }
+
+ if (netdev_ethtool_get_eeprom(port_id, &eeprom, data_in)) {
+ printf("failed to read eeprom break from post-run");
+ free(data_in);
+ return TEST_FAIL;
+ }
+
+ if (netdev_ethtool_set_eeprom(port_id, &eeprom, data_in)) {
+ printf("Fail to write read-back data to eeprom!!!\n");
+ free(data_in);
+ return TEST_FAIL;
+ }
+
+ data_out = malloc(eeprom.len);
+ if (data_out == NULL) {
+ printf("Fail to allocate memory, bailed out !!!\n");
+ free(data_in);
+ return TEST_FAIL;
+ }
+ /* read-back for comparison */
+ if (netdev_ethtool_get_eeprom(port_id, &eeprom, data_out)) {
+ printf("failed to read eeprom break from post-run");
+ free(data_in);
+ free(data_out);
+ return TEST_FAIL;
+ }
+
+ for (i = eeprom.offset; i < (int)(eeprom.offset+eeprom.len); i++) {
+ unsigned char *in = (unsigned char *)data_in;
+ unsigned char *out = (unsigned char *)data_out;
+
+ ind = i - eeprom.offset;
+ if (in[ind] != out[ind])
+ printf("%d write-data:%x read-back-data:%x\n",
+ ind, in[ind], out[ind]);
+ }
+ free(data_in);
+ free(data_out);
+ return TEST_PASS;
+}
+
+static int
+test_regs_t(int port_id)
+{
+ int count, i;
+ void *data;
+ uint32_t *regs;
+ struct ethtool_regs reg_info;
+
+ count = netdev_ethtool_get_regs_len(port_id);
+ if (count <= 0)
+ printf("There are no registers available from port #%d",
+ port_id);
+ else
+ printf("Target has %d registers for dump", count);
+
+ data = malloc(count * sizeof(int));
+ if (data == NULL) {
+ printf("Fail to allocate memory, bailed out !!!\n");
+ return TEST_FAIL;
+ }
+ memset(®_info, 0xFF, sizeof(struct ethtool_regs));
+
+ if (netdev_ethtool_get_regs(port_id, ®_info, data)) {
+ printf("Fail to read register\n");
+ free(data);
+ return TEST_FAIL;
+ }
+
+ regs = data;
+ printf("version: %x;", reg_info.version);
+ printf("register[0:%d]:\n", TEST_READ_SIZE-1);
+ for (i = 0; i < TEST_READ_SIZE; i++)
+ printf("%x ", regs[i]);
+ printf("\n");
+ free(data);
+ return TEST_PASS;
+}
+
+static int
+test_mtu_t(int port_id)
+{
+ const int mtu = 1024;
+
+ if (netdev_net_change_mtu(port_id, mtu)) {
+ printf("failed to set mtu to %d\n", mtu);
+ return TEST_FAIL;
+ }
+ return TEST_PASS;
+}
+
+static int
+test_vlan_rx_t(int port_id)
+{
+ /* add/remove vlan to vid */
+ netdev_net_vlan_rx_add_vid(port_id, 0);
+ if (netdev_net_vlan_rx_add_vid(port_id, 0)) {
+ if (netdev_net_vlan_rx_kill_vid(port_id, 0)) {
+ printf("netdev_net_vlan_rx_kill_vid() fails\n");
+ return TEST_FAIL;
+ }
+ return TEST_PASS;
+ }
+ printf("netdev_net_vlan_rx_add_vid() fails\n");
+ return TEST_FAIL;
+}
+
+static int
+test_pauseparam_t(int port_id)
+{
+ struct ethtool_pauseparam pause_param_in;
+ struct ethtool_pauseparam pause_param_out;
+
+ if (netdev_ethtool_get_pauseparam(port_id, &pause_param_in)) {
+ printf("netdev_ethtool_get_pauseparam() fails\n");
+ return TEST_FAIL;
+ }
+ printf("pause setup: autoneg: %d ",
+ pause_param_in.autoneg);
+ printf("tx_pause: %d ",
+ pause_param_in.tx_pause);
+ printf("rx_pause: %d\n",
+ pause_param_in.rx_pause);
+ if (netdev_ethtool_set_pauseparam(port_id, &pause_param_in)) {
+ printf("netdev_ethtool_set_pauseparam() fails\n");
+ return TEST_FAIL;
+ }
+ /* read-back pause frame setting for comparison */
+ if (netdev_ethtool_get_pauseparam(port_id, &pause_param_out)) {
+ printf("netdev_ethtool_get_pauseparam() fails\n");
+ return TEST_FAIL;
+ }
+ printf("pause frame checking auto:%s tx_pause:%s rx_pause:%s\n",
+ check(pause_param_in.autoneg == pause_param_out.autoneg),
+ check(pause_param_in.tx_pause == pause_param_out.tx_pause),
+ check(pause_param_in.rx_pause == pause_param_out.tx_pause));
+
+ return TEST_PASS;
+}
+
+static int
+test_get_drvinfo(int port_id)
+{
+ struct ethtool_drvinfo drvinfo;
+
+ if (netdev_ethtool_get_drvinfo(port_id, &drvinfo)) {
+ printf("fail to get drvinfo ...\n");
+ return TEST_FAIL;
+ }
+ printf("driver: %s version: %s fw_version: %s bus_info=%s\n",
+ drvinfo.driver, drvinfo.version,
+ drvinfo.fw_version, drvinfo.bus_info);
+ printf("reg-size(bytes)=%d eeprom-size=%d\n",
+ drvinfo.regdump_len,
+ drvinfo.eedump_len);
+ return TEST_PASS;
+}
+
+static int
+test_mac_addr(uint8_t port_id)
+{
+ unsigned char mac_addr[MAC_ADDR_SIZE];
+ unsigned char mac_addr_base[MAC_ADDR_SIZE] = {0x52, 0x54, 0, 0, 0, 1};
+ struct ether_addr *mac_addr_t;
+ struct ethter_add *mac_addr2;
+ int result;
+
+ mac_addr_t = to_mac_type(mac_addr);
+ result = netdev_net_get_mac_addr(port_id, mac_addr_t);
+ if (netdev_net_get_mac_addr(port_id, mac_addr_t)) {
+ printf("Fail to get mac addr from port #%d!!!\n", port_id);
+ return TEST_FAIL;
+ }
+ printf("Port #%d, device mac addr is %s\n", port_id,
+ mac_addr_str(mac_addr));
+
+ result = netdev_net_validate_addr(port_id, mac_addr_t);
+ if (!result) {
+ printf("Default mac addr, %s, is not valid\n",
+ mac_addr_str(mac_addr));
+ strncpy((char *)mac_addr, (char *)mac_addr_base, MAC_ADDR_SIZE);
+ mac_addr[MAC_ADDR_SIZE-1] += port_id;
+ printf("New mac address:%s is used.\n", mac_addr_str(mac_addr));
+
+ result = netdev_net_set_mac_addr(port_id, mac_addr_t);
+ if (result == TEST_FAIL)
+ return TEST_FAIL;
+
+ result = netdev_net_get_mac_addr(port_id, &mac_addr2);
+ if (strncmp(cast_ptr(mac_addr, char*),
+ cast_ptr(mac_addr2, char*),
+ MAC_ADDR_SIZE))
+ printf("Expected mac_addr %s return addr %s\n",
+ mac_addr_str(mac_addr),
+ mac_addr_str(cast_ptr(mac_addr2, unsigned char*)
+ ));
+ }
+ return TEST_PASS;
+}
+
+struct api_test test_table[test_counts] = {
+ {"-test_eeprom", test_eeprom, test_eeprom_t},
+ {"-test_regs", test_regs, test_regs_t},
+ {"-test_mtu", test_mtu, test_mtu_t},
+ {"-test_vlan_rx", test_vlan_rx, test_vlan_rx_t},
+ {"-test_pauseparam", test_pauseparam, test_pauseparam_t},
+};
+
+static inline unsigned int
+get_test_mask(char *name)
+{
+ int ind = 0;
+ struct api_test *test = &test_table[ind];
+
+ while (ind++ < test_counts) {
+ if (!strncmp(name, test->test_name, strlen(name)))
+ return (1 << test->mask_bit);
+ test++;
+ }
+ return 0;
+}
+
+static unsigned int
+parse_args(int argc, char **argv)
+{
+ int i;
+ unsigned int test_mask = 0;
+
+
+ if (argc <= 1)
+ return 0;
+ for (i = 1; i < argc; i++)
+ test_mask |= get_test_mask(argv[i]);
+ return test_mask;
+}
+
+static inline void
+test_update(int result, int *fails, int *passes)
+{
+ if (result == TEST_PASS)
+ (*passes)++;
+ else
+ (*fails)++;
+}
+
+static void
+run_test(uint8_t port_id, unsigned int test_mask, int *fails, int *passes)
+{
+ int i;
+ int result;
+
+ for (i = 0; i < test_counts; i++) {
+ if (test_mask & (1<<i)) {
+ result = (*test_table[i].test_task)(port_id);
+ test_update(result, fails, passes);
+ }
+ }
+}
+
+static void
+wait_for_linkdown(uint8_t port_id)
+{
+ int link_up;
+
+ link_up = netdev_ethtool_get_link(port_id);
+ while (link_up) {
+ sleep(10);
+ link_up = netdev_ethtool_get_link(port_id);
+ }
+}
+
+int
+main(int argc, char **argv)
+{
+ uint8_t port_id;
+ unsigned int test_mask;
+ int passes = 0;
+ int fails = 0;
+ int iter_count = 0;
+ int link_up;
+ int result;
+
+
+ /* get command parameter */
+ test_mask = parse_args(argc, argv);
+
+ /* initialize request pipe */
+ init_req_pipe();
+
+ printf("issue ipc begin\n");
+ /* send a request to start the NIC device */
+ num_of_ports = netdev_ipc_begin();
+ while (num_of_ports == 0)
+ num_of_ports = netdev_ipc_begin() & 0xFF;
+
+ for (port_id = 0; port_id < num_of_ports; port_id++) {
+ link_up = netdev_ethtool_get_link(port_id);
+ printf("port #%d is %s\n", port_id, link_up?"up":"down");
+ if (!link_up) {
+ if (netdev_net_open(port_id) == 0)
+ netdev_net_set_rx_mode(port_id);
+ else
+ printf("failed to start port #%d\n", port_id);
+ }
+ }
+
+ /* Testing ethtool register/eeprom get */
+ for (port_id = 0; port_id < num_of_ports; port_id++) {
+ if (!is_port_enabled(port_id))
+ continue;
+
+ result = test_mac_addr(port_id);
+ test_update(result, &fails, &passes);
+
+ result = test_get_drvinfo(port_id);
+ test_update(result, &fails, &passes);
+
+ result = test_regs_t(port_id);
+ test_update(result, &fails, &passes);
+
+ /* Only testing eeprom access over a PF */
+ if (!is_vf_port(port_id)) {
+ result = test_eeprom_get(port_id);
+ test_update(result, &fails, &passes);
+ }
+ }
+
+ printf("start nic statistics collection ...\n");
+ port_id = get_port();
+ while (iter_count++ < ITER_LIMIT) {
+ uint64_t last_ts, ts;
+ struct rte_eth_stats last_stats, stats;
+
+ if (netdev_net_get_stats64(port_id, &last_stats)) {
+ printf("Fail to query statistics from port %d\n",
+ port_id);
+ break;
+ }
+ last_ts = rdtsc();
+
+ sleep(STATS_PERIOD);
+
+ if (netdev_net_get_stats64(port_id, &stats)) {
+ printf("Fail to query statistics from port %d\n",
+ port_id);
+ break;
+ }
+ ts = rdtsc();
+
+ printf("rx packet rate = %lf, tx packet rate = %lf\n",
+ PACKET_RATE(last_stats.ipackets, stats.ipackets,
+ last_ts, ts),
+ PACKET_RATE(last_stats.opackets, stats.opackets,
+ last_ts, ts));
+
+
+ printf("rx bit rate = %lf, tx bit rate = %lf\n",
+ BYTE2BIT_RATE(last_stats.ibytes, stats.ibytes,
+ last_ts, ts),
+ BYTE2BIT_RATE(last_stats.obytes, stats.obytes,
+ last_ts, ts));
+
+ sleep(STATS_PERIOD);
+ }
+
+ /* Stop link, testing APIs specified in command arguments */
+ if (test_mask) {
+ for (port_id = 0; port_id < num_of_ports; port_id++) {
+ link_up = netdev_ethtool_get_link(port_id);
+ if (link_up) {
+ netdev_net_stop(port_id);
+ wait_for_linkdown(port_id);
+ }
+ }
+
+ for (port_id = 0; port_id < num_of_ports; port_id++) {
+ link_up = netdev_ethtool_get_link(port_id);
+ if (!is_vf_port(port_id) && !link_up)
+ run_test(port_id, test_mask, &fails, &passes);
+ }
+ }
+
+ while (netdev_ipc_end() < 0)
+ ;
+
+ printf("Pass count: %d Fail count: %d\n", passes, fails);
+ return 0;
+}
diff --git a/mk/rte.lib.mk b/mk/rte.lib.mk
index 9ff5cce..77689bf 100644
--- a/mk/rte.lib.mk
+++ b/mk/rte.lib.mk
@@ -43,8 +43,10 @@ LIB := $(patsubst %.a,%.so.$(LIBABIVER),$(LIB))
ifeq ($(CONFIG_RTE_NEXT_ABI),y)
LIB := $(LIB).1
endif
+ifdef EXPORT_MAP
CPU_LDFLAGS += --version-script=$(SRCDIR)/$(EXPORT_MAP)
endif
+endif
_BUILD = $(LIB)
--
2.1.4
^ permalink raw reply [flat|nested] 10+ messages in thread
* [dpdk-dev] [PATCH v2 0/2] Example: l2fwd-ethtool
2015-07-20 14:12 ` [dpdk-dev] [PATCH] examples: new example: l2fwd-ethtool Liang-Min Larry Wang
@ 2015-07-23 15:00 ` Liang-Min Larry Wang
2015-07-23 15:00 ` [dpdk-dev] [PATCH v2 1/2] Remove ABI requierment for external library builds Liang-Min Larry Wang
2015-07-23 15:00 ` [dpdk-dev] [PATCH v2 2/2] examples: new example: l2fwd-ethtool Liang-Min Larry Wang
0 siblings, 2 replies; 10+ messages in thread
From: Liang-Min Larry Wang @ 2015-07-23 15:00 UTC (permalink / raw)
To: dev; +Cc: Liang-Min Larry Wang
This implementation is designed to provide an example illlustrating how to create a
user-space ethtool library from existing ethdev APIs. In contrast to kernel version
of same API (such as ops defined in KNI), the user-space APIs enable a fast-path
(no kernel API calls) for device query and data return. This example implements 19 popular
used Ethtool and Netdevice ops as described in examples/l2fwd-ethtool/lib/rte_ethtool.h,
and commnity support of un-implemented Ethtool and Netdevice ops are very welcomed.
v2 change:
- Separate changes on .mk files into a separate patch file
- Remove requirement of ABI version for external library build
- Fix example/l2fwd-ethtool share object build
Andrew G. Harvey (1):
Remove ABI requierment for external library builds.
Liang-Min Larry Wang (1):
examples: new example: l2fwd-ethtool
examples/Makefile | 1 +
examples/l2fwd-ethtool/Makefile | 48 +
examples/l2fwd-ethtool/l2fwd-app/Makefile | 58 ++
examples/l2fwd-ethtool/l2fwd-app/main.c | 1025 ++++++++++++++++++++++
examples/l2fwd-ethtool/l2fwd-app/netdev_api.h | 770 ++++++++++++++++
examples/l2fwd-ethtool/l2fwd-app/shared_fifo.h | 159 ++++
examples/l2fwd-ethtool/lib/Makefile | 57 ++
examples/l2fwd-ethtool/lib/rte_ethtool.c | 336 +++++++
examples/l2fwd-ethtool/lib/rte_ethtool.h | 385 ++++++++
examples/l2fwd-ethtool/nic-control/Makefile | 55 ++
examples/l2fwd-ethtool/nic-control/nic_control.c | 614 +++++++++++++
mk/rte.extlib.mk | 2 +
mk/rte.lib.mk | 6 +
13 files changed, 3516 insertions(+)
create mode 100644 examples/l2fwd-ethtool/Makefile
create mode 100644 examples/l2fwd-ethtool/l2fwd-app/Makefile
create mode 100644 examples/l2fwd-ethtool/l2fwd-app/main.c
create mode 100644 examples/l2fwd-ethtool/l2fwd-app/netdev_api.h
create mode 100644 examples/l2fwd-ethtool/l2fwd-app/shared_fifo.h
create mode 100644 examples/l2fwd-ethtool/lib/Makefile
create mode 100644 examples/l2fwd-ethtool/lib/rte_ethtool.c
create mode 100644 examples/l2fwd-ethtool/lib/rte_ethtool.h
create mode 100644 examples/l2fwd-ethtool/nic-control/Makefile
create mode 100644 examples/l2fwd-ethtool/nic-control/nic_control.c
--
2.1.4
^ permalink raw reply [flat|nested] 10+ messages in thread
* [dpdk-dev] [PATCH v2 1/2] Remove ABI requierment for external library builds.
2015-07-23 15:00 ` [dpdk-dev] [PATCH v2 0/2] Example: l2fwd-ethtool Liang-Min Larry Wang
@ 2015-07-23 15:00 ` Liang-Min Larry Wang
2015-10-21 16:31 ` Thomas Monjalon
2015-07-23 15:00 ` [dpdk-dev] [PATCH v2 2/2] examples: new example: l2fwd-ethtool Liang-Min Larry Wang
1 sibling, 1 reply; 10+ messages in thread
From: Liang-Min Larry Wang @ 2015-07-23 15:00 UTC (permalink / raw)
To: dev
From: "Andrew G. Harvey" <agh@cisco.com>
Signed-off-by: Andrew G. Harvey <agh@cisco.com>
---
mk/rte.extlib.mk | 2 ++
mk/rte.lib.mk | 6 ++++++
2 files changed, 8 insertions(+)
diff --git a/mk/rte.extlib.mk b/mk/rte.extlib.mk
index ba066bc..d2a9b6d 100644
--- a/mk/rte.extlib.mk
+++ b/mk/rte.extlib.mk
@@ -31,6 +31,8 @@
MAKEFLAGS += --no-print-directory
+export EXTLIB_BUILD := 1
+
# we must create the output dir first and recall the same Makefile
# from this directory
ifeq ($(NOT_FIRST_CALL),)
diff --git a/mk/rte.lib.mk b/mk/rte.lib.mk
index 9ff5cce..63ca640 100644
--- a/mk/rte.lib.mk
+++ b/mk/rte.lib.mk
@@ -40,11 +40,13 @@ VPATH += $(SRCDIR)
ifeq ($(CONFIG_RTE_BUILD_SHARED_LIB),y)
LIB := $(patsubst %.a,%.so.$(LIBABIVER),$(LIB))
+ifndef EXTLIB_BUILD
ifeq ($(CONFIG_RTE_NEXT_ABI),y)
LIB := $(LIB).1
endif
CPU_LDFLAGS += --version-script=$(SRCDIR)/$(EXPORT_MAP)
endif
+endif
_BUILD = $(LIB)
@@ -173,12 +175,16 @@ $(RTE_OUTPUT)/lib/$(LIB): $(LIB)
@[ -d $(RTE_OUTPUT)/lib ] || mkdir -p $(RTE_OUTPUT)/lib
$(Q)cp -f $(LIB) $(RTE_OUTPUT)/lib
ifeq ($(CONFIG_RTE_BUILD_SHARED_LIB),y)
+ifdef EXTLIB_BUILD
+ $(Q)ln -s -f $< $(basename $@)
+else
ifeq ($(CONFIG_RTE_NEXT_ABI),y)
$(Q)ln -s -f $< $(basename $(basename $@))
else
$(Q)ln -s -f $< $(basename $@)
endif
endif
+endif
#
# Clean all generated files
--
2.1.4
^ permalink raw reply [flat|nested] 10+ messages in thread
* [dpdk-dev] [PATCH v2 2/2] examples: new example: l2fwd-ethtool
2015-07-23 15:00 ` [dpdk-dev] [PATCH v2 0/2] Example: l2fwd-ethtool Liang-Min Larry Wang
2015-07-23 15:00 ` [dpdk-dev] [PATCH v2 1/2] Remove ABI requierment for external library builds Liang-Min Larry Wang
@ 2015-07-23 15:00 ` Liang-Min Larry Wang
2015-10-21 16:36 ` Thomas Monjalon
1 sibling, 1 reply; 10+ messages in thread
From: Liang-Min Larry Wang @ 2015-07-23 15:00 UTC (permalink / raw)
To: dev; +Cc: Liang-Min Larry Wang
The example includes an ethtool library and two applications:
one application is a non- DPDK process (nic-control)
and the other is a DPDK l2fwd applicaiton (l2fwd-app).
The nic-control process sends ethtool alike device management
requests to l2fwd-app through a named pipe IPC. This example
is designed to show how to build a ethtool shim library and
how to use ethtool apis to manage device parameters.
Signed-off-by: Liang-Min Larry Wang <liang-min.wang@intel.com>
---
examples/Makefile | 1 +
examples/l2fwd-ethtool/Makefile | 48 +
examples/l2fwd-ethtool/l2fwd-app/Makefile | 58 ++
examples/l2fwd-ethtool/l2fwd-app/main.c | 1025 ++++++++++++++++++++++
examples/l2fwd-ethtool/l2fwd-app/netdev_api.h | 770 ++++++++++++++++
examples/l2fwd-ethtool/l2fwd-app/shared_fifo.h | 159 ++++
examples/l2fwd-ethtool/lib/Makefile | 57 ++
examples/l2fwd-ethtool/lib/rte_ethtool.c | 336 +++++++
examples/l2fwd-ethtool/lib/rte_ethtool.h | 385 ++++++++
examples/l2fwd-ethtool/nic-control/Makefile | 55 ++
examples/l2fwd-ethtool/nic-control/nic_control.c | 614 +++++++++++++
11 files changed, 3508 insertions(+)
create mode 100644 examples/l2fwd-ethtool/Makefile
create mode 100644 examples/l2fwd-ethtool/l2fwd-app/Makefile
create mode 100644 examples/l2fwd-ethtool/l2fwd-app/main.c
create mode 100644 examples/l2fwd-ethtool/l2fwd-app/netdev_api.h
create mode 100644 examples/l2fwd-ethtool/l2fwd-app/shared_fifo.h
create mode 100644 examples/l2fwd-ethtool/lib/Makefile
create mode 100644 examples/l2fwd-ethtool/lib/rte_ethtool.c
create mode 100644 examples/l2fwd-ethtool/lib/rte_ethtool.h
create mode 100644 examples/l2fwd-ethtool/nic-control/Makefile
create mode 100644 examples/l2fwd-ethtool/nic-control/nic_control.c
diff --git a/examples/Makefile b/examples/Makefile
index b4eddbd..3dc049c 100644
--- a/examples/Makefile
+++ b/examples/Makefile
@@ -53,6 +53,7 @@ DIRS-$(CONFIG_RTE_LIBRTE_KNI) += kni
DIRS-y += l2fwd
DIRS-$(CONFIG_RTE_LIBRTE_IVSHMEM) += l2fwd-ivshmem
DIRS-$(CONFIG_RTE_LIBRTE_JOBSTATS) += l2fwd-jobstats
+DIRS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += l2fwd-ethtool
DIRS-y += l3fwd
DIRS-$(CONFIG_RTE_LIBRTE_ACL) += l3fwd-acl
DIRS-$(CONFIG_RTE_LIBRTE_POWER) += l3fwd-power
diff --git a/examples/l2fwd-ethtool/Makefile b/examples/l2fwd-ethtool/Makefile
new file mode 100644
index 0000000..d9ad439
--- /dev/null
+++ b/examples/l2fwd-ethtool/Makefile
@@ -0,0 +1,48 @@
+# BSD LICENSE
+#
+# Copyright(c) 2015 Intel Corporation. All rights reserved.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in
+# the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Intel Corporation nor the names of its
+# contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ifeq ($(RTE_SDK),)
+$(error "Please define RTE_SDK environment variable")
+endif
+
+# Default target, can be overwritten by command line or environment
+RTE_TARGET ?= x86_64-native-linuxapp-gcc
+
+include $(RTE_SDK)/mk/rte.vars.mk
+
+ifneq ($(CONFIG_RTE_EXEC_ENV),"linuxapp")
+$(error This application can only operate in a linuxapp environment, \
+please change the definition of the RTE_TARGET environment variable)
+endif
+
+DIRS-y += lib nic-control l2fwd-app
+
+include $(RTE_SDK)/mk/rte.extsubdir.mk
diff --git a/examples/l2fwd-ethtool/l2fwd-app/Makefile b/examples/l2fwd-ethtool/l2fwd-app/Makefile
new file mode 100644
index 0000000..69405f2
--- /dev/null
+++ b/examples/l2fwd-ethtool/l2fwd-app/Makefile
@@ -0,0 +1,58 @@
+# BSD LICENSE
+#
+# Copyright(c) 2015 Intel Corporation. All rights reserved.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in
+# the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Intel Corporation nor the names of its
+# contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ifeq ($(RTE_SDK),)
+$(error "Please define RTE_SDK environment variable")
+endif
+
+# Default target, can be overwritten by command line or environment
+RTE_TARGET ?= x86_64-native-linuxapp-gcc
+
+include $(RTE_SDK)/mk/rte.vars.mk
+
+ifneq ($(CONFIG_RTE_EXEC_ENV),"linuxapp")
+$(error This application can only operate in a linuxapp environment, \
+please change the definition of the RTE_TARGET environment variable)
+endif
+
+# binary name
+APP = l2fwd-app
+
+# all source are stored in SRCS-y
+SRCS-y := main.c
+
+CFLAGS += -O3 -D_GNU_SOURCE -pthread -I$(SRCDIR)/../lib
+CFLAGS += $(WERROR_FLAGS)
+
+LDLIBS += -L$(subst l2fwd-app,lib,$(RTE_OUTPUT))/lib
+LDLIBS += -lrte_ethtool
+
+include $(RTE_SDK)/mk/rte.extapp.mk
diff --git a/examples/l2fwd-ethtool/l2fwd-app/main.c b/examples/l2fwd-ethtool/l2fwd-app/main.c
new file mode 100644
index 0000000..73c29e3
--- /dev/null
+++ b/examples/l2fwd-ethtool/l2fwd-app/main.c
@@ -0,0 +1,1025 @@
+/*-
+ * BSD LICENSE
+ *
+ * Copyright(c) 2015 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+#include <inttypes.h>
+#include <sys/types.h>
+#include <sys/queue.h>
+#include <netinet/in.h>
+#include <setjmp.h>
+#include <stdarg.h>
+#include <ctype.h>
+#include <errno.h>
+#include <getopt.h>
+#include <pthread.h>
+#include <unistd.h>
+
+#include <rte_common.h>
+#include <rte_log.h>
+#include <rte_memory.h>
+#include <rte_memcpy.h>
+#include <rte_memzone.h>
+#include <rte_tailq.h>
+#include <rte_eal.h>
+#include <rte_per_lcore.h>
+#include <rte_launch.h>
+#include <rte_atomic.h>
+#include <rte_cycles.h>
+#include <rte_prefetch.h>
+#include <rte_lcore.h>
+#include <rte_per_lcore.h>
+#include <rte_branch_prediction.h>
+#include <rte_interrupts.h>
+#include <rte_pci.h>
+#include <rte_random.h>
+#include <rte_debug.h>
+#include <rte_ether.h>
+#include <rte_ethdev.h>
+#include <rte_ring.h>
+#include <rte_mempool.h>
+#include <rte_mbuf.h>
+#include "rte_ethtool.h"
+#define NETDEV_OP_REPLY 1
+#include "netdev_api.h"
+
+#define RTE_LOGTYPE_L2FWD RTE_LOGTYPE_USER1
+
+#define MBUF_SIZE (2048 + sizeof(struct rte_mbuf) + RTE_PKTMBUF_HEADROOM)
+#define NB_MBUF 8192
+
+#define MAX_PKT_BURST 32
+#define BURST_TX_DRAIN_US 100 /* TX drain every ~100us */
+
+#define is_vf_port(vf_mask, port_id) ((vf_mask & (1 << port_id)) > 0)
+#define is_port_enabled(port_mask, port_id) ((port_mask & (1 << port_id)) > 0)
+#define TX_PTHRESH 32
+#define TX_HTHRESH 0
+#define TX_WTHRESH 0
+/*
+ * Configurable number of RX/TX ring descriptors
+ */
+#define RTE_TEST_RX_DESC_DEFAULT 128
+#define RTE_TEST_TX_DESC_DEFAULT 512
+static uint16_t nb_rxd = RTE_TEST_RX_DESC_DEFAULT;
+static uint16_t nb_txd = RTE_TEST_TX_DESC_DEFAULT;
+
+/* ethernet addresses of ports */
+static struct ether_addr l2fwd_ports_eth_addr[RTE_MAX_ETHPORTS];
+
+/* mask of enabled ports */
+static uint32_t l2fwd_enabled_port_mask;
+
+/* virtio setup enable */
+static int virtio_setup;
+
+/* list of enabled ports */
+static uint32_t l2fwd_dst_ports[RTE_MAX_ETHPORTS];
+
+static unsigned int l2fwd_rx_queue_per_lcore = 1;
+
+struct mbuf_table {
+ unsigned len;
+ struct rte_mbuf *m_table[MAX_PKT_BURST];
+};
+
+#define MAX_RX_QUEUE_PER_LCORE 16
+#define MAX_TX_QUEUE_PER_PORT 16
+struct lcore_queue_conf {
+ unsigned n_rx_port;
+ unsigned rx_port_list[MAX_RX_QUEUE_PER_LCORE];
+ struct mbuf_table tx_mbufs[RTE_MAX_ETHPORTS];
+
+} __rte_cache_aligned;
+struct lcore_queue_conf lcore_queue_conf[RTE_MAX_LCORE];
+
+static struct rte_eth_conf port_conf = {
+ .rxmode = {
+ .split_hdr_size = 0,
+ .header_split = 0, /**< Header Split disabled */
+ .hw_ip_checksum = 0, /**< IP checksum offload disabled */
+ .hw_vlan_filter = 0, /**< VLAN filtering disabled */
+ .jumbo_frame = 0, /**< Jumbo Frame Support disabled */
+ .hw_strip_crc = 0, /**< CRC stripped by hardware */
+ },
+ .txmode = {
+ .mq_mode = ETH_MQ_TX_NONE,
+ },
+};
+
+static struct rte_eth_txconf tx_conf = {
+ .tx_thresh = {
+ .pthresh = TX_PTHRESH,
+ .hthresh = TX_HTHRESH,
+ .wthresh = TX_WTHRESH,
+ },
+ .tx_free_thresh = 32,
+ .tx_rs_thresh = 32,
+ .txq_flags = 0xf00,
+};
+
+struct rte_mempool *l2fwd_pktmbuf_pool;
+
+/* Per-port statistics struct */
+struct l2fwd_port_statistics {
+ uint64_t tx;
+ uint64_t rx;
+ uint64_t dropped;
+} __rte_cache_aligned;
+struct l2fwd_port_statistics port_statistics[RTE_MAX_ETHPORTS];
+
+/* A tsc-based timer responsible for triggering statistics printout */
+#define TIMER_MILLISECOND 2000000ULL /* around 1ms at 2 Ghz */
+#define MAX_TIMER_PERIOD 86400 /* 1 day max */
+/* default period is 10 seconds */
+static int64_t timer_period = 10 * TIMER_MILLISECOND * 1000;
+
+/* IPC done checking utility function */
+/* status of ipc completed */
+static rte_atomic64_t ipc_done;
+
+static inline void init_ipc_done(void)
+{
+ rte_atomic64_init(&ipc_done);
+}
+
+static inline int is_ipc_done(void)
+{
+ return rte_atomic64_read(&ipc_done) > 0;
+}
+
+static inline void set_ipc_done(void)
+{
+ rte_atomic64_inc(&ipc_done);
+}
+
+/* Print out statistics on packets dropped */
+static void
+print_stats(void)
+{
+ uint64_t total_packets_dropped, total_packets_tx, total_packets_rx;
+ unsigned portid;
+
+ total_packets_dropped = 0;
+ total_packets_tx = 0;
+ total_packets_rx = 0;
+
+ const char clr[] = { 27, '[', '2', 'J', '\0' };
+ const char topLeft[] = { 27, '[', '1', ';', '1', 'H', '\0' };
+
+ /* Clear screen and move to top left */
+ printf("%s%s", clr, topLeft);
+
+ printf("\nPort statistics ====================================");
+
+ for (portid = 0; portid < RTE_MAX_ETHPORTS; portid++) {
+ /* skip disabled ports */
+ if ((l2fwd_enabled_port_mask & (1 << portid)) == 0)
+ continue;
+ printf("\nStatistics for port %u ----------------------------",
+ portid);
+ printf("\nPackets sent: %24"PRIu64, port_statistics[portid].tx);
+ printf("\nPackets received: %20"PRIu64,
+ port_statistics[portid].rx);
+ printf("\nPackets dropped: %21"PRIu64,
+ port_statistics[portid].dropped);
+
+ total_packets_dropped += port_statistics[portid].dropped;
+ total_packets_tx += port_statistics[portid].tx;
+ total_packets_rx += port_statistics[portid].rx;
+ }
+ printf("\nAggregate statistics ===============================");
+ printf("\nTotal packets sent: %18"PRIu64, total_packets_tx);
+ printf("\nTotal packets received: %14"PRIu64, total_packets_rx);
+ printf("\nTotal packets dropped: %15"PRIu64, total_packets_dropped);
+ printf("\n====================================================\n");
+}
+
+/* Send the burst of packets on an output interface */
+static int
+l2fwd_send_burst(struct lcore_queue_conf *qconf, unsigned n, uint8_t port)
+{
+ struct rte_mbuf **m_table;
+ unsigned ret;
+ unsigned queueid = 0;
+
+ m_table = (struct rte_mbuf **)qconf->tx_mbufs[port].m_table;
+
+ ret = rte_eth_tx_burst(port, (uint16_t) queueid, m_table, (uint16_t) n);
+ port_statistics[port].tx += ret;
+ if (unlikely(ret < n)) {
+ port_statistics[port].dropped += (n - ret);
+ do {
+ rte_pktmbuf_free(m_table[ret]);
+ } while (++ret < n);
+ }
+
+ return 0;
+}
+
+/* Enqueue packets for TX and prepare them to be sent */
+static int
+l2fwd_send_packet(struct rte_mbuf *m, uint8_t port)
+{
+ unsigned lcore_id, len;
+ struct lcore_queue_conf *qconf;
+
+ lcore_id = rte_lcore_id();
+
+ qconf = &lcore_queue_conf[lcore_id];
+ len = qconf->tx_mbufs[port].len;
+ qconf->tx_mbufs[port].m_table[len] = m;
+ len++;
+
+ /* enough pkts to be sent */
+ if (unlikely(len == MAX_PKT_BURST)) {
+ l2fwd_send_burst(qconf, MAX_PKT_BURST, port);
+ len = 0;
+ }
+
+ qconf->tx_mbufs[port].len = len;
+ return 0;
+}
+
+static void
+l2fwd_simple_forward(struct rte_mbuf *m, unsigned portid)
+{
+ struct ether_hdr *eth;
+ void *tmp;
+ unsigned dst_port;
+
+ dst_port = l2fwd_dst_ports[portid];
+ eth = rte_pktmbuf_mtod(m, struct ether_hdr *);
+
+ /* 02:00:00:00:00:xx */
+ tmp = ð->d_addr.addr_bytes[0];
+ *((uint64_t *)tmp) = 0x000000000002 + ((uint64_t)dst_port << 40);
+
+ /* src addr */
+ ether_addr_copy(&l2fwd_ports_eth_addr[dst_port], ð->s_addr);
+
+ l2fwd_send_packet(m, (uint8_t) dst_port);
+}
+
+/* main processing loop */
+static void
+l2fwd_main_loop(void)
+{
+ struct rte_mbuf *pkts_burst[MAX_PKT_BURST];
+ struct rte_mbuf *m;
+ unsigned lcore_id;
+ uint64_t prev_tsc, diff_tsc, cur_tsc, timer_tsc;
+ unsigned i, j, portid, nb_rx;
+ struct lcore_queue_conf *qconf;
+ const uint64_t drain_tsc = (rte_get_tsc_hz() + US_PER_S - 1) /
+ US_PER_S * BURST_TX_DRAIN_US;
+
+ prev_tsc = 0;
+ timer_tsc = 0;
+
+ lcore_id = rte_lcore_id();
+ qconf = &lcore_queue_conf[lcore_id];
+
+ if (qconf->n_rx_port == 0) {
+ RTE_LOG(INFO, L2FWD, "lcore %u has nothing to do\n", lcore_id);
+ return;
+ }
+
+ RTE_LOG(INFO, L2FWD, "entering main loop on lcore %u\n", lcore_id);
+
+ for (i = 0; i < qconf->n_rx_port; i++) {
+
+ portid = qconf->rx_port_list[i];
+ RTE_LOG(INFO, L2FWD, " -- lcoreid=%u portid=%u\n", lcore_id,
+ portid);
+ }
+
+ if (virtio_setup) {
+ while (is_ipc_done() == 0)
+ usleep(50);
+ }
+
+ while (1) {
+ cur_tsc = rte_rdtsc();
+
+ /* TX burst queue drain */
+ diff_tsc = cur_tsc - prev_tsc;
+ if (unlikely(diff_tsc > drain_tsc)) {
+
+ for (portid = 0; portid < RTE_MAX_ETHPORTS; portid++) {
+ if (qconf->tx_mbufs[portid].len == 0)
+ continue;
+ l2fwd_send_burst(&lcore_queue_conf[lcore_id],
+ qconf->tx_mbufs[portid].len,
+ (uint8_t) portid);
+ qconf->tx_mbufs[portid].len = 0;
+ }
+
+ /* if timer is enabled */
+ if (timer_period > 0) {
+
+ /* advance the timer */
+ timer_tsc += diff_tsc;
+
+ /* if timer has reached its timeout */
+ if (unlikely(timer_tsc >=
+ (uint64_t) timer_period)) {
+
+ /* do this only on master core */
+ if (lcore_id ==
+ rte_get_master_lcore()) {
+ print_stats();
+ /* reset the timer */
+ timer_tsc = 0;
+ }
+ }
+ }
+
+ prev_tsc = cur_tsc;
+ }
+
+ /*
+ * Read packet from RX queues
+ */
+ for (i = 0; i < qconf->n_rx_port; i++) {
+
+ portid = qconf->rx_port_list[i];
+ nb_rx = rte_eth_rx_burst((uint8_t) portid, 0,
+ pkts_burst, MAX_PKT_BURST);
+
+ port_statistics[portid].rx += nb_rx;
+
+ for (j = 0; j < nb_rx; j++) {
+ m = pkts_burst[j];
+ rte_prefetch0(rte_pktmbuf_mtod(m, void *));
+ l2fwd_simple_forward(m, portid);
+ }
+ }
+ }
+}
+
+static int
+l2fwd_launch_one_lcore(__attribute__((unused)) void *dummy)
+{
+ l2fwd_main_loop();
+ return 0;
+}
+
+/* display usage */
+static void
+l2fwd_usage(const char *prgname)
+{
+ printf("%s [EAL options] -- -p PORTMASK [-q NQ]\n"
+ " -p PORTMASK: hexadecimal bitmask of ports to configure\n"
+ " -q NQ: number of queue (=ports) per lcore (default is 1)\n"
+ " -V : setting rx/tx mode to enable virtio\n"
+ " -T PERIOD: statistics will be refreshed each PERIOD seconds",
+ prgname);
+ printf("(0 to disable, 10 default, 86400 maximum)\n");
+}
+
+static int
+l2fwd_parse_portmask(const char *portmask)
+{
+ char *end = NULL;
+ unsigned long pm;
+
+ /* parse hexadecimal string */
+ pm = strtoul(portmask, &end, 16);
+ if ((portmask[0] == '\0') || (end == NULL) || (*end != '\0'))
+ return -1;
+
+ if (pm == 0)
+ return -1;
+
+ return pm;
+}
+
+static unsigned int
+l2fwd_parse_nqueue(const char *q_arg)
+{
+ char *end = NULL;
+ unsigned long n;
+
+ /* parse hexadecimal string */
+ n = strtoul(q_arg, &end, 10);
+ if ((q_arg[0] == '\0') || (end == NULL) || (*end != '\0'))
+ return 0;
+ if (n == 0)
+ return 0;
+ if (n >= MAX_RX_QUEUE_PER_LCORE)
+ return 0;
+
+ return n;
+}
+
+static int
+l2fwd_parse_timer_period(const char *q_arg)
+{
+ char *end = NULL;
+ int n;
+
+ /* parse number string */
+ n = strtol(q_arg, &end, 10);
+ if ((q_arg[0] == '\0') || (end == NULL) || (*end != '\0'))
+ return -1;
+ if (n >= MAX_TIMER_PERIOD)
+ return -1;
+
+ return n;
+}
+
+static int
+l2fwd_parse_virtio_setup(const char *q_arg)
+{
+ char *end = NULL;
+ int n;
+
+ /* parse number string */
+ n = strtol(q_arg, &end, 10);
+ if ((q_arg[0] == '\0') || (end == NULL) || (*end != '\0'))
+ return -1;
+ if (n >= MAX_TIMER_PERIOD)
+ return -1;
+
+ return n;
+}
+
+/* Parse the argument given in the command line of the application */
+static int
+l2fwd_parse_args(int argc, char **argv)
+{
+ int opt, ret;
+ char **argvopt;
+ int option_index;
+ char *prgname = argv[0];
+ static struct option lgopts[] = {
+ {NULL, 0, 0, 0}
+ };
+
+ argvopt = argv;
+
+ while ((opt = getopt_long(argc, argvopt, "p:q:T:V:",
+ lgopts, &option_index)) != EOF) {
+
+ switch (opt) {
+ /* portmask */
+ case 'p':
+ l2fwd_enabled_port_mask = l2fwd_parse_portmask(optarg);
+ if (l2fwd_enabled_port_mask == 0) {
+ printf("invalid portmask\n");
+ l2fwd_usage(prgname);
+ return -1;
+ }
+ break;
+
+ /* nqueue */
+ case 'q':
+ l2fwd_rx_queue_per_lcore = l2fwd_parse_nqueue(optarg);
+ if (l2fwd_rx_queue_per_lcore == 0) {
+ printf("invalid queue number\n");
+ l2fwd_usage(prgname);
+ return -1;
+ }
+ break;
+
+ /* timer period */
+ case 'T':
+ timer_period = l2fwd_parse_timer_period(optarg) *
+ 1000 * TIMER_MILLISECOND;
+ if (timer_period < 0) {
+ printf("invalid timer period\n");
+ l2fwd_usage(prgname);
+ return -1;
+ }
+ break;
+
+ /* virtio setup */
+ case 'V':
+ /* get option as the pf mac addr */
+ virtio_setup = l2fwd_parse_virtio_setup(optarg);
+ if (virtio_setup) {
+ port_conf.rxmode.hw_vlan_strip = 0;
+ port_conf.rxmode.hw_vlan_extend = 0;
+ }
+ break;
+
+ /* long options */
+ case 0:
+ l2fwd_usage(prgname);
+ return -1;
+
+ default:
+ l2fwd_usage(prgname);
+ return -1;
+ }
+ }
+
+ if (optind >= 0)
+ argv[optind-1] = prgname;
+
+ ret = optind-1;
+ optind = 0; /* reset getopt lib */
+ return ret;
+}
+
+/* Check the link status of all ports in up to 9s, and print them finally */
+static void
+check_all_ports_link_status(uint8_t port_num, uint32_t port_mask)
+{
+#define CHECK_INTERVAL 100 /* 100ms */
+#define MAX_CHECK_TIME 90 /* 9s (90 * 100ms) in total */
+ uint8_t portid, count, all_ports_up, print_flag = 0;
+ struct rte_eth_link link;
+
+ printf("\nChecking link status!!!");
+ fflush(stdout);
+ for (count = 0; count <= MAX_CHECK_TIME; count++) {
+ all_ports_up = 1;
+ for (portid = 0; portid < port_num; portid++) {
+ if ((port_mask & (1 << portid)) == 0)
+ continue;
+ memset(&link, 0, sizeof(link));
+ rte_eth_link_get_nowait(portid, &link);
+ /* print link status if flag set */
+ if (print_flag == 1) {
+ if (link.link_status) {
+ printf("Port %d Link Up - speed %u "
+ , (uint8_t)portid,
+ (unsigned)link.link_speed);
+ printf("Mbps - %s\n", (link.link_duplex
+ == ETH_LINK_FULL_DUPLEX) ?
+ ("full-duplex") :
+ ("half-duplex\n"));
+ } else
+ printf("Port %d Link Down\n",
+ (uint8_t)portid);
+ continue;
+ }
+ /* clear all_ports_up flag if any link down */
+ if (link.link_status == 0) {
+ all_ports_up = 0;
+ break;
+ }
+ }
+ /* after finally printing all link status, get out */
+ if (print_flag == 1)
+ break;
+
+ if (all_ports_up == 0) {
+ printf(".");
+ fflush(stdout);
+ rte_delay_ms(CHECK_INTERVAL);
+ }
+
+ /* set the print_flag if all ports up or timeout */
+ if (all_ports_up == 1 || count == (MAX_CHECK_TIME - 1)) {
+ print_flag = 1;
+ printf("done\n");
+ }
+ }
+}
+
+static inline char*
+mac_addr_str(unsigned char *mac_addr)
+{
+#define MAC_STR_SIZE (3*MAC_ADDR_SIZE+1)
+ static char addr_string[MAC_STR_SIZE];
+
+ snprintf(addr_string, MAC_STR_SIZE, "%02x:%02x:%02x:%02x:%02x:%02x",
+ mac_addr[0], mac_addr[1], mac_addr[2],
+ mac_addr[3], mac_addr[4], mac_addr[5]);
+ return addr_string;
+}
+
+static int
+proc_ipc_begin(struct nic_info *info, uint16_t req_id)
+{
+ struct ethtool_drvinfo drvinfo;
+ uint8_t mac_addr[MAC_ADDR_SIZE];
+ uint8_t param[4], port_id, num_of_ports = info->num_of_ports;
+ uint32_t param2[2];
+ int status;
+
+ param[0] = num_of_ports;
+ info->vf_port_mask = 0;
+ for (port_id = 0; port_id < num_of_ports; port_id++) {
+ status = rte_ethtool_get_drvinfo(port_id, &drvinfo);
+ if (status) {
+ printf("get_drvinfo from port #%d fails\n", port_id);
+ return -1;
+ }
+ info->vf_port_mask |= (drvinfo.eedump_len == 0?1:0) << port_id;
+ rte_ethtool_net_stop(port_id);
+ }
+ param2[0] = info->port_mask;
+ param2[1] = info->vf_port_mask;
+
+ for (port_id = 0; port_id < num_of_ports; port_id++) {
+ rte_ethtool_net_open(port_id);
+ if (!is_vf_port(info->vf_port_mask, port_id)) {
+ struct rte_eth_dev *dev = &rte_eth_devices[port_id];
+ struct rte_eth_dev_data *dev_data =
+ (struct rte_eth_dev_data *)dev->data;
+
+ dev_data->promiscuous = 1;
+ rte_ethtool_net_set_rx_mode(port_id);
+ }
+ rte_ethtool_net_get_mac_addr(port_id, (void *)mac_addr);
+ printf("Port #%d init mac address is", port_id);
+ printf(" %s", mac_addr_str(mac_addr));
+
+ }
+
+ send_reply2(req_id, 1, param, (uint16_t)(sizeof(uint32_t)*2), param2);
+ return 0;
+}
+
+static inline void
+proc_no_action(uint16_t req_id)
+{
+ send_reply(req_id, 0, NULL);
+}
+
+static inline void
+proc_invalid(uint16_t req_id)
+{
+ send_reply(req_id, BAD_RETURN(0), NULL);
+}
+
+static void*
+ethtool(void *ctx)
+{
+ struct nic_info *info = ctx;
+ int keep_req = 1;
+ int reg_count, eeprom_size;
+ uint16_t req_id, param1_size, param2_size;
+ uint8_t req_type, port_id;
+ int status;
+ uint8_t param1[MAXI_PARA];
+ uint8_t param2[MAXI_PARA];
+ uint8_t reply1[MAXI_DATA];
+ void *first_param = FIRST_PARAM(param1);
+
+ init_rep_pipe();
+ while (1) {
+ read_request(&req_id, &req_type, ¶m1_size, param1,
+ ¶m2_size, param2);
+ if (req_type != (enum req_t)ipc_begin)
+ proc_invalid(req_id);
+ else
+ break;
+ }
+ proc_ipc_begin(info, req_id);
+
+ set_ipc_done();
+ reg_count = eeprom_size = 0;
+
+ while (keep_req) {
+ status = NETDEV_INVALID;
+ read_request(&req_id, &req_type, ¶m1_size, param1,
+ ¶m2_size, param2);
+ port_id = param1[0];
+
+ switch ((enum req_t)req_type) {
+ case get_drvinfo:
+ status = proc_ethtool_get_drvinfo(port_id, req_id,
+ first_param);
+ break;
+
+ case get_regs_len:
+ status = reg_count = proc_ethtool_get_regs_len(
+ port_id, req_id);
+ break;
+
+ case get_regs:
+ if (reg_count == 0)
+ reg_count = rte_ethtool_get_regs_len(port_id);
+ if (reg_count)
+ status = proc_ethtool_get_regs(port_id, req_id,
+ first_param, reply1);
+ break;
+
+ case get_link:
+ status = proc_ethtool_get_link(port_id, req_id);
+ break;
+
+ case get_eeprom_len:
+ if (eeprom_size == 0)
+ eeprom_size = rte_ethtool_get_eeprom_len(
+ port_id);
+ status = proc_ethtool_get_eeprom_len(port_id, req_id);
+ break;
+
+ case get_eeprom:
+ status = proc_ethtool_get_eeprom(port_id, req_id,
+ first_param, reply1);
+ break;
+
+ case set_eeprom:
+ status = proc_ethtool_set_eeprom(port_id, req_id,
+ first_param, param2);
+ break;
+
+ case get_pauseparam:
+ status = proc_ethtool_get_pauseparam(port_id,
+ req_id,
+ cast_ptr(reply1, struct ethtool_pauseparam *));
+ break;
+
+ case set_pauseparam:
+ status = proc_ethtool_set_pauseparam(port_id,
+ req_id,
+ cast_ptr(reply1, struct ethtool_pauseparam *));
+ break;
+
+ case dev_open:
+ status = proc_net_open(port_id, req_id);
+ break;
+
+ case dev_stop:
+ status = proc_net_stop(port_id, req_id);
+ break;
+
+ case set_rx_mode:
+ status = proc_net_set_rx_mode(port_id, req_id);
+ break;
+
+ case get_mac_addr:
+ status = proc_net_get_mac_addr(port_id,
+ req_id, first_param);
+ break;
+
+ case set_mac_addr:
+ status = proc_net_set_mac_addr(port_id,
+ req_id, first_param);
+ break;
+
+ case validate_addr:
+ status = proc_net_validate_addr(port_id,
+ req_id, first_param);
+ break;
+
+ case set_config:
+ status = proc_net_set_config(port_id,
+ req_id, first_param);
+ break;
+
+ case change_mtu:
+ status = proc_net_change_mtu(port_id,
+ req_id, first_param);
+ break;
+
+ case get_stats64:
+ status = proc_net_get_stats64(port_id,
+ req_id, reply1);
+ break;
+
+ case vlan_rx_add_vid:
+ status = proc_net_vlan_rx_add_vid(port_id,
+ req_id, first_param);
+ break;
+
+ case vlan_rx_kill_vid:
+ status = proc_net_vlan_rx_kill_vid(port_id,
+ req_id, first_param);
+ break;
+
+ case ipc_end:
+ keep_req = 0;
+ proc_no_action(req_id);
+ status = 0;
+ break;
+
+ default:
+ proc_invalid(req_id);
+ printf("unsupported service request type:");
+ printf(" %d\n", req_type);
+ break;
+ }
+ if (status < 0)
+ printf("Request type (=%d) failed\n", (int)req_type);
+ /* check if termination flag is set */
+ }
+ printf("IPC session is over\n");
+ return NULL;
+}
+
+int
+main(int argc, char **argv)
+{
+ struct lcore_queue_conf *qconf;
+ struct rte_eth_dev_info dev_info;
+ int ret;
+ uint8_t nb_ports;
+ uint8_t nb_ports_available;
+ uint8_t portid, last_port;
+ unsigned lcore_id, rx_lcore_id;
+ unsigned nb_ports_in_mask = 0;
+
+ init_ipc_done();
+ /* init EAL */
+ ret = rte_eal_init(argc, argv);
+ if (ret < 0)
+ rte_exit(EXIT_FAILURE, "Invalid EAL arguments\n");
+ argc -= ret;
+ argv += ret;
+
+ /* parse application arguments (after the EAL ones) */
+ ret = l2fwd_parse_args(argc, argv);
+ if (ret < 0)
+ rte_exit(EXIT_FAILURE, "Invalid L2FWD arguments\n");
+
+ /* create the mbuf pool */
+ l2fwd_pktmbuf_pool =
+ rte_mempool_create("mbuf_pool", NB_MBUF,
+ MBUF_SIZE, 32,
+ sizeof(struct rte_pktmbuf_pool_private),
+ rte_pktmbuf_pool_init, NULL,
+ rte_pktmbuf_init, NULL,
+ rte_socket_id(), 0);
+ if (l2fwd_pktmbuf_pool == NULL)
+ rte_exit(EXIT_FAILURE, "Cannot init mbuf pool\n");
+
+ nb_ports = rte_eth_dev_count();
+ if (nb_ports == 0)
+ rte_exit(EXIT_FAILURE, "No Ethernet ports - bye\n");
+
+ if (nb_ports > RTE_MAX_ETHPORTS)
+ nb_ports = RTE_MAX_ETHPORTS;
+
+ /* reset l2fwd_dst_ports */
+ for (portid = 0; portid < RTE_MAX_ETHPORTS; portid++)
+ l2fwd_dst_ports[portid] = 0;
+ last_port = 0;
+
+ /*
+ * Each logical core is assigned a dedicated TX queue on each port.
+ */
+ for (portid = 0; portid < nb_ports; portid++) {
+ /* skip ports that are not enabled */
+ if ((l2fwd_enabled_port_mask & (1 << portid)) == 0)
+ continue;
+
+ if (nb_ports_in_mask % 2) {
+ l2fwd_dst_ports[portid] = last_port;
+ l2fwd_dst_ports[last_port] = portid;
+ } else
+ last_port = portid;
+
+ nb_ports_in_mask++;
+
+ rte_eth_dev_info_get(portid, &dev_info);
+ }
+ if (nb_ports_in_mask % 2) {
+ printf("Notice: odd number of ports in portmask.\n");
+ l2fwd_dst_ports[last_port] = last_port;
+ }
+
+ rx_lcore_id = 0;
+ qconf = NULL;
+
+ /* Initialize the port/queue configuration of each logical core */
+ for (portid = 0; portid < nb_ports; portid++) {
+ /* skip ports that are not enabled */
+ if ((l2fwd_enabled_port_mask & (1 << portid)) == 0)
+ continue;
+
+ /* get the lcore_id for this port */
+ while (rte_lcore_is_enabled(rx_lcore_id) == 0 ||
+ lcore_queue_conf[rx_lcore_id].n_rx_port ==
+ l2fwd_rx_queue_per_lcore) {
+ rx_lcore_id++;
+ if (rx_lcore_id >= RTE_MAX_LCORE)
+ rte_exit(EXIT_FAILURE, "Not enough cores\n");
+ }
+
+ if (qconf != &lcore_queue_conf[rx_lcore_id])
+ /* Assigned a new logical core in the loop above. */
+ qconf = &lcore_queue_conf[rx_lcore_id];
+
+ qconf->rx_port_list[qconf->n_rx_port] = portid;
+ qconf->n_rx_port++;
+ printf("Lcore %u: RX port %u\n", rx_lcore_id,
+ (unsigned) portid);
+ }
+
+ nb_ports_available = nb_ports;
+
+ /* Initialise each port */
+ for (portid = 0; portid < nb_ports; portid++) {
+ /* skip ports that are not enabled */
+ if ((l2fwd_enabled_port_mask & (1 << portid)) == 0) {
+ printf("Skipping disabled port %u\n",
+ (unsigned) portid);
+ nb_ports_available--;
+ continue;
+ }
+ /* init port */
+ printf("Initializing port %u... ", (unsigned) portid);
+ fflush(stdout);
+ ret = rte_eth_dev_configure(portid, 1, 1, &port_conf);
+ if (ret < 0)
+ rte_exit(EXIT_FAILURE,
+ "Cannot configure device: err=%d, port=%u\n",
+ ret, (unsigned) portid);
+
+ rte_eth_macaddr_get(portid, &l2fwd_ports_eth_addr[portid]);
+
+ /* init one RX queue */
+ fflush(stdout);
+ ret = rte_eth_rx_queue_setup(portid, 0, nb_rxd,
+ rte_eth_dev_socket_id(portid),
+ NULL,
+ l2fwd_pktmbuf_pool);
+ if (ret < 0)
+ rte_exit(EXIT_FAILURE,
+ "rte_eth_rx_queue_setup:err=%d, port=%u\n",
+ ret, (unsigned) portid);
+
+ /* init one TX queue on each port */
+ fflush(stdout);
+ if (virtio_setup) {
+ ret = rte_eth_tx_queue_setup(portid, 0, nb_txd,
+ rte_eth_dev_socket_id(portid), &tx_conf);
+ } else {
+ ret = rte_eth_tx_queue_setup(portid, 0, nb_txd,
+ rte_eth_dev_socket_id(portid),
+ NULL);
+ }
+ if (ret < 0)
+ rte_exit(EXIT_FAILURE,
+ "rte_eth_tx_queue_setup:err=%d, port=%u\n",
+ ret, (unsigned) portid);
+ }
+
+ /* create a ethtool proxy thread */
+ pthread_attr_t attr;
+ cpu_set_t cpus;
+ pthread_t ethtool_thread;
+ struct nic_info info;
+
+ /* set core affinity to core 1 */
+ CPU_ZERO(&cpus);
+ CPU_SET(2, &cpus);
+ pthread_attr_init(&attr);
+ pthread_attr_setaffinity_np(&attr, sizeof(cpu_set_t), &cpus);
+ /* Since the register size is more than 4K (1147*4) */
+ pthread_attr_setstacksize(&attr, 4*PAGE_SIZE);
+
+ info.num_of_ports = nb_ports;
+ info.port_mask = l2fwd_enabled_port_mask;
+ if (pthread_create(ðtool_thread, NULL, ðtool, &info)) {
+ rte_exit(EXIT_FAILURE,
+ "Fail to create a pthread for ethtool task!!!\n");
+ }
+ memset(&port_statistics, 0, sizeof(port_statistics));
+
+ if (!nb_ports_available) {
+ rte_exit(EXIT_FAILURE,
+ "All available ports are disabled. Please set portmask.\n");
+ }
+
+ check_all_ports_link_status(nb_ports, l2fwd_enabled_port_mask);
+
+ /* launch per-lcore init on every lcore */
+ rte_eal_mp_remote_launch(l2fwd_launch_one_lcore, NULL, CALL_MASTER);
+ RTE_LCORE_FOREACH_SLAVE(lcore_id) {
+ if (rte_eal_wait_lcore(lcore_id) < 0)
+ return -1;
+ }
+
+ return 0;
+}
diff --git a/examples/l2fwd-ethtool/l2fwd-app/netdev_api.h b/examples/l2fwd-ethtool/l2fwd-app/netdev_api.h
new file mode 100644
index 0000000..2e93e9a
--- /dev/null
+++ b/examples/l2fwd-ethtool/l2fwd-app/netdev_api.h
@@ -0,0 +1,770 @@
+/*-
+ * BSD LICENSE
+ *
+ * Copyright(c) 2015 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _NETDEV_API_H_
+#define _NETDEV_API_H_
+
+#include <linux/ethtool.h>
+#include <string.h>
+#include "shared_fifo.h"
+
+#define MAC_ADDR_SIZE 6
+#define quad_aligned_size(x) ((x & 0x7) ? ((x+7)&0x7) : x)
+
+#define size16(data_type) (uint16_t)(sizeof(data_type))
+
+/* NETDEV_STATUS = 0 if successful */
+#define NETDEV_UNSUPPORTED -1
+#define NETDEV_INVALID -1
+#define NETDEV_STATUS(data_size) (GOOD_RETURN(data_size) \
+ ? 0 : NETDEV_INVALID)
+#define UNUSED(x) (void)(x)
+
+#ifdef NETDEV_OP_REQUEST
+static uint16_t
+next_reqid(void) {
+ static uint16_t request_id;
+
+ return request_id++;
+}
+
+/*
+ * send request (with one or two variables) to request-pipe
+ * (invoked by non- DPDK process)
+ */
+static int
+send_request(uint16_t req_id, uint8_t req_type, uint16_t param_size,
+ void *param_data)
+{
+ int fd;
+ uint32_t req[2];
+
+ req[0] = REQ_DWORD_LO(req_id, 0, req_type);
+ req[1] = REQ_DWORD_HI(param_size, 0);
+
+ fd = open(REQ_PIPE, O_WRONLY);
+ write(fd, req, PIPE_CTL_BYTE_COUNT);
+ if (param_size)
+ write(fd, param_data, param_size);
+ close(fd);
+
+ return 0;
+}
+
+/*
+ * send request (with more than two variables) to request-pipe
+ * (invoked by non- DPDK process)
+ */
+static int
+send_request2(uint16_t req_id, uint8_t req_type, uint16_t param1_size,
+ void *param1_data, int param2_size, void *param2_data)
+{
+ int fd;
+ uint32_t req[2];
+
+ req[0] = REQ_DWORD_LO(req_id, 1, req_type);
+ req[1] = REQ_DWORD_HI(param1_size, param2_size);
+
+ fd = open(REQ_PIPE, O_WRONLY);
+ write(fd, req, PIPE_CTL_BYTE_COUNT);
+
+ if (param1_size)
+ write(fd, param1_data, param1_size);
+ if (param2_size)
+ write(fd, param2_data, param2_size);
+ close(fd);
+
+ return 0;
+}
+
+/* read return variables from the reply-pipe (invoked by non- DPDK process) */
+static int
+read_reply(uint16_t expected_id, uint16_t *byte_count, void *reply_data1,
+ void *reply_data2)
+{
+ int fd;
+ uint32_t req[2];
+ uint16_t rx_id, data1_size;
+
+ /* block on read if reply is not available */
+ fd = open(REP_PIPE, O_RDONLY);
+ read(fd, req, PIPE_CTL_BYTE_COUNT);
+
+ *byte_count = REP_DATA1_COUNT(req);
+ rx_id = REP_ID(req);
+
+ if (!GOOD_RETURN(*byte_count)) {
+ close(fd);
+ return -1;
+ }
+ data1_size = BYTE_COUNT((*byte_count));
+ read(fd, reply_data1, data1_size);
+ if (MULTIPLE_DATA(*byte_count)) {
+ assert(reply_data2);
+ read(fd, reply_data2, REP_DATA2_COUNT(req));
+ }
+ close(fd);
+
+ if (expected_id != rx_id)
+ return -1;
+ return 0;
+}
+
+/* definition of netdev op request */
+
+static int
+netdev_ethtool_get_drvinfo(uint8_t port_id, struct ethtool_drvinfo *drvinfo)
+{
+ uint16_t req_id = next_reqid();
+ uint16_t data_size;
+
+ send_request(req_id, get_drvinfo, 1, &port_id);
+ read_reply(req_id, &data_size, drvinfo, NULL);
+
+ return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_ethtool_get_regs_len(uint8_t port_id)
+{
+ uint16_t req_id = next_reqid();
+ uint16_t data_size;
+ int length;
+
+ send_request(req_id, get_regs_len, 1, &port_id);
+ read_reply(req_id, &data_size, &length, NULL);
+
+ if (GOOD_RETURN(data_size))
+ return length;
+ return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_ethtool_get_regs(uint8_t port_id, struct ethtool_regs *regs, void *buf)
+{
+ uint16_t req_id = next_reqid();
+ uint16_t data_size;
+ uint8_t param_data[PARAM_SIZE(struct ethtool_regs)];
+
+ param_data[0] = port_id;
+ memcpy(FIRST_PARAM(param_data), regs, sizeof(struct ethtool_regs));
+
+ send_request(req_id, get_regs, PARAM_SIZE(struct ethtool_regs),
+ param_data);
+ read_reply(req_id, &data_size, regs, buf);
+
+ return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_ethtool_get_link(uint8_t port_id)
+{
+ uint16_t req_id = next_reqid();
+ uint16_t data_size;
+ int link_status;
+
+ send_request(req_id, get_link, 1, &port_id);
+ read_reply(req_id, &data_size, &link_status, NULL);
+ if (GOOD_RETURN(data_size))
+ return link_status;
+ return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_ethtool_get_eeprom_len(uint8_t port_id)
+{
+ uint16_t req_id = next_reqid();
+ uint16_t data_size;
+ int length;
+
+ send_request(req_id, get_eeprom_len, 1, &port_id);
+ read_reply(req_id, &data_size, &length, NULL);
+
+ if (GOOD_RETURN(data_size))
+ return length;
+ return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_ethtool_get_eeprom(uint8_t port_id, struct ethtool_eeprom *eeprom,
+ void *words)
+{
+ uint16_t req_id = next_reqid();
+ uint16_t data_size;
+ uint8_t param_data[PARAM_SIZE(struct ethtool_eeprom)];
+
+ param_data[0] = port_id;
+ memcpy(FIRST_PARAM(param_data), eeprom, sizeof(struct ethtool_eeprom));
+
+ send_request(req_id, get_eeprom, PARAM_SIZE(struct ethtool_eeprom),
+ param_data);
+ read_reply(req_id, &data_size, eeprom, words);
+
+ return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_ethtool_set_eeprom(uint8_t port_id, struct ethtool_eeprom *eeprom,
+ void *words)
+{
+ uint16_t req_id = next_reqid();
+ uint16_t data_size;
+ uint8_t param_data[PARAM_SIZE(struct ethtool_eeprom)];
+
+ param_data[0] = port_id;
+ memcpy(FIRST_PARAM(param_data), eeprom, sizeof(struct ethtool_eeprom));
+
+ send_request2(req_id, set_eeprom, PARAM_SIZE(struct ethtool_eeprom),
+ param_data, eeprom->len, words);
+ read_reply(req_id, &data_size, eeprom, NULL);
+
+ return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_ethtool_get_pauseparam(uint8_t port_id, struct ethtool_pauseparam *param)
+{
+ uint16_t req_id = next_reqid();
+ uint16_t data_size;
+
+ send_request(req_id, get_pauseparam, 1, &port_id);
+ read_reply(req_id, &data_size, param, NULL);
+
+ return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_ethtool_set_pauseparam(uint8_t port_id, struct ethtool_pauseparam *param)
+{
+ uint16_t req_id = next_reqid();
+ uint16_t data_size;
+
+ send_request(req_id, set_pauseparam, 1, &port_id);
+ read_reply(req_id, &data_size, param, NULL);
+
+ return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_net_open(uint8_t port_id) {
+ uint16_t req_id = next_reqid();
+ uint16_t data_size;
+
+ send_request(req_id, dev_open, 1, &port_id);
+ read_reply(req_id, &data_size, NULL, NULL);
+
+ return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_net_stop(uint8_t port_id) {
+ uint16_t req_id = next_reqid();
+ uint16_t data_size;
+
+ send_request(req_id, dev_stop, 1, &port_id);
+ read_reply(req_id, &data_size, NULL, NULL);
+
+ return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_net_set_rx_mode(uint8_t port_id)
+{
+ uint16_t req_id = next_reqid();
+ uint16_t data_size;
+
+ send_request(req_id, set_rx_mode, 1, &port_id);
+ read_reply(req_id, &data_size, NULL, NULL);
+
+ return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_net_get_mac_addr(uint8_t port_id, void *addr)
+{
+ uint16_t req_id = next_reqid();
+ uint16_t data_size;
+
+ send_request(req_id, get_mac_addr, 1, &port_id);
+ read_reply(req_id, &data_size, addr, NULL);
+
+ return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_net_set_mac_addr(uint8_t port_id, void *addr)
+{
+ uint16_t req_id = next_reqid();
+ uint16_t data_size;
+ uint8_t param_data[FIRST_DATA_OFFSET+MAC_ADDR_SIZE];
+
+ param_data[0] = port_id;
+ memcpy(FIRST_PARAM(param_data), addr, MAC_ADDR_SIZE);
+ send_request(req_id, set_mac_addr,
+ (FIRST_DATA_OFFSET+MAC_ADDR_SIZE), param_data);
+ read_reply(req_id, &data_size, NULL, NULL);
+
+ return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_net_validate_addr(uint8_t port_id, void *addr)
+{
+ uint16_t req_id = next_reqid();
+ uint16_t data_size;
+ uint8_t param_data[FIRST_DATA_OFFSET+MAC_ADDR_SIZE];
+ int valid;
+
+ param_data[0] = port_id;
+ memcpy(FIRST_PARAM(param_data), addr, MAC_ADDR_SIZE);
+ send_request(req_id, validate_addr,
+ (FIRST_DATA_OFFSET+MAC_ADDR_SIZE), param_data);
+ read_reply(req_id, &data_size, &valid, NULL);
+
+ if (GOOD_RETURN(data_size))
+ return valid;
+ return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_net_change_mtu(uint8_t port_id, int mtu)
+{
+ uint16_t req_id = next_reqid();
+ uint16_t data_size;
+ uint8_t param_data[PARAM_SIZE(int)];
+
+ param_data[0] = port_id;
+ memcpy(FIRST_PARAM(param_data), &mtu, sizeof(int));
+ send_request(req_id, change_mtu, PARAM_SIZE(int), param_data);
+ read_reply(req_id, &data_size, NULL, NULL);
+
+ return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_net_get_stats64(uint8_t port_id, void *stats)
+{
+ uint16_t req_id = next_reqid();
+ uint16_t data_size;
+
+ send_request(req_id, get_stats64, 1, &port_id);
+ read_reply(req_id, &data_size, stats, NULL);
+
+ return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_net_vlan_rx_add_vid(uint8_t port_id, uint16_t vid)
+{
+ uint16_t req_id = next_reqid();
+ uint16_t data_size;
+ uint8_t param_data[PARAM_SIZE(int)];
+
+ param_data[0] = port_id;
+ memcpy(FIRST_PARAM(param_data), &vid, sizeof(uint16_t));
+ send_request(req_id, vlan_rx_add_vid, FIRST_DATA_OFFSET+sizeof(int),
+ param_data);
+ read_reply(req_id, &data_size, NULL, NULL);
+
+ return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_net_vlan_rx_kill_vid(uint8_t port_id, uint16_t vid)
+{
+ uint16_t req_id = next_reqid();
+ uint16_t data_size;
+ uint8_t param_data[PARAM_SIZE(int)];
+
+ param_data[0] = port_id;
+ memcpy(FIRST_PARAM(param_data), &vid, sizeof(uint16_t));
+ send_request(req_id, vlan_rx_kill_vid, FIRST_DATA_OFFSET+sizeof(int),
+ param_data);
+ read_reply(req_id, &data_size, NULL, NULL);
+
+ return NETDEV_STATUS(data_size);
+};
+
+#endif /* NETDEV_OP_REQUEST */
+
+#ifdef NETDEV_OP_REPLY
+/* read request from request-pipe (invoked by rte-api server thread) */
+static int
+read_request(uint16_t *req_id, uint8_t *req_type, uint16_t *param1_size,
+ uint8_t *param1_data, uint16_t *param2_size, void *param2_data)
+{
+ int fd;
+ uint32_t req[2];
+
+ /* block on read if request is not sent ... */
+ fd = open(REQ_PIPE, O_RDONLY);
+ read(fd, req, PIPE_CTL_BYTE_COUNT);
+
+ *req_id = REQ_ID(req);
+ *req_type = REQ_TYPE(req);
+ *param1_size = REQ_PARAM1_SIZE(req);
+
+ if (*param1_size > 0) {
+ read(fd, param1_data, *param1_size);
+ if (REQ_IDTYPE(req)) {
+ *param2_size = REQ_PARAM2_SIZE(req);
+ read(fd, param2_data, *param2_size);
+ } else
+ *param2_size = 0;
+ }
+ close(fd);
+
+ return 0;
+}
+
+/* definition of netdev op service */
+/*
+ * rep[1:0]: request id
+ * rep[3:2]: data byte count; bit[15]: error status bit[14]: multiple return
+ * variables are requested
+ *
+ * send reply with one return variable to reply-pipe
+ * (invoked by rte-api server thread)
+ */
+static int
+send_reply(uint16_t rx_id, uint16_t byte_count, void *reply_data)
+{
+ int fd;
+ uint32_t req[2];
+
+ req[0] = REP_DWORD_LO(rx_id, byte_count);
+ req[1] = REP_DWORD_HI(0);
+
+ fd = open(REP_PIPE, O_WRONLY);
+ write(fd, req, PIPE_CTL_BYTE_COUNT);
+
+ if (GOOD_RETURN(byte_count) && (byte_count > 0))
+ write(fd, reply_data, byte_count);
+ close(fd);
+
+ return 0;
+}
+
+/*
+ * send reply with two or more variables to reply-pipe
+ * (invoked by rte-api server thread)
+ */
+static int
+send_reply2(uint16_t rx_id, uint16_t byte_count1, void *reply_data1,
+ uint16_t byte_count2, void *reply_data2)
+{
+ int fd;
+ uint32_t req[2];
+
+ req[0] = REP_DWORD_LO(rx_id, REP_MUTILPLE_DATA(byte_count1));
+ req[1] = REP_DWORD_HI(byte_count2);
+
+ fd = open(REP_PIPE, O_WRONLY);
+ write(fd, req, PIPE_CTL_BYTE_COUNT);
+
+ if (GOOD_RETURN(byte_count1) && (byte_count2 > 0)) {
+ write(fd, reply_data1, byte_count1);
+ write(fd, reply_data2, byte_count2);
+ }
+ close(fd);
+
+ return 0;
+}
+
+/* Functions for netdev service thread */
+static int
+proc_ethtool_get_drvinfo(uint8_t port_id, uint16_t req_id, void *param_data)
+{
+ struct ethtool_drvinfo *drvinfo = param_data;
+ uint16_t data_size;
+
+ if (rte_ethtool_get_drvinfo(port_id, drvinfo))
+ data_size = STATUS_MASK;
+ else
+ data_size = size16(struct ethtool_drvinfo);
+ return send_reply(req_id, data_size, param_data);
+};
+
+static int
+proc_ethtool_get_regs_len(uint8_t port_id, uint16_t req_id)
+{
+ int reg_len;
+ uint16_t data_size;
+
+ reg_len = rte_ethtool_get_regs_len(port_id);
+ if (reg_len == 0)
+ data_size = STATUS_MASK;
+ else
+ data_size = size16(int);
+ return send_reply(req_id, data_size, ®_len);
+};
+
+static int
+proc_ethtool_get_regs(uint8_t port_id, uint16_t req_id, void *param_data,
+ void *reply_data2)
+{
+ struct ethtool_regs *reg_info = param_data;
+ void *buf = reply_data2;
+ uint16_t data_size;
+
+ if (rte_ethtool_get_regs(port_id, reg_info, buf))
+ data_size = STATUS_MASK;
+ else
+ data_size = sizeof(struct ethtool_regs);
+ return send_reply2(req_id, data_size, reg_info,
+ rte_ethtool_get_regs_len(port_id)*sizeof(int), reply_data2);
+};
+
+static int
+proc_ethtool_get_link(uint8_t port_id, uint16_t req_id)
+{
+ int link_status;
+
+ link_status = rte_ethtool_get_link(port_id);
+ return send_reply(req_id, (uint16_t)sizeof(int), &link_status);
+};
+
+static int
+proc_ethtool_get_eeprom_len(uint8_t port_id, uint16_t req_id)
+{
+ int eeprom_length;
+ uint16_t data_size;
+
+ eeprom_length = rte_ethtool_get_eeprom_len(port_id);
+ if (eeprom_length == 0)
+ data_size = STATUS_MASK;
+ else
+ data_size = size16(int);
+ return send_reply(req_id, data_size, &eeprom_length);
+};
+
+static int
+proc_ethtool_get_eeprom(uint8_t port_id, uint16_t req_id, void *param_data,
+ void *reply_data2)
+{
+ struct ethtool_eeprom *eeprom_ptr = param_data;
+ uint16_t data_size;
+
+ if (rte_ethtool_get_eeprom(port_id, eeprom_ptr, reply_data2))
+ data_size = STATUS_MASK;
+ else
+ data_size = sizeof(struct ethtool_eeprom);
+ return send_reply2(req_id, data_size, eeprom_ptr,
+ eeprom_ptr->len & ~1, reply_data2);
+};
+
+static int
+proc_ethtool_set_eeprom(uint8_t port_id, uint16_t req_id, void *param_data,
+ void *param2_data)
+{
+ struct ethtool_eeprom *eeprom_ptr = param_data;
+ uint16_t data_size;
+
+ if (rte_ethtool_set_eeprom(port_id, eeprom_ptr, param2_data))
+ data_size = STATUS_MASK;
+ else
+ data_size = sizeof(struct ethtool_eeprom);
+ return send_reply(req_id, data_size, eeprom_ptr);
+};
+
+static int
+proc_ethtool_get_pauseparam(uint8_t port_id, uint16_t req_id, void *reply_data)
+{
+ uint16_t data_size;
+
+ if (rte_ethtool_get_pauseparam(port_id,
+ (struct ethtool_pauseparam *)reply_data))
+ data_size = STATUS_MASK;
+ else
+ data_size = (uint16_t)(sizeof(struct ethtool_pauseparam));
+ return send_reply(req_id, data_size, reply_data);
+};
+
+static int
+proc_ethtool_set_pauseparam(uint8_t port_id, uint16_t req_id, void *set_data)
+{
+ uint16_t data_size;
+
+ if (rte_ethtool_set_pauseparam(port_id,
+ (struct ethtool_pauseparam *)set_data))
+ data_size = STATUS_MASK;
+ else
+ data_size = (uint16_t)(sizeof(struct ethtool_pauseparam));
+ return send_reply(req_id, data_size, set_data);
+};
+
+static int
+proc_net_open(uint8_t port_id, uint16_t req_id)
+{
+ uint16_t data_size;
+
+ if (rte_ethtool_net_open(port_id))
+ data_size = STATUS_MASK;
+ else
+ data_size = 0;
+
+ return send_reply(req_id, data_size, &data_size);
+};
+
+static int
+proc_net_stop(uint8_t port_id, uint16_t req_id)
+{
+ uint16_t data_size;
+
+ rte_ethtool_net_stop(port_id);
+ data_size = 0;
+
+ return send_reply(req_id, data_size, &data_size);
+};
+
+static int
+proc_net_set_rx_mode(uint8_t port_id, uint16_t req_id)
+{
+ uint16_t data_size;
+
+ if (rte_ethtool_net_set_rx_mode(port_id))
+ data_size = STATUS_MASK;
+ else
+ data_size = 0;
+
+ return send_reply(req_id, data_size, &data_size);
+};
+
+static int
+proc_net_get_mac_addr(uint8_t port_id, uint16_t req_id, void *param_data)
+{
+ uint16_t data_size;
+
+ if (rte_ethtool_net_get_mac_addr(port_id, param_data))
+ data_size = STATUS_MASK;
+ else
+ data_size = MAC_ADDR_SIZE;
+
+ return send_reply(req_id, data_size, param_data);
+};
+
+static int
+proc_net_set_mac_addr(uint8_t port_id, uint16_t req_id, void *param_data)
+{
+ uint16_t data_size;
+
+ if (rte_ethtool_net_set_mac_addr(port_id, param_data))
+ data_size = STATUS_MASK;
+ else
+ data_size = 0;
+
+ return send_reply(req_id, data_size, &data_size);
+};
+
+static int
+proc_net_validate_addr(uint8_t port_id, uint16_t req_id, void *param_data)
+{
+ int status;
+
+ status = rte_ethtool_net_validate_addr(port_id, param_data);
+
+ return send_reply(req_id, (uint16_t)sizeof(int), &status);
+};
+
+static int
+proc_net_set_config(uint8_t port_id, uint16_t req_id, void *param_data)
+{
+ uint16_t data_size;
+
+ if (rte_ethtool_net_set_config(port_id, param_data))
+ data_size = STATUS_MASK;
+ else
+ data_size = 0;
+
+ return send_reply(req_id, data_size, &data_size);
+};
+
+static int
+proc_net_change_mtu(uint8_t port_id, uint16_t req_id, void *param_data)
+{
+ uint16_t data_size;
+ int mtu = *(int *)(param_data);
+
+ if (rte_ethtool_net_change_mtu(port_id, mtu))
+ data_size = STATUS_MASK;
+ else
+ data_size = 0;
+
+ return send_reply(req_id, data_size, &data_size);
+};
+
+static int
+proc_net_get_stats64(uint8_t port_id, uint16_t req_id, void *reply_data)
+{
+ uint16_t data_size;
+
+ if (rte_ethtool_net_get_stats64(port_id, reply_data))
+ data_size = STATUS_MASK;
+ else
+ data_size = size16(struct rte_eth_stats);
+
+ return send_reply(req_id, data_size, reply_data);
+};
+
+static int
+proc_net_vlan_rx_add_vid(uint8_t port_id, uint16_t req_id,
+ void *param_data)
+{
+ uint16_t data_size;
+ int *vid_ptr = (int *)param_data;
+
+ if (rte_ethtool_net_vlan_rx_add_vid(port_id, *vid_ptr))
+ data_size = STATUS_MASK;
+ else
+ data_size = 0;
+
+ return send_reply(req_id, data_size, &data_size);
+};
+
+static int
+proc_net_vlan_rx_kill_vid(uint8_t port_id, uint16_t req_id,
+ void *param_data)
+{
+ uint16_t data_size;
+ int *vid_ptr = (int *)param_data;
+
+ if (rte_ethtool_net_vlan_rx_kill_vid(port_id, *vid_ptr))
+ data_size = STATUS_MASK;
+ else
+ data_size = 0;
+
+ return send_reply(req_id, data_size, &data_size);
+};
+
+#endif /* NETDEV_OP_REPLY */
+#endif /* _NETDEV_API_H_ */
diff --git a/examples/l2fwd-ethtool/l2fwd-app/shared_fifo.h b/examples/l2fwd-ethtool/l2fwd-app/shared_fifo.h
new file mode 100644
index 0000000..be528b8
--- /dev/null
+++ b/examples/l2fwd-ethtool/l2fwd-app/shared_fifo.h
@@ -0,0 +1,159 @@
+/*-
+ * BSD LICENSE
+ *
+ * Copyright(c) 2015 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _SHARED_FIFO_H_
+#define _SHARED_FIFO_H_
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <assert.h>
+
+#define REQ_PIPE "/tmp/nic_request"
+#define REP_PIPE "/tmp/nic_reply"
+#define PAGE_SIZE (4*1024)
+#define STACK_SIZE (4*PAGE_SIZE)
+#define MAXI_DATA (1024*6)
+#define MAXI_PARA 1024
+#define STATUS_MASK 0x8000
+#define MULTIPLE_DATA_MASK 0x4000
+#define MAXI_REQ_TYPE 16
+#define FIRST_DATA_OFFSET 8
+#define cast_ptr(x, new_type) (new_type)(void *)(x)
+#define to_ptr(new_ptr_type, data, offset) \
+ (new_ptr_type)(&((unsigned char *)(void *)data)[offset])
+#define u8ptr(x) cast_ptr(x, uint8_t *)
+#define to_mac_type(x) cast_ptr(x, struct ether_addr *)
+
+/*
+ * req[1:0]: request-id
+ * req[2]: request-id type
+ * req[3]: request type
+ * req[4:5]: param1-size
+ * req[7:6]: param2-size
+ *
+ * rep[1:0] reply-id
+ * rep[3:2]: data1-size // bit[15]: status bit[14]: two return data
+ * rep[7:4]: data2-size
+ */
+#define PIPE_CTL_BYTE_COUNT (sizeof(uint32_t)*2)
+#define REQ_DWORD_LO(req_id, id_type, req_tye) \
+ (((uint32_t)req_type << 24) | ((uint32_t)id_type << 16) | req_id)
+#define REQ_DWORD_HI(param1_size, param2_size) \
+ (((uint32_t)param2_size << 16) | param1_size)
+
+#define REP_DWORD_LO(rep_id, data_bytes) \
+ (((uint32_t)data_bytes << 16) | (uint32_t)rep_id)
+#define REP_DWORD_HI(data2_bytes) (data2_bytes)
+
+#define REP_MUTILPLE_DATA(data1_size) (data1_size | MULTIPLE_DATA_MASK)
+#define REQ_ID(dword_ptr) (dword_ptr[0] & 0xFFFF)
+#define REQ_IDTYPE(dword_ptr) ((dword_ptr[0] >> 16) & 0xFF)
+#define REQ_TYPE(dword_ptr) ((dword_ptr[0] >> 24) & 0xFF)
+#define REQ_PARAM1_SIZE(dword_ptr) (dword_ptr[1] & 0xFFFF)
+#define REQ_PARAM2_SIZE(dword_ptr) ((dword_ptr[1]>>16) & 0xFFFF)
+#define REP_ID(dword_ptr) (dword_ptr[0] & 0xFFFF)
+#define REP_DATA1_COUNT(dword_ptr) ((dword_ptr[0] >> 16) & 0xFFFF)
+#define REP_DATA2_COUNT(dword_ptr) (dword_ptr[1])
+
+#define BAD_RETURN(data_size) (data_size | STATUS_MASK)
+#define GOOD_RETURN(data_size) ((data_size & STATUS_MASK) == 0)
+#define MULTIPLE_DATA(data_size) (data_size & MULTIPLE_DATA_MASK)
+#define BYTE_COUNT(data_size) \
+ (data_size & ~(STATUS_MASK|MULTIPLE_DATA_MASK))
+
+#define PARAM_SIZE(type) \
+ ((uint16_t)(FIRST_DATA_OFFSET+sizeof(type)))
+#define FIRST_PARAM(param_data) (void *)(&(param_data[FIRST_DATA_OFFSET]))
+#define FIRST_PARAM_TYPE(param_data, ptr_type) \
+ (ptr_type)(FIRST_PARAM(param_data))
+
+void init_req_pipe(void);
+void init_rep_pipe(void);
+
+struct nic_info {
+ uint8_t num_of_ports;
+ uint32_t port_mask;
+ uint32_t vf_port_mask;
+ uint32_t flag;
+} nic_info;
+
+enum req_t {
+ get_drvinfo = 0,
+ get_setting,
+ set_setting,
+ get_regs_len,
+ get_regs,
+ get_link,
+ get_eeprom_len,
+ get_eeprom,
+ set_eeprom,
+ get_coalesce,
+ set_coalesce,
+ get_pauseparam,
+ set_pauseparam,
+ dump_data,
+
+ dev_open,
+ dev_stop,
+ set_rx_mode,
+ get_mac_addr,
+ set_mac_addr,
+ validate_addr,
+ set_config,
+ change_mtu,
+ get_stats64,
+ get_stats,
+ vlan_rx_add_vid,
+ vlan_rx_kill_vid,
+ ipc_begin, /* request to start ipc, and get nic info ... */
+ ipc_end, /* request to stop ipc ... */
+ invalid_req,
+};
+
+void
+init_req_pipe(void)
+{
+ mkfifo(REQ_PIPE, 0666);
+}
+
+void
+init_rep_pipe(void)
+{
+ mkfifo(REP_PIPE, 0666);
+}
+
+#endif /* _SHARED_FIFO_H_ */
diff --git a/examples/l2fwd-ethtool/lib/Makefile b/examples/l2fwd-ethtool/lib/Makefile
new file mode 100644
index 0000000..d7ee955
--- /dev/null
+++ b/examples/l2fwd-ethtool/lib/Makefile
@@ -0,0 +1,57 @@
+# BSD LICENSE
+#
+# Copyright(c) 2015 Intel Corporation. All rights reserved.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in
+# the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Intel Corporation nor the names of its
+# contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ifeq ($(RTE_SDK),)
+$(error "Please define RTE_SDK environment variable")
+endif
+
+# Default target, can be overwritten by command line or environment
+RTE_TARGET ?= x86_64-native-linuxapp-gcc
+
+include $(RTE_SDK)/mk/rte.vars.mk
+
+ifneq ($(CONFIG_RTE_EXEC_ENV),"linuxapp")
+$(error This application can only operate in a linuxapp 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)
+
+include $(RTE_SDK)/mk/rte.extlib.mk
diff --git a/examples/l2fwd-ethtool/lib/rte_ethtool.c b/examples/l2fwd-ethtool/lib/rte_ethtool.c
new file mode 100644
index 0000000..2ef78f1
--- /dev/null
+++ b/examples/l2fwd-ethtool/lib/rte_ethtool.c
@@ -0,0 +1,336 @@
+/*-
+ * BSD LICENSE
+ *
+ * Copyright(c) 2010-2015 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include <stdio.h>
+#include <string.h>
+#include <stdint.h>
+#include <rte_version.h>
+#include <rte_ethdev.h>
+#include "rte_ethtool.h"
+
+int
+rte_ethtool_get_drvinfo(uint8_t port_id, struct ethtool_drvinfo *drvinfo)
+{
+ struct rte_eth_dev_info dev_info;
+ int n;
+
+ memset(&dev_info, 0, sizeof(dev_info));
+ rte_eth_dev_info_get(port_id, &dev_info);
+
+ snprintf(drvinfo->driver, sizeof(drvinfo->driver), "%s",
+ dev_info.driver_name);
+ snprintf(drvinfo->version, sizeof(drvinfo->version), "%s",
+ rte_version());
+ snprintf(drvinfo->bus_info, sizeof(drvinfo->bus_info),
+ "%04x:%02x:%02x.%x",
+ dev_info.pci_dev->addr.domain, dev_info.pci_dev->addr.bus,
+ dev_info.pci_dev->addr.devid, dev_info.pci_dev->addr.function);
+
+ n = rte_eth_dev_get_reg_length(port_id);
+ 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(uint8_t port_id)
+{
+ return rte_eth_dev_get_reg_length(port_id);
+}
+
+int
+rte_ethtool_get_regs(uint8_t port_id, struct ethtool_regs *regs, void *data)
+{
+ struct rte_dev_reg_info reg_info;
+ int status;
+
+ reg_info.data = data;
+ reg_info.length = 0;
+
+ status = rte_eth_dev_get_reg_info(port_id, ®_info);
+ if (status)
+ return status;
+ regs->version = reg_info.version;
+
+ return 0;
+}
+
+int
+rte_ethtool_get_link(uint8_t port_id)
+{
+ struct rte_eth_link link;
+
+ rte_eth_link_get(port_id, &link);
+ return link.link_status;
+}
+
+int
+rte_ethtool_get_eeprom_len(uint8_t port_id)
+{
+ return rte_eth_dev_get_eeprom_length(port_id);
+}
+
+int
+rte_ethtool_get_eeprom(uint8_t port_id, struct ethtool_eeprom *eeprom,
+ void *words)
+{
+ struct rte_dev_eeprom_info eeprom_info;
+ int status;
+
+ 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(uint8_t port_id, struct ethtool_eeprom *eeprom,
+ void *words)
+{
+ struct rte_dev_eeprom_info eeprom_info;
+ int status;
+
+ 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_pauseparam(uint8_t port_id,
+ struct ethtool_pauseparam *pause_param)
+{
+ struct rte_eth_fc_conf fc_conf;
+ int status;
+
+ 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_NONE:
+ /* dummy block to avoid compiler warning */
+ break;
+ 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;
+ }
+ pause_param->autoneg = (uint32_t)fc_conf.autoneg;
+
+ return 0;
+}
+
+int
+rte_ethtool_set_pauseparam(uint8_t port_id,
+ struct ethtool_pauseparam *pause_param)
+{
+ struct rte_eth_fc_conf fc_conf;
+ int status;
+ /*
+ * 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(uint8_t port_id)
+{
+ rte_eth_dev_stop(port_id);
+
+ return rte_eth_dev_start(port_id);
+}
+
+int
+rte_ethtool_net_stop(uint8_t port_id)
+{
+ rte_eth_dev_stop(port_id);
+
+ return 0;
+}
+
+int
+rte_ethtool_net_get_mac_addr(uint8_t port_id, struct ether_addr *addr)
+{
+ rte_eth_macaddr_get(port_id, addr);
+
+ return 0;
+}
+
+int
+rte_ethtool_net_set_mac_addr(uint8_t port_id, struct ether_addr *addr)
+{
+ return rte_eth_dev_default_mac_addr_set(port_id, addr);
+}
+
+int
+rte_ethtool_net_validate_addr(uint8_t port_id __rte_unused,
+ struct ether_addr *addr)
+{
+ return is_valid_assigned_ether_addr(addr);
+}
+
+int
+rte_ethtool_net_set_config(uint8_t port_id, void *config __rte_unused)
+{
+ struct rte_eth_link link;
+
+ memset(&link, 0, sizeof(link));
+ rte_eth_link_get(port_id, &link);
+ if (link.link_status == 1)
+ return -EINVAL;
+ return 0;
+}
+
+int
+rte_ethtool_net_change_mtu(uint8_t port_id, int mtu)
+{
+ return rte_eth_dev_set_mtu(port_id, (uint16_t)mtu);
+}
+
+int
+rte_ethtool_net_get_stats64(uint8_t port_id, struct rte_eth_stats *stats)
+{
+ return rte_eth_stats_get(port_id, stats);
+}
+
+int
+rte_ethtool_net_vlan_rx_add_vid(uint8_t port_id, uint16_t vid)
+{
+ return rte_eth_dev_vlan_filter(port_id, vid, 1);
+}
+
+int
+rte_ethtool_net_vlan_rx_kill_vid(uint8_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(uint8_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;
+
+ /* Setting single cast promiscuous mode */
+ if (rte_eth_promiscuous_get(port_id) == 1)
+ rte_eth_promiscuous_enable(port_id);
+ else if (rte_eth_promiscuous_get(port_id) == 0)
+ rte_eth_promiscuous_disable(port_id);
+
+ /* Setting multi-cast promiscuous mode */
+ if (rte_eth_allmulticast_get(port_id) == 1)
+ rte_eth_allmulticast_enable(port_id);
+ else if (rte_eth_allmulticast_get(port_id) == 0)
+ rte_eth_allmulticast_disable(port_id);
+
+ /* Set VF vf_rx_mode, VF unsupport status is discard */
+ for (vf = 0; vf < num_vfs; vf++)
+ rte_eth_dev_set_vf_rxmode(port_id, vf, 1, 1);
+
+ /* Enable Rx vlan filter, VF unspport status is discard */
+ rte_eth_dev_set_vlan_offload(port_id, ETH_VLAN_FILTER_MASK);
+
+ return 0;
+}
diff --git a/examples/l2fwd-ethtool/lib/rte_ethtool.h b/examples/l2fwd-ethtool/lib/rte_ethtool.h
new file mode 100644
index 0000000..5d48b0d
--- /dev/null
+++ b/examples/l2fwd-ethtool/lib/rte_ethtool.h
@@ -0,0 +1,385 @@
+/*-
+ * BSD LICENSE
+ *
+ * Copyright(c) 2010-2015 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _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_driverinfo
+ * 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_set_config: net_device_ops::ndo_set_config
+ * rte_ethtool_net_change_mtu: net_device_ops::rte_net_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.
+ * - (-ENOTSUP) if hardware doesn't support.
+ * - (-ENODEV) if *port_id* invalid.
+ * - others depends on the specific operations implementation.
+ */
+int rte_ethtool_get_drvinfo(uint8_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(uint8_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(uint8_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.
+ * - others depends on the specific operations implementation.
+ */
+int rte_ethtool_get_link(uint8_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(uint8_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(uint8_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.
+ * - others depends on the specific operations implementation.
+ */
+int rte_ethtool_set_eeprom(uint8_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.
+ * - others depends on the specific operations implementation.
+ */
+int rte_ethtool_get_pauseparam(uint8_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.
+ * - others depends on the specific operations implementation.
+ */
+int rte_ethtool_set_pauseparam(uint8_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(uint8_t port_id);
+
+/**
+ * Stop 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_stop(uint8_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.
+ * - (-ENOTSUP) if hardware doesn't support.
+ * - (-ENODEV) if *port_id* invalid.
+ * - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_get_mac_addr(uint8_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.
+ * - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_set_mac_addr(uint8_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.
+ * - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_validate_addr(uint8_t port_id, struct ether_addr *addr);
+
+/**
+ * Setting the Ethernet device configuration.
+ *
+ * @param port_id
+ * The port identifier of the Ethernet device.
+ * @param config
+ * A opintr to a configuration parameter.
+ * @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_config(uint8_t port_id, void *config);
+
+/**
+ * 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.
+ * - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_change_mtu(uint8_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.
+ * - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_get_stats64(uint8_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(uint8_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(uint8_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(uint8_t port_id);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _RTE_ETHTOOL_H_ */
diff --git a/examples/l2fwd-ethtool/nic-control/Makefile b/examples/l2fwd-ethtool/nic-control/Makefile
new file mode 100644
index 0000000..17ab4a3
--- /dev/null
+++ b/examples/l2fwd-ethtool/nic-control/Makefile
@@ -0,0 +1,55 @@
+# BSD LICENSE
+#
+# Copyright(c) 2015 Intel Corporation. All rights reserved.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in
+# the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Intel Corporation nor the names of its
+# contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ifeq ($(RTE_SDK),)
+$(error "Please define RTE_SDK environment variable")
+endif
+
+# Default target, can be overwritten by command line or environment
+RTE_TARGET ?= x86_64-native-linuxapp-gcc
+
+include $(RTE_SDK)/mk/rte.vars.mk
+
+ifneq ($(CONFIG_RTE_EXEC_ENV),"linuxapp")
+$(error This application can only operate in a linuxapp environment, \
+please change the definition of the RTE_TARGET environment variable)
+endif
+
+# binary name
+APP = nic-control
+
+# all source are stored in SRCS-y
+SRCS-y := nic_control.c
+
+CFLAGS += -O3 -I$(SRCDIR)/../l2fwd-app -I$(SRCDIR)/../lib
+CFLAGS += $(WERROR_FLAGS)
+
+include $(RTE_SDK)/mk/rte.extapp.mk
diff --git a/examples/l2fwd-ethtool/nic-control/nic_control.c b/examples/l2fwd-ethtool/nic-control/nic_control.c
new file mode 100644
index 0000000..32769cb
--- /dev/null
+++ b/examples/l2fwd-ethtool/nic-control/nic_control.c
@@ -0,0 +1,614 @@
+/*-
+* BSD LICENSE
+*
+* Copyright(c) 2015 Intel Corporation. All rights reserved.
+* All rights reserved.
+*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions
+* are met:
+*
+* * Redistributions of source code must retain the above copyright
+* notice, this list of conditions and the following disclaimer.
+* * Redistributions in binary form must reproduce the above copyright
+* notice, this list of conditions and the following disclaimer in
+* the documentation and/or other materials provided with the
+* distribution.
+* * Neither the name of Intel Corporation nor the names of its
+* contributors may be used to endorse or promote products derived
+* from this software without specific prior written permission.
+*
+* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*
+ * This is a non- DPDK application that sends NIC device management request
+ * through named pipe to a DPDK data plan process.
+ *
+ */
+#define USE_NEW_TYPE
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <sys/resource.h>
+
+#include "rte_ethtool.h"
+#define NETDEV_OP_REQUEST 1
+#include "netdev_api.h"
+
+#define ITER_LIMIT 30
+#define CPU_CYCLES (double)(2400.0*1000000)
+#define TEST_FAIL -1
+#define TEST_PASS 0
+#define TEST_READ_SIZE 16
+#define STATS_PERIOD 10
+
+#define PACKET_RATE(before_value, after_value, before_ts, after_ts) \
+ ((double)(after_value - before_value) * \
+ CPU_CYCLES/(after_ts - before_ts))
+
+#define BYTE2BIT_RATE(before_value, after_value, before_ts, after_ts) \
+ ((double)(after_value - before_value) * \
+ CPU_CYCLES*8/(after_ts - before_ts))
+
+#define check(cond) (cond?"match":"miss-match")
+#define MAC_STR_SIZE (3*MAC_ADDR_SIZE+1)
+
+struct time_stamp {
+ uint32_t hi;
+ uint32_t lo;
+};
+
+enum test_type {
+ test_eeprom = 0,
+ test_regs,
+ test_mtu,
+ test_vlan_rx,
+ test_pauseparam,
+ test_counts,
+};
+
+struct api_test {
+ const char *test_name;
+ int mask_bit;
+ int (*test_task)(int port_id);
+};
+
+static inline unsigned long long
+rdtsc(void)
+{
+ unsigned hi, lo;
+
+ __asm__ __volatile__ ("rdtsc" : "=a"(lo), "=d"(hi));
+ return ((unsigned long long)lo) | (((unsigned long long)hi) << 32);
+}
+
+static uint32_t port_mask;
+static uint32_t vf_port_mask;
+static uint8_t num_of_ports;
+static char addr_string[MAC_STR_SIZE];
+
+static inline int
+is_port_enabled(uint8_t port_id)
+{
+ return (port_mask & (1 << port_id)) > 0;
+}
+
+static inline int
+is_vf_port(uint8_t port_id)
+{
+ return (vf_port_mask & (1 << port_id)) > 0;
+}
+
+static int
+netdev_ipc_begin(void)
+{
+ uint8_t reply_data[sizeof(double)];
+ uint16_t req_id = next_reqid();
+ uint16_t data_size;
+ uint32_t reply_data2[2];
+ uint8_t param_data[FIRST_DATA_OFFSET];
+
+ param_data[0] = 0;
+ send_request(req_id, ipc_begin,
+ FIRST_DATA_OFFSET, param_data);
+ read_reply(req_id, &data_size, reply_data, reply_data2);
+ num_of_ports = reply_data[0];
+ port_mask = reply_data2[0];
+ vf_port_mask = reply_data2[1];
+
+ return reply_data[0];
+}
+
+static int
+netdev_ipc_end(void)
+{
+ uint8_t reply_data[sizeof(double)];
+ uint16_t req_id = next_reqid();
+ uint16_t data_size;
+
+ send_request(req_id, ipc_end, 0, NULL);
+ read_reply(req_id, &data_size, reply_data, NULL);
+
+ return NETDEV_STATUS(data_size);
+}
+
+static uint8_t
+get_port(void)
+{
+ uint8_t port_id;
+ /* assume maximum of 32 ports */
+ port_id = rand() & 0x1F;
+ while (!is_port_enabled(port_id))
+ port_id = rand() & 0x1F;
+
+ return port_id;
+}
+
+static inline char*
+mac_addr_str(void *mac_addr_in)
+{
+ unsigned char *mac_addr = mac_addr_in;
+
+ snprintf(addr_string, MAC_STR_SIZE, "%02x:%02x:%02x:%02x:%02x:%02x",
+ mac_addr[0], mac_addr[1], mac_addr[2],
+ mac_addr[3], mac_addr[4], mac_addr[5]);
+ return addr_string;
+}
+
+static int
+test_eeprom_get(int port_id)
+{
+ int count, i;
+ void *data;
+ uint16_t *word;
+ struct ethtool_eeprom eeprom;
+
+ count = netdev_ethtool_get_eeprom_len(port_id);
+ if (count <= 0) {
+ printf("fail to retrieve eeprom");
+ printf("count from port #%d\n", port_id);
+ return TEST_FAIL;
+ }
+
+ printf("eeprom size is %d bytes\n", count);
+ eeprom.offset = 0;
+ eeprom.len = TEST_READ_SIZE;
+ data = malloc(TEST_READ_SIZE);
+ if (data == NULL) {
+ printf("Fail to allocate memory, bailed out !!!\n");
+ return TEST_FAIL;
+ }
+
+ if (netdev_ethtool_get_eeprom(port_id, &eeprom, data)) {
+ printf("Fail to read eeprom from port #%d\n", port_id);
+ free(data);
+ return TEST_FAIL;
+ }
+
+ word = data;
+ printf("eeprom-magic: %x;", eeprom.magic);
+ printf("eeprom data[0:%d]:\n", TEST_READ_SIZE-1);
+ for (i = 0; i < (int)(eeprom.len >> 1); i++)
+ printf("%4x ", word[i]);
+ printf("\n");
+ free(data);
+ return TEST_PASS;
+}
+
+/*
+ * Testing eeprom get/set by getting eeprom data and write-back
+ * the same data
+ */
+static int
+test_eeprom_t(int port_id)
+{
+ int i, ind;
+ void *data_in, *data_out;
+ struct ethtool_eeprom eeprom;
+
+ eeprom.offset = 0;
+ eeprom.len = TEST_READ_SIZE;
+ data_in = malloc(eeprom.len);
+ if (data_in == NULL) {
+ printf("Fail to allocate memory, bailed out !!!\n");
+ return TEST_FAIL;
+ }
+
+ if (netdev_ethtool_get_eeprom(port_id, &eeprom, data_in)) {
+ printf("failed to read eeprom break from post-run");
+ free(data_in);
+ return TEST_FAIL;
+ }
+
+ if (netdev_ethtool_set_eeprom(port_id, &eeprom, data_in)) {
+ printf("Fail to write read-back data to eeprom!!!\n");
+ free(data_in);
+ return TEST_FAIL;
+ }
+
+ data_out = malloc(eeprom.len);
+ if (data_out == NULL) {
+ printf("Fail to allocate memory, bailed out !!!\n");
+ free(data_in);
+ return TEST_FAIL;
+ }
+ /* read-back for comparison */
+ if (netdev_ethtool_get_eeprom(port_id, &eeprom, data_out)) {
+ printf("failed to read eeprom break from post-run");
+ free(data_in);
+ free(data_out);
+ return TEST_FAIL;
+ }
+
+ for (i = eeprom.offset; i < (int)(eeprom.offset+eeprom.len); i++) {
+ unsigned char *in = (unsigned char *)data_in;
+ unsigned char *out = (unsigned char *)data_out;
+
+ ind = i - eeprom.offset;
+ if (in[ind] != out[ind])
+ printf("%d write-data:%x read-back-data:%x\n",
+ ind, in[ind], out[ind]);
+ }
+ free(data_in);
+ free(data_out);
+ return TEST_PASS;
+}
+
+static int
+test_regs_t(int port_id)
+{
+ int count, i;
+ void *data;
+ uint32_t *regs;
+ struct ethtool_regs reg_info;
+
+ count = netdev_ethtool_get_regs_len(port_id);
+ if (count <= 0)
+ printf("There are no registers available from port #%d",
+ port_id);
+ else
+ printf("Target has %d registers for dump", count);
+
+ data = malloc(count * sizeof(int));
+ if (data == NULL) {
+ printf("Fail to allocate memory, bailed out !!!\n");
+ return TEST_FAIL;
+ }
+ memset(®_info, 0xFF, sizeof(struct ethtool_regs));
+
+ if (netdev_ethtool_get_regs(port_id, ®_info, data)) {
+ printf("Fail to read register\n");
+ free(data);
+ return TEST_FAIL;
+ }
+
+ regs = data;
+ printf("version: %x;", reg_info.version);
+ printf("register[0:%d]:\n", TEST_READ_SIZE-1);
+ for (i = 0; i < TEST_READ_SIZE; i++)
+ printf("%x ", regs[i]);
+ printf("\n");
+ free(data);
+ return TEST_PASS;
+}
+
+static int
+test_mtu_t(int port_id)
+{
+ const int mtu = 1024;
+
+ if (netdev_net_change_mtu(port_id, mtu)) {
+ printf("failed to set mtu to %d\n", mtu);
+ return TEST_FAIL;
+ }
+ return TEST_PASS;
+}
+
+static int
+test_vlan_rx_t(int port_id)
+{
+ /* add/remove vlan to vid */
+ netdev_net_vlan_rx_add_vid(port_id, 0);
+ if (netdev_net_vlan_rx_add_vid(port_id, 0)) {
+ if (netdev_net_vlan_rx_kill_vid(port_id, 0)) {
+ printf("netdev_net_vlan_rx_kill_vid() fails\n");
+ return TEST_FAIL;
+ }
+ return TEST_PASS;
+ }
+ printf("netdev_net_vlan_rx_add_vid() fails\n");
+ return TEST_FAIL;
+}
+
+static int
+test_pauseparam_t(int port_id)
+{
+ struct ethtool_pauseparam pause_param_in;
+ struct ethtool_pauseparam pause_param_out;
+
+ if (netdev_ethtool_get_pauseparam(port_id, &pause_param_in)) {
+ printf("netdev_ethtool_get_pauseparam() fails\n");
+ return TEST_FAIL;
+ }
+ printf("pause setup: autoneg: %d ",
+ pause_param_in.autoneg);
+ printf("tx_pause: %d ",
+ pause_param_in.tx_pause);
+ printf("rx_pause: %d\n",
+ pause_param_in.rx_pause);
+ if (netdev_ethtool_set_pauseparam(port_id, &pause_param_in)) {
+ printf("netdev_ethtool_set_pauseparam() fails\n");
+ return TEST_FAIL;
+ }
+ /* read-back pause frame setting for comparison */
+ if (netdev_ethtool_get_pauseparam(port_id, &pause_param_out)) {
+ printf("netdev_ethtool_get_pauseparam() fails\n");
+ return TEST_FAIL;
+ }
+ printf("pause frame checking auto:%s tx_pause:%s rx_pause:%s\n",
+ check(pause_param_in.autoneg == pause_param_out.autoneg),
+ check(pause_param_in.tx_pause == pause_param_out.tx_pause),
+ check(pause_param_in.rx_pause == pause_param_out.tx_pause));
+
+ return TEST_PASS;
+}
+
+static int
+test_get_drvinfo(int port_id)
+{
+ struct ethtool_drvinfo drvinfo;
+
+ if (netdev_ethtool_get_drvinfo(port_id, &drvinfo)) {
+ printf("fail to get drvinfo ...\n");
+ return TEST_FAIL;
+ }
+ printf("driver: %s version: %s fw_version: %s bus_info=%s\n",
+ drvinfo.driver, drvinfo.version,
+ drvinfo.fw_version, drvinfo.bus_info);
+ printf("reg-size(bytes)=%d eeprom-size=%d\n",
+ drvinfo.regdump_len,
+ drvinfo.eedump_len);
+ return TEST_PASS;
+}
+
+static int
+test_mac_addr(uint8_t port_id)
+{
+ unsigned char mac_addr[MAC_ADDR_SIZE];
+ unsigned char mac_addr_base[MAC_ADDR_SIZE] = {0x52, 0x54, 0, 0, 0, 1};
+ struct ether_addr *mac_addr_t;
+ struct ethter_add *mac_addr2;
+ int result;
+
+ mac_addr_t = to_mac_type(mac_addr);
+ result = netdev_net_get_mac_addr(port_id, mac_addr_t);
+ if (netdev_net_get_mac_addr(port_id, mac_addr_t)) {
+ printf("Fail to get mac addr from port #%d!!!\n", port_id);
+ return TEST_FAIL;
+ }
+ printf("Port #%d, device mac addr is %s\n", port_id,
+ mac_addr_str(mac_addr));
+
+ result = netdev_net_validate_addr(port_id, mac_addr_t);
+ if (!result) {
+ printf("Default mac addr, %s, is not valid\n",
+ mac_addr_str(mac_addr));
+ strncpy((char *)mac_addr, (char *)mac_addr_base, MAC_ADDR_SIZE);
+ mac_addr[MAC_ADDR_SIZE-1] += port_id;
+ printf("New mac address:%s is used.\n", mac_addr_str(mac_addr));
+
+ result = netdev_net_set_mac_addr(port_id, mac_addr_t);
+ if (result == TEST_FAIL)
+ return TEST_FAIL;
+
+ result = netdev_net_get_mac_addr(port_id, &mac_addr2);
+ if (strncmp(cast_ptr(mac_addr, char*),
+ cast_ptr(mac_addr2, char*),
+ MAC_ADDR_SIZE))
+ printf("Expected mac_addr %s return addr %s\n",
+ mac_addr_str(mac_addr),
+ mac_addr_str(cast_ptr(mac_addr2, unsigned char*)
+ ));
+ }
+ return TEST_PASS;
+}
+
+struct api_test test_table[test_counts] = {
+ {"-test_eeprom", test_eeprom, test_eeprom_t},
+ {"-test_regs", test_regs, test_regs_t},
+ {"-test_mtu", test_mtu, test_mtu_t},
+ {"-test_vlan_rx", test_vlan_rx, test_vlan_rx_t},
+ {"-test_pauseparam", test_pauseparam, test_pauseparam_t},
+};
+
+static inline unsigned int
+get_test_mask(char *name)
+{
+ int ind = 0;
+ struct api_test *test = &test_table[ind];
+
+ while (ind++ < test_counts) {
+ if (!strncmp(name, test->test_name, strlen(name)))
+ return (1 << test->mask_bit);
+ test++;
+ }
+ return 0;
+}
+
+static unsigned int
+parse_args(int argc, char **argv)
+{
+ int i;
+ unsigned int test_mask = 0;
+
+
+ if (argc <= 1)
+ return 0;
+ for (i = 1; i < argc; i++)
+ test_mask |= get_test_mask(argv[i]);
+ return test_mask;
+}
+
+static inline void
+test_update(int result, int *fails, int *passes)
+{
+ if (result == TEST_PASS)
+ (*passes)++;
+ else
+ (*fails)++;
+}
+
+static void
+run_test(uint8_t port_id, unsigned int test_mask, int *fails, int *passes)
+{
+ int i;
+ int result;
+
+ for (i = 0; i < test_counts; i++) {
+ if (test_mask & (1<<i)) {
+ result = (*test_table[i].test_task)(port_id);
+ test_update(result, fails, passes);
+ }
+ }
+}
+
+static void
+wait_for_linkdown(uint8_t port_id)
+{
+ int link_up;
+
+ link_up = netdev_ethtool_get_link(port_id);
+ while (link_up) {
+ sleep(10);
+ link_up = netdev_ethtool_get_link(port_id);
+ }
+}
+
+int
+main(int argc, char **argv)
+{
+ uint8_t port_id;
+ unsigned int test_mask;
+ int passes = 0;
+ int fails = 0;
+ int iter_count = 0;
+ int link_up;
+ int result;
+
+
+ /* get command parameter */
+ test_mask = parse_args(argc, argv);
+
+ /* initialize request pipe */
+ init_req_pipe();
+
+ printf("issue ipc begin\n");
+ /* send a request to start the NIC device */
+ num_of_ports = netdev_ipc_begin();
+ while (num_of_ports == 0)
+ num_of_ports = netdev_ipc_begin() & 0xFF;
+
+ for (port_id = 0; port_id < num_of_ports; port_id++) {
+ link_up = netdev_ethtool_get_link(port_id);
+ printf("port #%d is %s\n", port_id, link_up?"up":"down");
+ if (!link_up) {
+ if (netdev_net_open(port_id) == 0)
+ netdev_net_set_rx_mode(port_id);
+ else
+ printf("failed to start port #%d\n", port_id);
+ }
+ }
+
+ /* Testing ethtool register/eeprom get */
+ for (port_id = 0; port_id < num_of_ports; port_id++) {
+ if (!is_port_enabled(port_id))
+ continue;
+
+ result = test_mac_addr(port_id);
+ test_update(result, &fails, &passes);
+
+ result = test_get_drvinfo(port_id);
+ test_update(result, &fails, &passes);
+
+ result = test_regs_t(port_id);
+ test_update(result, &fails, &passes);
+
+ /* Only testing eeprom access over a PF */
+ if (!is_vf_port(port_id)) {
+ result = test_eeprom_get(port_id);
+ test_update(result, &fails, &passes);
+ }
+ }
+
+ printf("start nic statistics collection ...\n");
+ port_id = get_port();
+ while (iter_count++ < ITER_LIMIT) {
+ uint64_t last_ts, ts;
+ struct rte_eth_stats last_stats, stats;
+
+ if (netdev_net_get_stats64(port_id, &last_stats)) {
+ printf("Fail to query statistics from port %d\n",
+ port_id);
+ break;
+ }
+ last_ts = rdtsc();
+
+ sleep(STATS_PERIOD);
+
+ if (netdev_net_get_stats64(port_id, &stats)) {
+ printf("Fail to query statistics from port %d\n",
+ port_id);
+ break;
+ }
+ ts = rdtsc();
+
+ printf("rx packet rate = %lf, tx packet rate = %lf\n",
+ PACKET_RATE(last_stats.ipackets, stats.ipackets,
+ last_ts, ts),
+ PACKET_RATE(last_stats.opackets, stats.opackets,
+ last_ts, ts));
+
+
+ printf("rx bit rate = %lf, tx bit rate = %lf\n",
+ BYTE2BIT_RATE(last_stats.ibytes, stats.ibytes,
+ last_ts, ts),
+ BYTE2BIT_RATE(last_stats.obytes, stats.obytes,
+ last_ts, ts));
+
+ sleep(STATS_PERIOD);
+ }
+
+ /* Stop link, testing APIs specified in command arguments */
+ if (test_mask) {
+ for (port_id = 0; port_id < num_of_ports; port_id++) {
+ link_up = netdev_ethtool_get_link(port_id);
+ if (link_up) {
+ netdev_net_stop(port_id);
+ wait_for_linkdown(port_id);
+ }
+ }
+
+ for (port_id = 0; port_id < num_of_ports; port_id++) {
+ link_up = netdev_ethtool_get_link(port_id);
+ if (!is_vf_port(port_id) && !link_up)
+ run_test(port_id, test_mask, &fails, &passes);
+ }
+ }
+
+ while (netdev_ipc_end() < 0)
+ ;
+
+ printf("Pass count: %d Fail count: %d\n", passes, fails);
+ return 0;
+}
--
2.1.4
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [dpdk-dev] [PATCH v2 1/2] Remove ABI requierment for external library builds.
2015-07-23 15:00 ` [dpdk-dev] [PATCH v2 1/2] Remove ABI requierment for external library builds Liang-Min Larry Wang
@ 2015-10-21 16:31 ` Thomas Monjalon
0 siblings, 0 replies; 10+ messages in thread
From: Thomas Monjalon @ 2015-10-21 16:31 UTC (permalink / raw)
To: Liang-Min Larry Wang; +Cc: dev
2015-07-23 11:00, Liang-Min Larry Wang:
> From: "Andrew G. Harvey" <agh@cisco.com>
> --- a/mk/rte.extlib.mk
> +++ b/mk/rte.extlib.mk
> @@ -31,6 +31,8 @@
>
> MAKEFLAGS += --no-print-directory
>
> +export EXTLIB_BUILD := 1
Is export really needed?
Except that, this patch looks OK.
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [dpdk-dev] [PATCH v2 2/2] examples: new example: l2fwd-ethtool
2015-07-23 15:00 ` [dpdk-dev] [PATCH v2 2/2] examples: new example: l2fwd-ethtool Liang-Min Larry Wang
@ 2015-10-21 16:36 ` Thomas Monjalon
2015-10-21 16:46 ` Wang, Liang-min
2015-11-17 22:33 ` Wang, Liang-min
0 siblings, 2 replies; 10+ messages in thread
From: Thomas Monjalon @ 2015-10-21 16:36 UTC (permalink / raw)
To: Liang-Min Larry Wang; +Cc: dev
2015-07-23 11:00, Liang-Min Larry Wang:
> examples/Makefile | 1 +
> examples/l2fwd-ethtool/Makefile | 48 +
> examples/l2fwd-ethtool/l2fwd-app/Makefile | 58 ++
> examples/l2fwd-ethtool/l2fwd-app/main.c | 1025 ++++++++++++++++++++++
> examples/l2fwd-ethtool/l2fwd-app/netdev_api.h | 770 ++++++++++++++++
> examples/l2fwd-ethtool/l2fwd-app/shared_fifo.h | 159 ++++
> examples/l2fwd-ethtool/lib/Makefile | 57 ++
> examples/l2fwd-ethtool/lib/rte_ethtool.c | 336 +++++++
> examples/l2fwd-ethtool/lib/rte_ethtool.h | 385 ++++++++
> examples/l2fwd-ethtool/nic-control/Makefile | 55 ++
> examples/l2fwd-ethtool/nic-control/nic_control.c | 614 +++++++++++++
> 11 files changed, 3508 insertions(+)
This patch is huge.
Please split a bit.
> --- a/examples/Makefile
> +++ b/examples/Makefile
> @@ -53,6 +53,7 @@ DIRS-$(CONFIG_RTE_LIBRTE_KNI) += kni
> DIRS-y += l2fwd
> DIRS-$(CONFIG_RTE_LIBRTE_IVSHMEM) += l2fwd-ivshmem
> DIRS-$(CONFIG_RTE_LIBRTE_JOBSTATS) += l2fwd-jobstats
> +DIRS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += l2fwd-ethtool
> DIRS-y += l3fwd
Please keep the alphabetical order.
I do not plan to review it more.
If nobody complains, it means it's accepted.
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [dpdk-dev] [PATCH v2 2/2] examples: new example: l2fwd-ethtool
2015-10-21 16:36 ` Thomas Monjalon
@ 2015-10-21 16:46 ` Wang, Liang-min
2015-11-17 22:33 ` Wang, Liang-min
1 sibling, 0 replies; 10+ messages in thread
From: Wang, Liang-min @ 2015-10-21 16:46 UTC (permalink / raw)
To: Thomas Monjalon; +Cc: dev
Thomas,
Let's put this patch on defer list because there are related work might take a different approach. Let's only review the make file change (PATCH 1/2). I believe "export" is needed since the variable is shared by all the build but it might be already included due to the mk file inclusion. Since Andy is on vacation, I am not sure if he could make a comment on that.
Larry
> -----Original Message-----
> From: Thomas Monjalon [mailto:thomas.monjalon@6wind.com]
> Sent: Wednesday, October 21, 2015 12:36 PM
> To: Wang, Liang-min
> Cc: dev@dpdk.org
> Subject: Re: [dpdk-dev] [PATCH v2 2/2] examples: new example: l2fwd-
> ethtool
>
> 2015-07-23 11:00, Liang-Min Larry Wang:
> > examples/Makefile | 1 +
> > examples/l2fwd-ethtool/Makefile | 48 +
> > examples/l2fwd-ethtool/l2fwd-app/Makefile | 58 ++
> > examples/l2fwd-ethtool/l2fwd-app/main.c | 1025
> ++++++++++++++++++++++
> > examples/l2fwd-ethtool/l2fwd-app/netdev_api.h | 770
> ++++++++++++++++
> > examples/l2fwd-ethtool/l2fwd-app/shared_fifo.h | 159 ++++
> > examples/l2fwd-ethtool/lib/Makefile | 57 ++
> > examples/l2fwd-ethtool/lib/rte_ethtool.c | 336 +++++++
> > examples/l2fwd-ethtool/lib/rte_ethtool.h | 385 ++++++++
> > examples/l2fwd-ethtool/nic-control/Makefile | 55 ++
> > examples/l2fwd-ethtool/nic-control/nic_control.c | 614 +++++++++++++
> > 11 files changed, 3508 insertions(+)
>
> This patch is huge.
> Please split a bit.
>
> > --- a/examples/Makefile
> > +++ b/examples/Makefile
> > @@ -53,6 +53,7 @@ DIRS-$(CONFIG_RTE_LIBRTE_KNI) += kni
> > DIRS-y += l2fwd
> > DIRS-$(CONFIG_RTE_LIBRTE_IVSHMEM) += l2fwd-ivshmem
> > DIRS-$(CONFIG_RTE_LIBRTE_JOBSTATS) += l2fwd-jobstats
> > +DIRS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += l2fwd-ethtool
> > DIRS-y += l3fwd
>
> Please keep the alphabetical order.
>
> I do not plan to review it more.
> If nobody complains, it means it's accepted.
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [dpdk-dev] [PATCH v2 2/2] examples: new example: l2fwd-ethtool
2015-10-21 16:36 ` Thomas Monjalon
2015-10-21 16:46 ` Wang, Liang-min
@ 2015-11-17 22:33 ` Wang, Liang-min
2015-11-18 17:56 ` Thomas Monjalon
1 sibling, 1 reply; 10+ messages in thread
From: Wang, Liang-min @ 2015-11-17 22:33 UTC (permalink / raw)
To: Thomas Monjalon; +Cc: dev
Thomas,
Could you explain why this patch is put on RFC?
Thanks,
Larry
> -----Original Message-----
> From: Wang, Liang-min
> Sent: Wednesday, October 21, 2015 12:47 PM
> To: 'Thomas Monjalon'
> Cc: dev@dpdk.org; Andrew Harvey (agh) (agh@cisco.com)
> Subject: RE: [dpdk-dev] [PATCH v2 2/2] examples: new example: l2fwd-ethtool
>
> Thomas,
> Let's put this patch on defer list because there are related work might
> take a different approach. Let's only review the make file change (PATCH 1/2).
> I believe "export" is needed since the variable is shared by all the build but it
> might be already included due to the mk file inclusion. Since Andy is on
> vacation, I am not sure if he could make a comment on that.
>
> Larry
>
> > -----Original Message-----
> > From: Thomas Monjalon [mailto:thomas.monjalon@6wind.com]
> > Sent: Wednesday, October 21, 2015 12:36 PM
> > To: Wang, Liang-min
> > Cc: dev@dpdk.org
> > Subject: Re: [dpdk-dev] [PATCH v2 2/2] examples: new example: l2fwd-
> > ethtool
> >
> > 2015-07-23 11:00, Liang-Min Larry Wang:
> > > examples/Makefile | 1 +
> > > examples/l2fwd-ethtool/Makefile | 48 +
> > > examples/l2fwd-ethtool/l2fwd-app/Makefile | 58 ++
> > > examples/l2fwd-ethtool/l2fwd-app/main.c | 1025
> > ++++++++++++++++++++++
> > > examples/l2fwd-ethtool/l2fwd-app/netdev_api.h | 770
> > ++++++++++++++++
> > > examples/l2fwd-ethtool/l2fwd-app/shared_fifo.h | 159 ++++
> > > examples/l2fwd-ethtool/lib/Makefile | 57 ++
> > > examples/l2fwd-ethtool/lib/rte_ethtool.c | 336 +++++++
> > > examples/l2fwd-ethtool/lib/rte_ethtool.h | 385 ++++++++
> > > examples/l2fwd-ethtool/nic-control/Makefile | 55 ++
> > > examples/l2fwd-ethtool/nic-control/nic_control.c | 614 +++++++++++++
> > > 11 files changed, 3508 insertions(+)
> >
> > This patch is huge.
> > Please split a bit.
> >
> > > --- a/examples/Makefile
> > > +++ b/examples/Makefile
> > > @@ -53,6 +53,7 @@ DIRS-$(CONFIG_RTE_LIBRTE_KNI) += kni
> > > DIRS-y += l2fwd
> > > DIRS-$(CONFIG_RTE_LIBRTE_IVSHMEM) += l2fwd-ivshmem
> > > DIRS-$(CONFIG_RTE_LIBRTE_JOBSTATS) += l2fwd-jobstats
> > > +DIRS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += l2fwd-ethtool
> > > DIRS-y += l3fwd
> >
> > Please keep the alphabetical order.
> >
> > I do not plan to review it more.
> > If nobody complains, it means it's accepted.
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [dpdk-dev] [PATCH v2 2/2] examples: new example: l2fwd-ethtool
2015-11-17 22:33 ` Wang, Liang-min
@ 2015-11-18 17:56 ` Thomas Monjalon
0 siblings, 0 replies; 10+ messages in thread
From: Thomas Monjalon @ 2015-11-18 17:56 UTC (permalink / raw)
To: Wang, Liang-min; +Cc: dev
2015-11-17 22:33, Wang, Liang-min:
> Thomas,
> Could you explain why this patch is put on RFC?
Hi,
It is not RFC but Changes Requested.
It means a new version is expected to adress comments.
^ permalink raw reply [flat|nested] 10+ messages in thread
end of thread, other threads:[~2015-11-18 17:58 UTC | newest]
Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-07-20 14:12 [dpdk-dev] [PATCH] User-space Ethool example Liang-Min Larry Wang
2015-07-20 14:12 ` [dpdk-dev] [PATCH] examples: new example: l2fwd-ethtool Liang-Min Larry Wang
2015-07-23 15:00 ` [dpdk-dev] [PATCH v2 0/2] Example: l2fwd-ethtool Liang-Min Larry Wang
2015-07-23 15:00 ` [dpdk-dev] [PATCH v2 1/2] Remove ABI requierment for external library builds Liang-Min Larry Wang
2015-10-21 16:31 ` Thomas Monjalon
2015-07-23 15:00 ` [dpdk-dev] [PATCH v2 2/2] examples: new example: l2fwd-ethtool Liang-Min Larry Wang
2015-10-21 16:36 ` Thomas Monjalon
2015-10-21 16:46 ` Wang, Liang-min
2015-11-17 22:33 ` Wang, Liang-min
2015-11-18 17:56 ` Thomas Monjalon
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).