DPDK patches and discussions
 help / color / mirror / Atom feed
* [dpdk-dev] [RFC PATCH v1] rte: LCore heartbeat example
@ 2015-09-15 12:16 Remy Horton
  2015-09-15 13:10 ` Thomas Monjalon
  2015-09-30  9:04 ` [dpdk-dev] [PATCH v2 0/3] Keepalive monitoring & reporting Remy Horton
  0 siblings, 2 replies; 44+ messages in thread
From: Remy Horton @ 2015-09-15 12:16 UTC (permalink / raw)
  To: dev

Provides a basic framework for detecting and reporting live-ness of 
LCores, the primary requirement of which is minimal overheads for the 
core(s) being checked. Core failures are notified via an application 
defined callback. As an example l2fwd with random failures is used.

Signed-off-by: Remy Horton <remy.horton@intel.com>
---
 examples/l2fwd-heartbeat/Makefile |  50 +++
 examples/l2fwd-heartbeat/hbeat.c  | 121 ++++++
 examples/l2fwd-heartbeat/hbeat.h  | 143 +++++++
 examples/l2fwd-heartbeat/main.c   | 809 ++++++++++++++++++++++++++++++++++++++
 4 files changed, 1123 insertions(+)
 create mode 100644 examples/l2fwd-heartbeat/Makefile
 create mode 100644 examples/l2fwd-heartbeat/hbeat.c
 create mode 100644 examples/l2fwd-heartbeat/hbeat.h
 create mode 100644 examples/l2fwd-heartbeat/main.c

diff --git a/examples/l2fwd-heartbeat/Makefile b/examples/l2fwd-heartbeat/Makefile
new file mode 100644
index 0000000..8b89476
--- /dev/null
+++ b/examples/l2fwd-heartbeat/Makefile
@@ -0,0 +1,50 @@
+#   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.
+
+ifeq ($(RTE_SDK),)
+$(error "Please define RTE_SDK environment variable")
+endif
+
+# Default target, can be overridden by command line or environment
+RTE_TARGET ?= x86_64-native-linuxapp-gcc
+
+include $(RTE_SDK)/mk/rte.vars.mk
+
+# binary name
+APP = l2fwd-heartbeat
+
+# all source are stored in SRCS-y
+SRCS-y := main.c hbeat.c
+
+CFLAGS += -O3
+CFLAGS += $(WERROR_FLAGS)
+
+include $(RTE_SDK)/mk/rte.extapp.mk
diff --git a/examples/l2fwd-heartbeat/hbeat.c b/examples/l2fwd-heartbeat/hbeat.c
new file mode 100644
index 0000000..755f3e8
--- /dev/null
+++ b/examples/l2fwd-heartbeat/hbeat.c
@@ -0,0 +1,121 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright 2015 Intel Shannon Ltd. 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 <inttypes.h>
+
+#include <rte_timer.h>
+#include <rte_cycles.h>
+#include <rte_lcore.h>
+
+#include "hbeat.h"
+
+#ifdef HBEAT_DEBUG_MSGS
+static void
+print_trace(const char *msg, struct rte_heartbeat *keepcfg, int idx_core)
+{
+	printf("%sLast seen %" PRId64  "ms ago.\n",
+		msg,
+		((rte_rdtsc() - keepcfg->core[idx_core].last_alive)*1000)
+		/ rte_get_tsc_hz()
+	      );
+}
+#else
+static void
+print_trace(__attribute__((unused)) const char *msg,
+	__attribute__((unused)) struct rte_heartbeat *keepcfg,
+	__attribute__((unused)) int idx_core)
+{
+}
+#endif
+
+
+
+void
+hbeat_dispatch_pings(__attribute__((unused)) struct rte_timer *ptr_timer,
+	void *ptr_data)
+{
+	struct rte_heartbeat *keepcfg = (struct rte_heartbeat *)ptr_data;
+	int idx_core;
+
+	for (idx_core = 0; idx_core < RTE_HBEAT_MAXCORES; idx_core++) {
+		if (keepcfg->active_cores[idx_core] == 0)
+			continue;
+		switch (keepcfg->core[idx_core].state_flags) {
+		case 1: /* Alive */
+			keepcfg->core[idx_core].state_flags = 0;
+			keepcfg->core[idx_core].last_alive = rte_rdtsc();
+			break;
+		case 0: /* MIA */
+			print_trace("Core MIA. ", keepcfg, idx_core);
+			keepcfg->core[idx_core].state_flags = 2;
+			break;
+		case 2: /* Dead */
+			keepcfg->core[idx_core].state_flags = 3;
+			print_trace("Core died. ", keepcfg, idx_core);
+			if (keepcfg->callback)
+				keepcfg->callback(
+					keepcfg->callback_data,
+					idx_core
+					);
+			break;
+		case 3: /* Buried */
+			break;
+		}
+	}
+}
+
+
+int
+hbeat_init(struct rte_heartbeat *keepcfg,
+	rte_heartbeat_failure_callback_t callback,
+	void *data)
+{
+	int idx_core;
+
+	for (idx_core = 0; idx_core < RTE_HBEAT_MAXCORES; idx_core++) {
+		keepcfg->core[idx_core].state_flags = 0;
+		keepcfg->active_cores[idx_core] = 0;
+	}
+	keepcfg->callback = callback;
+	keepcfg->callback_data = data;
+	keepcfg->tsc_initial = rte_rdtsc();
+	keepcfg->tsc_mhz = rte_get_tsc_hz() / 1000;
+	return 0;
+}
+
+
+void
+hbeat_register_core(struct rte_heartbeat *keepcfg, const int id_core)
+{
+	if (id_core < RTE_HBEAT_MAXCORES)
+		keepcfg->active_cores[id_core] = 1;
+}
diff --git a/examples/l2fwd-heartbeat/hbeat.h b/examples/l2fwd-heartbeat/hbeat.h
new file mode 100644
index 0000000..b70503e
--- /dev/null
+++ b/examples/l2fwd-heartbeat/hbeat.h
@@ -0,0 +1,143 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright 2015 Intel Shannon Ltd. 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.
+ */
+
+/**
+ * @file hbeat.h
+ * DPDK RTE LCore Heartbeat Monitor.
+ *
+ **/
+
+#ifndef _HBEAT_H_
+#define _HBEAT_H_
+
+#include <rte_memory.h>
+
+#ifndef RTE_HBEAT_MAXCORES
+/**
+ * Number of cores to track.
+ * @note Must be larger than the highest core id. */
+#define RTE_HBEAT_MAXCORES RTE_MAX_LCORE
+#endif
+
+
+/**
+ * Heartbeat failure callback.
+ *
+ *  Receives a data pointer passed to hbeat_init() and the id of the
+ *  failed core.
+ */
+typedef void (*rte_heartbeat_failure_callback_t)(
+	void *data,
+	const int id_core);
+
+
+/**
+ * Heartbeat state structure.
+ * @internal
+ */
+struct rte_heartbeat {
+	/** Core-local information */
+	struct {
+		/** Core Liveness. */
+		uint32_t __rte_cache_aligned state_flags;
+		uint64_t last_alive;
+	} core[RTE_HBEAT_MAXCORES];
+
+	/**
+	 * Cores to check.
+	 * Indexed by core id, non-zero if the core should be checked.
+	 */
+	uint8_t active_cores[RTE_HBEAT_MAXCORES];
+
+	/** Dead core handler. */
+	rte_heartbeat_failure_callback_t callback;
+
+	/**
+	 * Dead core handler app data.
+	 * Pointer is passed to dead core handler.
+	 */
+	void *callback_data;
+	uint64_t tsc_initial;
+	uint64_t tsc_mhz;
+};
+
+
+/**
+ * Initialise Heartbeat sub-system.
+ * @param *keepcfg
+ *   Heartbeat structure pointer
+ * @param callback
+ *   Function called upon detection of a dead core.
+ * @param data
+ *   Data pointer to be passed to function callback.
+ * @return
+ *   0 on success, negative value on failure.
+ */
+int  hbeat_init(struct rte_heartbeat *keepcfg,
+	rte_heartbeat_failure_callback_t callback,
+	void *data);
+
+
+/**
+ * @param *ptr_timer Triggering timer
+ * @param *ptr_data  Data pointer (heartbeat structure)
+ */
+void hbeat_dispatch_pings(__attribute__((unused)) struct rte_timer *ptr_timer,
+	void *ptr_data);
+
+
+/**
+ * Registers a core for heartbeat checks.
+ * @param *keepcfg
+ *   Heartbeat structure pointer
+ * @param id_core
+ *   ID number of core to register.
+ */
+void hbeat_register_core(struct rte_heartbeat *keepcfg, const int id_core);
+
+
+/**
+ * Per-core heartbeat check.
+ * @param *keepcfg
+ *   Heartbeat structure pointer
+ *
+ * This function needs to be called from within the main process loop of
+ * the LCore to be checked.
+ */
+static inline void
+hbeat_mark_alive(struct rte_heartbeat *keepcfg)
+{
+	keepcfg->core[rte_lcore_id()].state_flags = 1;
+}
+
+
+#endif /* _HBEAT_H_ */
diff --git a/examples/l2fwd-heartbeat/main.c b/examples/l2fwd-heartbeat/main.c
new file mode 100644
index 0000000..96b6531
--- /dev/null
+++ b/examples/l2fwd-heartbeat/main.c
@@ -0,0 +1,809 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2015 Intel Corporation. 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 <rte_common.h>
+#include <rte_log.h>
+#include <rte_memory.h>
+#include <rte_memcpy.h>
+#include <rte_memzone.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_timer.h>
+
+#include "hbeat.h"
+
+#define RTE_LOGTYPE_L2FWD RTE_LOGTYPE_USER1
+
+#define NB_MBUF   8192
+
+#define MAX_PKT_BURST 32
+#define BURST_TX_DRAIN_US 100 /* TX drain every ~100us */
+
+/*
+ * 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;
+
+/* 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 const 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,
+	},
+};
+
+struct rte_mempool *l2fwd_pktmbuf_pool = NULL;
+
+/* 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 */
+static int64_t timer_period = 10 * 1000; /* default period is 10 seconds */
+static int64_t check_period = 5; /* default check cycle is 5ms */
+
+
+/* Heartbeat structure */
+struct rte_heartbeat rte_global_hbeat_info;
+
+
+
+/* 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 ------------------------------"
+			   "\nPackets sent: %24"PRIu64
+			   "\nPackets received: %20"PRIu64
+			   "\nPackets dropped: %21"PRIu64,
+			   portid,
+			   port_statistics[portid].tx,
+			   port_statistics[portid].rx,
+			   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 ==============================="
+		   "\nTotal packets sent: %18"PRIu64
+		   "\nTotal packets received: %14"PRIu64
+		   "\nTotal packets dropped: %15"PRIu64,
+		   total_packets_tx,
+		   total_packets_rx,
+		   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 = &eth->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], &eth->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;
+	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;
+
+	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);
+	}
+
+	uint64_t tsc_initial = rte_rdtsc();
+	uint64_t tsc_lifetime = (rand()&0x07) * rte_get_tsc_hz();
+
+	while (1) {
+		/* Keepalive heartbeat */
+		hbeat_mark_alive(&rte_global_hbeat_info);
+
+		cur_tsc = rte_rdtsc();
+
+		/* Die randomly within 7 secs for demo purposes.. */
+		if (cur_tsc - tsc_initial > tsc_lifetime)
+			break;
+
+		/*
+		 * 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;
+			}
+
+			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"
+	       "  -K PERIOD: Heartbeat check period (5 default; 86400 max\n)"
+		   "  -T PERIOD: statistics will be refreshed each PERIOD seconds (0 to disable, 10 default, 86400 maximum)\n",
+	       prgname);
+}
+
+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_check_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;
+}
+
+/* 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:K:",
+				  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;
+			if (timer_period < 0) {
+				printf("invalid timer period\n");
+				l2fwd_usage(prgname);
+				return -1;
+			}
+			break;
+
+		/* Check period */
+		case 'K':
+			check_period = l2fwd_parse_check_period(optarg);
+			if (check_period < 0) {
+				printf("invalid check period\n");
+				l2fwd_usage(prgname);
+				return -1;
+			}
+			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 "
+						"Mbps - %s\n", (uint8_t)portid,
+						(unsigned)link.link_speed,
+				(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 void
+dead_core(__attribute__((unused)) void *ptr_data, const int id_core)
+{
+	printf("Dead core %i - restarting..\n", id_core);
+	if (rte_eal_get_lcore_state(id_core) == FINISHED) {
+		rte_eal_wait_lcore(id_core);
+		rte_eal_remote_launch(l2fwd_launch_one_lcore, NULL, id_core);
+	} else {
+		printf("..false positive!\n");
+	}
+}
+
+static void
+dispatch_stats(
+	__attribute__((unused)) struct rte_timer *ptr_timer,
+	__attribute__((unused)) void *ptr_data)
+{
+	print_stats();
+}
+
+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;
+
+	l2fwd_enabled_port_mask = 0;
+
+
+	/* 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_pktmbuf_pool_create("mbuf_pool", NB_MBUF, 32,
+		0, RTE_MBUF_DEFAULT_BUF_SIZE, rte_socket_id());
+	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 = 1;
+	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);
+		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);
+
+		/* Start device */
+		ret = rte_eth_dev_start(portid);
+		if (ret < 0)
+			rte_exit(EXIT_FAILURE,
+				"rte_eth_dev_start:err=%d, port=%u\n",
+				ret, (unsigned) portid);
+
+		rte_eth_promiscuous_enable(portid);
+
+		printf("Port %u,"
+			" MAC address: %02X:%02X:%02X:%02X:%02X:%02X\n\n",
+				(unsigned) portid,
+				l2fwd_ports_eth_addr[portid].addr_bytes[0],
+				l2fwd_ports_eth_addr[portid].addr_bytes[1],
+				l2fwd_ports_eth_addr[portid].addr_bytes[2],
+				l2fwd_ports_eth_addr[portid].addr_bytes[3],
+				l2fwd_ports_eth_addr[portid].addr_bytes[4],
+				l2fwd_ports_eth_addr[portid].addr_bytes[5]);
+
+		/* initialize port stats */
+		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);
+
+	struct rte_timer hb_timer, stats_timer;
+
+	rte_timer_subsystem_init();
+	if (hbeat_init(&rte_global_hbeat_info, &dead_core, NULL) < 0)
+		rte_exit(EXIT_FAILURE, "init_keep_alive() failed");
+	rte_timer_init(&hb_timer);
+	rte_timer_init(&stats_timer);
+
+
+	if (rte_timer_reset(&hb_timer,
+			(check_period * rte_get_timer_hz()) / 1000,
+			PERIODICAL,
+			rte_lcore_id(),
+			&hbeat_dispatch_pings, &rte_global_hbeat_info
+			) != 0 )
+		rte_exit(EXIT_FAILURE, "Heartbeat setup failure.\n");
+
+	if (timer_period > 0) {
+		if (rte_timer_reset(&stats_timer,
+				(timer_period * rte_get_timer_hz()) / 1000,
+				PERIODICAL,
+				rte_lcore_id(),
+				&dispatch_stats, NULL
+				) != 0 )
+			rte_exit(EXIT_FAILURE, "Stats setup failure.\n");
+	}
+	/* launch per-lcore init on every slave lcore */
+	RTE_LCORE_FOREACH_SLAVE(lcore_id) {
+		struct lcore_queue_conf *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
+				);
+		else {
+			rte_eal_remote_launch(
+				l2fwd_launch_one_lcore,
+				NULL,
+				lcore_id
+				);
+			hbeat_register_core(&rte_global_hbeat_info, lcore_id);
+		}
+	}
+	for (;;) {
+		rte_timer_manage();
+		rte_delay_ms(5);
+		}
+
+	RTE_LCORE_FOREACH_SLAVE(lcore_id) {
+		if (rte_eal_wait_lcore(lcore_id) < 0)
+			return -1;
+	}
+
+	return 0;
+}
-- 
1.9.3

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [dpdk-dev] [RFC PATCH v1] rte: LCore heartbeat example
  2015-09-15 12:16 [dpdk-dev] [RFC PATCH v1] rte: LCore heartbeat example Remy Horton
@ 2015-09-15 13:10 ` Thomas Monjalon
  2015-09-23  9:00   ` Remy Horton
  2015-10-05 11:16   ` Mcnamara, John
  2015-09-30  9:04 ` [dpdk-dev] [PATCH v2 0/3] Keepalive monitoring & reporting Remy Horton
  1 sibling, 2 replies; 44+ messages in thread
From: Thomas Monjalon @ 2015-09-15 13:10 UTC (permalink / raw)
  To: Remy Horton; +Cc: dev

Hi,

2015-09-15 13:16, Remy Horton:
> Provides a basic framework for detecting and reporting live-ness of 
> LCores, the primary requirement of which is minimal overheads for the 
> core(s) being checked. Core failures are notified via an application 
> defined callback. As an example l2fwd with random failures is used.

No it's not a framework, it's a sample application.
If the feature is interesting, it must be integrated in a library.
Then you need some doc, unit tests and an example to demonstrate its usage.
Please try to use an existing example instead of creating a new one.

Thanks

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [dpdk-dev] [RFC PATCH v1] rte: LCore heartbeat example
  2015-09-15 13:10 ` Thomas Monjalon
@ 2015-09-23  9:00   ` Remy Horton
  2015-10-05 11:16   ` Mcnamara, John
  1 sibling, 0 replies; 44+ messages in thread
From: Remy Horton @ 2015-09-23  9:00 UTC (permalink / raw)
  To: dev


On 15/09/2015 14:10, Thomas Monjalon wrote:
> 2015-09-15 13:16, Remy Horton:
>> Provides a basic framework for detecting and reporting live-ness of
>> LCores, the primary requirement of which is minimal overheads for the
>> core(s) being checked. Core failures are notified via an application
>> defined callback. As an example l2fwd with random failures is used.
> No it's not a framework, it's a sample application.
> If the feature is interesting, it must be integrated in a library.

We are looking into this and will get back.

..Remy

^ permalink raw reply	[flat|nested] 44+ messages in thread

* [dpdk-dev] [PATCH v2 0/3] Keepalive monitoring & reporting
  2015-09-15 12:16 [dpdk-dev] [RFC PATCH v1] rte: LCore heartbeat example Remy Horton
  2015-09-15 13:10 ` Thomas Monjalon
@ 2015-09-30  9:04 ` Remy Horton
  2015-09-30  9:04   ` [dpdk-dev] [PATCH v2 1/3] rte: add keep alive functionality Remy Horton
                     ` (3 more replies)
  1 sibling, 4 replies; 44+ messages in thread
From: Remy Horton @ 2015-09-30  9:04 UTC (permalink / raw)
  To: dev

This patch-set adds functions for detecting and reporting live-ness of
LCores, the primary requirement of which is minimal overheads for the
core(s) being checked. Core failures are notified via an application
defined callback. As an example l2fwd with random failures is used.

Due to its size, the keepalive functions are built directly into the
EAL, rather than being in their own library - this point needs discussing, 
as does the integration into l2fwd as opposed to being a new application.

Remy Horton (3):
  rte: add keep alive functionality
  l2fwd: keep alive sample application
  docs: add keep alive sample app guide

 doc/guides/sample_app_ug/index.rst            |   1 +
 doc/guides/sample_app_ug/keep_alive.rst       | 191 ++++++++++++++++++++++++++
 examples/l2fwd/Makefile                       |   2 +-
 examples/l2fwd/main.c                         | 125 +++++++++++++++--
 lib/librte_eal/bsdapp/eal/Makefile            |   1 +
 lib/librte_eal/common/Makefile                |   2 +-
 lib/librte_eal/common/include/rte_keepalive.h | 140 +++++++++++++++++++
 lib/librte_eal/common/rte_keepalive.c         | 122 ++++++++++++++++
 lib/librte_eal/linuxapp/eal/Makefile          |   1 +
 9 files changed, 575 insertions(+), 10 deletions(-)
 create mode 100644 doc/guides/sample_app_ug/keep_alive.rst
 create mode 100644 lib/librte_eal/common/include/rte_keepalive.h
 create mode 100644 lib/librte_eal/common/rte_keepalive.c

-- 
1.9.3

^ permalink raw reply	[flat|nested] 44+ messages in thread

* [dpdk-dev] [PATCH v2 1/3] rte: add keep alive functionality
  2015-09-30  9:04 ` [dpdk-dev] [PATCH v2 0/3] Keepalive monitoring & reporting Remy Horton
@ 2015-09-30  9:04   ` Remy Horton
  2015-10-23 11:40     ` Tahhan, Maryam
  2015-10-23 14:27     ` Wiles, Keith
  2015-09-30  9:04   ` [dpdk-dev] [PATCH v2 2/3] l2fwd: keep alive sample application Remy Horton
                     ` (2 subsequent siblings)
  3 siblings, 2 replies; 44+ messages in thread
From: Remy Horton @ 2015-09-30  9:04 UTC (permalink / raw)
  To: dev

Adds functions for detecting and reporting the live-ness of LCores,
the primary requirement of which is minimal overheads for the
core(s) being checked. Core failures are notified via an application
defined callback.

Signed-off-by: Remy Horton <remy.horton@intel.com>
---
 lib/librte_eal/bsdapp/eal/Makefile            |   1 +
 lib/librte_eal/common/Makefile                |   2 +-
 lib/librte_eal/common/include/rte_keepalive.h | 140 ++++++++++++++++++++++++++
 lib/librte_eal/common/rte_keepalive.c         | 122 ++++++++++++++++++++++
 lib/librte_eal/linuxapp/eal/Makefile          |   1 +
 5 files changed, 265 insertions(+), 1 deletion(-)
 create mode 100644 lib/librte_eal/common/include/rte_keepalive.h
 create mode 100644 lib/librte_eal/common/rte_keepalive.c

diff --git a/lib/librte_eal/bsdapp/eal/Makefile b/lib/librte_eal/bsdapp/eal/Makefile
index a49dcec..65b293f 100644
--- a/lib/librte_eal/bsdapp/eal/Makefile
+++ b/lib/librte_eal/bsdapp/eal/Makefile
@@ -80,6 +80,7 @@ SRCS-$(CONFIG_RTE_LIBRTE_EAL_BSDAPP) += eal_common_thread.c
 SRCS-$(CONFIG_RTE_LIBRTE_EAL_BSDAPP) += rte_malloc.c
 SRCS-$(CONFIG_RTE_LIBRTE_EAL_BSDAPP) += malloc_elem.c
 SRCS-$(CONFIG_RTE_LIBRTE_EAL_BSDAPP) += malloc_heap.c
+SRCS-$(CONFIG_RTE_LIBRTE_EAL_BSDAPP) += rte_keepalive.c
 
 CFLAGS_eal.o := -D_GNU_SOURCE
 #CFLAGS_eal_thread.o := -D_GNU_SOURCE
diff --git a/lib/librte_eal/common/Makefile b/lib/librte_eal/common/Makefile
index 0c43d6a..7f1757a 100644
--- a/lib/librte_eal/common/Makefile
+++ b/lib/librte_eal/common/Makefile
@@ -40,7 +40,7 @@ INC += rte_string_fns.h rte_version.h
 INC += rte_eal_memconfig.h rte_malloc_heap.h
 INC += rte_hexdump.h rte_devargs.h rte_dev.h
 INC += rte_pci_dev_feature_defs.h rte_pci_dev_features.h
-INC += rte_malloc.h
+INC += rte_malloc.h rte_keepalive.h
 
 ifeq ($(CONFIG_RTE_INSECURE_FUNCTION_WARNING),y)
 INC += rte_warnings.h
diff --git a/lib/librte_eal/common/include/rte_keepalive.h b/lib/librte_eal/common/include/rte_keepalive.h
new file mode 100644
index 0000000..d67bf4b
--- /dev/null
+++ b/lib/librte_eal/common/include/rte_keepalive.h
@@ -0,0 +1,140 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright 2015 Intel Shannon Ltd. 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.
+ */
+
+/**
+ * @file keepalive.h
+ * DPDK RTE LCore Keepalive Monitor.
+ *
+ **/
+
+#ifndef _KEEPALIVE_H_
+#define _KEEPALIVE_H_
+
+#include <rte_memory.h>
+
+#ifndef RTE_KEEPALIVE_MAXCORES
+/**
+ * Number of cores to track.
+ * @note Must be larger than the highest core id. */
+#define RTE_KEEPALIVE_MAXCORES RTE_MAX_LCORE
+#endif
+
+
+/**
+ * Keepalive failure callback.
+ *
+ *  Receives a data pointer passed to rte_keepalive_create() and the id of the
+ *  failed core.
+ */
+typedef void (*rte_keepalive_failure_callback_t)(
+	void *data,
+	const int id_core);
+
+
+/**
+ * Keepalive state structure.
+ * @internal
+ */
+struct rte_keepalive {
+	/** Core Liveness. */
+	uint32_t __rte_cache_aligned state_flags[RTE_KEEPALIVE_MAXCORES];
+
+	/** Last-seen-alive timestamps */
+	uint64_t last_alive[RTE_KEEPALIVE_MAXCORES];
+
+	/**
+	 * Cores to check.
+	 * Indexed by core id, non-zero if the core should be checked.
+	 */
+	uint8_t active_cores[RTE_KEEPALIVE_MAXCORES];
+
+	/** Dead core handler. */
+	rte_keepalive_failure_callback_t callback;
+
+	/**
+	 * Dead core handler app data.
+	 * Pointer is passed to dead core handler.
+	 */
+	void *callback_data;
+	uint64_t tsc_initial;
+	uint64_t tsc_mhz;
+};
+
+
+/**
+ * Initialise keepalive sub-system.
+ * @param callback
+ *   Function called upon detection of a dead core.
+ * @param data
+ *   Data pointer to be passed to function callback.
+ * @return
+ *   Keepalive structure success, NULL on failure.
+ */
+struct rte_keepalive *rte_keepalive_create(
+	rte_keepalive_failure_callback_t callback,
+	void *data);
+
+
+/**
+ * @param *ptr_timer Triggering timer (unused)
+ * @param *ptr_data  Data pointer (keepalive structure)
+ */
+void rte_keepalive_dispatch_pings(__attribute__((unused)) void *ptr_timer,
+	void *ptr_data);
+
+
+/**
+ * Registers a core for keepalive checks.
+ * @param *keepcfg
+ *   Keepalive structure pointer
+ * @param id_core
+ *   ID number of core to register.
+ */
+void rte_keepalive_register_core(struct rte_keepalive *keepcfg, const int id_core);
+
+
+/**
+ * Per-core keepalive check.
+ * @param *keepcfg
+ *   Keepalive structure pointer
+ *
+ * This function needs to be called from within the main process loop of
+ * the LCore to be checked.
+ */
+static inline void
+rte_keepalive_mark_alive(struct rte_keepalive *keepcfg)
+{
+	keepcfg->state_flags[rte_lcore_id()] = 1;
+}
+
+
+#endif /* _KEEPALIVE_H_ */
diff --git a/lib/librte_eal/common/rte_keepalive.c b/lib/librte_eal/common/rte_keepalive.c
new file mode 100644
index 0000000..cbdd801
--- /dev/null
+++ b/lib/librte_eal/common/rte_keepalive.c
@@ -0,0 +1,122 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright 2015 Intel Shannon Ltd. 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 <inttypes.h>
+
+#include <rte_cycles.h>
+#include <rte_lcore.h>
+#include <rte_keepalive.h>
+
+#ifdef KEEPALIVE_DEBUG_MSGS
+static void
+print_trace(const char *msg, struct rte_keepalive *keepcfg, int idx_core)
+{
+	printf("%sLast seen %" PRId64  "ms ago.\n",
+		msg,
+		((rte_rdtsc() - keepcfg->last_alive[idx_core])*1000)
+		/ rte_get_tsc_hz()
+	      );
+}
+#else
+static void
+print_trace(__attribute__((unused)) const char *msg,
+	__attribute__((unused)) struct rte_keepalive *keepcfg,
+	__attribute__((unused)) int idx_core)
+{
+}
+#endif
+
+
+
+void
+rte_keepalive_dispatch_pings(__attribute__((unused)) void *ptr_timer,
+	void *ptr_data)
+{
+	struct rte_keepalive *keepcfg = (struct rte_keepalive *)ptr_data;
+	int idx_core;
+
+	for (idx_core = 0; idx_core < RTE_KEEPALIVE_MAXCORES; idx_core++) {
+		if (keepcfg->active_cores[idx_core] == 0)
+			continue;
+		switch (keepcfg->state_flags[idx_core]) {
+		case 1: /* Alive */
+			keepcfg->state_flags[idx_core] = 0;
+			keepcfg->last_alive[idx_core] = rte_rdtsc();
+			break;
+		case 0: /* MIA */
+			print_trace("Core MIA. ", keepcfg, idx_core);
+			keepcfg->state_flags[idx_core] = 2;
+			break;
+		case 2: /* Dead */
+			keepcfg->state_flags[idx_core] = 3;
+			print_trace("Core died. ", keepcfg, idx_core);
+			if (keepcfg->callback)
+				keepcfg->callback(
+					keepcfg->callback_data,
+					idx_core
+					);
+			break;
+		case 3: /* Buried */
+			break;
+		}
+	}
+}
+
+
+struct rte_keepalive *
+rte_keepalive_create(rte_keepalive_failure_callback_t callback,
+	void *data)
+{
+	int idx_core;
+	struct rte_keepalive *keepcfg;
+
+	keepcfg = malloc(sizeof(struct rte_keepalive));
+	if (keepcfg != NULL) {
+		for (idx_core = 0; idx_core < RTE_KEEPALIVE_MAXCORES; idx_core++) {
+			keepcfg->state_flags[idx_core] = 0;
+			keepcfg->active_cores[idx_core] = 0;
+		}
+		keepcfg->callback = callback;
+		keepcfg->callback_data = data;
+		keepcfg->tsc_initial = rte_rdtsc();
+		keepcfg->tsc_mhz = rte_get_tsc_hz() / 1000;
+	}
+	return keepcfg;
+}
+
+
+void
+rte_keepalive_register_core(struct rte_keepalive *keepcfg, const int id_core)
+{
+	if (id_core < RTE_KEEPALIVE_MAXCORES)
+		keepcfg->active_cores[id_core] = 1;
+}
diff --git a/lib/librte_eal/linuxapp/eal/Makefile b/lib/librte_eal/linuxapp/eal/Makefile
index d62196e..05a44d7 100644
--- a/lib/librte_eal/linuxapp/eal/Makefile
+++ b/lib/librte_eal/linuxapp/eal/Makefile
@@ -90,6 +90,7 @@ SRCS-$(CONFIG_RTE_LIBRTE_EAL_LINUXAPP) += eal_common_thread.c
 SRCS-$(CONFIG_RTE_LIBRTE_EAL_LINUXAPP) += rte_malloc.c
 SRCS-$(CONFIG_RTE_LIBRTE_EAL_LINUXAPP) += malloc_elem.c
 SRCS-$(CONFIG_RTE_LIBRTE_EAL_LINUXAPP) += malloc_heap.c
+SRCS-$(CONFIG_RTE_LIBRTE_EAL_LINUXAPP) += rte_keepalive.c
 
 CFLAGS_eal.o := -D_GNU_SOURCE
 CFLAGS_eal_interrupts.o := -D_GNU_SOURCE
-- 
1.9.3

^ permalink raw reply	[flat|nested] 44+ messages in thread

* [dpdk-dev] [PATCH v2 2/3] l2fwd: keep alive sample application
  2015-09-30  9:04 ` [dpdk-dev] [PATCH v2 0/3] Keepalive monitoring & reporting Remy Horton
  2015-09-30  9:04   ` [dpdk-dev] [PATCH v2 1/3] rte: add keep alive functionality Remy Horton
@ 2015-09-30  9:04   ` Remy Horton
  2015-10-23 14:23     ` Tahhan, Maryam
  2015-09-30  9:04   ` [dpdk-dev] [PATCH v2 3/3] docs: add keep alive sample app guide Remy Horton
  2015-10-28  8:52   ` [dpdk-dev] [PATCH v3 0/3] Keepalive monitoring & reporting Remy Horton
  3 siblings, 1 reply; 44+ messages in thread
From: Remy Horton @ 2015-09-30  9:04 UTC (permalink / raw)
  To: dev

Modification of l2fwd to demonstrate keep-alive functionality.

Signed-off-by: Remy Horton <remy.horton@intel.com>
---
 examples/l2fwd/Makefile |   2 +-
 examples/l2fwd/main.c   | 125 ++++++++++++++++++++++++++++++++++++++++++++----
 2 files changed, 118 insertions(+), 9 deletions(-)

diff --git a/examples/l2fwd/Makefile b/examples/l2fwd/Makefile
index 78feeeb..8647174 100644
--- a/examples/l2fwd/Makefile
+++ b/examples/l2fwd/Makefile
@@ -39,7 +39,7 @@ RTE_TARGET ?= x86_64-native-linuxapp-gcc
 include $(RTE_SDK)/mk/rte.vars.mk
 
 # binary name
-APP = l2fwd
+APP = l2fwd-keepalive
 
 # all source are stored in SRCS-y
 SRCS-y := main.c
diff --git a/examples/l2fwd/main.c b/examples/l2fwd/main.c
index 720fd5a..131e5a2 100644
--- a/examples/l2fwd/main.c
+++ b/examples/l2fwd/main.c
@@ -1,7 +1,7 @@
 /*-
  *   BSD LICENSE
  *
- *   Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
+ *   Copyright(c) 2010-2015 Intel Corporation. All rights reserved.
  *   All rights reserved.
  *
  *   Redistribution and use in source and binary forms, with or without
@@ -68,6 +68,8 @@
 #include <rte_ring.h>
 #include <rte_mempool.h>
 #include <rte_mbuf.h>
+#include <rte_timer.h>
+#include <rte_keepalive.h>
 
 #define RTE_LOGTYPE_L2FWD RTE_LOGTYPE_USER1
 
@@ -135,13 +137,18 @@ struct l2fwd_port_statistics {
 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 TIMER_MILLISECOND 1
 #define MAX_TIMER_PERIOD 86400 /* 1 day max */
 static int64_t timer_period = 10 * TIMER_MILLISECOND * 1000; /* default period is 10 seconds */
+static int64_t check_period = 5; /* default check cycle is 5ms */
+
+/* Keepalive structure */
+struct rte_keepalive * rte_global_keepalive_info;
 
 /* Print out statistics on packets dropped */
 static void
-print_stats(void)
+print_stats(__attribute__((unused)) struct rte_timer *ptr_timer,
+	__attribute__((unused)) void *ptr_data)
 {
 	uint64_t total_packets_dropped, total_packets_tx, total_packets_rx;
 	unsigned portid;
@@ -283,11 +290,23 @@ l2fwd_main_loop(void)
 			portid);
 	}
 
+	uint64_t tsc_initial = rte_rdtsc();
+	uint64_t tsc_lifetime = (rand()&0x07) * rte_get_tsc_hz();
+
 	while (1) {
+		/* Keepalive heartbeat */
+		rte_keepalive_mark_alive(rte_global_keepalive_info);
 
 		cur_tsc = rte_rdtsc();
 
 		/*
+		 * Die randomly within 7 secs for demo purposes if
+		 * keepalive enables
+		 */
+		if (check_period > 0 && cur_tsc - tsc_initial > tsc_lifetime)
+			break;
+
+		/*
 		 * TX burst queue drain
 		 */
 		diff_tsc = cur_tsc - prev_tsc;
@@ -313,7 +332,7 @@ l2fwd_main_loop(void)
 
 					/* do this only on master core */
 					if (lcore_id == rte_get_master_lcore()) {
-						print_stats();
+						print_stats(NULL, NULL);
 						/* reset the timer */
 						timer_tsc = 0;
 					}
@@ -357,6 +376,7 @@ 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"
+	       "  -K PERIOD: Keepalive check period (5 default; 86400 max)\n"
 		   "  -T PERIOD: statistics will be refreshed each PERIOD seconds (0 to disable, 10 default, 86400 maximum)\n",
 	       prgname);
 }
@@ -412,6 +432,22 @@ l2fwd_parse_timer_period(const char *q_arg)
 	return n;
 }
 
+static int
+l2fwd_parse_check_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;
+}
+
 /* Parse the argument given in the command line of the application */
 static int
 l2fwd_parse_args(int argc, char **argv)
@@ -426,7 +462,7 @@ l2fwd_parse_args(int argc, char **argv)
 
 	argvopt = argv;
 
-	while ((opt = getopt_long(argc, argvopt, "p:q:T:",
+	while ((opt = getopt_long(argc, argvopt, "p:q:T:K:",
 				  lgopts, &option_index)) != EOF) {
 
 		switch (opt) {
@@ -460,6 +496,16 @@ l2fwd_parse_args(int argc, char **argv)
 			}
 			break;
 
+		/* Check period */
+		case 'K':
+			check_period = l2fwd_parse_check_period(optarg);
+			if (check_period < 0) {
+				printf("invalid check period\n");
+				l2fwd_usage(prgname);
+				return -1;
+			}
+			break;
+
 		/* long options */
 		case 0:
 			l2fwd_usage(prgname);
@@ -534,6 +580,18 @@ check_all_ports_link_status(uint8_t port_num, uint32_t port_mask)
 	}
 }
 
+static void
+dead_core(__attribute__((unused)) void *ptr_data, const int id_core)
+{
+	printf("Dead core %i - restarting..\n", id_core);
+	if (rte_eal_get_lcore_state(id_core) == FINISHED) {
+		rte_eal_wait_lcore(id_core);
+		rte_eal_remote_launch(l2fwd_launch_one_lcore, NULL, id_core);
+	} else {
+		printf("..false positive!\n");
+	}
+}
+
 int
 main(int argc, char **argv)
 {
@@ -600,7 +658,7 @@ main(int argc, char **argv)
 		l2fwd_dst_ports[last_port] = last_port;
 	}
 
-	rx_lcore_id = 0;
+	rx_lcore_id = 1;
 	qconf = NULL;
 
 	/* Initialize the port/queue configuration of each logical core */
@@ -696,8 +754,59 @@ main(int argc, char **argv)
 
 	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);
+	struct rte_timer hb_timer, stats_timer;
+
+	rte_timer_subsystem_init();
+	rte_timer_init(&stats_timer);
+
+	if (check_period > 0) {
+		rte_global_keepalive_info = rte_keepalive_create(&dead_core, NULL);
+		if( rte_global_keepalive_info == NULL)
+			rte_exit(EXIT_FAILURE, "init_keep_alive() failed");
+		rte_timer_init(&hb_timer);
+		if (rte_timer_reset(&hb_timer,
+				(check_period * rte_get_timer_hz()) / 1000,
+				PERIODICAL,
+				rte_lcore_id(),
+				(void(*)(struct rte_timer*, void*))
+				&rte_keepalive_dispatch_pings,
+				rte_global_keepalive_info
+				) != 0 )
+			rte_exit(EXIT_FAILURE, "Keepalive setup failure.\n");
+	}
+	if (timer_period > 0) {
+		if (rte_timer_reset(&stats_timer,
+				(timer_period * rte_get_timer_hz()) / 1000,
+				PERIODICAL,
+				rte_lcore_id(),
+				&print_stats, NULL
+				) != 0 )
+			rte_exit(EXIT_FAILURE, "Stats setup failure.\n");
+	}
+	/* launch per-lcore init on every slave lcore */
+	RTE_LCORE_FOREACH_SLAVE(lcore_id) {
+		struct lcore_queue_conf *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
+				);
+		else {
+			rte_eal_remote_launch(
+				l2fwd_launch_one_lcore,
+				NULL,
+				lcore_id
+				);
+			rte_keepalive_register_core(rte_global_keepalive_info,
+				lcore_id);
+		}
+	}
+	for (;;) {
+		rte_timer_manage();
+		rte_delay_ms(5);
+		}
+
 	RTE_LCORE_FOREACH_SLAVE(lcore_id) {
 		if (rte_eal_wait_lcore(lcore_id) < 0)
 			return -1;
-- 
1.9.3

^ permalink raw reply	[flat|nested] 44+ messages in thread

* [dpdk-dev] [PATCH v2 3/3] docs: add keep alive sample app guide
  2015-09-30  9:04 ` [dpdk-dev] [PATCH v2 0/3] Keepalive monitoring & reporting Remy Horton
  2015-09-30  9:04   ` [dpdk-dev] [PATCH v2 1/3] rte: add keep alive functionality Remy Horton
  2015-09-30  9:04   ` [dpdk-dev] [PATCH v2 2/3] l2fwd: keep alive sample application Remy Horton
@ 2015-09-30  9:04   ` Remy Horton
  2015-10-28  8:52   ` [dpdk-dev] [PATCH v3 0/3] Keepalive monitoring & reporting Remy Horton
  3 siblings, 0 replies; 44+ messages in thread
From: Remy Horton @ 2015-09-30  9:04 UTC (permalink / raw)
  To: dev; +Cc: John J Browne

Signed-off-by: Maryam Tahhan <maryam.tahhan@intel.com>
Signed-off-by: John J Browne <john.j.browne@intel.com>
Signed-off-by: Remy Horton <remy.horton@intel.com>
---
 doc/guides/sample_app_ug/index.rst      |   1 +
 doc/guides/sample_app_ug/keep_alive.rst | 191 ++++++++++++++++++++++++++++++++
 2 files changed, 192 insertions(+)
 create mode 100644 doc/guides/sample_app_ug/keep_alive.rst

diff --git a/doc/guides/sample_app_ug/index.rst b/doc/guides/sample_app_ug/index.rst
index 9beedd9..11b8b14 100644
--- a/doc/guides/sample_app_ug/index.rst
+++ b/doc/guides/sample_app_ug/index.rst
@@ -49,6 +49,7 @@ Sample Applications User Guide
     ipv4_multicast
     ip_reassembly
     kernel_nic_interface
+    keep_alive
     l2_forward_job_stats
     l2_forward_real_virtual
     l3_forward
diff --git a/doc/guides/sample_app_ug/keep_alive.rst b/doc/guides/sample_app_ug/keep_alive.rst
new file mode 100644
index 0000000..080811b
--- /dev/null
+++ b/doc/guides/sample_app_ug/keep_alive.rst
@@ -0,0 +1,191 @@
+
+..  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.
+
+Keep Alive Sample Application
+=============================
+
+The Keep Alive application is a simple example of a
+heartbeat/watchdog for packet processing cores. It demonstrates how
+to detect 'failed' DPDK cores and notify a fault management entity
+of this failure. Its purpose is to ensure the failure of the core
+does not result in a fault that is not detectable by a management
+entity.
+
+
+Overview
+--------
+
+The application demonstrates how to protect against 'silent outages'
+on packet processing cores. A Keep Alive Monitor Agent Core (master)
+monitors the state of packet processing cores (worker cores) by
+dispatching pings at a regular time interval (default is 5ms) and
+monitoring the state of the cores. Cores states are: Alive, MIA, Dead
+or Buried. MIA indicates a missed ping, and Dead indicates two missed
+pings within the specified time interval. When a core is Dead, a
+callback function is invoked to restart the packet processing core;
+A real life application might use this callback function to notify a
+higher level fault management entity of the core failure in order to
+take the appropriate corrective action.
+
+Note: Only the worker cores are monitored. A local (on the host) mechanism
+or agent to supervise the Keep Alive Monitor Agent Core DPDK core is required
+to detect its failure.
+
+Note: This application is based on the L2 forwarding application. As
+such, the initialization and run-time paths are very similar to those
+of the L2 forwarding application.
+
+Compiling the Application
+-------------------------
+
+To compile the application:
+
+#.  Go to the sample application directory:
+
+    .. code-block:: console
+
+        export RTE_SDK=/path/to/rte_sdk cd ${RTE_SDK}/examples/keep_alive
+
+#.  Set the target (a default target is used if not specified). For example:
+
+    .. code-block:: console
+
+        export RTE_TARGET=x86_64-native-linuxapp-gcc
+
+    See the *DPDK Getting Started Guide* for possible RTE_TARGET values.
+
+#.  Build the application:
+
+    .. code-block:: console
+
+        make
+
+Running the Application
+-----------------------
+
+The application has a number of command line options:
+
+.. code-block:: console
+
+    ./build/l2fwd-keepalive [EAL options] \
+            -- -p PORTMASK [-q NQ] [-K PERIOD] [-T PERIOD]
+
+where,
+
+* ``p PORTMASK``: A hexadecimal bitmask of the ports to configure
+
+* ``q NQ``: A number of queues (=ports) per lcore (default is 1)
+
+* ``K PERIOD``: Heartbeat check period in ms(5ms default; 86400 max)
+
+* ``T PERIOD``: statistics will be refreshed each PERIOD seconds (0 to
+  disable, 10 default, 86400 maximum).
+
+To run the application in linuxapp environment with 4 lcores, 16 ports
+8 RX queues per lcore and a ping interval of 10ms, issue the command:
+
+.. code-block:: console
+
+    ./build/l2fwd-keepalive -c f -n 4 -- -q 8 -p ffff -K 10
+
+Refer to the *DPDK Getting Started Guide* for general information on
+running applications and the Environment Abstraction Layer (EAL)
+options.
+
+
+Explanation
+-----------
+
+The following sections provide some explanation of the The
+Keep-Alive/'Liveliness' conceptual scheme. As mentioned in the
+overview section, the initialization and run-time paths are very
+similar to those of the L2 forwarding application (see Chapter 9
+"L2 Forwarding Sample Application (in Real and Virtualized
+Environments)" for more information).
+
+The Keep-Alive/'Liveliness' conceptual scheme:
+
+* A Keep- Alive Agent Runs every N Milliseconds.
+
+* DPDK Cores respond to the keep-alive agent.
+
+* If keep-alive agent detects time-outs, it notifies the
+  fault management entity through a callback function.
+
+The following sections provide some explanation of the code aspects
+that are specific to the Keep Alive sample application.
+
+The heartbeat functionality is initialized with a struct
+rte_heartbeat and the callback function to invoke in the
+case of a timeout.
+
+.. code-block:: c
+
+    rte_global_keepalive_info = rte_keepalive_create(&dead_core, NULL);
+    if (rte_global_hbeat_info == NULL)
+        rte_exit(EXIT_FAILURE, "keepalive_create() failed");
+
+The function that issues the pings hbeat_dispatch_pings()
+is configured to run every check_period milliseconds.
+
+.. code-block:: c
+
+    if (rte_timer_reset(&hb_timer,
+            (check_period * rte_get_timer_hz()) / 1000,
+            PERIODICAL,
+            rte_lcore_id(),
+            &hbeat_dispatch_pings, rte_global_keepalive_info
+            ) != 0 )
+        rte_exit(EXIT_FAILURE, "Keepalive setup failure.\n");
+
+The rest of the initialization and run-time path follows
+the same paths as the the L2 forwarding application. The only
+addition to the main processing loop is the mark alive
+functionality and the example random failures.
+
+.. code-block:: c
+
+    rte_keepalive_mark_alive(&rte_global_hbeat_info);
+    cur_tsc = rte_rdtsc();
+
+    /* Die randomly within 7 secs for demo purposes.. */
+    if (cur_tsc - tsc_initial > tsc_lifetime)
+    break;
+
+The rte_keepalive_mark_alive function simply sets the core state to alive.
+
+.. code-block:: c
+
+    static inline void
+    rte_keepalive_mark_alive(struct rte_heartbeat *keepcfg)
+    {
+        keepcfg->state_flags[rte_lcore_id()] = 1;
+    }
-- 
1.9.3

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [dpdk-dev] [RFC PATCH v1] rte: LCore heartbeat example
  2015-09-15 13:10 ` Thomas Monjalon
  2015-09-23  9:00   ` Remy Horton
@ 2015-10-05 11:16   ` Mcnamara, John
  1 sibling, 0 replies; 44+ messages in thread
From: Mcnamara, John @ 2015-10-05 11:16 UTC (permalink / raw)
  To: Thomas Monjalon, Horton, Remy; +Cc: dev

> -----Original Message-----
> From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of Thomas Monjalon
> Sent: Tuesday, September 15, 2015 2:11 PM
> To: Horton, Remy
> Cc: dev@dpdk.org
> Subject: Re: [dpdk-dev] [RFC PATCH v1] rte: LCore heartbeat example
> 
> Hi,
> 
> 2015-09-15 13:16, Remy Horton:
> > Provides a basic framework for detecting and reporting live-ness of
> > LCores, the primary requirement of which is minimal overheads for the
> > core(s) being checked. Core failures are notified via an application
> > defined callback. As an example l2fwd with random failures is used.
> 
> ...
> Please try to use an existing example instead of creating a new one.

Hi,

I don't know if this is a good general rule.

If the feature is distinct then a new sample application is appropriate. Grouping too much functionality into a single sample app makes them less useful as reference implementations of different DPDK functionality. The l2fwd application, for example, has become cluttered with different functionality.

John.
-- 

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [dpdk-dev] [PATCH v2 1/3] rte: add keep alive functionality
  2015-09-30  9:04   ` [dpdk-dev] [PATCH v2 1/3] rte: add keep alive functionality Remy Horton
@ 2015-10-23 11:40     ` Tahhan, Maryam
  2015-10-23 14:27     ` Wiles, Keith
  1 sibling, 0 replies; 44+ messages in thread
From: Tahhan, Maryam @ 2015-10-23 11:40 UTC (permalink / raw)
  To: Horton, Remy, dev

> From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of Remy Horton
> Sent: Wednesday, September 30, 2015 10:05 AM
> To: dev@dpdk.org
> Subject: [dpdk-dev] [PATCH v2 1/3] rte: add keep alive functionality
> 
> Adds functions for detecting and reporting the live-ness of LCores, the
> primary requirement of which is minimal overheads for the
> core(s) being checked. Core failures are notified via an application defined
> callback.
> 
> Signed-off-by: Remy Horton <remy.horton@intel.com>
> ---
>  lib/librte_eal/bsdapp/eal/Makefile            |   1 +
>  lib/librte_eal/common/Makefile                |   2 +-
>  lib/librte_eal/common/include/rte_keepalive.h | 140
> ++++++++++++++++++++++++++
>  lib/librte_eal/common/rte_keepalive.c         | 122
> ++++++++++++++++++++++
>  lib/librte_eal/linuxapp/eal/Makefile          |   1 +
>  5 files changed, 265 insertions(+), 1 deletion(-)  create mode 100644
> lib/librte_eal/common/include/rte_keepalive.h
>  create mode 100644 lib/librte_eal/common/rte_keepalive.c
> 
> diff --git a/lib/librte_eal/bsdapp/eal/Makefile
> b/lib/librte_eal/bsdapp/eal/Makefile
> index a49dcec..65b293f 100644
> --- a/lib/librte_eal/bsdapp/eal/Makefile
> +++ b/lib/librte_eal/bsdapp/eal/Makefile
> @@ -80,6 +80,7 @@ SRCS-$(CONFIG_RTE_LIBRTE_EAL_BSDAPP) +=
> eal_common_thread.c
>  SRCS-$(CONFIG_RTE_LIBRTE_EAL_BSDAPP) += rte_malloc.c
>  SRCS-$(CONFIG_RTE_LIBRTE_EAL_BSDAPP) += malloc_elem.c
>  SRCS-$(CONFIG_RTE_LIBRTE_EAL_BSDAPP) += malloc_heap.c
> +SRCS-$(CONFIG_RTE_LIBRTE_EAL_BSDAPP) += rte_keepalive.c
> 
>  CFLAGS_eal.o := -D_GNU_SOURCE
>  #CFLAGS_eal_thread.o := -D_GNU_SOURCE
> diff --git a/lib/librte_eal/common/Makefile b/lib/librte_eal/common/Makefile
> index 0c43d6a..7f1757a 100644
> --- a/lib/librte_eal/common/Makefile
> +++ b/lib/librte_eal/common/Makefile
> @@ -40,7 +40,7 @@ INC += rte_string_fns.h rte_version.h  INC +=
> rte_eal_memconfig.h rte_malloc_heap.h  INC += rte_hexdump.h
> rte_devargs.h rte_dev.h  INC += rte_pci_dev_feature_defs.h
> rte_pci_dev_features.h -INC += rte_malloc.h
> +INC += rte_malloc.h rte_keepalive.h
> 
>  ifeq ($(CONFIG_RTE_INSECURE_FUNCTION_WARNING),y)
>  INC += rte_warnings.h
> diff --git a/lib/librte_eal/common/include/rte_keepalive.h
> b/lib/librte_eal/common/include/rte_keepalive.h
> new file mode 100644
> index 0000000..d67bf4b
> --- /dev/null
> +++ b/lib/librte_eal/common/include/rte_keepalive.h
> @@ -0,0 +1,140 @@
> +/*-
> + *   BSD LICENSE
> + *
> + *   Copyright 2015 Intel Shannon Ltd. 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.
> + */
> +
> +/**
> + * @file keepalive.h
> + * DPDK RTE LCore Keepalive Monitor.
> + *
> + **/
> +
> +#ifndef _KEEPALIVE_H_
> +#define _KEEPALIVE_H_
> +
> +#include <rte_memory.h>
> +
> +#ifndef RTE_KEEPALIVE_MAXCORES
> +/**
> + * Number of cores to track.
> + * @note Must be larger than the highest core id. */ #define
> +RTE_KEEPALIVE_MAXCORES RTE_MAX_LCORE #endif
> +
> +
> +/**
> + * Keepalive failure callback.
> + *
> + *  Receives a data pointer passed to rte_keepalive_create() and the id
> +of the
> + *  failed core.
> + */
> +typedef void (*rte_keepalive_failure_callback_t)(
> +	void *data,
> +	const int id_core);
> +
> +
> +/**
> + * Keepalive state structure.
> + * @internal
> + */
> +struct rte_keepalive {
> +	/** Core Liveness. */
> +	uint32_t __rte_cache_aligned
> state_flags[RTE_KEEPALIVE_MAXCORES];
> +
> +	/** Last-seen-alive timestamps */
> +	uint64_t last_alive[RTE_KEEPALIVE_MAXCORES];
> +
> +	/**
> +	 * Cores to check.
> +	 * Indexed by core id, non-zero if the core should be checked.
> +	 */
> +	uint8_t active_cores[RTE_KEEPALIVE_MAXCORES];
> +
> +	/** Dead core handler. */
> +	rte_keepalive_failure_callback_t callback;
> +
> +	/**
> +	 * Dead core handler app data.
> +	 * Pointer is passed to dead core handler.
> +	 */
> +	void *callback_data;
> +	uint64_t tsc_initial;
> +	uint64_t tsc_mhz;
> +};
> +
> +
> +/**
> + * Initialise keepalive sub-system.
> + * @param callback
> + *   Function called upon detection of a dead core.
> + * @param data
> + *   Data pointer to be passed to function callback.
> + * @return
> + *   Keepalive structure success, NULL on failure.
> + */
> +struct rte_keepalive *rte_keepalive_create(
> +	rte_keepalive_failure_callback_t callback,
> +	void *data);
> +
> +
> +/**
> + * @param *ptr_timer Triggering timer (unused)
> + * @param *ptr_data  Data pointer (keepalive structure)  */ void
> +rte_keepalive_dispatch_pings(__attribute__((unused)) void *ptr_timer,
> +	void *ptr_data);
> +
> +
> +/**
> + * Registers a core for keepalive checks.
> + * @param *keepcfg
> + *   Keepalive structure pointer
> + * @param id_core
> + *   ID number of core to register.
> + */
> +void rte_keepalive_register_core(struct rte_keepalive *keepcfg, const
> +int id_core);
> +
> +
> +/**
> + * Per-core keepalive check.
> + * @param *keepcfg
> + *   Keepalive structure pointer
> + *
> + * This function needs to be called from within the main process loop
> +of
> + * the LCore to be checked.
> + */
> +static inline void
> +rte_keepalive_mark_alive(struct rte_keepalive *keepcfg) {
> +	keepcfg->state_flags[rte_lcore_id()] = 1; }
> +
> +
> +#endif /* _KEEPALIVE_H_ */
> diff --git a/lib/librte_eal/common/rte_keepalive.c
> b/lib/librte_eal/common/rte_keepalive.c
> new file mode 100644
> index 0000000..cbdd801
> --- /dev/null
> +++ b/lib/librte_eal/common/rte_keepalive.c
> @@ -0,0 +1,122 @@
> +/*-
> + *   BSD LICENSE
> + *
> + *   Copyright 2015 Intel Shannon Ltd. 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 <inttypes.h>
> +
> +#include <rte_cycles.h>
> +#include <rte_lcore.h>
> +#include <rte_keepalive.h>
> +
> +#ifdef KEEPALIVE_DEBUG_MSGS
> +static void
> +print_trace(const char *msg, struct rte_keepalive *keepcfg, int
> +idx_core) {
> +	printf("%sLast seen %" PRId64  "ms ago.\n",
> +		msg,
> +		((rte_rdtsc() - keepcfg->last_alive[idx_core])*1000)
> +		/ rte_get_tsc_hz()
> +	      );

Hi Remy
Looks great overall, should this be an RTE_LOG message rather than a printf?

BR 
Maryam
> +}
> +#else
> +static void
> +print_trace(__attribute__((unused)) const char *msg,
> +	__attribute__((unused)) struct rte_keepalive *keepcfg,
> +	__attribute__((unused)) int idx_core)
> +{
> +}
> +#endif
> +
> +
> +
> +void
> +rte_keepalive_dispatch_pings(__attribute__((unused)) void *ptr_timer,
> +	void *ptr_data)
> +{
> +	struct rte_keepalive *keepcfg = (struct rte_keepalive *)ptr_data;
> +	int idx_core;
> +
> +	for (idx_core = 0; idx_core < RTE_KEEPALIVE_MAXCORES;
> idx_core++) {
> +		if (keepcfg->active_cores[idx_core] == 0)
> +			continue;
> +		switch (keepcfg->state_flags[idx_core]) {
> +		case 1: /* Alive */
> +			keepcfg->state_flags[idx_core] = 0;
> +			keepcfg->last_alive[idx_core] = rte_rdtsc();
> +			break;
> +		case 0: /* MIA */
> +			print_trace("Core MIA. ", keepcfg, idx_core);
> +			keepcfg->state_flags[idx_core] = 2;
> +			break;
> +		case 2: /* Dead */
> +			keepcfg->state_flags[idx_core] = 3;
> +			print_trace("Core died. ", keepcfg, idx_core);
> +			if (keepcfg->callback)
> +				keepcfg->callback(
> +					keepcfg->callback_data,
> +					idx_core
> +					);
> +			break;
> +		case 3: /* Buried */
> +			break;
> +		}
> +	}
> +}
> +
> +
> +struct rte_keepalive *
> +rte_keepalive_create(rte_keepalive_failure_callback_t callback,
> +	void *data)
> +{
> +	int idx_core;
> +	struct rte_keepalive *keepcfg;
> +
> +	keepcfg = malloc(sizeof(struct rte_keepalive));
> +	if (keepcfg != NULL) {
> +		for (idx_core = 0; idx_core < RTE_KEEPALIVE_MAXCORES;
> idx_core++) {
> +			keepcfg->state_flags[idx_core] = 0;
> +			keepcfg->active_cores[idx_core] = 0;
> +		}
> +		keepcfg->callback = callback;
> +		keepcfg->callback_data = data;
> +		keepcfg->tsc_initial = rte_rdtsc();
> +		keepcfg->tsc_mhz = rte_get_tsc_hz() / 1000;
> +	}
> +	return keepcfg;
> +}
> +
> +
> +void
> +rte_keepalive_register_core(struct rte_keepalive *keepcfg, const int
> +id_core) {
> +	if (id_core < RTE_KEEPALIVE_MAXCORES)
> +		keepcfg->active_cores[id_core] = 1;
> +}
> diff --git a/lib/librte_eal/linuxapp/eal/Makefile
> b/lib/librte_eal/linuxapp/eal/Makefile
> index d62196e..05a44d7 100644
> --- a/lib/librte_eal/linuxapp/eal/Makefile
> +++ b/lib/librte_eal/linuxapp/eal/Makefile
> @@ -90,6 +90,7 @@ SRCS-$(CONFIG_RTE_LIBRTE_EAL_LINUXAPP) +=
> eal_common_thread.c
>  SRCS-$(CONFIG_RTE_LIBRTE_EAL_LINUXAPP) += rte_malloc.c
>  SRCS-$(CONFIG_RTE_LIBRTE_EAL_LINUXAPP) += malloc_elem.c
>  SRCS-$(CONFIG_RTE_LIBRTE_EAL_LINUXAPP) += malloc_heap.c
> +SRCS-$(CONFIG_RTE_LIBRTE_EAL_LINUXAPP) += rte_keepalive.c
> 
>  CFLAGS_eal.o := -D_GNU_SOURCE
>  CFLAGS_eal_interrupts.o := -D_GNU_SOURCE
> --
> 1.9.3

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [dpdk-dev] [PATCH v2 2/3] l2fwd: keep alive sample application
  2015-09-30  9:04   ` [dpdk-dev] [PATCH v2 2/3] l2fwd: keep alive sample application Remy Horton
@ 2015-10-23 14:23     ` Tahhan, Maryam
  2015-10-27  8:48       ` Remy Horton
  0 siblings, 1 reply; 44+ messages in thread
From: Tahhan, Maryam @ 2015-10-23 14:23 UTC (permalink / raw)
  To: Horton, Remy, dev

> From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of Remy Horton
> Sent: Wednesday, September 30, 2015 10:05 AM
> To: dev@dpdk.org
> Subject: [dpdk-dev] [PATCH v2 2/3] l2fwd: keep alive sample application
> 
> Modification of l2fwd to demonstrate keep-alive functionality.
> 
> Signed-off-by: Remy Horton <remy.horton@intel.com>
> ---
>  examples/l2fwd/Makefile |   2 +-
>  examples/l2fwd/main.c   | 125
> ++++++++++++++++++++++++++++++++++++++++++++----
>  2 files changed, 118 insertions(+), 9 deletions(-)
> 
> diff --git a/examples/l2fwd/Makefile b/examples/l2fwd/Makefile index
> 78feeeb..8647174 100644
> --- a/examples/l2fwd/Makefile
> +++ b/examples/l2fwd/Makefile
> @@ -39,7 +39,7 @@ RTE_TARGET ?= x86_64-native-linuxapp-gcc  include
> $(RTE_SDK)/mk/rte.vars.mk
> 
>  # binary name
> -APP = l2fwd
> +APP = l2fwd-keepalive
> 
Hi Remy,
Looks great overall, just a couple of comments
For backward compatibility the rename could be a nightmare? What do you think?

>  # all source are stored in SRCS-y
>  SRCS-y := main.c
> diff --git a/examples/l2fwd/main.c b/examples/l2fwd/main.c index
> 720fd5a..131e5a2 100644
> --- a/examples/l2fwd/main.c
> +++ b/examples/l2fwd/main.c
> @@ -1,7 +1,7 @@
>  /*-
>   *   BSD LICENSE
>   *
> - *   Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
> + *   Copyright(c) 2010-2015 Intel Corporation. All rights reserved.
>   *   All rights reserved.
>   *
>   *   Redistribution and use in source and binary forms, with or without
> @@ -68,6 +68,8 @@
>  #include <rte_ring.h>
>  #include <rte_mempool.h>
>  #include <rte_mbuf.h>
> +#include <rte_timer.h>
> +#include <rte_keepalive.h>
> 
>  #define RTE_LOGTYPE_L2FWD RTE_LOGTYPE_USER1
> 
> @@ -135,13 +137,18 @@ struct l2fwd_port_statistics {  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 TIMER_MILLISECOND 1
>  #define MAX_TIMER_PERIOD 86400 /* 1 day max */  static int64_t
> timer_period = 10 * TIMER_MILLISECOND * 1000; /* default period is 10
> seconds */
> +static int64_t check_period = 5; /* default check cycle is 5ms */
> +
> +/* Keepalive structure */
> +struct rte_keepalive * rte_global_keepalive_info;
> 
>  /* Print out statistics on packets dropped */  static void
> -print_stats(void)
> +print_stats(__attribute__((unused)) struct rte_timer *ptr_timer,
> +	__attribute__((unused)) void *ptr_data)
>  {
>  	uint64_t total_packets_dropped, total_packets_tx, total_packets_rx;
>  	unsigned portid;
> @@ -283,11 +290,23 @@ l2fwd_main_loop(void)
>  			portid);
>  	}
> 
> +	uint64_t tsc_initial = rte_rdtsc();
> +	uint64_t tsc_lifetime = (rand()&0x07) * rte_get_tsc_hz();
> +
>  	while (1) {
> +		/* Keepalive heartbeat */
> +		rte_keepalive_mark_alive(rte_global_keepalive_info);
> 
>  		cur_tsc = rte_rdtsc();
> 
>  		/*
> +		 * Die randomly within 7 secs for demo purposes if
> +		 * keepalive enables
> +		 */

Typo: If keepalive is enabled

> +		if (check_period > 0 && cur_tsc - tsc_initial > tsc_lifetime)
> +			break;
> +
> +		/*
>  		 * TX burst queue drain
>  		 */
>  		diff_tsc = cur_tsc - prev_tsc;
> @@ -313,7 +332,7 @@ l2fwd_main_loop(void)
> 
>  					/* do this only on master core */
>  					if (lcore_id ==
> rte_get_master_lcore()) {
> -						print_stats();
> +						print_stats(NULL, NULL);
>  						/* reset the timer */
>  						timer_tsc = 0;
>  					}
> @@ -357,6 +376,7 @@ 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"
> +	       "  -K PERIOD: Keepalive check period (5 default; 86400 max)\n"
>  		   "  -T PERIOD: statistics will be refreshed each PERIOD
> seconds (0 to disable, 10 default, 86400 maximum)\n",
>  	       prgname);
>  }
> @@ -412,6 +432,22 @@ l2fwd_parse_timer_period(const char *q_arg)
>  	return n;
>  }
> 
> +static int
> +l2fwd_parse_check_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;
> +}
> +
>  /* Parse the argument given in the command line of the application */  static
> int  l2fwd_parse_args(int argc, char **argv) @@ -426,7 +462,7 @@
> l2fwd_parse_args(int argc, char **argv)
> 
>  	argvopt = argv;
> 
> -	while ((opt = getopt_long(argc, argvopt, "p:q:T:",
> +	while ((opt = getopt_long(argc, argvopt, "p:q:T:K:",
>  				  lgopts, &option_index)) != EOF) {
> 
>  		switch (opt) {
> @@ -460,6 +496,16 @@ l2fwd_parse_args(int argc, char **argv)
>  			}
>  			break;
> 
> +		/* Check period */
> +		case 'K':
> +			check_period = l2fwd_parse_check_period(optarg);
> +			if (check_period < 0) {
> +				printf("invalid check period\n");
> +				l2fwd_usage(prgname);
> +				return -1;
> +			}
> +			break;
> +
>  		/* long options */
>  		case 0:
>  			l2fwd_usage(prgname);
> @@ -534,6 +580,18 @@ check_all_ports_link_status(uint8_t port_num,
> uint32_t port_mask)
>  	}
>  }
> 
> +static void
> +dead_core(__attribute__((unused)) void *ptr_data, const int id_core) {
> +	printf("Dead core %i - restarting..\n", id_core);
> +	if (rte_eal_get_lcore_state(id_core) == FINISHED) {
> +		rte_eal_wait_lcore(id_core);
> +		rte_eal_remote_launch(l2fwd_launch_one_lcore, NULL,
> id_core);
> +	} else {
> +		printf("..false positive!\n");
> +	}
> +}
> +
>  int
>  main(int argc, char **argv)
>  {
> @@ -600,7 +658,7 @@ main(int argc, char **argv)
>  		l2fwd_dst_ports[last_port] = last_port;
>  	}
> 
> -	rx_lcore_id = 0;
> +	rx_lcore_id = 1;
>  	qconf = NULL;
> 
>  	/* Initialize the port/queue configuration of each logical core */ @@ -
> 696,8 +754,59 @@ main(int argc, char **argv)
> 
>  	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);
> +	struct rte_timer hb_timer, stats_timer;
> +
> +	rte_timer_subsystem_init();
> +	rte_timer_init(&stats_timer);
> +
> +	if (check_period > 0) {
> +		rte_global_keepalive_info =
> rte_keepalive_create(&dead_core, NULL);
> +		if( rte_global_keepalive_info == NULL)
> +			rte_exit(EXIT_FAILURE, "init_keep_alive() failed");
> +		rte_timer_init(&hb_timer);
> +		if (rte_timer_reset(&hb_timer,
> +				(check_period * rte_get_timer_hz()) / 1000,
> +				PERIODICAL,
> +				rte_lcore_id(),
> +				(void(*)(struct rte_timer*, void*))
> +				&rte_keepalive_dispatch_pings,
> +				rte_global_keepalive_info
> +				) != 0 )
> +			rte_exit(EXIT_FAILURE, "Keepalive setup failure.\n");
> +	}
> +	if (timer_period > 0) {
> +		if (rte_timer_reset(&stats_timer,
> +				(timer_period * rte_get_timer_hz()) / 1000,
> +				PERIODICAL,
> +				rte_lcore_id(),
> +				&print_stats, NULL
> +				) != 0 )
> +			rte_exit(EXIT_FAILURE, "Stats setup failure.\n");
> +	}
> +	/* launch per-lcore init on every slave lcore */
> +	RTE_LCORE_FOREACH_SLAVE(lcore_id) {
> +		struct lcore_queue_conf *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
> +				);
> +		else {
> +			rte_eal_remote_launch(
> +				l2fwd_launch_one_lcore,
> +				NULL,
> +				lcore_id
> +				);
> +
> 	rte_keepalive_register_core(rte_global_keepalive_info,
> +				lcore_id);
> +		}
> +	}
> +	for (;;) {
> +		rte_timer_manage();
> +		rte_delay_ms(5);
> +		}
> +
>  	RTE_LCORE_FOREACH_SLAVE(lcore_id) {
>  		if (rte_eal_wait_lcore(lcore_id) < 0)
>  			return -1;
> --
> 1.9.3

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [dpdk-dev] [PATCH v2 1/3] rte: add keep alive functionality
  2015-09-30  9:04   ` [dpdk-dev] [PATCH v2 1/3] rte: add keep alive functionality Remy Horton
  2015-10-23 11:40     ` Tahhan, Maryam
@ 2015-10-23 14:27     ` Wiles, Keith
  2015-10-26 16:36       ` Remy Horton
  1 sibling, 1 reply; 44+ messages in thread
From: Wiles, Keith @ 2015-10-23 14:27 UTC (permalink / raw)
  To: Horton, Remy, dev

Hi Remy, I have few questions inline.
— 
Regards,
++Keith Wiles

Intel Corporation







On 9/30/15, 6:04 AM, "dev on behalf of Remy Horton" <dev-bounces@dpdk.org on behalf of remy.horton@intel.com> wrote:

>Adds functions for detecting and reporting the live-ness of LCores,
>the primary requirement of which is minimal overheads for the
>core(s) being checked. Core failures are notified via an application
>defined callback.
>
>Signed-off-by: Remy Horton <remy.horton@intel.com>
>---
> lib/librte_eal/bsdapp/eal/Makefile            |   1 +
> lib/librte_eal/common/Makefile                |   2 +-
> lib/librte_eal/common/include/rte_keepalive.h | 140 ++++++++++++++++++++++++++
> lib/librte_eal/common/rte_keepalive.c         | 122 ++++++++++++++++++++++
> lib/librte_eal/linuxapp/eal/Makefile          |   1 +
> 5 files changed, 265 insertions(+), 1 deletion(-)
> create mode 100644 lib/librte_eal/common/include/rte_keepalive.h
> create mode 100644 lib/librte_eal/common/rte_keepalive.c
>
>diff --git a/lib/librte_eal/bsdapp/eal/Makefile b/lib/librte_eal/bsdapp/eal/Makefile
>index a49dcec..65b293f 100644
>--- a/lib/librte_eal/bsdapp/eal/Makefile
>+++ b/lib/librte_eal/bsdapp/eal/Makefile
>@@ -80,6 +80,7 @@ SRCS-$(CONFIG_RTE_LIBRTE_EAL_BSDAPP) += eal_common_thread.c
> SRCS-$(CONFIG_RTE_LIBRTE_EAL_BSDAPP) += rte_malloc.c
> SRCS-$(CONFIG_RTE_LIBRTE_EAL_BSDAPP) += malloc_elem.c
> SRCS-$(CONFIG_RTE_LIBRTE_EAL_BSDAPP) += malloc_heap.c
>+SRCS-$(CONFIG_RTE_LIBRTE_EAL_BSDAPP) += rte_keepalive.c
> 
> CFLAGS_eal.o := -D_GNU_SOURCE
> #CFLAGS_eal_thread.o := -D_GNU_SOURCE
>diff --git a/lib/librte_eal/common/Makefile b/lib/librte_eal/common/Makefile
>index 0c43d6a..7f1757a 100644
>--- a/lib/librte_eal/common/Makefile
>+++ b/lib/librte_eal/common/Makefile
>@@ -40,7 +40,7 @@ INC += rte_string_fns.h rte_version.h
> INC += rte_eal_memconfig.h rte_malloc_heap.h
> INC += rte_hexdump.h rte_devargs.h rte_dev.h
> INC += rte_pci_dev_feature_defs.h rte_pci_dev_features.h
>-INC += rte_malloc.h
>+INC += rte_malloc.h rte_keepalive.h
> 
> ifeq ($(CONFIG_RTE_INSECURE_FUNCTION_WARNING),y)
> INC += rte_warnings.h
>diff --git a/lib/librte_eal/common/include/rte_keepalive.h b/lib/librte_eal/common/include/rte_keepalive.h
>new file mode 100644
>index 0000000..d67bf4b
>--- /dev/null
>+++ b/lib/librte_eal/common/include/rte_keepalive.h
>@@ -0,0 +1,140 @@
>+/*-
>+ *   BSD LICENSE
>+ *
>+ *   Copyright 2015 Intel Shannon Ltd. 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.
>+ */
>+
>+/**
>+ * @file keepalive.h
>+ * DPDK RTE LCore Keepalive Monitor.
>+ *
>+ **/
>+
>+#ifndef _KEEPALIVE_H_
>+#define _KEEPALIVE_H_
>+
>+#include <rte_memory.h>
>+
>+#ifndef RTE_KEEPALIVE_MAXCORES
>+/**
>+ * Number of cores to track.
>+ * @note Must be larger than the highest core id. */
>+#define RTE_KEEPALIVE_MAXCORES RTE_MAX_LCORE
>+#endif
>+
>+
>+/**
>+ * Keepalive failure callback.
>+ *
>+ *  Receives a data pointer passed to rte_keepalive_create() and the id of the
>+ *  failed core.
>+ */
>+typedef void (*rte_keepalive_failure_callback_t)(
>+	void *data,
>+	const int id_core);
>+
>+
>+/**
>+ * Keepalive state structure.
>+ * @internal
>+ */
>+struct rte_keepalive {
>+	/** Core Liveness. */
>+	uint32_t __rte_cache_aligned state_flags[RTE_KEEPALIVE_MAXCORES];

Normally I see the __rte_cache_aligned at the end of the line before the ‘;’ did you have a reason to have it here? If not then I would move it to the end to look the same as the others. I did a quick grop in the code and that is the normal location.

My next question is why not align the whole, which would do the same thing. I did not check the compiler output, but I was thinking it would possible leave gaps in the structure for bytes we can not use normally, but maybe that is not a problem.

Next it appears the state_flags is only being set to 0-3, which means it does not need to be a uint43_t, but could be a uint8_t, correct?

Also setting the value 0-3 could be turned into a enum with real names so the debuggers could print them out instead of these numbers.

>+
>+	/** Last-seen-alive timestamps */
>+	uint64_t last_alive[RTE_KEEPALIVE_MAXCORES];
>+
>+	/**
>+	 * Cores to check.
>+	 * Indexed by core id, non-zero if the core should be checked.
>+	 */
>+	uint8_t active_cores[RTE_KEEPALIVE_MAXCORES];
>+
>+	/** Dead core handler. */
>+	rte_keepalive_failure_callback_t callback;
>+
>+	/**
>+	 * Dead core handler app data.
>+	 * Pointer is passed to dead core handler.
>+	 */
>+	void *callback_data;
>+	uint64_t tsc_initial;
>+	uint64_t tsc_mhz;
>+};
>+
>+
>+/**
>+ * Initialise keepalive sub-system.
>+ * @param callback
>+ *   Function called upon detection of a dead core.
>+ * @param data
>+ *   Data pointer to be passed to function callback.
>+ * @return
>+ *   Keepalive structure success, NULL on failure.
>+ */
>+struct rte_keepalive *rte_keepalive_create(
>+	rte_keepalive_failure_callback_t callback,
>+	void *data);
>+
>+
>+/**
>+ * @param *ptr_timer Triggering timer (unused)
>+ * @param *ptr_data  Data pointer (keepalive structure)
>+ */
>+void rte_keepalive_dispatch_pings(__attribute__((unused)) void *ptr_timer,
>+	void *ptr_data);

Normally I do not see the unused attribute on the declare of a function, does this help the compiler at all? I do not believe it does, so I would remove it from here as you already have it in the function.
>+
>+
>+/**
>+ * Registers a core for keepalive checks.
>+ * @param *keepcfg
>+ *   Keepalive structure pointer
>+ * @param id_core
>+ *   ID number of core to register.
>+ */
>+void rte_keepalive_register_core(struct rte_keepalive *keepcfg, const int id_core);
>+
>+
>+/**
>+ * Per-core keepalive check.
>+ * @param *keepcfg
>+ *   Keepalive structure pointer
>+ *
>+ * This function needs to be called from within the main process loop of
>+ * the LCore to be checked.
>+ */
>+static inline void
>+rte_keepalive_mark_alive(struct rte_keepalive *keepcfg)
>+{
>+	keepcfg->state_flags[rte_lcore_id()] = 1;
>+}
>+
>+
>+#endif /* _KEEPALIVE_H_ */
>diff --git a/lib/librte_eal/common/rte_keepalive.c b/lib/librte_eal/common/rte_keepalive.c
>new file mode 100644
>index 0000000..cbdd801
>--- /dev/null
>+++ b/lib/librte_eal/common/rte_keepalive.c
>@@ -0,0 +1,122 @@
>+/*-
>+ *   BSD LICENSE
>+ *
>+ *   Copyright 2015 Intel Shannon Ltd. 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 <inttypes.h>
>+
>+#include <rte_cycles.h>
>+#include <rte_lcore.h>
>+#include <rte_keepalive.h>
>+
>+#ifdef KEEPALIVE_DEBUG_MSGS
>+static void
>+print_trace(const char *msg, struct rte_keepalive *keepcfg, int idx_core)
>+{
>+	printf("%sLast seen %" PRId64  "ms ago.\n",
>+		msg,
>+		((rte_rdtsc() - keepcfg->last_alive[idx_core])*1000)
>+		/ rte_get_tsc_hz()
>+	      );
>+}
>+#else
>+static void
>+print_trace(__attribute__((unused)) const char *msg,
>+	__attribute__((unused)) struct rte_keepalive *keepcfg,
>+	__attribute__((unused)) int idx_core)
>+{
>+}
>+#endif
>+
>+
>+
>+void
>+rte_keepalive_dispatch_pings(__attribute__((unused)) void *ptr_timer,
>+	void *ptr_data)
>+{
>+	struct rte_keepalive *keepcfg = (struct rte_keepalive *)ptr_data;
>+	int idx_core;
>+
>+	for (idx_core = 0; idx_core < RTE_KEEPALIVE_MAXCORES; idx_core++) {
>+		if (keepcfg->active_cores[idx_core] == 0)
>+			continue;
>+		switch (keepcfg->state_flags[idx_core]) {
>+		case 1: /* Alive */
>+			keepcfg->state_flags[idx_core] = 0;
>+			keepcfg->last_alive[idx_core] = rte_rdtsc();
>+			break;
>+		case 0: /* MIA */
>+			print_trace("Core MIA. ", keepcfg, idx_core);
>+			keepcfg->state_flags[idx_core] = 2;
>+			break;
>+		case 2: /* Dead */
>+			keepcfg->state_flags[idx_core] = 3;
>+			print_trace("Core died. ", keepcfg, idx_core);
>+			if (keepcfg->callback)
>+				keepcfg->callback(
>+					keepcfg->callback_data,
>+					idx_core
>+					);
>+			break;
>+		case 3: /* Buried */
>+			break;
>+		}
>+	}
>+}
>+
>+
>+struct rte_keepalive *
>+rte_keepalive_create(rte_keepalive_failure_callback_t callback,
>+	void *data)
>+{
>+	int idx_core;
>+	struct rte_keepalive *keepcfg;
>+
>+	keepcfg = malloc(sizeof(struct rte_keepalive));
>+	if (keepcfg != NULL) {
>+		for (idx_core = 0; idx_core < RTE_KEEPALIVE_MAXCORES; idx_core++) {
>+			keepcfg->state_flags[idx_core] = 0;
>+			keepcfg->active_cores[idx_core] = 0;
>+		}

Could you have done a calloc then you do not need the for loop to zero stuff?
>+		keepcfg->callback = callback;
>+		keepcfg->callback_data = data;
>+		keepcfg->tsc_initial = rte_rdtsc();
>+		keepcfg->tsc_mhz = rte_get_tsc_hz() / 1000;
>+	}
>+	return keepcfg;
>+}
>+
>+
>+void
>+rte_keepalive_register_core(struct rte_keepalive *keepcfg, const int id_core)
>+{
>+	if (id_core < RTE_KEEPALIVE_MAXCORES)
>+		keepcfg->active_cores[id_core] = 1;
>+}
>diff --git a/lib/librte_eal/linuxapp/eal/Makefile b/lib/librte_eal/linuxapp/eal/Makefile
>index d62196e..05a44d7 100644
>--- a/lib/librte_eal/linuxapp/eal/Makefile
>+++ b/lib/librte_eal/linuxapp/eal/Makefile
>@@ -90,6 +90,7 @@ SRCS-$(CONFIG_RTE_LIBRTE_EAL_LINUXAPP) += eal_common_thread.c
> SRCS-$(CONFIG_RTE_LIBRTE_EAL_LINUXAPP) += rte_malloc.c
> SRCS-$(CONFIG_RTE_LIBRTE_EAL_LINUXAPP) += malloc_elem.c
> SRCS-$(CONFIG_RTE_LIBRTE_EAL_LINUXAPP) += malloc_heap.c
>+SRCS-$(CONFIG_RTE_LIBRTE_EAL_LINUXAPP) += rte_keepalive.c
> 
> CFLAGS_eal.o := -D_GNU_SOURCE
> CFLAGS_eal_interrupts.o := -D_GNU_SOURCE
>-- 
>1.9.3
>

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [dpdk-dev] [PATCH v2 1/3] rte: add keep alive functionality
  2015-10-23 14:27     ` Wiles, Keith
@ 2015-10-26 16:36       ` Remy Horton
  0 siblings, 0 replies; 44+ messages in thread
From: Remy Horton @ 2015-10-26 16:36 UTC (permalink / raw)
  To: Wiles, Keith, dev

'noon,

On 23/10/2015 15:27, Wiles, Keith wrote:
>> +	uint32_t __rte_cache_aligned state_flags[RTE_KEEPALIVE_MAXCORES];
> Normally I see the __rte_cache_aligned at the end of the line before
> the ‘;’ did you have a reason to have it here? If not then I would
> move it to the end to look the same as the others. I did a quick grop
> in the code and that is the normal location.
>
> My next question is why not align the whole, which would do the same
> thing. I did not check the compiler output, but I was thinking it
> would possible leave gaps in the structure for bytes we can not use
> normally, but maybe that is not a problem.

Each element of state_flags is assigned to a different LCore, so they 
have to be individually cache-aligned. The gaps it leaves behind are 
unavoidable.


> Next it appears the state_flags is only being set to 0-3, which means
> it does not need to be a uint43_t, but could be a uint8_t, correct?

Yes, but since it all needs to be cache aligned anyway, wouldn't 
actually gain anything.


>> +	keepcfg = malloc(sizeof(struct rte_keepalive));
>> +	if (keepcfg != NULL) {
>> +		for (idx_core = 0; idx_core < RTE_KEEPALIVE_MAXCORES; idx_core++) {
>> +			keepcfg->state_flags[idx_core] = 0;
>> +			keepcfg->active_cores[idx_core] = 0;
>> +		}
>
> Could you have done a calloc then you do not need the for loop to zero stuff?

Could do. It was written this way because the function originally took a 
structure rather than allocate one.


..Remy

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [dpdk-dev] [PATCH v2 2/3] l2fwd: keep alive sample application
  2015-10-23 14:23     ` Tahhan, Maryam
@ 2015-10-27  8:48       ` Remy Horton
  2015-10-27 10:10         ` Bruce Richardson
  0 siblings, 1 reply; 44+ messages in thread
From: Remy Horton @ 2015-10-27  8:48 UTC (permalink / raw)
  To: Tahhan, Maryam, dev



On 23/10/2015 15:23, Tahhan, Maryam wrote:

>>   # binary name
>> -APP = l2fwd
>> +APP = l2fwd-keepalive
> Hi Remy,
> Looks great overall, just a couple of comments
> For backward compatibility the rename could be a nightmare? What do you think?

True. Undecided whether to change the Makefile(s) so that both keepalive 
and non-keepalive l2fwd are built, or to simply clone all of l2fwd..


>> +		 * Die randomly within 7 secs for demo purposes if
>> +		 * keepalive enables
>> +		 */
>
> Typo: If keepalive is enabled

Fixed.. :)

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [dpdk-dev] [PATCH v2 2/3] l2fwd: keep alive sample application
  2015-10-27  8:48       ` Remy Horton
@ 2015-10-27 10:10         ` Bruce Richardson
  0 siblings, 0 replies; 44+ messages in thread
From: Bruce Richardson @ 2015-10-27 10:10 UTC (permalink / raw)
  To: Remy Horton; +Cc: dev

On Tue, Oct 27, 2015 at 08:48:41AM +0000, Remy Horton wrote:
> 
> 
> On 23/10/2015 15:23, Tahhan, Maryam wrote:
> 
> >>  # binary name
> >>-APP = l2fwd
> >>+APP = l2fwd-keepalive
> >Hi Remy,
> >Looks great overall, just a couple of comments
> >For backward compatibility the rename could be a nightmare? What do you think?
> 
> True. Undecided whether to change the Makefile(s) so that both keepalive and
> non-keepalive l2fwd are built, or to simply clone all of l2fwd..
> 

My opinion is that l2fwd should be kept as simple as possible, so I'd suggest
cloning to provide a separate keepalive example.

/Bruce

^ permalink raw reply	[flat|nested] 44+ messages in thread

* [dpdk-dev] [PATCH v3 0/3] Keepalive monitoring & reporting
  2015-09-30  9:04 ` [dpdk-dev] [PATCH v2 0/3] Keepalive monitoring & reporting Remy Horton
                     ` (2 preceding siblings ...)
  2015-09-30  9:04   ` [dpdk-dev] [PATCH v2 3/3] docs: add keep alive sample app guide Remy Horton
@ 2015-10-28  8:52   ` Remy Horton
  2015-10-28  8:52     ` [dpdk-dev] [PATCH v3 1/3] rte: add keep alive functionality Remy Horton
                       ` (3 more replies)
  3 siblings, 4 replies; 44+ messages in thread
From: Remy Horton @ 2015-10-28  8:52 UTC (permalink / raw)
  To: dev

This patch-set adds functions for detecting and reporting live-ness of
LCores, the primary requirement of which is minimal overheads for the
core(s) being checked. Core failures are notified via an application
defined callback. As an example l2fwd with random failures is used.


Remy Horton (3):
  rte: add keep alive functionality
  docs: add keep alive sample app guide
  example: add keep alive sample application

 doc/guides/sample_app_ug/index.rst            |   1 +
 doc/guides/sample_app_ug/keep_alive.rst       | 191 ++++++
 examples/l2fwd-keepalive/Makefile             |  50 ++
 examples/l2fwd-keepalive/main.c               | 806 ++++++++++++++++++++++++++
 lib/librte_eal/bsdapp/eal/Makefile            |   1 +
 lib/librte_eal/common/Makefile                |   2 +-
 lib/librte_eal/common/include/rte_keepalive.h | 146 +++++
 lib/librte_eal/common/rte_keepalive.c         | 124 ++++
 lib/librte_eal/linuxapp/eal/Makefile          |   1 +
 9 files changed, 1321 insertions(+), 1 deletion(-)
 create mode 100644 doc/guides/sample_app_ug/keep_alive.rst
 create mode 100644 examples/l2fwd-keepalive/Makefile
 create mode 100644 examples/l2fwd-keepalive/main.c
 create mode 100644 lib/librte_eal/common/include/rte_keepalive.h
 create mode 100644 lib/librte_eal/common/rte_keepalive.c

-- 
1.9.3

^ permalink raw reply	[flat|nested] 44+ messages in thread

* [dpdk-dev] [PATCH v3 1/3] rte: add keep alive functionality
  2015-10-28  8:52   ` [dpdk-dev] [PATCH v3 0/3] Keepalive monitoring & reporting Remy Horton
@ 2015-10-28  8:52     ` Remy Horton
  2015-10-28 12:25       ` Tahhan, Maryam
                         ` (2 more replies)
  2015-10-28  8:52     ` [dpdk-dev] [PATCH v3 2/3] docs: add keep alive sample app guide Remy Horton
                       ` (2 subsequent siblings)
  3 siblings, 3 replies; 44+ messages in thread
From: Remy Horton @ 2015-10-28  8:52 UTC (permalink / raw)
  To: dev

Adds functions for detecting and reporting the live-ness of LCores,
the primary requirement of which is minimal overheads for the
core(s) being checked. Core failures are notified via an application
defined callback.

Signed-off-by: Remy Horton <remy.horton@intel.com>
---
 lib/librte_eal/bsdapp/eal/Makefile            |   1 +
 lib/librte_eal/common/Makefile                |   2 +-
 lib/librte_eal/common/include/rte_keepalive.h | 146 ++++++++++++++++++++++++++
 lib/librte_eal/common/rte_keepalive.c         | 124 ++++++++++++++++++++++
 lib/librte_eal/linuxapp/eal/Makefile          |   1 +
 5 files changed, 273 insertions(+), 1 deletion(-)
 create mode 100644 lib/librte_eal/common/include/rte_keepalive.h
 create mode 100644 lib/librte_eal/common/rte_keepalive.c

diff --git a/lib/librte_eal/bsdapp/eal/Makefile b/lib/librte_eal/bsdapp/eal/Makefile
index a49dcec..65b293f 100644
--- a/lib/librte_eal/bsdapp/eal/Makefile
+++ b/lib/librte_eal/bsdapp/eal/Makefile
@@ -80,6 +80,7 @@ SRCS-$(CONFIG_RTE_LIBRTE_EAL_BSDAPP) += eal_common_thread.c
 SRCS-$(CONFIG_RTE_LIBRTE_EAL_BSDAPP) += rte_malloc.c
 SRCS-$(CONFIG_RTE_LIBRTE_EAL_BSDAPP) += malloc_elem.c
 SRCS-$(CONFIG_RTE_LIBRTE_EAL_BSDAPP) += malloc_heap.c
+SRCS-$(CONFIG_RTE_LIBRTE_EAL_BSDAPP) += rte_keepalive.c
 
 CFLAGS_eal.o := -D_GNU_SOURCE
 #CFLAGS_eal_thread.o := -D_GNU_SOURCE
diff --git a/lib/librte_eal/common/Makefile b/lib/librte_eal/common/Makefile
index 0c43d6a..7f1757a 100644
--- a/lib/librte_eal/common/Makefile
+++ b/lib/librte_eal/common/Makefile
@@ -40,7 +40,7 @@ INC += rte_string_fns.h rte_version.h
 INC += rte_eal_memconfig.h rte_malloc_heap.h
 INC += rte_hexdump.h rte_devargs.h rte_dev.h
 INC += rte_pci_dev_feature_defs.h rte_pci_dev_features.h
-INC += rte_malloc.h
+INC += rte_malloc.h rte_keepalive.h
 
 ifeq ($(CONFIG_RTE_INSECURE_FUNCTION_WARNING),y)
 INC += rte_warnings.h
diff --git a/lib/librte_eal/common/include/rte_keepalive.h b/lib/librte_eal/common/include/rte_keepalive.h
new file mode 100644
index 0000000..eab7255
--- /dev/null
+++ b/lib/librte_eal/common/include/rte_keepalive.h
@@ -0,0 +1,146 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright 2015 Intel Shannon Ltd. 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.
+ */
+
+/**
+ * @file keepalive.h
+ * DPDK RTE LCore Keepalive Monitor.
+ *
+ **/
+
+#ifndef _KEEPALIVE_H_
+#define _KEEPALIVE_H_
+
+#include <rte_memory.h>
+
+#ifndef RTE_KEEPALIVE_MAXCORES
+/**
+ * Number of cores to track.
+ * @note Must be larger than the highest core id. */
+#define RTE_KEEPALIVE_MAXCORES RTE_MAX_LCORE
+#endif
+
+
+/**
+ * Keepalive failure callback.
+ *
+ *  Receives a data pointer passed to rte_keepalive_create() and the id of the
+ *  failed core.
+ */
+typedef void (*rte_keepalive_failure_callback_t)(
+	void *data,
+	const int id_core);
+
+
+/**
+ * Keepalive state structure.
+ * @internal
+ */
+struct rte_keepalive {
+	/** Core Liveness. */
+
+	enum {
+		ALIVE = 1,
+		MISSING = 0,
+		DEAD = 2,
+		GONE = 3
+	} __rte_cache_aligned state_flags[RTE_KEEPALIVE_MAXCORES];
+
+	/** Last-seen-alive timestamps */
+	uint64_t last_alive[RTE_KEEPALIVE_MAXCORES];
+
+	/**
+	 * Cores to check.
+	 * Indexed by core id, non-zero if the core should be checked.
+	 */
+	uint8_t active_cores[RTE_KEEPALIVE_MAXCORES];
+
+	/** Dead core handler. */
+	rte_keepalive_failure_callback_t callback;
+
+	/**
+	 * Dead core handler app data.
+	 * Pointer is passed to dead core handler.
+	 */
+	void *callback_data;
+	uint64_t tsc_initial;
+	uint64_t tsc_mhz;
+};
+
+
+/**
+ * Initialise keepalive sub-system.
+ * @param callback
+ *   Function called upon detection of a dead core.
+ * @param data
+ *   Data pointer to be passed to function callback.
+ * @return
+ *   Keepalive structure success, NULL on failure.
+ */
+struct rte_keepalive *rte_keepalive_create(
+	rte_keepalive_failure_callback_t callback,
+	void *data);
+
+
+/**
+ * @param *ptr_timer Triggering timer (unused)
+ * @param *ptr_data  Data pointer (keepalive structure)
+ */
+void rte_keepalive_dispatch_pings(void *ptr_timer, void *ptr_data);
+
+
+/**
+ * Registers a core for keepalive checks.
+ * @param *keepcfg
+ *   Keepalive structure pointer
+ * @param id_core
+ *   ID number of core to register.
+ */
+void rte_keepalive_register_core(struct rte_keepalive *keepcfg,
+	const int id_core);
+
+
+/**
+ * Per-core keepalive check.
+ * @param *keepcfg
+ *   Keepalive structure pointer
+ *
+ * This function needs to be called from within the main process loop of
+ * the LCore to be checked.
+ */
+static inline void
+rte_keepalive_mark_alive(struct rte_keepalive *keepcfg)
+{
+	keepcfg->state_flags[rte_lcore_id()] = 1;
+}
+
+
+#endif /* _KEEPALIVE_H_ */
diff --git a/lib/librte_eal/common/rte_keepalive.c b/lib/librte_eal/common/rte_keepalive.c
new file mode 100644
index 0000000..6a54f20
--- /dev/null
+++ b/lib/librte_eal/common/rte_keepalive.c
@@ -0,0 +1,124 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright 2015 Intel Shannon Ltd. 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 <inttypes.h>
+
+#include <rte_cycles.h>
+#include <rte_lcore.h>
+#include <rte_keepalive.h>
+
+#ifdef KEEPALIVE_DEBUG_MSGS
+static void
+print_trace(const char *msg, struct rte_keepalive *keepcfg, int idx_core)
+{
+	printf("%sLast seen %" PRId64  "ms ago.\n",
+		msg,
+		((rte_rdtsc() - keepcfg->last_alive[idx_core])*1000)
+		/ rte_get_tsc_hz()
+	      );
+}
+#else
+static void
+print_trace(__attribute__((unused)) const char *msg,
+	__attribute__((unused)) struct rte_keepalive *keepcfg,
+	__attribute__((unused)) int idx_core)
+{
+}
+#endif
+
+
+
+void
+rte_keepalive_dispatch_pings(__attribute__((unused)) void *ptr_timer,
+	void *ptr_data)
+{
+	struct rte_keepalive *keepcfg = (struct rte_keepalive *)ptr_data;
+	int idx_core;
+
+	for (idx_core = 0; idx_core < RTE_KEEPALIVE_MAXCORES; idx_core++) {
+		if (keepcfg->active_cores[idx_core] == 0)
+			continue;
+		switch (keepcfg->state_flags[idx_core]) {
+		case ALIVE: /* Alive */
+			keepcfg->state_flags[idx_core] = 0;
+			keepcfg->last_alive[idx_core] = rte_rdtsc();
+			break;
+		case MISSING: /* MIA */
+			print_trace("Core MIA. ", keepcfg, idx_core);
+			keepcfg->state_flags[idx_core] = 2;
+			break;
+		case DEAD: /* Dead */
+			keepcfg->state_flags[idx_core] = 3;
+			print_trace("Core died. ", keepcfg, idx_core);
+			if (keepcfg->callback)
+				keepcfg->callback(
+					keepcfg->callback_data,
+					idx_core
+					);
+			break;
+		case GONE: /* Buried */
+			break;
+		}
+	}
+}
+
+
+struct rte_keepalive *
+rte_keepalive_create(rte_keepalive_failure_callback_t callback,
+	void *data)
+{
+	int idx_core;
+	struct rte_keepalive *keepcfg;
+
+	keepcfg = malloc(sizeof(struct rte_keepalive));
+	if (keepcfg != NULL) {
+		for (idx_core = 0;
+				idx_core < RTE_KEEPALIVE_MAXCORES;
+				idx_core++) {
+			keepcfg->state_flags[idx_core] = 0;
+			keepcfg->active_cores[idx_core] = 0;
+		}
+		keepcfg->callback = callback;
+		keepcfg->callback_data = data;
+		keepcfg->tsc_initial = rte_rdtsc();
+		keepcfg->tsc_mhz = rte_get_tsc_hz() / 1000;
+	}
+	return keepcfg;
+}
+
+
+void
+rte_keepalive_register_core(struct rte_keepalive *keepcfg, const int id_core)
+{
+	if (id_core < RTE_KEEPALIVE_MAXCORES)
+		keepcfg->active_cores[id_core] = 1;
+}
diff --git a/lib/librte_eal/linuxapp/eal/Makefile b/lib/librte_eal/linuxapp/eal/Makefile
index d62196e..05a44d7 100644
--- a/lib/librte_eal/linuxapp/eal/Makefile
+++ b/lib/librte_eal/linuxapp/eal/Makefile
@@ -90,6 +90,7 @@ SRCS-$(CONFIG_RTE_LIBRTE_EAL_LINUXAPP) += eal_common_thread.c
 SRCS-$(CONFIG_RTE_LIBRTE_EAL_LINUXAPP) += rte_malloc.c
 SRCS-$(CONFIG_RTE_LIBRTE_EAL_LINUXAPP) += malloc_elem.c
 SRCS-$(CONFIG_RTE_LIBRTE_EAL_LINUXAPP) += malloc_heap.c
+SRCS-$(CONFIG_RTE_LIBRTE_EAL_LINUXAPP) += rte_keepalive.c
 
 CFLAGS_eal.o := -D_GNU_SOURCE
 CFLAGS_eal_interrupts.o := -D_GNU_SOURCE
-- 
1.9.3

^ permalink raw reply	[flat|nested] 44+ messages in thread

* [dpdk-dev] [PATCH v3 2/3] docs: add keep alive sample app guide
  2015-10-28  8:52   ` [dpdk-dev] [PATCH v3 0/3] Keepalive monitoring & reporting Remy Horton
  2015-10-28  8:52     ` [dpdk-dev] [PATCH v3 1/3] rte: add keep alive functionality Remy Horton
@ 2015-10-28  8:52     ` Remy Horton
  2015-10-28 11:22       ` Van Haaren, Harry
  2015-10-28  8:52     ` [dpdk-dev] [PATCH v3 3/3] example: add keep alive sample application Remy Horton
  2015-11-05 11:32     ` [dpdk-dev] [PATCH v4 0/3] Keepalive monitoring & reporting Remy Horton
  3 siblings, 1 reply; 44+ messages in thread
From: Remy Horton @ 2015-10-28  8:52 UTC (permalink / raw)
  To: dev; +Cc: John J Browne

Signed-off-by: Maryam Tahhan <maryam.tahhan@intel.com>
Signed-off-by: John J Browne <john.j.browne@intel.com>
Signed-off-by: Remy Horton <remy.horton@intel.com>
---
 doc/guides/sample_app_ug/index.rst      |   1 +
 doc/guides/sample_app_ug/keep_alive.rst | 191 ++++++++++++++++++++++++++++++++
 2 files changed, 192 insertions(+)
 create mode 100644 doc/guides/sample_app_ug/keep_alive.rst

diff --git a/doc/guides/sample_app_ug/index.rst b/doc/guides/sample_app_ug/index.rst
index 9beedd9..11b8b14 100644
--- a/doc/guides/sample_app_ug/index.rst
+++ b/doc/guides/sample_app_ug/index.rst
@@ -49,6 +49,7 @@ Sample Applications User Guide
     ipv4_multicast
     ip_reassembly
     kernel_nic_interface
+    keep_alive
     l2_forward_job_stats
     l2_forward_real_virtual
     l3_forward
diff --git a/doc/guides/sample_app_ug/keep_alive.rst b/doc/guides/sample_app_ug/keep_alive.rst
new file mode 100644
index 0000000..080811b
--- /dev/null
+++ b/doc/guides/sample_app_ug/keep_alive.rst
@@ -0,0 +1,191 @@
+
+..  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.
+
+Keep Alive Sample Application
+=============================
+
+The Keep Alive application is a simple example of a
+heartbeat/watchdog for packet processing cores. It demonstrates how
+to detect 'failed' DPDK cores and notify a fault management entity
+of this failure. Its purpose is to ensure the failure of the core
+does not result in a fault that is not detectable by a management
+entity.
+
+
+Overview
+--------
+
+The application demonstrates how to protect against 'silent outages'
+on packet processing cores. A Keep Alive Monitor Agent Core (master)
+monitors the state of packet processing cores (worker cores) by
+dispatching pings at a regular time interval (default is 5ms) and
+monitoring the state of the cores. Cores states are: Alive, MIA, Dead
+or Buried. MIA indicates a missed ping, and Dead indicates two missed
+pings within the specified time interval. When a core is Dead, a
+callback function is invoked to restart the packet processing core;
+A real life application might use this callback function to notify a
+higher level fault management entity of the core failure in order to
+take the appropriate corrective action.
+
+Note: Only the worker cores are monitored. A local (on the host) mechanism
+or agent to supervise the Keep Alive Monitor Agent Core DPDK core is required
+to detect its failure.
+
+Note: This application is based on the L2 forwarding application. As
+such, the initialization and run-time paths are very similar to those
+of the L2 forwarding application.
+
+Compiling the Application
+-------------------------
+
+To compile the application:
+
+#.  Go to the sample application directory:
+
+    .. code-block:: console
+
+        export RTE_SDK=/path/to/rte_sdk cd ${RTE_SDK}/examples/keep_alive
+
+#.  Set the target (a default target is used if not specified). For example:
+
+    .. code-block:: console
+
+        export RTE_TARGET=x86_64-native-linuxapp-gcc
+
+    See the *DPDK Getting Started Guide* for possible RTE_TARGET values.
+
+#.  Build the application:
+
+    .. code-block:: console
+
+        make
+
+Running the Application
+-----------------------
+
+The application has a number of command line options:
+
+.. code-block:: console
+
+    ./build/l2fwd-keepalive [EAL options] \
+            -- -p PORTMASK [-q NQ] [-K PERIOD] [-T PERIOD]
+
+where,
+
+* ``p PORTMASK``: A hexadecimal bitmask of the ports to configure
+
+* ``q NQ``: A number of queues (=ports) per lcore (default is 1)
+
+* ``K PERIOD``: Heartbeat check period in ms(5ms default; 86400 max)
+
+* ``T PERIOD``: statistics will be refreshed each PERIOD seconds (0 to
+  disable, 10 default, 86400 maximum).
+
+To run the application in linuxapp environment with 4 lcores, 16 ports
+8 RX queues per lcore and a ping interval of 10ms, issue the command:
+
+.. code-block:: console
+
+    ./build/l2fwd-keepalive -c f -n 4 -- -q 8 -p ffff -K 10
+
+Refer to the *DPDK Getting Started Guide* for general information on
+running applications and the Environment Abstraction Layer (EAL)
+options.
+
+
+Explanation
+-----------
+
+The following sections provide some explanation of the The
+Keep-Alive/'Liveliness' conceptual scheme. As mentioned in the
+overview section, the initialization and run-time paths are very
+similar to those of the L2 forwarding application (see Chapter 9
+"L2 Forwarding Sample Application (in Real and Virtualized
+Environments)" for more information).
+
+The Keep-Alive/'Liveliness' conceptual scheme:
+
+* A Keep- Alive Agent Runs every N Milliseconds.
+
+* DPDK Cores respond to the keep-alive agent.
+
+* If keep-alive agent detects time-outs, it notifies the
+  fault management entity through a callback function.
+
+The following sections provide some explanation of the code aspects
+that are specific to the Keep Alive sample application.
+
+The heartbeat functionality is initialized with a struct
+rte_heartbeat and the callback function to invoke in the
+case of a timeout.
+
+.. code-block:: c
+
+    rte_global_keepalive_info = rte_keepalive_create(&dead_core, NULL);
+    if (rte_global_hbeat_info == NULL)
+        rte_exit(EXIT_FAILURE, "keepalive_create() failed");
+
+The function that issues the pings hbeat_dispatch_pings()
+is configured to run every check_period milliseconds.
+
+.. code-block:: c
+
+    if (rte_timer_reset(&hb_timer,
+            (check_period * rte_get_timer_hz()) / 1000,
+            PERIODICAL,
+            rte_lcore_id(),
+            &hbeat_dispatch_pings, rte_global_keepalive_info
+            ) != 0 )
+        rte_exit(EXIT_FAILURE, "Keepalive setup failure.\n");
+
+The rest of the initialization and run-time path follows
+the same paths as the the L2 forwarding application. The only
+addition to the main processing loop is the mark alive
+functionality and the example random failures.
+
+.. code-block:: c
+
+    rte_keepalive_mark_alive(&rte_global_hbeat_info);
+    cur_tsc = rte_rdtsc();
+
+    /* Die randomly within 7 secs for demo purposes.. */
+    if (cur_tsc - tsc_initial > tsc_lifetime)
+    break;
+
+The rte_keepalive_mark_alive function simply sets the core state to alive.
+
+.. code-block:: c
+
+    static inline void
+    rte_keepalive_mark_alive(struct rte_heartbeat *keepcfg)
+    {
+        keepcfg->state_flags[rte_lcore_id()] = 1;
+    }
-- 
1.9.3

^ permalink raw reply	[flat|nested] 44+ messages in thread

* [dpdk-dev] [PATCH v3 3/3] example: add keep alive sample application
  2015-10-28  8:52   ` [dpdk-dev] [PATCH v3 0/3] Keepalive monitoring & reporting Remy Horton
  2015-10-28  8:52     ` [dpdk-dev] [PATCH v3 1/3] rte: add keep alive functionality Remy Horton
  2015-10-28  8:52     ` [dpdk-dev] [PATCH v3 2/3] docs: add keep alive sample app guide Remy Horton
@ 2015-10-28  8:52     ` Remy Horton
  2015-10-28 12:28       ` Tahhan, Maryam
  2015-11-05 11:32     ` [dpdk-dev] [PATCH v4 0/3] Keepalive monitoring & reporting Remy Horton
  3 siblings, 1 reply; 44+ messages in thread
From: Remy Horton @ 2015-10-28  8:52 UTC (permalink / raw)
  To: dev

Modification of l2fwd to demonstrate keep-alive functionality.

Signed-off-by: Remy Horton <remy.horton@intel.com>
---
 examples/l2fwd-keepalive/Makefile |  50 +++
 examples/l2fwd-keepalive/main.c   | 806 ++++++++++++++++++++++++++++++++++++++
 2 files changed, 856 insertions(+)
 create mode 100644 examples/l2fwd-keepalive/Makefile
 create mode 100644 examples/l2fwd-keepalive/main.c

diff --git a/examples/l2fwd-keepalive/Makefile b/examples/l2fwd-keepalive/Makefile
new file mode 100644
index 0000000..568edcb
--- /dev/null
+++ b/examples/l2fwd-keepalive/Makefile
@@ -0,0 +1,50 @@
+#   BSD LICENSE
+#
+#   Copyright(c) 2010-2014 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 overridden by command line or environment
+RTE_TARGET ?= x86_64-native-linuxapp-gcc
+
+include $(RTE_SDK)/mk/rte.vars.mk
+
+# binary name
+APP = l2fwd-keepalive
+
+# all source are stored in SRCS-y
+SRCS-y := main.c
+
+CFLAGS += -O3
+CFLAGS += $(WERROR_FLAGS)
+
+include $(RTE_SDK)/mk/rte.extapp.mk
diff --git a/examples/l2fwd-keepalive/main.c b/examples/l2fwd-keepalive/main.c
new file mode 100644
index 0000000..8d7b09e
--- /dev/null
+++ b/examples/l2fwd-keepalive/main.c
@@ -0,0 +1,806 @@
+/*-
+ *   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 <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 <rte_common.h>
+#include <rte_log.h>
+#include <rte_memory.h>
+#include <rte_memcpy.h>
+#include <rte_memzone.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_timer.h>
+#include <rte_keepalive.h>
+
+#define RTE_LOGTYPE_L2FWD RTE_LOGTYPE_USER1
+
+#define NB_MBUF   8192
+
+#define MAX_PKT_BURST 32
+#define BURST_TX_DRAIN_US 100 /* TX drain every ~100us */
+
+/*
+ * 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;
+
+/* 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 const 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,
+	},
+};
+
+struct rte_mempool *l2fwd_pktmbuf_pool = NULL;
+
+/* 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 1
+#define MAX_TIMER_PERIOD 86400 /* 1 day max */
+static int64_t timer_period = 10 * TIMER_MILLISECOND * 1000; /* 10 seconds */
+static int64_t check_period = 5; /* default check cycle is 5ms */
+
+/* Keepalive structure */
+struct rte_keepalive *rte_global_keepalive_info;
+
+/* Print out statistics on packets dropped */
+static void
+print_stats(__attribute__((unused)) struct rte_timer *ptr_timer,
+	__attribute__((unused)) void *ptr_data)
+{
+	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 ------------------------------"
+			   "\nPackets sent: %24"PRIu64
+			   "\nPackets received: %20"PRIu64
+			   "\nPackets dropped: %21"PRIu64,
+			   portid,
+			   port_statistics[portid].tx,
+			   port_statistics[portid].rx,
+			   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 ==============================="
+		   "\nTotal packets sent: %18"PRIu64
+		   "\nTotal packets received: %14"PRIu64
+		   "\nTotal packets dropped: %15"PRIu64,
+		   total_packets_tx,
+		   total_packets_rx,
+		   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 = &eth->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], &eth->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;
+	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;
+
+	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);
+	}
+
+	uint64_t tsc_initial = rte_rdtsc();
+	uint64_t tsc_lifetime = (rand()&0x07) * rte_get_tsc_hz();
+
+	while (1) {
+		/* Keepalive heartbeat */
+		rte_keepalive_mark_alive(rte_global_keepalive_info);
+
+		cur_tsc = rte_rdtsc();
+
+		/*
+		 * Die randomly within 7 secs for demo purposes if
+		 * keepalive enabled
+		 */
+		if (check_period > 0 && cur_tsc - tsc_initial > tsc_lifetime)
+			break;
+
+		/*
+		 * 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;
+			}
+
+			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"
+	       "  -K PERIOD: Keepalive check period (5 default; 86400 max)\n"
+		   "  -T PERIOD: statistics will be refreshed each PERIOD seconds (0 to disable, 10 default, 86400 maximum)\n",
+	       prgname);
+}
+
+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_check_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;
+}
+
+/* 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:K:",
+				  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;
+
+		/* Check period */
+		case 'K':
+			check_period = l2fwd_parse_check_period(optarg);
+			if (check_period < 0) {
+				printf("invalid check period\n");
+				l2fwd_usage(prgname);
+				return -1;
+			}
+			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 "
+						"Mbps - %s\n", (uint8_t)portid,
+						(unsigned)link.link_speed,
+				(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 void
+dead_core(__attribute__((unused)) void *ptr_data, const int id_core)
+{
+	printf("Dead core %i - restarting..\n", id_core);
+	if (rte_eal_get_lcore_state(id_core) == FINISHED) {
+		rte_eal_wait_lcore(id_core);
+		rte_eal_remote_launch(l2fwd_launch_one_lcore, NULL, id_core);
+	} else {
+		printf("..false positive!\n");
+	}
+}
+
+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 EAL */
+	ret = rte_eal_init(argc, argv);
+	if (ret < 0)
+		rte_exit(EXIT_FAILURE, "Invalid EAL arguments\n");
+	argc -= ret;
+	argv += ret;
+
+	l2fwd_enabled_port_mask = 0;
+
+	/* 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_pktmbuf_pool_create("mbuf_pool", NB_MBUF, 32,
+		0, RTE_MBUF_DEFAULT_BUF_SIZE, rte_socket_id());
+	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 = 1;
+	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);
+		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);
+
+		/* Start device */
+		ret = rte_eth_dev_start(portid);
+		if (ret < 0)
+			rte_exit(EXIT_FAILURE,
+				"rte_eth_dev_start:err=%d, port=%u\n",
+				  ret, (unsigned) portid);
+
+		rte_eth_promiscuous_enable(portid);
+
+		printf("Port %u, MAC address: "
+			"%02X:%02X:%02X:%02X:%02X:%02X\n\n",
+			(unsigned) portid,
+			l2fwd_ports_eth_addr[portid].addr_bytes[0],
+			l2fwd_ports_eth_addr[portid].addr_bytes[1],
+			l2fwd_ports_eth_addr[portid].addr_bytes[2],
+			l2fwd_ports_eth_addr[portid].addr_bytes[3],
+			l2fwd_ports_eth_addr[portid].addr_bytes[4],
+			l2fwd_ports_eth_addr[portid].addr_bytes[5]);
+
+		/* initialize port stats */
+		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);
+
+	struct rte_timer hb_timer, stats_timer;
+
+	rte_timer_subsystem_init();
+	rte_timer_init(&stats_timer);
+
+	if (check_period > 0) {
+		rte_global_keepalive_info =
+			rte_keepalive_create(&dead_core, NULL);
+		if (rte_global_keepalive_info == NULL)
+			rte_exit(EXIT_FAILURE, "init_keep_alive() failed");
+		rte_timer_init(&hb_timer);
+		if (rte_timer_reset(&hb_timer,
+				(check_period * rte_get_timer_hz()) / 1000,
+				PERIODICAL,
+				rte_lcore_id(),
+				(void(*)(struct rte_timer*, void*))
+				&rte_keepalive_dispatch_pings,
+				rte_global_keepalive_info
+				) != 0 )
+			rte_exit(EXIT_FAILURE, "Keepalive setup failure.\n");
+	}
+	if (timer_period > 0) {
+		if (rte_timer_reset(&stats_timer,
+				(timer_period * rte_get_timer_hz()) / 1000,
+				PERIODICAL,
+				rte_lcore_id(),
+				&print_stats, NULL
+				) != 0 )
+			rte_exit(EXIT_FAILURE, "Stats setup failure.\n");
+	}
+	/* launch per-lcore init on every slave lcore */
+	RTE_LCORE_FOREACH_SLAVE(lcore_id) {
+		struct lcore_queue_conf *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
+				);
+		else {
+			rte_eal_remote_launch(
+				l2fwd_launch_one_lcore,
+				NULL,
+				lcore_id
+				);
+			rte_keepalive_register_core(rte_global_keepalive_info,
+				lcore_id);
+		}
+	}
+	for (;;) {
+		rte_timer_manage();
+		rte_delay_ms(5);
+		}
+
+	RTE_LCORE_FOREACH_SLAVE(lcore_id) {
+		if (rte_eal_wait_lcore(lcore_id) < 0)
+			return -1;
+	}
+
+	return 0;
+}
-- 
1.9.3

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [dpdk-dev] [PATCH v3 2/3] docs: add keep alive sample app guide
  2015-10-28  8:52     ` [dpdk-dev] [PATCH v3 2/3] docs: add keep alive sample app guide Remy Horton
@ 2015-10-28 11:22       ` Van Haaren, Harry
  0 siblings, 0 replies; 44+ messages in thread
From: Van Haaren, Harry @ 2015-10-28 11:22 UTC (permalink / raw)
  To: Horton, Remy, dev; +Cc: Browne, John J

> From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of Remy Horton
> Sent: Wednesday, October 28, 2015 8:52 AM
> To: dev@dpdk.org
> Cc: Browne, John J
> Subject: [dpdk-dev] [PATCH v3 2/3] docs: add keep alive sample app guide
> 
> Signed-off-by: Maryam Tahhan <maryam.tahhan@intel.com>
> Signed-off-by: John J Browne <john.j.browne@intel.com>
> Signed-off-by: Remy Horton <remy.horton@intel.com>
> ---
>  doc/guides/sample_app_ug/index.rst      |   1 +
>  doc/guides/sample_app_ug/keep_alive.rst | 191 ++++++++++++++++++++++++++++++++
>  2 files changed, 192 insertions(+)
>  create mode 100644 doc/guides/sample_app_ug/keep_alive.rst

Acked-by: Harry van Haaren <harry.van.haaren@intel.com>

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [dpdk-dev] [PATCH v3 1/3] rte: add keep alive functionality
  2015-10-28  8:52     ` [dpdk-dev] [PATCH v3 1/3] rte: add keep alive functionality Remy Horton
@ 2015-10-28 12:25       ` Tahhan, Maryam
  2015-11-04  1:48       ` Thomas Monjalon
  2015-11-04  1:54       ` Thomas Monjalon
  2 siblings, 0 replies; 44+ messages in thread
From: Tahhan, Maryam @ 2015-10-28 12:25 UTC (permalink / raw)
  To: Horton, Remy, dev

> From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of Remy Horton
> Sent: Wednesday, October 28, 2015 8:52 AM
> To: dev@dpdk.org
> Subject: [dpdk-dev] [PATCH v3 1/3] rte: add keep alive functionality
> 
> Adds functions for detecting and reporting the live-ness of LCores, the
> primary requirement of which is minimal overheads for the
> core(s) being checked. Core failures are notified via an application defined
> callback.
> 
> Signed-off-by: Remy Horton <remy.horton@intel.com>
> ---

Acked-by: Maryam Tahhan <maryam.tahhan@intel.com>

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [dpdk-dev] [PATCH v3 3/3] example: add keep alive sample application
  2015-10-28  8:52     ` [dpdk-dev] [PATCH v3 3/3] example: add keep alive sample application Remy Horton
@ 2015-10-28 12:28       ` Tahhan, Maryam
  0 siblings, 0 replies; 44+ messages in thread
From: Tahhan, Maryam @ 2015-10-28 12:28 UTC (permalink / raw)
  To: Horton, Remy, dev

> From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of Remy Horton
> Sent: Wednesday, October 28, 2015 8:52 AM
> To: dev@dpdk.org
> Subject: [dpdk-dev] [PATCH v3 3/3] example: add keep alive sample
> application
> 
> Modification of l2fwd to demonstrate keep-alive functionality.
> 
> Signed-off-by: Remy Horton <remy.horton@intel.com>
> ---

Acked-by: Maryam Tahhan <maryam.tahhan@intel.com>

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [dpdk-dev] [PATCH v3 1/3] rte: add keep alive functionality
  2015-10-28  8:52     ` [dpdk-dev] [PATCH v3 1/3] rte: add keep alive functionality Remy Horton
  2015-10-28 12:25       ` Tahhan, Maryam
@ 2015-11-04  1:48       ` Thomas Monjalon
  2015-11-04  1:54       ` Thomas Monjalon
  2 siblings, 0 replies; 44+ messages in thread
From: Thomas Monjalon @ 2015-11-04  1:48 UTC (permalink / raw)
  To: Remy Horton; +Cc: dev

2015-10-28 08:52, Remy Horton:
> +/**
> + * @file keepalive.h
> + * DPDK RTE LCore Keepalive Monitor.
> + *
> + **/

The filename is rte_keepalive.h (seen with doxygen).

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [dpdk-dev] [PATCH v3 1/3] rte: add keep alive functionality
  2015-10-28  8:52     ` [dpdk-dev] [PATCH v3 1/3] rte: add keep alive functionality Remy Horton
  2015-10-28 12:25       ` Tahhan, Maryam
  2015-11-04  1:48       ` Thomas Monjalon
@ 2015-11-04  1:54       ` Thomas Monjalon
  2 siblings, 0 replies; 44+ messages in thread
From: Thomas Monjalon @ 2015-11-04  1:54 UTC (permalink / raw)
  To: Remy Horton; +Cc: dev

2015-10-28 08:52, Remy Horton:
> Adds functions for detecting and reporting the live-ness of LCores,
> the primary requirement of which is minimal overheads for the
> core(s) being checked. Core failures are notified via an application
> defined callback.
> 
> Signed-off-by: Remy Horton <remy.horton@intel.com>
> ---
>  lib/librte_eal/bsdapp/eal/Makefile            |   1 +
>  lib/librte_eal/common/Makefile                |   2 +-
>  lib/librte_eal/common/include/rte_keepalive.h | 146 ++++++++++++++++++++++++++
>  lib/librte_eal/common/rte_keepalive.c         | 124 ++++++++++++++++++++++
>  lib/librte_eal/linuxapp/eal/Makefile          |   1 +
>  5 files changed, 273 insertions(+), 1 deletion(-)

Why there is no update in the release notes, MAINTAINERS and .map file?

^ permalink raw reply	[flat|nested] 44+ messages in thread

* [dpdk-dev] [PATCH v4 0/3] Keepalive monitoring & reporting
  2015-10-28  8:52   ` [dpdk-dev] [PATCH v3 0/3] Keepalive monitoring & reporting Remy Horton
                       ` (2 preceding siblings ...)
  2015-10-28  8:52     ` [dpdk-dev] [PATCH v3 3/3] example: add keep alive sample application Remy Horton
@ 2015-11-05 11:32     ` Remy Horton
  2015-11-05 11:32       ` [dpdk-dev] [PATCH v4 1/3] rte: add keep alive functionality Remy Horton
                         ` (4 more replies)
  3 siblings, 5 replies; 44+ messages in thread
From: Remy Horton @ 2015-11-05 11:32 UTC (permalink / raw)
  To: dev

This patch-set adds functions for detecting and reporting live-ness of
LCores, the primary requirement of which is minimal overheads for the
core(s) being checked. Core failures are notified via an application
defined callback. As an example l2fwd with random failures is used.

Remy Horton (3):
  rte: add keep alive functionality
  docs: add keep alive sample app guide & release notes
  example: add keep alive sample application

 MAINTAINERS                                     |   4 +
 doc/guides/rel_notes/release_2_2.rst            |   3 +
 doc/guides/sample_app_ug/index.rst              |   1 +
 doc/guides/sample_app_ug/keep_alive.rst         | 191 ++++++
 examples/l2fwd-keepalive/Makefile               |  50 ++
 examples/l2fwd-keepalive/main.c                 | 806 ++++++++++++++++++++++++
 lib/librte_eal/bsdapp/eal/Makefile              |   1 +
 lib/librte_eal/bsdapp/eal/rte_eal_version.map   |   6 +-
 lib/librte_eal/common/Makefile                  |   2 +-
 lib/librte_eal/common/include/rte_keepalive.h   | 146 +++++
 lib/librte_eal/common/rte_keepalive.c           | 124 ++++
 lib/librte_eal/linuxapp/eal/Makefile            |   1 +
 lib/librte_eal/linuxapp/eal/rte_eal_version.map |   6 +-
 13 files changed, 1338 insertions(+), 3 deletions(-)
 create mode 100644 doc/guides/sample_app_ug/keep_alive.rst
 create mode 100644 examples/l2fwd-keepalive/Makefile
 create mode 100644 examples/l2fwd-keepalive/main.c
 create mode 100644 lib/librte_eal/common/include/rte_keepalive.h
 create mode 100644 lib/librte_eal/common/rte_keepalive.c

-- 
1.9.3

^ permalink raw reply	[flat|nested] 44+ messages in thread

* [dpdk-dev] [PATCH v4 1/3] rte: add keep alive functionality
  2015-11-05 11:32     ` [dpdk-dev] [PATCH v4 0/3] Keepalive monitoring & reporting Remy Horton
@ 2015-11-05 11:32       ` Remy Horton
  2015-11-05 16:43         ` Tahhan, Maryam
                           ` (3 more replies)
  2015-11-05 11:32       ` [dpdk-dev] [PATCH v4 2/3] docs: add keep alive sample app guide & release notes Remy Horton
                         ` (3 subsequent siblings)
  4 siblings, 4 replies; 44+ messages in thread
From: Remy Horton @ 2015-11-05 11:32 UTC (permalink / raw)
  To: dev

Adds functions for detecting and reporting the live-ness of LCores,
the primary requirement of which is minimal overheads for the
core(s) being checked. Core failures are notified via an application
defined callback.

Signed-off-by: Remy Horton <remy.horton@intel.com>
---
 lib/librte_eal/bsdapp/eal/Makefile              |   1 +
 lib/librte_eal/bsdapp/eal/rte_eal_version.map   |   6 +-
 lib/librte_eal/common/Makefile                  |   2 +-
 lib/librte_eal/common/include/rte_keepalive.h   | 146 ++++++++++++++++++++++++
 lib/librte_eal/common/rte_keepalive.c           | 124 ++++++++++++++++++++
 lib/librte_eal/linuxapp/eal/Makefile            |   1 +
 lib/librte_eal/linuxapp/eal/rte_eal_version.map |   6 +-
 7 files changed, 283 insertions(+), 3 deletions(-)
 create mode 100644 lib/librte_eal/common/include/rte_keepalive.h
 create mode 100644 lib/librte_eal/common/rte_keepalive.c

diff --git a/lib/librte_eal/bsdapp/eal/Makefile b/lib/librte_eal/bsdapp/eal/Makefile
index a49dcec..65b293f 100644
--- a/lib/librte_eal/bsdapp/eal/Makefile
+++ b/lib/librte_eal/bsdapp/eal/Makefile
@@ -80,6 +80,7 @@ SRCS-$(CONFIG_RTE_LIBRTE_EAL_BSDAPP) += eal_common_thread.c
 SRCS-$(CONFIG_RTE_LIBRTE_EAL_BSDAPP) += rte_malloc.c
 SRCS-$(CONFIG_RTE_LIBRTE_EAL_BSDAPP) += malloc_elem.c
 SRCS-$(CONFIG_RTE_LIBRTE_EAL_BSDAPP) += malloc_heap.c
+SRCS-$(CONFIG_RTE_LIBRTE_EAL_BSDAPP) += rte_keepalive.c
 
 CFLAGS_eal.o := -D_GNU_SOURCE
 #CFLAGS_eal_thread.o := -D_GNU_SOURCE
diff --git a/lib/librte_eal/bsdapp/eal/rte_eal_version.map b/lib/librte_eal/bsdapp/eal/rte_eal_version.map
index 8b00761..f6c29be 100644
--- a/lib/librte_eal/bsdapp/eal/rte_eal_version.map
+++ b/lib/librte_eal/bsdapp/eal/rte_eal_version.map
@@ -130,5 +130,9 @@ DPDK_2.2 {
 	global:
 
 	rte_intr_cap_multiple;
+	rte_keepalive_create;
+	rte_keepalive_dispatch_pings;
+	rte_keepalive_register_core;
+	rte_keepalive_mark_alive;
 
-} DPDK_2.1;
\ No newline at end of file
+} DPDK_2.1;
diff --git a/lib/librte_eal/common/Makefile b/lib/librte_eal/common/Makefile
index 0c43d6a..7f1757a 100644
--- a/lib/librte_eal/common/Makefile
+++ b/lib/librte_eal/common/Makefile
@@ -40,7 +40,7 @@ INC += rte_string_fns.h rte_version.h
 INC += rte_eal_memconfig.h rte_malloc_heap.h
 INC += rte_hexdump.h rte_devargs.h rte_dev.h
 INC += rte_pci_dev_feature_defs.h rte_pci_dev_features.h
-INC += rte_malloc.h
+INC += rte_malloc.h rte_keepalive.h
 
 ifeq ($(CONFIG_RTE_INSECURE_FUNCTION_WARNING),y)
 INC += rte_warnings.h
diff --git a/lib/librte_eal/common/include/rte_keepalive.h b/lib/librte_eal/common/include/rte_keepalive.h
new file mode 100644
index 0000000..01d4205
--- /dev/null
+++ b/lib/librte_eal/common/include/rte_keepalive.h
@@ -0,0 +1,146 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright 2015 Intel Shannon Ltd. 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.
+ */
+
+/**
+ * @file rte_keepalive.h
+ * DPDK RTE LCore Keepalive Monitor.
+ *
+ **/
+
+#ifndef _KEEPALIVE_H_
+#define _KEEPALIVE_H_
+
+#include <rte_memory.h>
+
+#ifndef RTE_KEEPALIVE_MAXCORES
+/**
+ * Number of cores to track.
+ * @note Must be larger than the highest core id. */
+#define RTE_KEEPALIVE_MAXCORES RTE_MAX_LCORE
+#endif
+
+
+/**
+ * Keepalive failure callback.
+ *
+ *  Receives a data pointer passed to rte_keepalive_create() and the id of the
+ *  failed core.
+ */
+typedef void (*rte_keepalive_failure_callback_t)(
+	void *data,
+	const int id_core);
+
+
+/**
+ * Keepalive state structure.
+ * @internal
+ */
+struct rte_keepalive {
+	/** Core Liveness. */
+
+	enum {
+		ALIVE = 1,
+		MISSING = 0,
+		DEAD = 2,
+		GONE = 3
+	} __rte_cache_aligned state_flags[RTE_KEEPALIVE_MAXCORES];
+
+	/** Last-seen-alive timestamps */
+	uint64_t last_alive[RTE_KEEPALIVE_MAXCORES];
+
+	/**
+	 * Cores to check.
+	 * Indexed by core id, non-zero if the core should be checked.
+	 */
+	uint8_t active_cores[RTE_KEEPALIVE_MAXCORES];
+
+	/** Dead core handler. */
+	rte_keepalive_failure_callback_t callback;
+
+	/**
+	 * Dead core handler app data.
+	 * Pointer is passed to dead core handler.
+	 */
+	void *callback_data;
+	uint64_t tsc_initial;
+	uint64_t tsc_mhz;
+};
+
+
+/**
+ * Initialise keepalive sub-system.
+ * @param callback
+ *   Function called upon detection of a dead core.
+ * @param data
+ *   Data pointer to be passed to function callback.
+ * @return
+ *   Keepalive structure success, NULL on failure.
+ */
+struct rte_keepalive *rte_keepalive_create(
+	rte_keepalive_failure_callback_t callback,
+	void *data);
+
+
+/**
+ * @param *ptr_timer Triggering timer (unused)
+ * @param *ptr_data  Data pointer (keepalive structure)
+ */
+void rte_keepalive_dispatch_pings(void *ptr_timer, void *ptr_data);
+
+
+/**
+ * Registers a core for keepalive checks.
+ * @param *keepcfg
+ *   Keepalive structure pointer
+ * @param id_core
+ *   ID number of core to register.
+ */
+void rte_keepalive_register_core(struct rte_keepalive *keepcfg,
+	const int id_core);
+
+
+/**
+ * Per-core keepalive check.
+ * @param *keepcfg
+ *   Keepalive structure pointer
+ *
+ * This function needs to be called from within the main process loop of
+ * the LCore to be checked.
+ */
+static inline void
+rte_keepalive_mark_alive(struct rte_keepalive *keepcfg)
+{
+	keepcfg->state_flags[rte_lcore_id()] = 1;
+}
+
+
+#endif /* _KEEPALIVE_H_ */
diff --git a/lib/librte_eal/common/rte_keepalive.c b/lib/librte_eal/common/rte_keepalive.c
new file mode 100644
index 0000000..6a54f20
--- /dev/null
+++ b/lib/librte_eal/common/rte_keepalive.c
@@ -0,0 +1,124 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright 2015 Intel Shannon Ltd. 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 <inttypes.h>
+
+#include <rte_cycles.h>
+#include <rte_lcore.h>
+#include <rte_keepalive.h>
+
+#ifdef KEEPALIVE_DEBUG_MSGS
+static void
+print_trace(const char *msg, struct rte_keepalive *keepcfg, int idx_core)
+{
+	printf("%sLast seen %" PRId64  "ms ago.\n",
+		msg,
+		((rte_rdtsc() - keepcfg->last_alive[idx_core])*1000)
+		/ rte_get_tsc_hz()
+	      );
+}
+#else
+static void
+print_trace(__attribute__((unused)) const char *msg,
+	__attribute__((unused)) struct rte_keepalive *keepcfg,
+	__attribute__((unused)) int idx_core)
+{
+}
+#endif
+
+
+
+void
+rte_keepalive_dispatch_pings(__attribute__((unused)) void *ptr_timer,
+	void *ptr_data)
+{
+	struct rte_keepalive *keepcfg = (struct rte_keepalive *)ptr_data;
+	int idx_core;
+
+	for (idx_core = 0; idx_core < RTE_KEEPALIVE_MAXCORES; idx_core++) {
+		if (keepcfg->active_cores[idx_core] == 0)
+			continue;
+		switch (keepcfg->state_flags[idx_core]) {
+		case ALIVE: /* Alive */
+			keepcfg->state_flags[idx_core] = 0;
+			keepcfg->last_alive[idx_core] = rte_rdtsc();
+			break;
+		case MISSING: /* MIA */
+			print_trace("Core MIA. ", keepcfg, idx_core);
+			keepcfg->state_flags[idx_core] = 2;
+			break;
+		case DEAD: /* Dead */
+			keepcfg->state_flags[idx_core] = 3;
+			print_trace("Core died. ", keepcfg, idx_core);
+			if (keepcfg->callback)
+				keepcfg->callback(
+					keepcfg->callback_data,
+					idx_core
+					);
+			break;
+		case GONE: /* Buried */
+			break;
+		}
+	}
+}
+
+
+struct rte_keepalive *
+rte_keepalive_create(rte_keepalive_failure_callback_t callback,
+	void *data)
+{
+	int idx_core;
+	struct rte_keepalive *keepcfg;
+
+	keepcfg = malloc(sizeof(struct rte_keepalive));
+	if (keepcfg != NULL) {
+		for (idx_core = 0;
+				idx_core < RTE_KEEPALIVE_MAXCORES;
+				idx_core++) {
+			keepcfg->state_flags[idx_core] = 0;
+			keepcfg->active_cores[idx_core] = 0;
+		}
+		keepcfg->callback = callback;
+		keepcfg->callback_data = data;
+		keepcfg->tsc_initial = rte_rdtsc();
+		keepcfg->tsc_mhz = rte_get_tsc_hz() / 1000;
+	}
+	return keepcfg;
+}
+
+
+void
+rte_keepalive_register_core(struct rte_keepalive *keepcfg, const int id_core)
+{
+	if (id_core < RTE_KEEPALIVE_MAXCORES)
+		keepcfg->active_cores[id_core] = 1;
+}
diff --git a/lib/librte_eal/linuxapp/eal/Makefile b/lib/librte_eal/linuxapp/eal/Makefile
index 7e36b86..26eced5 100644
--- a/lib/librte_eal/linuxapp/eal/Makefile
+++ b/lib/librte_eal/linuxapp/eal/Makefile
@@ -90,6 +90,7 @@ SRCS-$(CONFIG_RTE_LIBRTE_EAL_LINUXAPP) += eal_common_thread.c
 SRCS-$(CONFIG_RTE_LIBRTE_EAL_LINUXAPP) += rte_malloc.c
 SRCS-$(CONFIG_RTE_LIBRTE_EAL_LINUXAPP) += malloc_elem.c
 SRCS-$(CONFIG_RTE_LIBRTE_EAL_LINUXAPP) += malloc_heap.c
+SRCS-$(CONFIG_RTE_LIBRTE_EAL_LINUXAPP) += rte_keepalive.c
 
 CFLAGS_eal.o := -D_GNU_SOURCE
 CFLAGS_eal_interrupts.o := -D_GNU_SOURCE
diff --git a/lib/librte_eal/linuxapp/eal/rte_eal_version.map b/lib/librte_eal/linuxapp/eal/rte_eal_version.map
index cb9f4d6..95726f7 100644
--- a/lib/librte_eal/linuxapp/eal/rte_eal_version.map
+++ b/lib/librte_eal/linuxapp/eal/rte_eal_version.map
@@ -133,5 +133,9 @@ DPDK_2.2 {
 	global:
 
 	rte_intr_cap_multiple;
+	rte_keepalive_create;
+	rte_keepalive_dispatch_pings;
+	rte_keepalive_register_core;
+	rte_keepalive_mark_alive;
 
-} DPDK_2.1;
\ No newline at end of file
+} DPDK_2.1;
-- 
1.9.3

^ permalink raw reply	[flat|nested] 44+ messages in thread

* [dpdk-dev] [PATCH v4 2/3] docs: add keep alive sample app guide & release notes
  2015-11-05 11:32     ` [dpdk-dev] [PATCH v4 0/3] Keepalive monitoring & reporting Remy Horton
  2015-11-05 11:32       ` [dpdk-dev] [PATCH v4 1/3] rte: add keep alive functionality Remy Horton
@ 2015-11-05 11:32       ` Remy Horton
  2015-11-05 16:40         ` Van Haaren, Harry
  2015-11-05 11:32       ` [dpdk-dev] [PATCH v4 3/3] example: add keep alive sample application Remy Horton
                         ` (2 subsequent siblings)
  4 siblings, 1 reply; 44+ messages in thread
From: Remy Horton @ 2015-11-05 11:32 UTC (permalink / raw)
  To: dev

Signed-off-by: Maryam Tahhan <maryam.tahhan@intel.com>
Signed-off-by: John J Browne <john.j.browne@intel.com>
Signed-off-by: Remy Horton <remy.horton@intel.com>
---
 doc/guides/rel_notes/release_2_2.rst    |   3 +
 doc/guides/sample_app_ug/index.rst      |   1 +
 doc/guides/sample_app_ug/keep_alive.rst | 191 ++++++++++++++++++++++++++++++++
 3 files changed, 195 insertions(+)
 create mode 100644 doc/guides/sample_app_ug/keep_alive.rst

diff --git a/doc/guides/rel_notes/release_2_2.rst b/doc/guides/rel_notes/release_2_2.rst
index 59dda59..9f3c524 100644
--- a/doc/guides/rel_notes/release_2_2.rst
+++ b/doc/guides/rel_notes/release_2_2.rst
@@ -94,6 +94,7 @@ New Features
 
 * **Added port hotplug support to xenvirt.**
 
+* **Added keepalive support to EAL.**
 
 Resolved Issues
 ---------------
@@ -187,6 +188,8 @@ Libraries
 Examples
 ~~~~~~~~
 
+* **l2fwd-keepalive: Added keep-alive demonstration.**
+
 
 Other
 ~~~~~
diff --git a/doc/guides/sample_app_ug/index.rst b/doc/guides/sample_app_ug/index.rst
index 9beedd9..11b8b14 100644
--- a/doc/guides/sample_app_ug/index.rst
+++ b/doc/guides/sample_app_ug/index.rst
@@ -49,6 +49,7 @@ Sample Applications User Guide
     ipv4_multicast
     ip_reassembly
     kernel_nic_interface
+    keep_alive
     l2_forward_job_stats
     l2_forward_real_virtual
     l3_forward
diff --git a/doc/guides/sample_app_ug/keep_alive.rst b/doc/guides/sample_app_ug/keep_alive.rst
new file mode 100644
index 0000000..080811b
--- /dev/null
+++ b/doc/guides/sample_app_ug/keep_alive.rst
@@ -0,0 +1,191 @@
+
+..  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.
+
+Keep Alive Sample Application
+=============================
+
+The Keep Alive application is a simple example of a
+heartbeat/watchdog for packet processing cores. It demonstrates how
+to detect 'failed' DPDK cores and notify a fault management entity
+of this failure. Its purpose is to ensure the failure of the core
+does not result in a fault that is not detectable by a management
+entity.
+
+
+Overview
+--------
+
+The application demonstrates how to protect against 'silent outages'
+on packet processing cores. A Keep Alive Monitor Agent Core (master)
+monitors the state of packet processing cores (worker cores) by
+dispatching pings at a regular time interval (default is 5ms) and
+monitoring the state of the cores. Cores states are: Alive, MIA, Dead
+or Buried. MIA indicates a missed ping, and Dead indicates two missed
+pings within the specified time interval. When a core is Dead, a
+callback function is invoked to restart the packet processing core;
+A real life application might use this callback function to notify a
+higher level fault management entity of the core failure in order to
+take the appropriate corrective action.
+
+Note: Only the worker cores are monitored. A local (on the host) mechanism
+or agent to supervise the Keep Alive Monitor Agent Core DPDK core is required
+to detect its failure.
+
+Note: This application is based on the L2 forwarding application. As
+such, the initialization and run-time paths are very similar to those
+of the L2 forwarding application.
+
+Compiling the Application
+-------------------------
+
+To compile the application:
+
+#.  Go to the sample application directory:
+
+    .. code-block:: console
+
+        export RTE_SDK=/path/to/rte_sdk cd ${RTE_SDK}/examples/keep_alive
+
+#.  Set the target (a default target is used if not specified). For example:
+
+    .. code-block:: console
+
+        export RTE_TARGET=x86_64-native-linuxapp-gcc
+
+    See the *DPDK Getting Started Guide* for possible RTE_TARGET values.
+
+#.  Build the application:
+
+    .. code-block:: console
+
+        make
+
+Running the Application
+-----------------------
+
+The application has a number of command line options:
+
+.. code-block:: console
+
+    ./build/l2fwd-keepalive [EAL options] \
+            -- -p PORTMASK [-q NQ] [-K PERIOD] [-T PERIOD]
+
+where,
+
+* ``p PORTMASK``: A hexadecimal bitmask of the ports to configure
+
+* ``q NQ``: A number of queues (=ports) per lcore (default is 1)
+
+* ``K PERIOD``: Heartbeat check period in ms(5ms default; 86400 max)
+
+* ``T PERIOD``: statistics will be refreshed each PERIOD seconds (0 to
+  disable, 10 default, 86400 maximum).
+
+To run the application in linuxapp environment with 4 lcores, 16 ports
+8 RX queues per lcore and a ping interval of 10ms, issue the command:
+
+.. code-block:: console
+
+    ./build/l2fwd-keepalive -c f -n 4 -- -q 8 -p ffff -K 10
+
+Refer to the *DPDK Getting Started Guide* for general information on
+running applications and the Environment Abstraction Layer (EAL)
+options.
+
+
+Explanation
+-----------
+
+The following sections provide some explanation of the The
+Keep-Alive/'Liveliness' conceptual scheme. As mentioned in the
+overview section, the initialization and run-time paths are very
+similar to those of the L2 forwarding application (see Chapter 9
+"L2 Forwarding Sample Application (in Real and Virtualized
+Environments)" for more information).
+
+The Keep-Alive/'Liveliness' conceptual scheme:
+
+* A Keep- Alive Agent Runs every N Milliseconds.
+
+* DPDK Cores respond to the keep-alive agent.
+
+* If keep-alive agent detects time-outs, it notifies the
+  fault management entity through a callback function.
+
+The following sections provide some explanation of the code aspects
+that are specific to the Keep Alive sample application.
+
+The heartbeat functionality is initialized with a struct
+rte_heartbeat and the callback function to invoke in the
+case of a timeout.
+
+.. code-block:: c
+
+    rte_global_keepalive_info = rte_keepalive_create(&dead_core, NULL);
+    if (rte_global_hbeat_info == NULL)
+        rte_exit(EXIT_FAILURE, "keepalive_create() failed");
+
+The function that issues the pings hbeat_dispatch_pings()
+is configured to run every check_period milliseconds.
+
+.. code-block:: c
+
+    if (rte_timer_reset(&hb_timer,
+            (check_period * rte_get_timer_hz()) / 1000,
+            PERIODICAL,
+            rte_lcore_id(),
+            &hbeat_dispatch_pings, rte_global_keepalive_info
+            ) != 0 )
+        rte_exit(EXIT_FAILURE, "Keepalive setup failure.\n");
+
+The rest of the initialization and run-time path follows
+the same paths as the the L2 forwarding application. The only
+addition to the main processing loop is the mark alive
+functionality and the example random failures.
+
+.. code-block:: c
+
+    rte_keepalive_mark_alive(&rte_global_hbeat_info);
+    cur_tsc = rte_rdtsc();
+
+    /* Die randomly within 7 secs for demo purposes.. */
+    if (cur_tsc - tsc_initial > tsc_lifetime)
+    break;
+
+The rte_keepalive_mark_alive function simply sets the core state to alive.
+
+.. code-block:: c
+
+    static inline void
+    rte_keepalive_mark_alive(struct rte_heartbeat *keepcfg)
+    {
+        keepcfg->state_flags[rte_lcore_id()] = 1;
+    }
-- 
1.9.3

^ permalink raw reply	[flat|nested] 44+ messages in thread

* [dpdk-dev] [PATCH v4 3/3] example: add keep alive sample application
  2015-11-05 11:32     ` [dpdk-dev] [PATCH v4 0/3] Keepalive monitoring & reporting Remy Horton
  2015-11-05 11:32       ` [dpdk-dev] [PATCH v4 1/3] rte: add keep alive functionality Remy Horton
  2015-11-05 11:32       ` [dpdk-dev] [PATCH v4 2/3] docs: add keep alive sample app guide & release notes Remy Horton
@ 2015-11-05 11:32       ` Remy Horton
  2015-11-05 16:44         ` Tahhan, Maryam
  2015-11-11  6:52       ` [dpdk-dev] [PATCH v4 0/3] Keepalive monitoring & reporting Cao, Min
  2015-11-18 14:05       ` [dpdk-dev] [PATCH v5 " Remy Horton
  4 siblings, 1 reply; 44+ messages in thread
From: Remy Horton @ 2015-11-05 11:32 UTC (permalink / raw)
  To: dev

Modified version of l2fwd to demonstrate keep-alive functionality.

Signed-off-by: Remy Horton <remy.horton@intel.com>
---
 MAINTAINERS                       |   4 +
 examples/l2fwd-keepalive/Makefile |  50 +++
 examples/l2fwd-keepalive/main.c   | 806 ++++++++++++++++++++++++++++++++++++++
 3 files changed, 860 insertions(+)
 create mode 100644 examples/l2fwd-keepalive/Makefile
 create mode 100644 examples/l2fwd-keepalive/main.c

diff --git a/MAINTAINERS b/MAINTAINERS
index c8be5d2..e6e054e 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -520,3 +520,7 @@ F: examples/tep_termination/
 F: examples/vmdq/
 F: examples/vmdq_dcb/
 F: doc/guides/sample_app_ug/vmdq_dcb_forwarding.rst
+
+M: Remy Horton <remy.horton@intel.com>
+F: examples/l2fwd-keepalive/
+F: doc/guides/sample_app_ug/keep_alive.rst
diff --git a/examples/l2fwd-keepalive/Makefile b/examples/l2fwd-keepalive/Makefile
new file mode 100644
index 0000000..568edcb
--- /dev/null
+++ b/examples/l2fwd-keepalive/Makefile
@@ -0,0 +1,50 @@
+#   BSD LICENSE
+#
+#   Copyright(c) 2010-2014 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 overridden by command line or environment
+RTE_TARGET ?= x86_64-native-linuxapp-gcc
+
+include $(RTE_SDK)/mk/rte.vars.mk
+
+# binary name
+APP = l2fwd-keepalive
+
+# all source are stored in SRCS-y
+SRCS-y := main.c
+
+CFLAGS += -O3
+CFLAGS += $(WERROR_FLAGS)
+
+include $(RTE_SDK)/mk/rte.extapp.mk
diff --git a/examples/l2fwd-keepalive/main.c b/examples/l2fwd-keepalive/main.c
new file mode 100644
index 0000000..8d7b09e
--- /dev/null
+++ b/examples/l2fwd-keepalive/main.c
@@ -0,0 +1,806 @@
+/*-
+ *   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 <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 <rte_common.h>
+#include <rte_log.h>
+#include <rte_memory.h>
+#include <rte_memcpy.h>
+#include <rte_memzone.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_timer.h>
+#include <rte_keepalive.h>
+
+#define RTE_LOGTYPE_L2FWD RTE_LOGTYPE_USER1
+
+#define NB_MBUF   8192
+
+#define MAX_PKT_BURST 32
+#define BURST_TX_DRAIN_US 100 /* TX drain every ~100us */
+
+/*
+ * 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;
+
+/* 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 const 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,
+	},
+};
+
+struct rte_mempool *l2fwd_pktmbuf_pool = NULL;
+
+/* 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 1
+#define MAX_TIMER_PERIOD 86400 /* 1 day max */
+static int64_t timer_period = 10 * TIMER_MILLISECOND * 1000; /* 10 seconds */
+static int64_t check_period = 5; /* default check cycle is 5ms */
+
+/* Keepalive structure */
+struct rte_keepalive *rte_global_keepalive_info;
+
+/* Print out statistics on packets dropped */
+static void
+print_stats(__attribute__((unused)) struct rte_timer *ptr_timer,
+	__attribute__((unused)) void *ptr_data)
+{
+	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 ------------------------------"
+			   "\nPackets sent: %24"PRIu64
+			   "\nPackets received: %20"PRIu64
+			   "\nPackets dropped: %21"PRIu64,
+			   portid,
+			   port_statistics[portid].tx,
+			   port_statistics[portid].rx,
+			   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 ==============================="
+		   "\nTotal packets sent: %18"PRIu64
+		   "\nTotal packets received: %14"PRIu64
+		   "\nTotal packets dropped: %15"PRIu64,
+		   total_packets_tx,
+		   total_packets_rx,
+		   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 = &eth->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], &eth->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;
+	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;
+
+	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);
+	}
+
+	uint64_t tsc_initial = rte_rdtsc();
+	uint64_t tsc_lifetime = (rand()&0x07) * rte_get_tsc_hz();
+
+	while (1) {
+		/* Keepalive heartbeat */
+		rte_keepalive_mark_alive(rte_global_keepalive_info);
+
+		cur_tsc = rte_rdtsc();
+
+		/*
+		 * Die randomly within 7 secs for demo purposes if
+		 * keepalive enabled
+		 */
+		if (check_period > 0 && cur_tsc - tsc_initial > tsc_lifetime)
+			break;
+
+		/*
+		 * 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;
+			}
+
+			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"
+	       "  -K PERIOD: Keepalive check period (5 default; 86400 max)\n"
+		   "  -T PERIOD: statistics will be refreshed each PERIOD seconds (0 to disable, 10 default, 86400 maximum)\n",
+	       prgname);
+}
+
+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_check_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;
+}
+
+/* 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:K:",
+				  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;
+
+		/* Check period */
+		case 'K':
+			check_period = l2fwd_parse_check_period(optarg);
+			if (check_period < 0) {
+				printf("invalid check period\n");
+				l2fwd_usage(prgname);
+				return -1;
+			}
+			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 "
+						"Mbps - %s\n", (uint8_t)portid,
+						(unsigned)link.link_speed,
+				(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 void
+dead_core(__attribute__((unused)) void *ptr_data, const int id_core)
+{
+	printf("Dead core %i - restarting..\n", id_core);
+	if (rte_eal_get_lcore_state(id_core) == FINISHED) {
+		rte_eal_wait_lcore(id_core);
+		rte_eal_remote_launch(l2fwd_launch_one_lcore, NULL, id_core);
+	} else {
+		printf("..false positive!\n");
+	}
+}
+
+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 EAL */
+	ret = rte_eal_init(argc, argv);
+	if (ret < 0)
+		rte_exit(EXIT_FAILURE, "Invalid EAL arguments\n");
+	argc -= ret;
+	argv += ret;
+
+	l2fwd_enabled_port_mask = 0;
+
+	/* 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_pktmbuf_pool_create("mbuf_pool", NB_MBUF, 32,
+		0, RTE_MBUF_DEFAULT_BUF_SIZE, rte_socket_id());
+	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 = 1;
+	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);
+		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);
+
+		/* Start device */
+		ret = rte_eth_dev_start(portid);
+		if (ret < 0)
+			rte_exit(EXIT_FAILURE,
+				"rte_eth_dev_start:err=%d, port=%u\n",
+				  ret, (unsigned) portid);
+
+		rte_eth_promiscuous_enable(portid);
+
+		printf("Port %u, MAC address: "
+			"%02X:%02X:%02X:%02X:%02X:%02X\n\n",
+			(unsigned) portid,
+			l2fwd_ports_eth_addr[portid].addr_bytes[0],
+			l2fwd_ports_eth_addr[portid].addr_bytes[1],
+			l2fwd_ports_eth_addr[portid].addr_bytes[2],
+			l2fwd_ports_eth_addr[portid].addr_bytes[3],
+			l2fwd_ports_eth_addr[portid].addr_bytes[4],
+			l2fwd_ports_eth_addr[portid].addr_bytes[5]);
+
+		/* initialize port stats */
+		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);
+
+	struct rte_timer hb_timer, stats_timer;
+
+	rte_timer_subsystem_init();
+	rte_timer_init(&stats_timer);
+
+	if (check_period > 0) {
+		rte_global_keepalive_info =
+			rte_keepalive_create(&dead_core, NULL);
+		if (rte_global_keepalive_info == NULL)
+			rte_exit(EXIT_FAILURE, "init_keep_alive() failed");
+		rte_timer_init(&hb_timer);
+		if (rte_timer_reset(&hb_timer,
+				(check_period * rte_get_timer_hz()) / 1000,
+				PERIODICAL,
+				rte_lcore_id(),
+				(void(*)(struct rte_timer*, void*))
+				&rte_keepalive_dispatch_pings,
+				rte_global_keepalive_info
+				) != 0 )
+			rte_exit(EXIT_FAILURE, "Keepalive setup failure.\n");
+	}
+	if (timer_period > 0) {
+		if (rte_timer_reset(&stats_timer,
+				(timer_period * rte_get_timer_hz()) / 1000,
+				PERIODICAL,
+				rte_lcore_id(),
+				&print_stats, NULL
+				) != 0 )
+			rte_exit(EXIT_FAILURE, "Stats setup failure.\n");
+	}
+	/* launch per-lcore init on every slave lcore */
+	RTE_LCORE_FOREACH_SLAVE(lcore_id) {
+		struct lcore_queue_conf *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
+				);
+		else {
+			rte_eal_remote_launch(
+				l2fwd_launch_one_lcore,
+				NULL,
+				lcore_id
+				);
+			rte_keepalive_register_core(rte_global_keepalive_info,
+				lcore_id);
+		}
+	}
+	for (;;) {
+		rte_timer_manage();
+		rte_delay_ms(5);
+		}
+
+	RTE_LCORE_FOREACH_SLAVE(lcore_id) {
+		if (rte_eal_wait_lcore(lcore_id) < 0)
+			return -1;
+	}
+
+	return 0;
+}
-- 
1.9.3

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [dpdk-dev] [PATCH v4 2/3] docs: add keep alive sample app guide & release notes
  2015-11-05 11:32       ` [dpdk-dev] [PATCH v4 2/3] docs: add keep alive sample app guide & release notes Remy Horton
@ 2015-11-05 16:40         ` Van Haaren, Harry
  0 siblings, 0 replies; 44+ messages in thread
From: Van Haaren, Harry @ 2015-11-05 16:40 UTC (permalink / raw)
  To: Horton, Remy, dev

> From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of Remy Horton
> Subject: [dpdk-dev] [PATCH v4 2/3] docs: add keep alive sample app guide & release notes
> 
> Signed-off-by: Maryam Tahhan <maryam.tahhan@intel.com>
> Signed-off-by: John J Browne <john.j.browne@intel.com>
> Signed-off-by: Remy Horton <remy.horton@intel.com>

Acked-by: Harry van Haaren <harry.van.haaren@intel.com>

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [dpdk-dev] [PATCH v4 1/3] rte: add keep alive functionality
  2015-11-05 11:32       ` [dpdk-dev] [PATCH v4 1/3] rte: add keep alive functionality Remy Horton
@ 2015-11-05 16:43         ` Tahhan, Maryam
  2015-11-10 14:02         ` Thomas Monjalon
                           ` (2 subsequent siblings)
  3 siblings, 0 replies; 44+ messages in thread
From: Tahhan, Maryam @ 2015-11-05 16:43 UTC (permalink / raw)
  To: Horton, Remy, dev

> From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of Remy Horton
> Sent: Thursday, November 5, 2015 11:33 AM
> To: dev@dpdk.org
> Subject: [dpdk-dev] [PATCH v4 1/3] rte: add keep alive functionality
> 
> Adds functions for detecting and reporting the live-ness of LCores, the primary
> requirement of which is minimal overheads for the
> core(s) being checked. Core failures are notified via an application defined
> callback.
> 
> Signed-off-by: Remy Horton <remy.horton@intel.com>
> ---

Acked-by: Maryam Tahhan <maryam.tahhan@intel.com>

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [dpdk-dev] [PATCH v4 3/3] example: add keep alive sample application
  2015-11-05 11:32       ` [dpdk-dev] [PATCH v4 3/3] example: add keep alive sample application Remy Horton
@ 2015-11-05 16:44         ` Tahhan, Maryam
  0 siblings, 0 replies; 44+ messages in thread
From: Tahhan, Maryam @ 2015-11-05 16:44 UTC (permalink / raw)
  To: Horton, Remy, dev

> From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of Remy Horton
> Sent: Thursday, November 5, 2015 11:33 AM
> To: dev@dpdk.org
> Subject: [dpdk-dev] [PATCH v4 3/3] example: add keep alive sample application
> 
> Modified version of l2fwd to demonstrate keep-alive functionality.
> 
> Signed-off-by: Remy Horton <remy.horton@intel.com>
> ---

Acked-by: Maryam Tahhan <maryam.tahhan@intel.com>

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [dpdk-dev] [PATCH v4 1/3] rte: add keep alive functionality
  2015-11-05 11:32       ` [dpdk-dev] [PATCH v4 1/3] rte: add keep alive functionality Remy Horton
  2015-11-05 16:43         ` Tahhan, Maryam
@ 2015-11-10 14:02         ` Thomas Monjalon
  2015-11-11  9:21           ` Remy Horton
  2015-11-11 16:28         ` Stephen Hemminger
  2015-11-13 16:09         ` Thomas Monjalon
  3 siblings, 1 reply; 44+ messages in thread
From: Thomas Monjalon @ 2015-11-10 14:02 UTC (permalink / raw)
  To: Remy Horton; +Cc: dev

Hi,

2015-11-05 11:32, Remy Horton:
> +/**
> + * @param *ptr_timer Triggering timer (unused)
> + * @param *ptr_data  Data pointer (keepalive structure)
> + */
> +void rte_keepalive_dispatch_pings(void *ptr_timer, void *ptr_data);

There is no description for this function.
Why ptr_timer is unused?

> +#ifdef KEEPALIVE_DEBUG_MSGS
> +static void
> +print_trace(const char *msg, struct rte_keepalive *keepcfg, int idx_core)
> +{
> +	printf("%sLast seen %" PRId64  "ms ago.\n",
> +		msg,
> +		((rte_rdtsc() - keepcfg->last_alive[idx_core])*1000)
> +		/ rte_get_tsc_hz()
> +	      );
> +}
> +#else
> +static void
> +print_trace(__attribute__((unused)) const char *msg,
> +	__attribute__((unused)) struct rte_keepalive *keepcfg,
> +	__attribute__((unused)) int idx_core)
> +{
> +}
> +#endif

This function will never be tested and do not use rte_log.
Please remove it and use the logging functions.

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [dpdk-dev] [PATCH v4 0/3] Keepalive monitoring & reporting
  2015-11-05 11:32     ` [dpdk-dev] [PATCH v4 0/3] Keepalive monitoring & reporting Remy Horton
                         ` (2 preceding siblings ...)
  2015-11-05 11:32       ` [dpdk-dev] [PATCH v4 3/3] example: add keep alive sample application Remy Horton
@ 2015-11-11  6:52       ` Cao, Min
  2015-11-18 14:05       ` [dpdk-dev] [PATCH v5 " Remy Horton
  4 siblings, 0 replies; 44+ messages in thread
From: Cao, Min @ 2015-11-11  6:52 UTC (permalink / raw)
  To: dev

Tested-by: Min Cao <min.cao@intel.com>

- OS/Kernel: Fedora 21/ 3.17.4-301
- GCC: gcc (GCC) 4.9.2 20150212 (Red Hat 4.9.2-6)
- CPU: Intel(R) Xeon(R) CPU E5-2658 0 @ 2.10GHz
- NIC: Intel Corporation 82599ES 10-Gigabit SFI/SFP+ Network Connection (rev 01)
- Total 3 cases, 3 passed, 0 failed. 

Test Case 1:  Disable/Enable parameter T PERIOD
Test case 2:  Maximum value with parameter K and T
Test case 3:  Keep Alive 

-----Original Message-----
From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of Remy Horton
Sent: Thursday, November 05, 2015 7:33 PM
To: dev@dpdk.org
Subject: [dpdk-dev] [PATCH v4 0/3] Keepalive monitoring & reporting

This patch-set adds functions for detecting and reporting live-ness of LCores, the primary requirement of which is minimal overheads for the
core(s) being checked. Core failures are notified via an application defined callback. As an example l2fwd with random failures is used.

Remy Horton (3):
  rte: add keep alive functionality
  docs: add keep alive sample app guide & release notes
  example: add keep alive sample application

 MAINTAINERS                                     |   4 +
 doc/guides/rel_notes/release_2_2.rst            |   3 +
 doc/guides/sample_app_ug/index.rst              |   1 +
 doc/guides/sample_app_ug/keep_alive.rst         | 191 ++++++
 examples/l2fwd-keepalive/Makefile               |  50 ++
 examples/l2fwd-keepalive/main.c                 | 806 ++++++++++++++++++++++++
 lib/librte_eal/bsdapp/eal/Makefile              |   1 +
 lib/librte_eal/bsdapp/eal/rte_eal_version.map   |   6 +-
 lib/librte_eal/common/Makefile                  |   2 +-
 lib/librte_eal/common/include/rte_keepalive.h   | 146 +++++
 lib/librte_eal/common/rte_keepalive.c           | 124 ++++
 lib/librte_eal/linuxapp/eal/Makefile            |   1 +
 lib/librte_eal/linuxapp/eal/rte_eal_version.map |   6 +-
 13 files changed, 1338 insertions(+), 3 deletions(-)  create mode 100644 doc/guides/sample_app_ug/keep_alive.rst
 create mode 100644 examples/l2fwd-keepalive/Makefile  create mode 100644 examples/l2fwd-keepalive/main.c  create mode 100644 lib/librte_eal/common/include/rte_keepalive.h
 create mode 100644 lib/librte_eal/common/rte_keepalive.c

--
1.9.3

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [dpdk-dev] [PATCH v4 1/3] rte: add keep alive functionality
  2015-11-10 14:02         ` Thomas Monjalon
@ 2015-11-11  9:21           ` Remy Horton
  0 siblings, 0 replies; 44+ messages in thread
From: Remy Horton @ 2015-11-11  9:21 UTC (permalink / raw)
  To: Thomas Monjalon; +Cc: dev


On 10/11/2015 14:02, Thomas Monjalon wrote:

> Why ptr_timer is unused?

Use as rte_timer callback requires the parameter be present, but 
responsibility for setting this up is delegated to the application.

..Remy

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [dpdk-dev] [PATCH v4 1/3] rte: add keep alive functionality
  2015-11-05 11:32       ` [dpdk-dev] [PATCH v4 1/3] rte: add keep alive functionality Remy Horton
  2015-11-05 16:43         ` Tahhan, Maryam
  2015-11-10 14:02         ` Thomas Monjalon
@ 2015-11-11 16:28         ` Stephen Hemminger
  2015-11-18 10:21           ` Remy Horton
  2015-11-13 16:09         ` Thomas Monjalon
  3 siblings, 1 reply; 44+ messages in thread
From: Stephen Hemminger @ 2015-11-11 16:28 UTC (permalink / raw)
  To: Remy Horton; +Cc: dev


In general, try not to introduce new thinks and avoid extra code.
Also Linux has more robust mechanism in the watchdog timers, why not use that?

Could you use RTE_PER_LCORE some how?




> +#ifdef KEEPALIVE_DEBUG_MSGS
Any #ifdef must have a config option to enable it.

> +static void
> +print_trace(const char *msg, struct rte_keepalive *keepcfg, int idx_core)
> +{
> +	printf("%sLast seen %" PRId64  "ms ago.\n",
> +		msg,
> +		((rte_rdtsc() - keepcfg->last_alive[idx_core])*1000)
> +		/ rte_get_tsc_hz()
> +	      );
> +}
> +#else
> +static void
> +print_trace(__attribute__((unused)) const char *msg,
> +	__attribute__((unused)) struct rte_keepalive *keepcfg,
> +	__attribute__((unused)) int idx_core)
> +{
> +}
> +#endif

Agree with others don't introduce not logging macros.


> +void
> +rte_keepalive_dispatch_pings(__attribute__((unused)) void *ptr_timer,

Use __rte_unused
> +	void *ptr_data)
> +{
> +	struct rte_keepalive *keepcfg = (struct rte_keepalive *)ptr_data;

Cast of void  * is unnecessary in C.

> +	int idx_core;
> +
> +	for (idx_core = 0; idx_core < RTE_KEEPALIVE_MAXCORES; idx_core++) {
> +		if (keepcfg->active_cores[idx_core] == 0)
> +			continue;
> +		switch (keepcfg->state_flags[idx_core]) {

My personal preference, prefer blank line after continue.

> +		case ALIVE: /* Alive */
> +			keepcfg->state_flags[idx_core] = 0;
> +			keepcfg->last_alive[idx_core] = rte_rdtsc();
> +			break;
> +		case MISSING: /* MIA */
> +			print_trace("Core MIA. ", keepcfg, idx_core);
> +			keepcfg->state_flags[idx_core] = 2;
> +			break;
> +		case DEAD: /* Dead */
> +			keepcfg->state_flags[idx_core] = 3;
> +			print_trace("Core died. ", keepcfg, idx_core);
> +			if (keepcfg->callback)
> +				keepcfg->callback(
> +					keepcfg->callback_data,
> +					idx_core
> +					);
> +			break;
> +		case GONE: /* Buried */
> +			break;
> +		}
> +	}
> +}
> +
> +
> +struct rte_keepalive *
> +rte_keepalive_create(rte_keepalive_failure_callback_t callback,
> +	void *data)
> +{
> +	int idx_core;
> +	struct rte_keepalive *keepcfg;
> +
> +	keepcfg = malloc(sizeof(struct rte_keepalive));

Why not use rte_zmalloc()?

> +	if (keepcfg != NULL) {
> +		for (idx_core = 0;
> +				idx_core < RTE_KEEPALIVE_MAXCORES;
> +				idx_core++) {
> +			keepcfg->state_flags[idx_core] = 0;
> +			keepcfg->active_cores[idx_core] = 0;
> +		}
> +		keepcfg->callback = callback;
> +		keepcfg->callback_data = data;
> +		keepcfg->tsc_initial = rte_rdtsc();
> +		keepcfg->tsc_mhz = rte_get_tsc_hz() / 1000;
> +	}
> +	return keepcfg;
> +}
> +
> +
> +void
> +rte_keepalive_register_core(struct rte_keepalive *keepcfg, const int id_core)
> +{
> +	if (id_core < RTE_KEEPALIVE_MAXCORES)
> +		keepcfg->active_cores[id_core] = 1;
> +}

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [dpdk-dev] [PATCH v4 1/3] rte: add keep alive functionality
  2015-11-05 11:32       ` [dpdk-dev] [PATCH v4 1/3] rte: add keep alive functionality Remy Horton
                           ` (2 preceding siblings ...)
  2015-11-11 16:28         ` Stephen Hemminger
@ 2015-11-13 16:09         ` Thomas Monjalon
  3 siblings, 0 replies; 44+ messages in thread
From: Thomas Monjalon @ 2015-11-13 16:09 UTC (permalink / raw)
  To: Remy Horton; +Cc: dev

2015-11-05 11:32, Remy Horton:
> --- /dev/null
> +++ b/lib/librte_eal/common/include/rte_keepalive.h

Please add it in doxygen configuration and index.

> --- a/lib/librte_eal/linuxapp/eal/rte_eal_version.map
> +++ b/lib/librte_eal/linuxapp/eal/rte_eal_version.map
> @@ -133,5 +133,9 @@ DPDK_2.2 {
>  	global:
>  
>  	rte_intr_cap_multiple;
> +	rte_keepalive_create;
> +	rte_keepalive_dispatch_pings;
> +	rte_keepalive_register_core;
> +	rte_keepalive_mark_alive;

Please keep alphabetical order.

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [dpdk-dev] [PATCH v4 1/3] rte: add keep alive functionality
  2015-11-11 16:28         ` Stephen Hemminger
@ 2015-11-18 10:21           ` Remy Horton
  0 siblings, 0 replies; 44+ messages in thread
From: Remy Horton @ 2015-11-18 10:21 UTC (permalink / raw)
  To: Stephen Hemminger; +Cc: dev


On 11/11/2015 16:28, Stephen Hemminger wrote:
> Also Linux has more robust mechanism in the watchdog timers, why not use that?

Keepalive was made with tight intra-process reporting intervals of 
5-10ms in mind, whereas Linux watchdog appears to be an inter-process 
system that operates with granularity of seconds.


> Could you use RTE_PER_LCORE some how?

Possibly, although not sure what it gains..


>> +	struct rte_keepalive *keepcfg = (struct rte_keepalive *)ptr_data;
> Cast of void  * is unnecessary in C.

Old habbits die hard.. :)

v+1 on way.


..Remy

^ permalink raw reply	[flat|nested] 44+ messages in thread

* [dpdk-dev] [PATCH v5 0/3] Keepalive monitoring & reporting
  2015-11-05 11:32     ` [dpdk-dev] [PATCH v4 0/3] Keepalive monitoring & reporting Remy Horton
                         ` (3 preceding siblings ...)
  2015-11-11  6:52       ` [dpdk-dev] [PATCH v4 0/3] Keepalive monitoring & reporting Cao, Min
@ 2015-11-18 14:05       ` Remy Horton
  2015-11-18 14:05         ` [dpdk-dev] [PATCH v5 1/3] rte: add keep alive functionality Remy Horton
                           ` (3 more replies)
  4 siblings, 4 replies; 44+ messages in thread
From: Remy Horton @ 2015-11-18 14:05 UTC (permalink / raw)
  To: dev

This patch-set adds functions for detecting and reporting live-ness of
LCores, the primary requirement of which is minimal overheads for the
core(s) being checked. Core failures are notified via an application
defined callback. As an example l2fwd with random failures is used.

v5
* Consistant use of ENUMs rather than integer literals
* Use RTE_INFO for logging
* Removed #ifdef's
* Missing Doxygen description & index entries
* Use rte_zmalloc rather than stock malloc
* Use __rte_unused rather than __attribute__((unused))
* Corrected .map function order
* Rebased to latest origin/master


Remy Horton (3):
  rte: add keep alive functionality
  docs: add keep alive sample app guide & release notes
  example: add keep alive sample application

 MAINTAINERS                                     |   4 +
 doc/api/doxy-api-index.md                       |   1 +
 doc/guides/rel_notes/release_2_2.rst            |   3 +
 doc/guides/sample_app_ug/index.rst              |   1 +
 doc/guides/sample_app_ug/keep_alive.rst         | 191 ++++++
 examples/l2fwd-keepalive/Makefile               |  50 ++
 examples/l2fwd-keepalive/main.c                 | 806 ++++++++++++++++++++++++
 lib/librte_eal/bsdapp/eal/Makefile              |   1 +
 lib/librte_eal/bsdapp/eal/rte_eal_version.map   |   6 +-
 lib/librte_eal/common/Makefile                  |   2 +-
 lib/librte_eal/common/include/rte_keepalive.h   | 146 +++++
 lib/librte_eal/common/rte_keepalive.c           | 113 ++++
 lib/librte_eal/linuxapp/eal/Makefile            |   1 +
 lib/librte_eal/linuxapp/eal/rte_eal_version.map |   6 +-
 14 files changed, 1328 insertions(+), 3 deletions(-)
 create mode 100644 doc/guides/sample_app_ug/keep_alive.rst
 create mode 100644 examples/l2fwd-keepalive/Makefile
 create mode 100644 examples/l2fwd-keepalive/main.c
 create mode 100644 lib/librte_eal/common/include/rte_keepalive.h
 create mode 100644 lib/librte_eal/common/rte_keepalive.c

-- 
1.9.3

^ permalink raw reply	[flat|nested] 44+ messages in thread

* [dpdk-dev] [PATCH v5 1/3] rte: add keep alive functionality
  2015-11-18 14:05       ` [dpdk-dev] [PATCH v5 " Remy Horton
@ 2015-11-18 14:05         ` Remy Horton
  2015-11-18 14:05         ` [dpdk-dev] [PATCH v5 2/3] docs: add keep alive sample app guide & release notes Remy Horton
                           ` (2 subsequent siblings)
  3 siblings, 0 replies; 44+ messages in thread
From: Remy Horton @ 2015-11-18 14:05 UTC (permalink / raw)
  To: dev

Adds functions for detecting and reporting the live-ness of LCores,
the primary requirement of which is minimal overheads for the
core(s) being checked. Core failures are notified via an application
defined callback.

Signed-off-by: Remy Horton <remy.horton@intel.com>
---
 lib/librte_eal/bsdapp/eal/Makefile              |   1 +
 lib/librte_eal/bsdapp/eal/rte_eal_version.map   |   6 +-
 lib/librte_eal/common/Makefile                  |   2 +-
 lib/librte_eal/common/include/rte_keepalive.h   | 146 ++++++++++++++++++++++++
 lib/librte_eal/common/rte_keepalive.c           | 113 ++++++++++++++++++
 lib/librte_eal/linuxapp/eal/Makefile            |   1 +
 lib/librte_eal/linuxapp/eal/rte_eal_version.map |   6 +-
 7 files changed, 272 insertions(+), 3 deletions(-)
 create mode 100644 lib/librte_eal/common/include/rte_keepalive.h
 create mode 100644 lib/librte_eal/common/rte_keepalive.c

diff --git a/lib/librte_eal/bsdapp/eal/Makefile b/lib/librte_eal/bsdapp/eal/Makefile
index a49dcec..65b293f 100644
--- a/lib/librte_eal/bsdapp/eal/Makefile
+++ b/lib/librte_eal/bsdapp/eal/Makefile
@@ -80,6 +80,7 @@ SRCS-$(CONFIG_RTE_LIBRTE_EAL_BSDAPP) += eal_common_thread.c
 SRCS-$(CONFIG_RTE_LIBRTE_EAL_BSDAPP) += rte_malloc.c
 SRCS-$(CONFIG_RTE_LIBRTE_EAL_BSDAPP) += malloc_elem.c
 SRCS-$(CONFIG_RTE_LIBRTE_EAL_BSDAPP) += malloc_heap.c
+SRCS-$(CONFIG_RTE_LIBRTE_EAL_BSDAPP) += rte_keepalive.c
 
 CFLAGS_eal.o := -D_GNU_SOURCE
 #CFLAGS_eal_thread.o := -D_GNU_SOURCE
diff --git a/lib/librte_eal/bsdapp/eal/rte_eal_version.map b/lib/librte_eal/bsdapp/eal/rte_eal_version.map
index 8b00761..f9d4b1c 100644
--- a/lib/librte_eal/bsdapp/eal/rte_eal_version.map
+++ b/lib/librte_eal/bsdapp/eal/rte_eal_version.map
@@ -130,5 +130,9 @@ DPDK_2.2 {
 	global:
 
 	rte_intr_cap_multiple;
+	rte_keepalive_create;
+	rte_keepalive_dispatch_pings;
+	rte_keepalive_mark_alive;
+	rte_keepalive_register_core;
 
-} DPDK_2.1;
\ No newline at end of file
+} DPDK_2.1;
diff --git a/lib/librte_eal/common/Makefile b/lib/librte_eal/common/Makefile
index 8508473..f5ea0ee 100644
--- a/lib/librte_eal/common/Makefile
+++ b/lib/librte_eal/common/Makefile
@@ -40,7 +40,7 @@ INC += rte_string_fns.h rte_version.h
 INC += rte_eal_memconfig.h rte_malloc_heap.h
 INC += rte_hexdump.h rte_devargs.h rte_dev.h
 INC += rte_pci_dev_feature_defs.h rte_pci_dev_features.h
-INC += rte_malloc.h rte_time.h
+INC += rte_malloc.h rte_keepalive.h rte_time.h
 
 ifeq ($(CONFIG_RTE_INSECURE_FUNCTION_WARNING),y)
 INC += rte_warnings.h
diff --git a/lib/librte_eal/common/include/rte_keepalive.h b/lib/librte_eal/common/include/rte_keepalive.h
new file mode 100644
index 0000000..02472c0
--- /dev/null
+++ b/lib/librte_eal/common/include/rte_keepalive.h
@@ -0,0 +1,146 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright 2015 Intel Shannon Ltd. 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.
+ */
+
+/**
+ * @file rte_keepalive.h
+ * DPDK RTE LCore Keepalive Monitor.
+ *
+ **/
+
+#ifndef _KEEPALIVE_H_
+#define _KEEPALIVE_H_
+
+#include <rte_memory.h>
+
+#ifndef RTE_KEEPALIVE_MAXCORES
+/**
+ * Number of cores to track.
+ * @note Must be larger than the highest core id. */
+#define RTE_KEEPALIVE_MAXCORES RTE_MAX_LCORE
+#endif
+
+
+/**
+ * Keepalive failure callback.
+ *
+ *  Receives a data pointer passed to rte_keepalive_create() and the id of the
+ *  failed core.
+ */
+typedef void (*rte_keepalive_failure_callback_t)(
+	void *data,
+	const int id_core);
+
+
+/**
+ * Keepalive state structure.
+ * @internal
+ */
+struct rte_keepalive {
+	/** Core Liveness. */
+	enum {
+		ALIVE = 1,
+		MISSING = 0,
+		DEAD = 2,
+		GONE = 3
+	} __rte_cache_aligned state_flags[RTE_KEEPALIVE_MAXCORES];
+
+	/** Last-seen-alive timestamps */
+	uint64_t last_alive[RTE_KEEPALIVE_MAXCORES];
+
+	/**
+	 * Cores to check.
+	 * Indexed by core id, non-zero if the core should be checked.
+	 */
+	uint8_t active_cores[RTE_KEEPALIVE_MAXCORES];
+
+	/** Dead core handler. */
+	rte_keepalive_failure_callback_t callback;
+
+	/**
+	 * Dead core handler app data.
+	 * Pointer is passed to dead core handler.
+	 */
+	void *callback_data;
+	uint64_t tsc_initial;
+	uint64_t tsc_mhz;
+};
+
+
+/**
+ * Initialise keepalive sub-system.
+ * @param callback
+ *   Function called upon detection of a dead core.
+ * @param data
+ *   Data pointer to be passed to function callback.
+ * @return
+ *   Keepalive structure success, NULL on failure.
+ */
+struct rte_keepalive *rte_keepalive_create(
+	rte_keepalive_failure_callback_t callback,
+	void *data);
+
+
+/**
+ * Checks & handles keepalive state of monitored cores.
+ * @param *ptr_timer Triggering timer (unused)
+ * @param *ptr_data  Data pointer (keepalive structure)
+ */
+void rte_keepalive_dispatch_pings(void *ptr_timer, void *ptr_data);
+
+
+/**
+ * Registers a core for keepalive checks.
+ * @param *keepcfg
+ *   Keepalive structure pointer
+ * @param id_core
+ *   ID number of core to register.
+ */
+void rte_keepalive_register_core(struct rte_keepalive *keepcfg,
+	const int id_core);
+
+
+/**
+ * Per-core keepalive check.
+ * @param *keepcfg
+ *   Keepalive structure pointer
+ *
+ * This function needs to be called from within the main process loop of
+ * the LCore to be checked.
+ */
+static inline void
+rte_keepalive_mark_alive(struct rte_keepalive *keepcfg)
+{
+	keepcfg->state_flags[rte_lcore_id()] = ALIVE;
+}
+
+
+#endif /* _KEEPALIVE_H_ */
diff --git a/lib/librte_eal/common/rte_keepalive.c b/lib/librte_eal/common/rte_keepalive.c
new file mode 100644
index 0000000..736fd0f
--- /dev/null
+++ b/lib/librte_eal/common/rte_keepalive.c
@@ -0,0 +1,113 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright 2015 Intel Shannon Ltd. 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 <inttypes.h>
+
+#include <rte_common.h>
+#include <rte_cycles.h>
+#include <rte_lcore.h>
+#include <rte_log.h>
+#include <rte_keepalive.h>
+#include <rte_malloc.h>
+
+static void
+print_trace(const char *msg, struct rte_keepalive *keepcfg, int idx_core)
+{
+	RTE_LOG(INFO, EAL, "%sLast seen %" PRId64 "ms ago.\n",
+		msg,
+		((rte_rdtsc() - keepcfg->last_alive[idx_core])*1000)
+		/ rte_get_tsc_hz()
+	      );
+}
+
+
+void
+rte_keepalive_dispatch_pings(__rte_unused void *ptr_timer,
+	void *ptr_data)
+{
+	struct rte_keepalive *keepcfg = ptr_data;
+	int idx_core;
+
+	for (idx_core = 0; idx_core < RTE_KEEPALIVE_MAXCORES; idx_core++) {
+		if (keepcfg->active_cores[idx_core] == 0)
+			continue;
+
+		switch (keepcfg->state_flags[idx_core]) {
+		case ALIVE: /* Alive */
+			keepcfg->state_flags[idx_core] = MISSING;
+			keepcfg->last_alive[idx_core] = rte_rdtsc();
+			break;
+		case MISSING: /* MIA */
+			print_trace("Core MIA. ", keepcfg, idx_core);
+			keepcfg->state_flags[idx_core] = DEAD;
+			break;
+		case DEAD: /* Dead */
+			keepcfg->state_flags[idx_core] = GONE;
+			print_trace("Core died. ", keepcfg, idx_core);
+			if (keepcfg->callback)
+				keepcfg->callback(
+					keepcfg->callback_data,
+					idx_core
+					);
+			break;
+		case GONE: /* Buried */
+			break;
+		}
+	}
+}
+
+
+struct rte_keepalive *
+rte_keepalive_create(rte_keepalive_failure_callback_t callback,
+	void *data)
+{
+	struct rte_keepalive *keepcfg;
+
+	keepcfg = rte_zmalloc("RTE_EAL_KEEPALIVE",
+		sizeof(struct rte_keepalive),
+		RTE_CACHE_LINE_SIZE);
+	if (keepcfg != NULL) {
+		keepcfg->callback = callback;
+		keepcfg->callback_data = data;
+		keepcfg->tsc_initial = rte_rdtsc();
+		keepcfg->tsc_mhz = rte_get_tsc_hz() / 1000;
+	}
+	return keepcfg;
+}
+
+
+void
+rte_keepalive_register_core(struct rte_keepalive *keepcfg, const int id_core)
+{
+	if (id_core < RTE_KEEPALIVE_MAXCORES)
+		keepcfg->active_cores[id_core] = 1;
+}
diff --git a/lib/librte_eal/linuxapp/eal/Makefile b/lib/librte_eal/linuxapp/eal/Makefile
index 7e36b86..26eced5 100644
--- a/lib/librte_eal/linuxapp/eal/Makefile
+++ b/lib/librte_eal/linuxapp/eal/Makefile
@@ -90,6 +90,7 @@ SRCS-$(CONFIG_RTE_LIBRTE_EAL_LINUXAPP) += eal_common_thread.c
 SRCS-$(CONFIG_RTE_LIBRTE_EAL_LINUXAPP) += rte_malloc.c
 SRCS-$(CONFIG_RTE_LIBRTE_EAL_LINUXAPP) += malloc_elem.c
 SRCS-$(CONFIG_RTE_LIBRTE_EAL_LINUXAPP) += malloc_heap.c
+SRCS-$(CONFIG_RTE_LIBRTE_EAL_LINUXAPP) += rte_keepalive.c
 
 CFLAGS_eal.o := -D_GNU_SOURCE
 CFLAGS_eal_interrupts.o := -D_GNU_SOURCE
diff --git a/lib/librte_eal/linuxapp/eal/rte_eal_version.map b/lib/librte_eal/linuxapp/eal/rte_eal_version.map
index cb9f4d6..54d496e 100644
--- a/lib/librte_eal/linuxapp/eal/rte_eal_version.map
+++ b/lib/librte_eal/linuxapp/eal/rte_eal_version.map
@@ -133,5 +133,9 @@ DPDK_2.2 {
 	global:
 
 	rte_intr_cap_multiple;
+	rte_keepalive_create;
+	rte_keepalive_dispatch_pings;
+	rte_keepalive_mark_alive;
+	rte_keepalive_register_core;
 
-} DPDK_2.1;
\ No newline at end of file
+} DPDK_2.1;
-- 
1.9.3

^ permalink raw reply	[flat|nested] 44+ messages in thread

* [dpdk-dev] [PATCH v5 2/3] docs: add keep alive sample app guide & release notes
  2015-11-18 14:05       ` [dpdk-dev] [PATCH v5 " Remy Horton
  2015-11-18 14:05         ` [dpdk-dev] [PATCH v5 1/3] rte: add keep alive functionality Remy Horton
@ 2015-11-18 14:05         ` Remy Horton
  2015-11-19 11:32           ` Thomas Monjalon
  2015-11-18 14:05         ` [dpdk-dev] [PATCH v5 3/3] example: add keep alive sample application Remy Horton
  2015-11-19 14:49         ` [dpdk-dev] [PATCH v5 0/3] Keepalive monitoring & reporting Thomas Monjalon
  3 siblings, 1 reply; 44+ messages in thread
From: Remy Horton @ 2015-11-18 14:05 UTC (permalink / raw)
  To: dev; +Cc: John J Browne

Signed-off-by: Maryam Tahhan <maryam.tahhan@intel.com>
Signed-off-by: John J Browne <john.j.browne@intel.com>
Signed-off-by: Remy Horton <remy.horton@intel.com>
---
 doc/api/doxy-api-index.md               |   1 +
 doc/guides/rel_notes/release_2_2.rst    |   3 +
 doc/guides/sample_app_ug/index.rst      |   1 +
 doc/guides/sample_app_ug/keep_alive.rst | 191 ++++++++++++++++++++++++++++++++
 4 files changed, 196 insertions(+)
 create mode 100644 doc/guides/sample_app_ug/keep_alive.rst

diff --git a/doc/api/doxy-api-index.md b/doc/api/doxy-api-index.md
index 72ac3c4..f2c0320 100644
--- a/doc/api/doxy-api-index.md
+++ b/doc/api/doxy-api-index.md
@@ -146,4 +146,5 @@ There are many libraries, so their headers may be grouped by topics:
   [EAL config]         (@ref rte_eal.h),
   [common]             (@ref rte_common.h),
   [ABI compat]         (@ref rte_compat.h),
+  [keepalive]          (@ref rte_keepalive.h),
   [version]            (@ref rte_version.h)
diff --git a/doc/guides/rel_notes/release_2_2.rst b/doc/guides/rel_notes/release_2_2.rst
index 0781ae6..c00ab26 100644
--- a/doc/guides/rel_notes/release_2_2.rst
+++ b/doc/guides/rel_notes/release_2_2.rst
@@ -102,6 +102,7 @@ New Features
 
 * **Added port hotplug support to xenvirt.**
 
+* **Added keepalive support to EAL.**
 
 Resolved Issues
 ---------------
@@ -207,6 +208,8 @@ Libraries
 Examples
 ~~~~~~~~
 
+* **l2fwd-keepalive: Added keep-alive demonstration.**
+
 
 Other
 ~~~~~
diff --git a/doc/guides/sample_app_ug/index.rst b/doc/guides/sample_app_ug/index.rst
index 8ae86c0..1f62ef5 100644
--- a/doc/guides/sample_app_ug/index.rst
+++ b/doc/guides/sample_app_ug/index.rst
@@ -49,6 +49,7 @@ Sample Applications User Guide
     ipv4_multicast
     ip_reassembly
     kernel_nic_interface
+    keep_alive
     l2_forward_job_stats
     l2_forward_real_virtual
     l3_forward
diff --git a/doc/guides/sample_app_ug/keep_alive.rst b/doc/guides/sample_app_ug/keep_alive.rst
new file mode 100644
index 0000000..080811b
--- /dev/null
+++ b/doc/guides/sample_app_ug/keep_alive.rst
@@ -0,0 +1,191 @@
+
+..  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.
+
+Keep Alive Sample Application
+=============================
+
+The Keep Alive application is a simple example of a
+heartbeat/watchdog for packet processing cores. It demonstrates how
+to detect 'failed' DPDK cores and notify a fault management entity
+of this failure. Its purpose is to ensure the failure of the core
+does not result in a fault that is not detectable by a management
+entity.
+
+
+Overview
+--------
+
+The application demonstrates how to protect against 'silent outages'
+on packet processing cores. A Keep Alive Monitor Agent Core (master)
+monitors the state of packet processing cores (worker cores) by
+dispatching pings at a regular time interval (default is 5ms) and
+monitoring the state of the cores. Cores states are: Alive, MIA, Dead
+or Buried. MIA indicates a missed ping, and Dead indicates two missed
+pings within the specified time interval. When a core is Dead, a
+callback function is invoked to restart the packet processing core;
+A real life application might use this callback function to notify a
+higher level fault management entity of the core failure in order to
+take the appropriate corrective action.
+
+Note: Only the worker cores are monitored. A local (on the host) mechanism
+or agent to supervise the Keep Alive Monitor Agent Core DPDK core is required
+to detect its failure.
+
+Note: This application is based on the L2 forwarding application. As
+such, the initialization and run-time paths are very similar to those
+of the L2 forwarding application.
+
+Compiling the Application
+-------------------------
+
+To compile the application:
+
+#.  Go to the sample application directory:
+
+    .. code-block:: console
+
+        export RTE_SDK=/path/to/rte_sdk cd ${RTE_SDK}/examples/keep_alive
+
+#.  Set the target (a default target is used if not specified). For example:
+
+    .. code-block:: console
+
+        export RTE_TARGET=x86_64-native-linuxapp-gcc
+
+    See the *DPDK Getting Started Guide* for possible RTE_TARGET values.
+
+#.  Build the application:
+
+    .. code-block:: console
+
+        make
+
+Running the Application
+-----------------------
+
+The application has a number of command line options:
+
+.. code-block:: console
+
+    ./build/l2fwd-keepalive [EAL options] \
+            -- -p PORTMASK [-q NQ] [-K PERIOD] [-T PERIOD]
+
+where,
+
+* ``p PORTMASK``: A hexadecimal bitmask of the ports to configure
+
+* ``q NQ``: A number of queues (=ports) per lcore (default is 1)
+
+* ``K PERIOD``: Heartbeat check period in ms(5ms default; 86400 max)
+
+* ``T PERIOD``: statistics will be refreshed each PERIOD seconds (0 to
+  disable, 10 default, 86400 maximum).
+
+To run the application in linuxapp environment with 4 lcores, 16 ports
+8 RX queues per lcore and a ping interval of 10ms, issue the command:
+
+.. code-block:: console
+
+    ./build/l2fwd-keepalive -c f -n 4 -- -q 8 -p ffff -K 10
+
+Refer to the *DPDK Getting Started Guide* for general information on
+running applications and the Environment Abstraction Layer (EAL)
+options.
+
+
+Explanation
+-----------
+
+The following sections provide some explanation of the The
+Keep-Alive/'Liveliness' conceptual scheme. As mentioned in the
+overview section, the initialization and run-time paths are very
+similar to those of the L2 forwarding application (see Chapter 9
+"L2 Forwarding Sample Application (in Real and Virtualized
+Environments)" for more information).
+
+The Keep-Alive/'Liveliness' conceptual scheme:
+
+* A Keep- Alive Agent Runs every N Milliseconds.
+
+* DPDK Cores respond to the keep-alive agent.
+
+* If keep-alive agent detects time-outs, it notifies the
+  fault management entity through a callback function.
+
+The following sections provide some explanation of the code aspects
+that are specific to the Keep Alive sample application.
+
+The heartbeat functionality is initialized with a struct
+rte_heartbeat and the callback function to invoke in the
+case of a timeout.
+
+.. code-block:: c
+
+    rte_global_keepalive_info = rte_keepalive_create(&dead_core, NULL);
+    if (rte_global_hbeat_info == NULL)
+        rte_exit(EXIT_FAILURE, "keepalive_create() failed");
+
+The function that issues the pings hbeat_dispatch_pings()
+is configured to run every check_period milliseconds.
+
+.. code-block:: c
+
+    if (rte_timer_reset(&hb_timer,
+            (check_period * rte_get_timer_hz()) / 1000,
+            PERIODICAL,
+            rte_lcore_id(),
+            &hbeat_dispatch_pings, rte_global_keepalive_info
+            ) != 0 )
+        rte_exit(EXIT_FAILURE, "Keepalive setup failure.\n");
+
+The rest of the initialization and run-time path follows
+the same paths as the the L2 forwarding application. The only
+addition to the main processing loop is the mark alive
+functionality and the example random failures.
+
+.. code-block:: c
+
+    rte_keepalive_mark_alive(&rte_global_hbeat_info);
+    cur_tsc = rte_rdtsc();
+
+    /* Die randomly within 7 secs for demo purposes.. */
+    if (cur_tsc - tsc_initial > tsc_lifetime)
+    break;
+
+The rte_keepalive_mark_alive function simply sets the core state to alive.
+
+.. code-block:: c
+
+    static inline void
+    rte_keepalive_mark_alive(struct rte_heartbeat *keepcfg)
+    {
+        keepcfg->state_flags[rte_lcore_id()] = 1;
+    }
-- 
1.9.3

^ permalink raw reply	[flat|nested] 44+ messages in thread

* [dpdk-dev] [PATCH v5 3/3] example: add keep alive sample application
  2015-11-18 14:05       ` [dpdk-dev] [PATCH v5 " Remy Horton
  2015-11-18 14:05         ` [dpdk-dev] [PATCH v5 1/3] rte: add keep alive functionality Remy Horton
  2015-11-18 14:05         ` [dpdk-dev] [PATCH v5 2/3] docs: add keep alive sample app guide & release notes Remy Horton
@ 2015-11-18 14:05         ` Remy Horton
  2015-11-19 11:31           ` Thomas Monjalon
  2015-11-19 14:49         ` [dpdk-dev] [PATCH v5 0/3] Keepalive monitoring & reporting Thomas Monjalon
  3 siblings, 1 reply; 44+ messages in thread
From: Remy Horton @ 2015-11-18 14:05 UTC (permalink / raw)
  To: dev

Modified version of l2fwd to demonstrate keep-alive functionality.

Signed-off-by: Remy Horton <remy.horton@intel.com>
---
 MAINTAINERS                       |   4 +
 examples/l2fwd-keepalive/Makefile |  50 +++
 examples/l2fwd-keepalive/main.c   | 806 ++++++++++++++++++++++++++++++++++++++
 3 files changed, 860 insertions(+)
 create mode 100644 examples/l2fwd-keepalive/Makefile
 create mode 100644 examples/l2fwd-keepalive/main.c

diff --git a/MAINTAINERS b/MAINTAINERS
index d6feada..056c246 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -526,3 +526,7 @@ F: doc/guides/sample_app_ug/vmdq_dcb_forwarding.rst
 M: Pablo de Lara <pablo.de.lara.guarch@intel.com>
 M: Daniel Mrzyglod <danielx.t.mrzyglod@intel.com>
 F: examples/ptpclient/
+
+M: Remy Horton <remy.horton@intel.com>
+F: examples/l2fwd-keepalive/
+F: doc/guides/sample_app_ug/keep_alive.rst
diff --git a/examples/l2fwd-keepalive/Makefile b/examples/l2fwd-keepalive/Makefile
new file mode 100644
index 0000000..568edcb
--- /dev/null
+++ b/examples/l2fwd-keepalive/Makefile
@@ -0,0 +1,50 @@
+#   BSD LICENSE
+#
+#   Copyright(c) 2010-2014 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 overridden by command line or environment
+RTE_TARGET ?= x86_64-native-linuxapp-gcc
+
+include $(RTE_SDK)/mk/rte.vars.mk
+
+# binary name
+APP = l2fwd-keepalive
+
+# all source are stored in SRCS-y
+SRCS-y := main.c
+
+CFLAGS += -O3
+CFLAGS += $(WERROR_FLAGS)
+
+include $(RTE_SDK)/mk/rte.extapp.mk
diff --git a/examples/l2fwd-keepalive/main.c b/examples/l2fwd-keepalive/main.c
new file mode 100644
index 0000000..8d7b09e
--- /dev/null
+++ b/examples/l2fwd-keepalive/main.c
@@ -0,0 +1,806 @@
+/*-
+ *   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 <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 <rte_common.h>
+#include <rte_log.h>
+#include <rte_memory.h>
+#include <rte_memcpy.h>
+#include <rte_memzone.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_timer.h>
+#include <rte_keepalive.h>
+
+#define RTE_LOGTYPE_L2FWD RTE_LOGTYPE_USER1
+
+#define NB_MBUF   8192
+
+#define MAX_PKT_BURST 32
+#define BURST_TX_DRAIN_US 100 /* TX drain every ~100us */
+
+/*
+ * 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;
+
+/* 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 const 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,
+	},
+};
+
+struct rte_mempool *l2fwd_pktmbuf_pool = NULL;
+
+/* 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 1
+#define MAX_TIMER_PERIOD 86400 /* 1 day max */
+static int64_t timer_period = 10 * TIMER_MILLISECOND * 1000; /* 10 seconds */
+static int64_t check_period = 5; /* default check cycle is 5ms */
+
+/* Keepalive structure */
+struct rte_keepalive *rte_global_keepalive_info;
+
+/* Print out statistics on packets dropped */
+static void
+print_stats(__attribute__((unused)) struct rte_timer *ptr_timer,
+	__attribute__((unused)) void *ptr_data)
+{
+	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 ------------------------------"
+			   "\nPackets sent: %24"PRIu64
+			   "\nPackets received: %20"PRIu64
+			   "\nPackets dropped: %21"PRIu64,
+			   portid,
+			   port_statistics[portid].tx,
+			   port_statistics[portid].rx,
+			   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 ==============================="
+		   "\nTotal packets sent: %18"PRIu64
+		   "\nTotal packets received: %14"PRIu64
+		   "\nTotal packets dropped: %15"PRIu64,
+		   total_packets_tx,
+		   total_packets_rx,
+		   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 = &eth->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], &eth->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;
+	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;
+
+	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);
+	}
+
+	uint64_t tsc_initial = rte_rdtsc();
+	uint64_t tsc_lifetime = (rand()&0x07) * rte_get_tsc_hz();
+
+	while (1) {
+		/* Keepalive heartbeat */
+		rte_keepalive_mark_alive(rte_global_keepalive_info);
+
+		cur_tsc = rte_rdtsc();
+
+		/*
+		 * Die randomly within 7 secs for demo purposes if
+		 * keepalive enabled
+		 */
+		if (check_period > 0 && cur_tsc - tsc_initial > tsc_lifetime)
+			break;
+
+		/*
+		 * 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;
+			}
+
+			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"
+	       "  -K PERIOD: Keepalive check period (5 default; 86400 max)\n"
+		   "  -T PERIOD: statistics will be refreshed each PERIOD seconds (0 to disable, 10 default, 86400 maximum)\n",
+	       prgname);
+}
+
+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_check_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;
+}
+
+/* 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:K:",
+				  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;
+
+		/* Check period */
+		case 'K':
+			check_period = l2fwd_parse_check_period(optarg);
+			if (check_period < 0) {
+				printf("invalid check period\n");
+				l2fwd_usage(prgname);
+				return -1;
+			}
+			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 "
+						"Mbps - %s\n", (uint8_t)portid,
+						(unsigned)link.link_speed,
+				(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 void
+dead_core(__attribute__((unused)) void *ptr_data, const int id_core)
+{
+	printf("Dead core %i - restarting..\n", id_core);
+	if (rte_eal_get_lcore_state(id_core) == FINISHED) {
+		rte_eal_wait_lcore(id_core);
+		rte_eal_remote_launch(l2fwd_launch_one_lcore, NULL, id_core);
+	} else {
+		printf("..false positive!\n");
+	}
+}
+
+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 EAL */
+	ret = rte_eal_init(argc, argv);
+	if (ret < 0)
+		rte_exit(EXIT_FAILURE, "Invalid EAL arguments\n");
+	argc -= ret;
+	argv += ret;
+
+	l2fwd_enabled_port_mask = 0;
+
+	/* 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_pktmbuf_pool_create("mbuf_pool", NB_MBUF, 32,
+		0, RTE_MBUF_DEFAULT_BUF_SIZE, rte_socket_id());
+	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 = 1;
+	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);
+		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);
+
+		/* Start device */
+		ret = rte_eth_dev_start(portid);
+		if (ret < 0)
+			rte_exit(EXIT_FAILURE,
+				"rte_eth_dev_start:err=%d, port=%u\n",
+				  ret, (unsigned) portid);
+
+		rte_eth_promiscuous_enable(portid);
+
+		printf("Port %u, MAC address: "
+			"%02X:%02X:%02X:%02X:%02X:%02X\n\n",
+			(unsigned) portid,
+			l2fwd_ports_eth_addr[portid].addr_bytes[0],
+			l2fwd_ports_eth_addr[portid].addr_bytes[1],
+			l2fwd_ports_eth_addr[portid].addr_bytes[2],
+			l2fwd_ports_eth_addr[portid].addr_bytes[3],
+			l2fwd_ports_eth_addr[portid].addr_bytes[4],
+			l2fwd_ports_eth_addr[portid].addr_bytes[5]);
+
+		/* initialize port stats */
+		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);
+
+	struct rte_timer hb_timer, stats_timer;
+
+	rte_timer_subsystem_init();
+	rte_timer_init(&stats_timer);
+
+	if (check_period > 0) {
+		rte_global_keepalive_info =
+			rte_keepalive_create(&dead_core, NULL);
+		if (rte_global_keepalive_info == NULL)
+			rte_exit(EXIT_FAILURE, "init_keep_alive() failed");
+		rte_timer_init(&hb_timer);
+		if (rte_timer_reset(&hb_timer,
+				(check_period * rte_get_timer_hz()) / 1000,
+				PERIODICAL,
+				rte_lcore_id(),
+				(void(*)(struct rte_timer*, void*))
+				&rte_keepalive_dispatch_pings,
+				rte_global_keepalive_info
+				) != 0 )
+			rte_exit(EXIT_FAILURE, "Keepalive setup failure.\n");
+	}
+	if (timer_period > 0) {
+		if (rte_timer_reset(&stats_timer,
+				(timer_period * rte_get_timer_hz()) / 1000,
+				PERIODICAL,
+				rte_lcore_id(),
+				&print_stats, NULL
+				) != 0 )
+			rte_exit(EXIT_FAILURE, "Stats setup failure.\n");
+	}
+	/* launch per-lcore init on every slave lcore */
+	RTE_LCORE_FOREACH_SLAVE(lcore_id) {
+		struct lcore_queue_conf *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
+				);
+		else {
+			rte_eal_remote_launch(
+				l2fwd_launch_one_lcore,
+				NULL,
+				lcore_id
+				);
+			rte_keepalive_register_core(rte_global_keepalive_info,
+				lcore_id);
+		}
+	}
+	for (;;) {
+		rte_timer_manage();
+		rte_delay_ms(5);
+		}
+
+	RTE_LCORE_FOREACH_SLAVE(lcore_id) {
+		if (rte_eal_wait_lcore(lcore_id) < 0)
+			return -1;
+	}
+
+	return 0;
+}
-- 
1.9.3

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [dpdk-dev] [PATCH v5 3/3] example: add keep alive sample application
  2015-11-18 14:05         ` [dpdk-dev] [PATCH v5 3/3] example: add keep alive sample application Remy Horton
@ 2015-11-19 11:31           ` Thomas Monjalon
  0 siblings, 0 replies; 44+ messages in thread
From: Thomas Monjalon @ 2015-11-19 11:31 UTC (permalink / raw)
  To: Remy Horton; +Cc: dev

2015-11-18 14:05, Remy Horton:
> Modified version of l2fwd to demonstrate keep-alive functionality.
> 
> Signed-off-by: Remy Horton <remy.horton@intel.com>
> ---
>  MAINTAINERS                       |   4 +
>  examples/l2fwd-keepalive/Makefile |  50 +++
>  examples/l2fwd-keepalive/main.c   | 806 ++++++++++++++++++++++++++++++++++++++
>  3 files changed, 860 insertions(+)

You missed examples/Makefile.
I'm going to fix it if you agree.

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [dpdk-dev] [PATCH v5 2/3] docs: add keep alive sample app guide & release notes
  2015-11-18 14:05         ` [dpdk-dev] [PATCH v5 2/3] docs: add keep alive sample app guide & release notes Remy Horton
@ 2015-11-19 11:32           ` Thomas Monjalon
  2015-11-19 11:43             ` Remy Horton
  0 siblings, 1 reply; 44+ messages in thread
From: Thomas Monjalon @ 2015-11-19 11:32 UTC (permalink / raw)
  To: Remy Horton; +Cc: dev, John J Browne

2015-11-18 14:05, Remy Horton:
> --- a/doc/guides/rel_notes/release_2_2.rst
> +++ b/doc/guides/rel_notes/release_2_2.rst
> @@ -102,6 +102,7 @@ New Features
>  
>  * **Added port hotplug support to xenvirt.**
>  
> +* **Added keepalive support to EAL.**
>  
>  Resolved Issues
>  ---------------
> @@ -207,6 +208,8 @@ Libraries
>  Examples
>  ~~~~~~~~
>  
> +* **l2fwd-keepalive: Added keep-alive demonstration.**
> +

It is the "Resolved Issues" section.
If you agree, I'll merge it with the above entry.

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [dpdk-dev] [PATCH v5 2/3] docs: add keep alive sample app guide & release notes
  2015-11-19 11:32           ` Thomas Monjalon
@ 2015-11-19 11:43             ` Remy Horton
  0 siblings, 0 replies; 44+ messages in thread
From: Remy Horton @ 2015-11-19 11:43 UTC (permalink / raw)
  To: Thomas Monjalon; +Cc: dev, John J Browne



On 19/11/2015 11:32, Thomas Monjalon wrote:
> 2015-11-18 14:05, Remy Horton:
>> --- a/doc/guides/rel_notes/release_2_2.rst
>> +++ b/doc/guides/rel_notes/release_2_2.rst
>> @@ -102,6 +102,7 @@ New Features
>>
>>   * **Added port hotplug support to xenvirt.**
>>
>> +* **Added keepalive support to EAL.**
>>
>>   Resolved Issues
>>   ---------------
>> @@ -207,6 +208,8 @@ Libraries
>>   Examples
>>   ~~~~~~~~
>>
>> +* **l2fwd-keepalive: Added keep-alive demonstration.**
>> +
>
> It is the "Resolved Issues" section.
> If you agree, I'll merge it with the above entry.
>

Ok with me. Ditto with example/Makefile.

..Remy

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [dpdk-dev] [PATCH v5 0/3] Keepalive monitoring & reporting
  2015-11-18 14:05       ` [dpdk-dev] [PATCH v5 " Remy Horton
                           ` (2 preceding siblings ...)
  2015-11-18 14:05         ` [dpdk-dev] [PATCH v5 3/3] example: add keep alive sample application Remy Horton
@ 2015-11-19 14:49         ` Thomas Monjalon
  3 siblings, 0 replies; 44+ messages in thread
From: Thomas Monjalon @ 2015-11-19 14:49 UTC (permalink / raw)
  To: Remy Horton; +Cc: dev

2015-11-18 14:05, Remy Horton:
> This patch-set adds functions for detecting and reporting live-ness of
> LCores, the primary requirement of which is minimal overheads for the
> core(s) being checked. Core failures are notified via an application
> defined callback. As an example l2fwd with random failures is used.

Applied, thanks

^ permalink raw reply	[flat|nested] 44+ messages in thread

end of thread, other threads:[~2015-11-19 15:04 UTC | newest]

Thread overview: 44+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-09-15 12:16 [dpdk-dev] [RFC PATCH v1] rte: LCore heartbeat example Remy Horton
2015-09-15 13:10 ` Thomas Monjalon
2015-09-23  9:00   ` Remy Horton
2015-10-05 11:16   ` Mcnamara, John
2015-09-30  9:04 ` [dpdk-dev] [PATCH v2 0/3] Keepalive monitoring & reporting Remy Horton
2015-09-30  9:04   ` [dpdk-dev] [PATCH v2 1/3] rte: add keep alive functionality Remy Horton
2015-10-23 11:40     ` Tahhan, Maryam
2015-10-23 14:27     ` Wiles, Keith
2015-10-26 16:36       ` Remy Horton
2015-09-30  9:04   ` [dpdk-dev] [PATCH v2 2/3] l2fwd: keep alive sample application Remy Horton
2015-10-23 14:23     ` Tahhan, Maryam
2015-10-27  8:48       ` Remy Horton
2015-10-27 10:10         ` Bruce Richardson
2015-09-30  9:04   ` [dpdk-dev] [PATCH v2 3/3] docs: add keep alive sample app guide Remy Horton
2015-10-28  8:52   ` [dpdk-dev] [PATCH v3 0/3] Keepalive monitoring & reporting Remy Horton
2015-10-28  8:52     ` [dpdk-dev] [PATCH v3 1/3] rte: add keep alive functionality Remy Horton
2015-10-28 12:25       ` Tahhan, Maryam
2015-11-04  1:48       ` Thomas Monjalon
2015-11-04  1:54       ` Thomas Monjalon
2015-10-28  8:52     ` [dpdk-dev] [PATCH v3 2/3] docs: add keep alive sample app guide Remy Horton
2015-10-28 11:22       ` Van Haaren, Harry
2015-10-28  8:52     ` [dpdk-dev] [PATCH v3 3/3] example: add keep alive sample application Remy Horton
2015-10-28 12:28       ` Tahhan, Maryam
2015-11-05 11:32     ` [dpdk-dev] [PATCH v4 0/3] Keepalive monitoring & reporting Remy Horton
2015-11-05 11:32       ` [dpdk-dev] [PATCH v4 1/3] rte: add keep alive functionality Remy Horton
2015-11-05 16:43         ` Tahhan, Maryam
2015-11-10 14:02         ` Thomas Monjalon
2015-11-11  9:21           ` Remy Horton
2015-11-11 16:28         ` Stephen Hemminger
2015-11-18 10:21           ` Remy Horton
2015-11-13 16:09         ` Thomas Monjalon
2015-11-05 11:32       ` [dpdk-dev] [PATCH v4 2/3] docs: add keep alive sample app guide & release notes Remy Horton
2015-11-05 16:40         ` Van Haaren, Harry
2015-11-05 11:32       ` [dpdk-dev] [PATCH v4 3/3] example: add keep alive sample application Remy Horton
2015-11-05 16:44         ` Tahhan, Maryam
2015-11-11  6:52       ` [dpdk-dev] [PATCH v4 0/3] Keepalive monitoring & reporting Cao, Min
2015-11-18 14:05       ` [dpdk-dev] [PATCH v5 " Remy Horton
2015-11-18 14:05         ` [dpdk-dev] [PATCH v5 1/3] rte: add keep alive functionality Remy Horton
2015-11-18 14:05         ` [dpdk-dev] [PATCH v5 2/3] docs: add keep alive sample app guide & release notes Remy Horton
2015-11-19 11:32           ` Thomas Monjalon
2015-11-19 11:43             ` Remy Horton
2015-11-18 14:05         ` [dpdk-dev] [PATCH v5 3/3] example: add keep alive sample application Remy Horton
2015-11-19 11:31           ` Thomas Monjalon
2015-11-19 14:49         ` [dpdk-dev] [PATCH v5 0/3] Keepalive monitoring & reporting 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).