xref: /dpdk/lib/eal/common/rte_keepalive.c (revision 3da59f30a23f2e795d2315f3d949e1b3e0ce0c3d)
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2015-2016 Intel Corporation
3  */
4 
5 #include <inttypes.h>
6 
7 #include <rte_common.h>
8 #include <rte_cycles.h>
9 #include <rte_lcore.h>
10 #include <rte_log.h>
11 #include <rte_keepalive.h>
12 #include <rte_malloc.h>
13 
14 #include "eal_private.h"
15 
16 struct rte_keepalive {
17 	/** Core Liveness. */
18 	struct {
19 		/*
20 		 * Each element must be cache aligned to prevent false sharing.
21 		 */
22 		enum rte_keepalive_state core_state __rte_cache_aligned;
23 	} live_data[RTE_KEEPALIVE_MAXCORES];
24 
25 	/** Last-seen-alive timestamps */
26 	uint64_t last_alive[RTE_KEEPALIVE_MAXCORES];
27 
28 	/**
29 	 * Cores to check.
30 	 * Indexed by core id, non-zero if the core should be checked.
31 	 */
32 	uint8_t active_cores[RTE_KEEPALIVE_MAXCORES];
33 
34 	/** Dead core handler. */
35 	rte_keepalive_failure_callback_t callback;
36 
37 	/**
38 	 * Dead core handler app data.
39 	 * Pointer is passed to dead core handler.
40 	 */
41 	void *callback_data;
42 	uint64_t tsc_initial;
43 	uint64_t tsc_mhz;
44 
45 	/** Core state relay handler. */
46 	rte_keepalive_relay_callback_t relay_callback;
47 
48 	/**
49 	 * Core state relay handler app data.
50 	 * Pointer is passed to live core handler.
51 	 */
52 	void *relay_callback_data;
53 };
54 
55 static void
56 print_trace(const char *msg, struct rte_keepalive *keepcfg, int idx_core)
57 {
58 	EAL_LOG(INFO, "%sLast seen %" PRId64 "ms ago.",
59 		msg,
60 		((rte_rdtsc() - keepcfg->last_alive[idx_core])*1000)
61 		/ rte_get_tsc_hz()
62 	      );
63 }
64 
65 void
66 rte_keepalive_dispatch_pings(__rte_unused void *ptr_timer,
67 	void *ptr_data)
68 {
69 	struct rte_keepalive *keepcfg = ptr_data;
70 	int idx_core;
71 
72 	for (idx_core = 0; idx_core < RTE_KEEPALIVE_MAXCORES; idx_core++) {
73 		if (keepcfg->active_cores[idx_core] == 0)
74 			continue;
75 
76 		switch (keepcfg->live_data[idx_core].core_state) {
77 		case RTE_KA_STATE_UNUSED:
78 			break;
79 		case RTE_KA_STATE_ALIVE: /* Alive */
80 			keepcfg->live_data[idx_core].core_state =
81 			    RTE_KA_STATE_MISSING;
82 			keepcfg->last_alive[idx_core] = rte_rdtsc();
83 			break;
84 		case RTE_KA_STATE_MISSING: /* MIA */
85 			print_trace("Core MIA. ", keepcfg, idx_core);
86 			keepcfg->live_data[idx_core].core_state =
87 			    RTE_KA_STATE_DEAD;
88 			break;
89 		case RTE_KA_STATE_DEAD: /* Dead */
90 			keepcfg->live_data[idx_core].core_state =
91 			    RTE_KA_STATE_GONE;
92 			print_trace("Core died. ", keepcfg, idx_core);
93 			if (keepcfg->callback)
94 				keepcfg->callback(
95 					keepcfg->callback_data,
96 					idx_core
97 					);
98 			break;
99 		case RTE_KA_STATE_GONE: /* Buried */
100 			break;
101 		case RTE_KA_STATE_DOZING: /* Core going idle */
102 			keepcfg->live_data[idx_core].core_state =
103 			    RTE_KA_STATE_SLEEP;
104 			keepcfg->last_alive[idx_core] = rte_rdtsc();
105 			break;
106 		case RTE_KA_STATE_SLEEP: /* Idled core */
107 			break;
108 		}
109 		if (keepcfg->relay_callback)
110 			keepcfg->relay_callback(
111 				keepcfg->relay_callback_data,
112 				idx_core,
113 				keepcfg->live_data[idx_core].core_state,
114 				keepcfg->last_alive[idx_core]
115 				);
116 	}
117 }
118 
119 struct rte_keepalive *
120 rte_keepalive_create(rte_keepalive_failure_callback_t callback,
121 	void *data)
122 {
123 	struct rte_keepalive *keepcfg;
124 
125 	keepcfg = rte_zmalloc("RTE_EAL_KEEPALIVE",
126 		sizeof(struct rte_keepalive),
127 		RTE_CACHE_LINE_SIZE);
128 	if (keepcfg != NULL) {
129 		keepcfg->callback = callback;
130 		keepcfg->callback_data = data;
131 		keepcfg->tsc_initial = rte_rdtsc();
132 		keepcfg->tsc_mhz = rte_get_tsc_hz() / 1000;
133 	}
134 	return keepcfg;
135 }
136 
137 void rte_keepalive_register_relay_callback(struct rte_keepalive *keepcfg,
138 	rte_keepalive_relay_callback_t callback,
139 	void *data)
140 {
141 	keepcfg->relay_callback = callback;
142 	keepcfg->relay_callback_data = data;
143 }
144 
145 void
146 rte_keepalive_register_core(struct rte_keepalive *keepcfg, const int id_core)
147 {
148 	if (id_core < RTE_KEEPALIVE_MAXCORES) {
149 		keepcfg->active_cores[id_core] = RTE_KA_STATE_ALIVE;
150 		keepcfg->last_alive[id_core] = rte_rdtsc();
151 	}
152 }
153 
154 void
155 rte_keepalive_mark_alive(struct rte_keepalive *keepcfg)
156 {
157 	keepcfg->live_data[rte_lcore_id()].core_state = RTE_KA_STATE_ALIVE;
158 }
159 
160 void
161 rte_keepalive_mark_sleep(struct rte_keepalive *keepcfg)
162 {
163 	keepcfg->live_data[rte_lcore_id()].core_state = RTE_KA_STATE_DOZING;
164 }
165