|
Safe API Framework 0.1.0 build 384e6ae
Layered API framework for safety-related applications (ERTMS RBC reference targeting CENELEC EN 50128 SIL 4)
|
See rte_site_role.h. Moved from RBC_GP's ab_gp_channel_negotiate.c (ADR-040 step 2): same link handling, same frame layout, same decisions, same log text; the application-specific parts (state codec, what a promotion takes over, readiness) are the Site Role Client's callbacks and local facts. More...
#include "rte/redundancy/site_role/rte_site_role.h"#include <stdio.h>#include "rte/oal/log/rte_log.h"#include "rte/oal/memory/rte_mem_util.h"#include "rte/oal/random/rte_random.h"#include "rte/oal/timer/rte_timer.h"#include "rte/utils/buffer/rte_buffer.h"Go to the source code of this file.
Macros | |
| #define | SITE_ROLE_TRACE_LINE_MAX 256U |
| #define | SITE_ROLE_SERVICE_DRAIN 4U |
Functions | |
| static void | trace_line (const rte_site_role_t *rs, const char *line) |
| static void | log_event (const rte_site_role_t *rs, rte_log_level_t level, uint32_t cycle, const char *source, const char *destination, const char *type, const char *info, const char *extra) |
| static size_t | state_size (const rte_site_role_t *rs) |
| static void | encode_frame (rte_site_role_t *rs, bool faulted, bool single_mode, uint32_t cycle, bool live) |
| static void | report_change (rte_site_role_t *rs, rte_site_role_change_kind_t kind, rte_site_role_reason_t reason, bool apply_state) |
| static void | promote_to_online (rte_site_role_t *rs, const char *message, rte_site_role_reason_t reason) |
| static void | demote_to_standby (rte_site_role_t *rs, const char *message, rte_site_role_reason_t reason) |
| static void | renegotiate_from_deadlock (rte_site_role_t *rs, rte_site_role_reason_t reason) |
| static void | on_negotiator_state_change (rte_dual_state_t new_own_state, rte_dual_state_t old_own_state, rte_dual_state_t new_peer_state, rte_dual_state_t old_peer_state, void *user_ctx) |
| static rte_status_t | open_link_once (rte_site_role_t *rs, rte_duration_ms_t timeout_ms) |
| static rte_status_t | open_link_blocking (rte_site_role_t *rs) |
| static rte_status_t | init_channel_and_negotiator (rte_site_role_t *rs, bool resume_standby) |
| static void | close_link (rte_site_role_t *rs) |
| static rte_status_t | reconnect (rte_site_role_t *rs) |
| static bool | send_frame (rte_site_role_t *rs, uint32_t cycle) |
| static rte_status_t | receive_frame (rte_site_role_t *rs, uint32_t cycle, bool quiet) |
| static void | handle_send_miss_and_link_teardown (rte_site_role_t *rs, uint32_t cycle, bool send_ok, rte_status_t receive_status) |
| static void | update_standby_warmth (rte_site_role_t *rs, uint32_t cycle) |
| static void | poll_sibling_source (rte_site_role_t *rs, uint32_t cycle) |
| static bool | sibling_reachable (const rte_site_role_t *rs) |
| static void | fill_sibling_facts (const rte_site_role_t *rs, const rte_site_role_local_t *local, rte_site_role_input_t *in) |
| static void | check_sibling_after_decision (rte_site_role_t *rs, uint32_t cycle, const rte_site_role_local_t *local) |
| static void | startup_role_from_sibling (rte_site_role_t *rs, bool *resume_standby) |
| static void | build_decision_input (const rte_site_role_t *rs, const rte_site_role_local_t *local, rte_site_role_input_t *in) |
| static bool | reason_changed (const rte_site_role_t *rs, rte_site_role_reason_t reason) |
| static void | set_reason (rte_site_role_t *rs, rte_site_role_reason_t reason) |
| static void | run_site_role_decision (rte_site_role_t *rs, uint32_t cycle, const rte_site_role_local_t *local) |
| static void | take_local (rte_site_role_t *rs, const rte_site_role_local_t *local) |
| static uint32_t | read_u32_le (const uint8_t *in) |
| static uint32_t | challenge_lifetime (const rte_site_role_t *rs) |
| static void | draw_challenge (rte_site_role_t *rs, uint32_t cycle) |
| static void | refresh_challenge (rte_site_role_t *rs, uint32_t cycle) |
| static void | record_takeover_confirmation (rte_site_role_t *rs, uint32_t cycle, const char *how) |
| static void | trace_ignored_while_online (const rte_site_role_t *rs) |
| static rte_site_role_token_result_t | check_token (const rte_site_role_t *rs, const uint8_t *token, size_t token_len) |
| static const char * | token_result_text (rte_site_role_token_result_t result) |
| rte_status_t | rte_site_role_init (rte_site_role_t *rs, const rte_site_role_config_t *cfg) |
| Validates and stores the configuration. Opens nothing. | |
| rte_status_t | rte_site_role_start (rte_site_role_t *rs) |
| Opens the link (blocking, bounded by startup_timeout_ms) and runs the startup negotiation until it settles (older startup timestamp wins). Setup phase only. | |
| void | rte_site_role_execute (rte_site_role_t *rs, uint32_t cycle, const rte_site_role_local_t *local) |
| One cycle: reconnect if needed, exchange frames, update the standby state, decide and apply the role. | |
| void | rte_site_role_service_link (rte_site_role_t *rs, uint32_t cycle) |
| Fast tick: drains up to 4 frames so acknowledgements do not depend on the two sites' cycle phase. | |
| void | rte_site_role_sync_standby (rte_site_role_t *rs, uint32_t cycle, const rte_site_role_local_t *local) |
| ONLINE, warm/hot standby: sends this cycle's snapshot before the output commit and tracks the ack. | |
| void | rte_site_role_on_takeover_confirm (rte_site_role_t *rs, uint32_t cycle) |
| Records an unauthenticated dispatcher confirmation that the other site is not ONLINE (ignored while ONLINE). Interim path: refused (and logged) when a MAC verifier is configured - use rte_site_role_on_takeover_token(). | |
| rte_site_role_token_result_t | rte_site_role_on_takeover_token (rte_site_role_t *rs, uint32_t cycle, const uint8_t *token, size_t token_len) |
| Verifies a takeover confirmation token (REQ-SITEROLE-015) and, when it is valid, records the confirmation exactly like rte_site_role_on_takeover_confirm() and draws a new challenge. Every outcome is logged. | |
| bool | rte_site_role_takeover_challenge (const rte_site_role_t *rs, uint32_t *out) |
| This channel's current takeover challenge, for the application's status line (the issuer MACs it). | |
| void | rte_site_role_note_lost_contact (rte_site_role_t *rs) |
| The application stalled while ONLINE long enough for the counterpart to have taken over: yield if it is. | |
| void | rte_site_role_flush_faulted (rte_site_role_t *rs, bool single_mode) |
| Best-effort final frame with faulted=1 before the process reboots, so the counterpart can promote. | |
| rte_site_role_sibling_verdict_t | rte_site_role_check_sibling (rte_site_role_t *rs, uint32_t cycle, bool own_single_mode, const rte_site_role_sibling_t *sibling) |
| A/B role agreement (REQ-SITEROLE-014): compares this channel's role and single_mode with its sibling's. | |
| rte_site_role_sibling_verdict_t | rte_site_role_sibling_verdict (const rte_site_role_t *rs) |
| The A/B agreement verdict of the check run by the last rte_site_role_execute() (REQ-SITEROLE-016). | |
| void | rte_site_role_shutdown (rte_site_role_t *rs) |
| Closes the link. Idempotent. | |
| bool | rte_site_role_is_online (const rte_site_role_t *rs) |
| void | rte_site_role_get_status (const rte_site_role_t *rs, rte_site_role_status_t *out) |
| Fills a status snapshot for monitors. | |
| void | rte_site_role_get_negotiator_states (const rte_site_role_t *rs, rte_dual_state_t *own, rte_dual_state_t *peer) |
| The underlying negotiator's own and peer states (diagnostic only; the role is rte_site_role_is_online()). | |
See rte_site_role.h. Moved from RBC_GP's ab_gp_channel_negotiate.c (ADR-040 step 2): same link handling, same frame layout, same decisions, same log text; the application-specific parts (state codec, what a promotion takes over, readiness) are the Site Role Client's callbacks and local facts.
Design note kept from the original: the negotiator (rte_dual_negotiator, ADR-020) settles the startup role and is logged every cycle as a diagnostic of the link's health. After startup the role is driven only by rte_site_role_decide() over the facts gathered here; the negotiator's own state can legitimately differ from the role after a FAULTED-driven promotion, because it has no view of that override.
Definition in file rte_site_role.c.
| #define SITE_ROLE_TRACE_LINE_MAX 256U |
Definition at line 22 of file rte_site_role.c.
| #define SITE_ROLE_SERVICE_DRAIN 4U |
Definition at line 23 of file rte_site_role.c.
|
static |
Definition at line 27 of file rte_site_role.c.
|
static |
Definition at line 35 of file rte_site_role.c.
|
static |
Definition at line 43 of file rte_site_role.c.
|
static |
Definition at line 48 of file rte_site_role.c.
|
static |
Definition at line 66 of file rte_site_role.c.
|
static |
Definition at line 90 of file rte_site_role.c.
|
static |
Definition at line 104 of file rte_site_role.c.
|
static |
Both sites FAULTED: the same deterministic, symmetric rule on both sides - WEST ONLINE, EAST STANDBY.
Definition at line 117 of file rte_site_role.c.
|
static |
Definition at line 132 of file rte_site_role.c.
|
static |
Definition at line 153 of file rte_site_role.c.
|
static |
Startup: the listen side opens once; the connect side retries until startup_timeout_ms (container start order is not guaranteed).
Definition at line 168 of file rte_site_role.c.
|
static |
(Re)initializes the dual channel and the negotiator over the open link. A reconnect resumes this channel's own identity (startup timestamp, and ONLINE if it is ONLINE) instead of re-litigating the startup tie-break; a start-up next to a running A/B sibling resumes the site's role the same way (REQ-SITEROLE-017: ONLINE when the sibling is ONLINE, STANDBY through resume_standby otherwise). A reconnect passes resume_standby false: a STANDBY reconnect keeps re-deciding from its resumed timestamp.
Definition at line 200 of file rte_site_role.c.
|
static |
Definition at line 254 of file rte_site_role.c.
|
static |
One bounded reconnect attempt per cycle on the cyclic executive's own thread (REQ-SITEROLE-012): with a silent counterpart a longer bound stretched every cycle of the site, also the ONLINE one.
Definition at line 265 of file rte_site_role.c.
|
static |
Definition at line 289 of file rte_site_role.c.
|
static |
Definition at line 307 of file rte_site_role.c.
|
static |
REQ-SITEROLE-013: closes the link after send_miss_threshold consecutive unacknowledged sends (one lost UDP datagram is routine) or at once on a receive failure other than a timeout (ADR-027).
Definition at line 374 of file rte_site_role.c.
|
static |
STANDBY, once per cycle: drops a snapshot that has gone stale (STANDBY goes cold) and logs the warm transition.
Definition at line 423 of file rte_site_role.c.
|
static |
Polls the sibling source once per cycle; a fresh frame is stamped with this cycle.
Definition at line 457 of file rte_site_role.c.
|
static |
The sibling's frame counts as reachable while it is at most sibling_reach_cycles old (the rule GP applied to its peer link: "frame within the last 3 cycles"). A cycle number that went back (a state transfer renumbers cycles) makes the frame stale rather than letting the unsigned difference wrap.
Definition at line 471 of file rte_site_role.c.
|
static |
With a source, the sibling facts are derived here; without one the application's local facts apply (step 3).
Definition at line 478 of file rte_site_role.c.
|
static |
After the role decision of this cycle (REQ-SITEROLE-014 against the role just decided): the same check, log lines and NEGOTIATION_MISMATCH event the application ran itself in step 3. Without a source the verdict stays UNKNOWN.
Definition at line 497 of file rte_site_role.c.
|
static |
Start-up role from the A/B sibling (REQ-SITEROLE-017), after the cycle-0 poll: a known sibling frame decides the start-up role - ONLINE when the sibling reports ONLINE, STANDBY otherwise (resume_standby) - so this channel joins the site's role instead of evaluating the timestamp tie-break. The frame's ready and single_mode take no part. Without a frame the tie-break runs as before; without a source nothing changes.
Definition at line 509 of file rte_site_role.c.
|
static |
Definition at line 539 of file rte_site_role.c.
|
static |
Definition at line 560 of file rte_site_role.c.
|
static |
Definition at line 565 of file rte_site_role.c.
|
static |
Gathers the facts, asks rte_site_role_decide(), applies the one action it returns (REQ-SITEROLE-011).
Definition at line 572 of file rte_site_role.c.
|
static |
Definition at line 629 of file rte_site_role.c.
|
static |
Definition at line 637 of file rte_site_role.c.
|
static |
Definition at line 642 of file rte_site_role.c.
|
static |
Definition at line 648 of file rte_site_role.c.
|
static |
Definition at line 675 of file rte_site_role.c.
|
static |
Definition at line 688 of file rte_site_role.c.
|
static |
Definition at line 701 of file rte_site_role.c.
|
static |
Definition at line 709 of file rte_site_role.c.
|
static |
Definition at line 743 of file rte_site_role.c.
| rte_status_t rte_site_role_init | ( | rte_site_role_t * | rs, |
| const rte_site_role_config_t * | cfg ) |
Validates and stores the configuration. Opens nothing.
Definition at line 777 of file rte_site_role.c.
| rte_status_t rte_site_role_start | ( | rte_site_role_t * | rs | ) |
Opens the link (blocking, bounded by startup_timeout_ms) and runs the startup negotiation until it settles (older startup timestamp wins). Setup phase only.
Start-up role from the A/B sibling (REQ-SITEROLE-017): with a sibling source configured, the source is polled once before the link is opened. A known sibling frame decides the role: sibling ONLINE -> this channel starts ONLINE, sibling STANDBY (ready or not) -> STANDBY; the negotiator is seeded to that state and does not evaluate the timestamp tie-break. The frame's ready (REQ-SITEROLE-002 gates promotions, not the start-up role) and single_mode (REQ-SITEROLE-014, checked from the first rte_site_role_execute()) are not consulted. No frame yet, or no source: the REQ-DUAL-NEGOTIATOR-003 tie-break as before. The startup timestamp is unchanged in every case.
| rs | Service state, initialized by rte_site_role_init(). NULL returns RTE_STATUS_INVALID_PARAM. |
Definition at line 805 of file rte_site_role.c.
| void rte_site_role_execute | ( | rte_site_role_t * | rs, |
| uint32_t | cycle, | ||
| const rte_site_role_local_t * | local ) |
One cycle: reconnect if needed, exchange frames, update the standby state, decide and apply the role.
Definition at line 890 of file rte_site_role.c.
| void rte_site_role_service_link | ( | rte_site_role_t * | rs, |
| uint32_t | cycle ) |
Fast tick: drains up to 4 frames so acknowledgements do not depend on the two sites' cycle phase.
Definition at line 947 of file rte_site_role.c.
| void rte_site_role_sync_standby | ( | rte_site_role_t * | rs, |
| uint32_t | cycle, | ||
| const rte_site_role_local_t * | local ) |
ONLINE, warm/hot standby: sends this cycle's snapshot before the output commit and tracks the ack.
Definition at line 967 of file rte_site_role.c.
| void rte_site_role_on_takeover_confirm | ( | rte_site_role_t * | rs, |
| uint32_t | cycle ) |
Records an unauthenticated dispatcher confirmation that the other site is not ONLINE (ignored while ONLINE). Interim path: refused (and logged) when a MAC verifier is configured - use rte_site_role_on_takeover_token().
Definition at line 1015 of file rte_site_role.c.
| rte_site_role_token_result_t rte_site_role_on_takeover_token | ( | rte_site_role_t * | rs, |
| uint32_t | cycle, | ||
| const uint8_t * | token, | ||
| size_t | token_len ) |
Verifies a takeover confirmation token (REQ-SITEROLE-015) and, when it is valid, records the confirmation exactly like rte_site_role_on_takeover_confirm() and draws a new challenge. Every outcome is logged.
| token | RTE_SITE_ROLE_TOKEN_LEN bytes as described above |
| token_len | number of bytes in token |
Definition at line 1041 of file rte_site_role.c.
| bool rte_site_role_takeover_challenge | ( | const rte_site_role_t * | rs, |
| uint32_t * | out ) |
This channel's current takeover challenge, for the application's status line (the issuer MACs it).
| out | receives the challenge |
Definition at line 1075 of file rte_site_role.c.
| void rte_site_role_note_lost_contact | ( | rte_site_role_t * | rs | ) |
The application stalled while ONLINE long enough for the counterpart to have taken over: yield if it is.
Definition at line 1085 of file rte_site_role.c.
| void rte_site_role_flush_faulted | ( | rte_site_role_t * | rs, |
| bool | single_mode ) |
Best-effort final frame with faulted=1 before the process reboots, so the counterpart can promote.
Definition at line 1093 of file rte_site_role.c.
| rte_site_role_sibling_verdict_t rte_site_role_check_sibling | ( | rte_site_role_t * | rs, |
| uint32_t | cycle, | ||
| bool | own_single_mode, | ||
| const rte_site_role_sibling_t * | sibling ) |
A/B role agreement (REQ-SITEROLE-014): compares this channel's role and single_mode with its sibling's.
| own_single_mode | this channel's single-channel mode at the time of the check |
Definition at line 1110 of file rte_site_role.c.
| rte_site_role_sibling_verdict_t rte_site_role_sibling_verdict | ( | const rte_site_role_t * | rs | ) |
The A/B agreement verdict of the check run by the last rte_site_role_execute() (REQ-SITEROLE-016).
| rs | the service; may be NULL |
Definition at line 1160 of file rte_site_role.c.
| void rte_site_role_shutdown | ( | rte_site_role_t * | rs | ) |
Closes the link. Idempotent.
Definition at line 1165 of file rte_site_role.c.
| bool rte_site_role_is_online | ( | const rte_site_role_t * | rs | ) |
Definition at line 1173 of file rte_site_role.c.
| void rte_site_role_get_status | ( | const rte_site_role_t * | rs, |
| rte_site_role_status_t * | out ) |
Fills a status snapshot for monitors.
Definition at line 1178 of file rte_site_role.c.
| void rte_site_role_get_negotiator_states | ( | const rte_site_role_t * | rs, |
| rte_dual_state_t * | own, | ||
| rte_dual_state_t * | peer ) |
The underlying negotiator's own and peer states (diagnostic only; the role is rte_site_role_is_online()).
Definition at line 1194 of file rte_site_role.c.