1 /*
2 * Copyright 2009-2026 the Pacemaker project contributors
3 *
4 * The version control history for this file may have further details.
5 *
6 * This source code is licensed under the GNU General Public License version 2
7 * or later (GPLv2+) WITHOUT ANY WARRANTY.
8 */
9
10 #include <crm_internal.h>
11
12 #include <inttypes.h> // uint32_t, PRIu32
13 #include <stdlib.h> // NULL, free, size_t
14
15 #include <corosync/cpg.h> // cpg_handle_t, cpg_name
16 #include <glib.h> // gpointer
17 #include <libxml/tree.h> // xmlNode
18
19 #include <crm/cluster.h> // pcmk_cluster_connect
20 #include <crm/common/ipc.h> // pcmk_ipc_server
21 #include <crm/common/results.h> // pcmk_rc_*
22 #include <crm/stonith-ng.h> // st_opt_*
23
24 #include "pacemaker-fenced.h"
25
26 pcmk_cluster_t *fenced_cluster = NULL;
27
28 static void
29 handle_cpg_reply(const char *remote_peer, xmlNode *request)
30 {
31 const char *op = pcmk__xe_get(request, PCMK__XA_ST_OP);
32
33 if (pcmk__str_eq(op, STONITH_OP_QUERY, pcmk__str_none)) {
34 process_remote_stonith_query(request);
35
36 } else if (pcmk__str_any_of(op, STONITH_OP_NOTIFY, STONITH_OP_FENCE,
37 NULL)) {
38 fenced_process_fencing_reply(request);
39
40 } else {
41 pcmk__err("Ignoring unknown %s reply from peer %s",
42 pcmk__s(op, "untyped"), remote_peer);
43 pcmk__log_xml_warn(request, "UnknownOp");
44 return;
45 }
46
47 pcmk__debug("Processed %s reply from peer %s", op, remote_peer);
48 }
49
50 static void
51 fenced_peer_message(pcmk__node_status_t *peer, xmlNode *xml)
52 {
53 const char *op = pcmk__xe_get(xml, PCMK__XA_ST_OP);
54 int rc = pcmk_rc_ok;
55
56 if (pcmk__str_eq(op, STONITH_OP_POKE, pcmk__str_none)) {
57 return;
58 }
59
60 if (pcmk__xpath_find_one(xml->doc, "//" PCMK__XE_ST_REPLY,
61 PCMK__LOG_NEVER) != NULL) {
62 handle_cpg_reply(peer->name, xml);
63
64 } else {
65 pcmk__request_t request = {
66 .ipc_client = NULL,
67 .ipc_id = 0,
68 .ipc_flags = crm_ipc_flags_none,
69 .peer = peer->name,
70 .xml = xml,
71 .call_options = st_opt_none,
72 .result = PCMK__UNKNOWN_RESULT,
73 };
74
75 rc = pcmk__xe_get_flags(xml, PCMK__XA_ST_CALLOPT,
76 (uint32_t *) &request.call_options, st_opt_none);
77 if (rc != pcmk_rc_ok) {
78 pcmk__warn("Couldn't parse options from request: %s",
79 pcmk_rc_str(rc));
80 }
81
82 request.op = pcmk__xe_get_copy(request.xml, PCMK__XA_ST_OP);
83 CRM_CHECK(request.op != NULL, return);
84
85 if (pcmk__is_set(request.call_options, st_opt_sync_call)) {
86 pcmk__set_request_flags(&request, pcmk__request_sync);
87 }
88
89 fenced_handle_request(&request);
90 }
91 }
92
93 /*!
94 * \internal
95 * \brief Callback for peer status changes
96 *
97 * \param[in] type What changed
98 * \param[in] node What peer had the change
99 * \param[in] data Previous value of what changed
100 */
101 static void
102 fenced_peer_change_cb(enum pcmk__node_update type, pcmk__node_status_t *node,
103 const void *data)
104 {
105 if ((type != pcmk__node_update_processes)
106 && !pcmk__is_set(node->flags, pcmk__node_status_remote)) {
107 /*
108 * This is a hack until we can send to a nodeid and/or we fix node name lookups
109 * These messages are ignored in stonith_peer_callback()
110 */
111 xmlNode *query = pcmk__xe_create(NULL, PCMK__XE_STONITH_COMMAND);
112
113 pcmk__xe_set(query, PCMK__XA_T, PCMK__VALUE_STONITH_NG);
114 pcmk__xe_set(query, PCMK__XA_ST_OP, STONITH_OP_POKE);
115
116 pcmk__debug("Broadcasting our uname because of node %" PRIu32,
117 node->cluster_layer_id);
118 pcmk__cluster_send_message(NULL, pcmk_ipc_fenced, query);
119
120 pcmk__xml_free(query);
121 }
122 }
123
124 #if SUPPORT_COROSYNC
125 /*!
126 * \internal
127 * \brief Callback for when a peer message is received
128 *
129 * \param[in] handle The cluster connection
130 * \param[in] group_name The group that \p nodeid is a member of
131 * \param[in] nodeid Peer node that sent \p msg
132 * \param[in] pid Process that sent \p msg
133 * \param[in,out] msg Received message
134 * \param[in] msg_len Length of \p msg
135 */
136 static void
137 fenced_cpg_dispatch(cpg_handle_t handle, const struct cpg_name *group_name,
138 uint32_t nodeid, uint32_t pid, void *msg, size_t msg_len)
139 {
140 xmlNode *xml = NULL;
141 const char *from = NULL;
142 char *data = pcmk__cpg_message_data(handle, nodeid, pid, msg, &from);
143
144 if (data == NULL) {
145 return;
146 }
147
148 xml = pcmk__xml_parse(data);
149 if (xml == NULL) {
150 pcmk__err("Bad message received from %s[%" PRIu32 "]: '%.120s'",
151 from, nodeid, data);
152 } else {
153 pcmk__xe_set(xml, PCMK__XA_SRC, from);
154 fenced_peer_message(pcmk__get_node(nodeid, from, NULL,
155 pcmk__node_search_cluster_member),
156 xml);
157 }
158
159 pcmk__xml_free(xml);
160 free(data);
161 }
162
163 /*!
164 * \internal
165 * \brief Callback for when the cluster object is destroyed
166 *
167 * \param[in] unused Unused
168 */
169 static void
170 fenced_cpg_destroy(gpointer unused)
171 {
172 pcmk__crit("Lost connection to cluster layer, shutting down");
173 stonith_shutdown(0);
174 }
175 #endif // SUPPORT_COROSYNC
176
177 int
178 fenced_cluster_connect(void)
179 {
180 int rc = pcmk_rc_ok;
181
182 fenced_cluster = pcmk_cluster_new();
183
184 #if SUPPORT_COROSYNC
185 if (pcmk_get_cluster_layer() == pcmk_cluster_layer_corosync) {
186 pcmk_cluster_set_destroy_fn(fenced_cluster, fenced_cpg_destroy);
187 pcmk_cpg_set_deliver_fn(fenced_cluster, fenced_cpg_dispatch);
188 pcmk_cpg_set_confchg_fn(fenced_cluster, pcmk__cpg_confchg_cb);
189 }
190 #endif // SUPPORT_COROSYNC
191
192 pcmk__cluster_set_status_callback(&fenced_peer_change_cb);
193
194 rc = pcmk_cluster_connect(fenced_cluster);
195 if (rc != pcmk_rc_ok) {
196 pcmk__err("Cluster connection failed");
197 }
198
199 return rc;
200 }
201
202 void
203 fenced_cluster_disconnect(void)
204 {
|
(1) Event path: |
Condition "fenced_cluster == NULL", taking false branch. |
205 if (fenced_cluster == NULL) {
206 return;
207 }
208
209 pcmk_cluster_disconnect(fenced_cluster);
|
CID (unavailable; MK=cf8bc0ac10c1620539d042a481cb742d) (#1 of 1): Inconsistent C union access (INCONSISTENT_UNION_ACCESS): |
|
(2) Event assign_union_field: |
The union field "in" of "_pp" is written. |
|
(3) Event inconsistent_union_field_access: |
In "_pp.out", the union field used: "out" is inconsistent with the field most recently stored: "in". |
210 g_clear_pointer(&fenced_cluster, pcmk_cluster_free);
211 }
212