Safe API Framework 0.1.0 build 384e6ae
Layered API framework for safety-related applications (ERTMS RBC reference targeting CENELEC EN 50128 SIL 4)
Loading...
Searching...
No Matches
rte_site_role_policy.c
Go to the documentation of this file.
1
7
10{
11 return (in->cycle >= in->peer_last_rx_cycle) && ((in->cycle - in->peer_last_rx_cycle) <= 2U);
12}
13
16{
17 return in->own_ready && (in->sibling_online || in->sibling_ready || !in->sibling_reachable);
18}
19
21{
23
25 d.reason = RTE_SITE_ROLE_REASON_NONE;
27
28 if (in->own_faulted && in->peer_faulted)
29 {
32 }
33 else if (!in->own_faulted && !in->is_online && in->peer_faulted)
34 {
37 }
38 else if (in->own_faulted && in->peer_snapshot_valid && !in->peer_faulted)
39 {
42 }
45 {
48 }
49 else if (in->is_online && !in->own_faulted && !in->peer_faulted && in->peer_online_now && peer_answering(in))
50 {
52 {
55 }
56 else
57 {
60 }
61 }
62 else if (!in->is_online && !in->own_faulted && in->link_up && !in->peer_unresponsive && peer_answering(in) &&
63 !in->peer_online_now && !in->peer_faulted)
64 {
67 {
71 }
72 }
73 else if (!in->is_online && !in->own_faulted && in->sibling_online && !in->peer_faulted &&
74 !(in->peer_online_now && peer_answering(in)))
75 {
76 /* The A/B sibling is ONLINE but this channel's own link view is unusable (link flapping, counterpart silent):
77 * the two channels of a site must agree, so follow the sibling once it has been ONLINE for 2 cycles, unless
78 * the counterpart is verifiably ONLINE right now (then the disagreement is real and the pair must reboot). */
80 if (d.both_standby_cycles >= 2U)
81 {
85 }
86 }
87 else
88 {
89 /* nothing applies: the counter stays at 0 (it counts consecutive cycles only) */
90 }
91
93 {
96 d.both_standby_cycles = in->both_standby_cycles + 1U; /* keep the tie-break condition counting */
97 }
98 return d;
99}
100
102{
103 const char *text = "none";
104
105 switch (reason)
106 {
108 text = "both sites FAULTED, WEST wins";
109 break;
111 text = "counterpart FAULTED";
112 break;
114 text = "was FAULTED, counterpart healthy ONLINE";
115 break;
117 text = "dispatcher confirmed the other site is not ONLINE";
118 break;
120 text = "negotiation - both sites STANDBY, WEST wins the tie";
121 break;
123 text = "negotiation - both sites STANDBY, joining the ONLINE A/B sibling";
124 break;
126 text = "counterpart took over while this channel was cut off";
127 break;
129 text = "both sites ONLINE without a lost-contact history";
130 break;
132 text = "promotion held back until both A/B channels are ready";
133 break;
134 case RTE_SITE_ROLE_REASON_NONE:
135 default:
136 break;
137 }
138 return text;
139}
140
142{
143 const char *token = "none";
144
145 switch (reason)
146 {
148 token = "both_faulted";
149 break;
151 token = "peer_faulted";
152 break;
154 token = "recovered";
155 break;
157 token = "dispatcher";
158 break;
160 token = "both_standby_west";
161 break;
163 token = "both_standby_sibling";
164 break;
166 token = "yield";
167 break;
169 token = "dual_online";
170 break;
172 token = "waiting_ready";
173 break;
174 case RTE_SITE_ROLE_REASON_NONE:
175 default:
176 break;
177 }
178 return token;
179}
180
181bool rte_site_role_standby_sync_due(bool sync_enabled, bool is_online, bool link_up, bool healthy, uint32_t cycle,
182 uint32_t last_try)
183{
184 bool due = false;
185
186 if (sync_enabled && is_online && link_up)
187 {
188 if (healthy)
189 {
190 due = true;
191 }
192 else
193 {
194 /* Unsigned subtraction is wrap-safe as long as cycle >= last_try; a cycle counter that
195 * restarted (resync) makes last_try > cycle, which retries immediately - the safe side. */
196 due = (cycle < last_try) || ((cycle - last_try) >= RTE_SITE_ROLE_STANDBY_SYNC_RETRY_CYCLES);
197 }
198 }
199 return due;
200}
201
202bool rte_site_role_standby_data_stale(bool sync_enabled, bool is_online, bool have_snapshot, uint32_t cycle,
203 uint32_t last_rx_cycle)
204{
205 bool stale = false;
206
207 if (sync_enabled && !is_online && have_snapshot)
208 {
209 /* A restarted cycle counter (cycle < last_rx_cycle) is treated as stale: the numbering the
210 * snapshot was stamped against is gone. */
211 stale = (cycle < last_rx_cycle) || ((cycle - last_rx_cycle) > RTE_SITE_ROLE_STANDBY_DATA_TIMEOUT_CYCLES);
212 }
213 return stale;
214}
215
216bool rte_site_role_takeover_allowed(bool is_online, bool own_faulted, bool peer_unresponsive, bool confirmed,
217 uint32_t cycle, uint32_t confirm_cycle)
218{
219 bool allowed = false;
220
221 if (!is_online && !own_faulted && peer_unresponsive && confirmed)
222 {
223 /* A restarted cycle counter (cycle < confirm_cycle) makes the stamp meaningless: expired. */
224 allowed = (cycle >= confirm_cycle) && ((cycle - confirm_cycle) <= RTE_SITE_ROLE_TAKEOVER_CONFIRM_VALID_CYCLES);
225 }
226 return allowed;
227}
228
229bool rte_site_role_both_standby_tiebreak(uint32_t both_standby_cycles, bool is_west, bool sibling_online)
230{
231 return (sibling_online && (both_standby_cycles >= 1U)) || (is_west && (both_standby_cycles >= RTE_SITE_ROLE_BOTH_STANDBY_CYCLES));
232}
static bool peer_answering(const rte_site_role_input_t *in)
static bool pair_ready_to_promote(const rte_site_role_input_t *in)
Site-role policy: one pure decision function for "should this channel promote, demote or stay?...
bool rte_site_role_standby_data_stale(bool sync_enabled, bool is_online, bool have_snapshot, uint32_t cycle, uint32_t last_rx_cycle)
Whether STANDBY's held snapshot is stale and must be dropped (STANDBY goes cold).
rte_site_role_decision_t rte_site_role_decide(const rte_site_role_input_t *in)
Decides this cycle's role action. Rules are evaluated in this order and the first that applies wins:
rte_site_role_reason_t
@ RTE_SITE_ROLE_REASON_DUAL_ONLINE
@ RTE_SITE_ROLE_REASON_WAITING_READY
@ RTE_SITE_ROLE_REASON_PEER_FAULTED
@ RTE_SITE_ROLE_REASON_BOTH_FAULTED
@ RTE_SITE_ROLE_REASON_DISPATCHER_CONFIRMED
@ RTE_SITE_ROLE_REASON_BOTH_STANDBY_SIBLING
@ RTE_SITE_ROLE_REASON_RECOVERED
@ RTE_SITE_ROLE_REASON_YIELD_TO_TAKEOVER
@ RTE_SITE_ROLE_REASON_BOTH_STANDBY_WEST
const char * rte_site_role_reason_text(rte_site_role_reason_t reason)
bool rte_site_role_both_standby_tiebreak(uint32_t both_standby_cycles, bool is_west, bool sibling_online)
Negotiation tie-break for "both sites STANDBY": a channel whose A/B sibling is already ONLINE joins i...
@ RTE_SITE_ROLE_ACTION_NONE
@ RTE_SITE_ROLE_ACTION_RENEGOTIATE
@ RTE_SITE_ROLE_ACTION_PROMOTE
@ RTE_SITE_ROLE_ACTION_DEMOTE
@ RTE_SITE_ROLE_ACTION_WAIT
@ RTE_SITE_ROLE_ACTION_ALARM
#define RTE_SITE_ROLE_STANDBY_SYNC_RETRY_CYCLES
bool rte_site_role_takeover_allowed(bool is_online, bool own_faulted, bool peer_unresponsive, bool confirmed, uint32_t cycle, uint32_t confirm_cycle)
Whether a STANDBY channel may promote itself because its counterpart stopped responding....
#define RTE_SITE_ROLE_STANDBY_DATA_TIMEOUT_CYCLES
#define RTE_SITE_ROLE_TAKEOVER_CONFIRM_VALID_CYCLES
#define RTE_SITE_ROLE_BOTH_STANDBY_CYCLES
bool rte_site_role_standby_sync_due(bool sync_enabled, bool is_online, bool link_up, bool healthy, uint32_t cycle, uint32_t last_try)
Whether ONLINE should attempt the pre-commit standby sync this cycle.
const char * rte_site_role_reason_token(rte_site_role_reason_t reason)