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