qdevice-net-algo-test.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457
  1. /*
  2. * Copyright (c) 2015-2019 Red Hat, Inc.
  3. *
  4. * All rights reserved.
  5. *
  6. * Author: Jan Friesse (jfriesse@redhat.com)
  7. *
  8. * This software licensed under BSD license, the text of which follows:
  9. *
  10. * Redistribution and use in source and binary forms, with or without
  11. * modification, are permitted provided that the following conditions are met:
  12. *
  13. * - Redistributions of source code must retain the above copyright notice,
  14. * this list of conditions and the following disclaimer.
  15. * - Redistributions in binary form must reproduce the above copyright notice,
  16. * this list of conditions and the following disclaimer in the documentation
  17. * and/or other materials provided with the distribution.
  18. * - Neither the name of the Red Hat, Inc. nor the names of its
  19. * contributors may be used to endorse or promote products derived from this
  20. * software without specific prior written permission.
  21. *
  22. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  23. * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  24. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  25. * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
  26. * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  27. * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  28. * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  29. * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  30. * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  31. * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
  32. * THE POSSIBILITY OF SUCH DAMAGE.
  33. */
  34. #include <sys/types.h>
  35. #include <string.h>
  36. #include "log.h"
  37. #include "qdevice-net-algo-test.h"
  38. #include "qdevice-net-send.h"
  39. #include "qdevice-net-cast-vote-timer.h"
  40. /*
  41. * Called after qdevice_net_instance is initialized. Connection to server is not yet
  42. * established. Used mainly for allocating instance->algorithm_data.
  43. *
  44. * Callback should return 0 on success or -1 on failure.
  45. */
  46. int
  47. qdevice_net_algo_test_init(struct qdevice_net_instance *instance)
  48. {
  49. instance->algorithm_data = NULL;
  50. log(LOG_INFO, "algo-test: Initialized");
  51. return (0);
  52. }
  53. /*
  54. * Called after qdevice connected to qnetd.
  55. * send_config_node_list, send_membership_node_list and send_quorum_node_list can be set to
  56. * nonzero (default) to make qdevice-net send given lists to qnetd
  57. * vote (default TLV_VOTE_WAIT_FOR_REPLY) can be set to update voting timer
  58. * heuristics is result of pre connect heuristics and can be updated
  59. *
  60. * Callback should return 0 on success or -1 on failure (-> disconnect client).
  61. */
  62. int
  63. qdevice_net_algo_test_connected(struct qdevice_net_instance *instance, enum tlv_heuristics *heuristics,
  64. int *send_config_node_list, int *send_membership_node_list, int *send_quorum_node_list, enum tlv_vote *vote)
  65. {
  66. log(LOG_INFO, "algo-test: Connected");
  67. return (0);
  68. }
  69. /*
  70. * Called after config node list changed.
  71. *
  72. * Callback can override send_node_list and vote.
  73. * Depending on net_instance->state, they are set acordingly:
  74. * If net_instance->state != QDEVICE_NET_INSTANCE_STATE_WAITING_VOTEQUORUM_CMAP_EVENTS
  75. * send_node_list = 0
  76. * if cast_vote_timer_vote != TLV_VOTE_ACK
  77. * vote = TLV_VOTE_NO_CHANGE
  78. * if cast_vote_timer_vote = TLV_VOTE_ACK
  79. * vote = TLV_VOTE_NACK.
  80. * Otherwise send_node_list = 1 and vote = TLV_VOTE_NO_CHANGE
  81. * If send_node_list is set to non zero, node list is sent to qnetd
  82. */
  83. int
  84. qdevice_net_algo_test_config_node_list_changed(struct qdevice_net_instance *instance,
  85. const struct node_list *nlist, int config_version_set, uint64_t config_version,
  86. int *send_node_list, enum tlv_vote *vote)
  87. {
  88. log(LOG_INFO, "algo-test: Config node list changed");
  89. return (0);
  90. }
  91. /*
  92. * Called after votequorum node list notify is dispatched but heuristics result is not
  93. * yet known (heuristics were just executed). Full list together with result of heuristics
  94. * are received in qdevice_net_algo_test_votequorum_node_list_heuristics_notify.
  95. * This applies also if heuristics are disabled.
  96. *
  97. * pause_cast_vote_timer is preset to 1. If after callback this value is still != 0,
  98. * cast vote timer is paused until heuristics finishes.
  99. *
  100. * vote is by default set to TLV_VOTE_NO_CHANGE with exception of situation when
  101. * net_instance->state != QDEVICE_NET_INSTANCE_STATE_WAITING_VOTEQUORUM_CMAP_EVENTS and
  102. * cast_vote_timer_vote = TLV_VOTE_ACK
  103. * then vote is set to TLV_VOTE_NACK. This is to allow qnetd disconnection and still vote
  104. * ACK as long as no change happens.
  105. *
  106. * Callback should return 0 on success or -1 on failure (-> disconnect client).
  107. */
  108. int
  109. qdevice_net_algo_test_votequorum_node_list_notify(struct qdevice_net_instance *instance,
  110. const struct tlv_ring_id *ring_id, uint32_t node_list_entries, uint32_t node_list[],
  111. int *pause_cast_vote_timer, enum tlv_vote *vote)
  112. {
  113. log(LOG_INFO, "algo-test: Votequorum list notify");
  114. return (0);
  115. }
  116. /*
  117. * Called after votequorum node list notify is dispatched and heuristics result is known.
  118. *
  119. * Callback should return 0 on success or -1 on failure (-> disconnect client).
  120. *
  121. * If net_instance->state != QDEVICE_NET_INSTANCE_STATE_WAITING_VOTEQUORUM_CMAP_EVENTS
  122. * send_node_list = 0
  123. * if cast_vote_timer_vote != TLV_VOTE_ACK
  124. * vote = TLV_VOTE_NO_CHANGE
  125. * if cast_vote_timer_vote = TLV_VOTE_ACK
  126. * vote = TLV_VOTE_NACK.
  127. * Otherwise send_node_list = 1 and vote = TLV_VOTE_WAIT_FOR_REPLY
  128. * If send_node_list is set to non zero, node list is sent to qnetd
  129. * heuristics results can be used (and overwrite)
  130. */
  131. int
  132. qdevice_net_algo_test_votequorum_node_list_heuristics_notify(struct qdevice_net_instance *instance,
  133. const struct tlv_ring_id *ring_id, uint32_t node_list_entries, uint32_t node_list[],
  134. int *send_node_list, enum tlv_vote *vote, enum tlv_heuristics *heuristics)
  135. {
  136. log(LOG_INFO, "algo-test: Votequorum heuristics list notify");
  137. return (0);
  138. }
  139. /*
  140. * Called after votequorum quorum notify is dispatched.
  141. *
  142. * Callback should return 0 on success or -1 on failure (-> disconnect client).
  143. *
  144. * Callback can override send_node_list and vote.
  145. * Depending on net_instance->state, they are set acordingly:
  146. * If net_instance->state != QDEVICE_NET_INSTANCE_STATE_WAITING_VOTEQUORUM_CMAP_EVENTS
  147. * send_node_list = 0
  148. * if cast_vote_timer_vote != TLV_VOTE_ACK
  149. * vote = TLV_VOTE_NO_CHANGE
  150. * if cast_vote_timer_vote = TLV_VOTE_ACK
  151. * vote = TLV_VOTE_NACK.
  152. * Otherwise send_node_list = 1 and vote = TLV_VOTE_NO_CHANGE
  153. *
  154. * If send_node_list is set to non zero, node list is sent to qnetd
  155. */
  156. int
  157. qdevice_net_algo_test_votequorum_quorum_notify(struct qdevice_net_instance *instance,
  158. uint32_t quorate, uint32_t node_list_entries, votequorum_node_t node_list[], int *send_node_list,
  159. enum tlv_vote *vote)
  160. {
  161. log(LOG_INFO, "algo-test: Votequorum quorum notify");
  162. return (0);
  163. }
  164. /*
  165. * Called after votequorum expected_votes notify is dispatched.
  166. *
  167. * Callback should return 0 on success or -1 on failure (-> disconnect client).
  168. *
  169. * Vote is set to TLV_VOTE_NO_CHANGE
  170. */
  171. int
  172. qdevice_net_algo_test_votequorum_expected_votes_notify(struct qdevice_net_instance *instance,
  173. uint32_t expected_votes, enum tlv_vote *vote)
  174. {
  175. log(LOG_INFO, "algo-test: Votequorum expected votes notify");
  176. return (0);
  177. }
  178. /*
  179. * Called when config node list reply is received. Vote is set to value returned by server (and can
  180. * be overwriten by algorithm). ring_id is returned by server. ring_id_is_valid is set to 1 only if
  181. * received ring id matches last sent ring id. If it is 0, then it usually makes sense to not
  182. * update timer.
  183. *
  184. * Callback should return 0 on success or -1 on failure (-> disconnect client).
  185. */
  186. int
  187. qdevice_net_algo_test_config_node_list_reply_received(struct qdevice_net_instance *instance,
  188. uint32_t seq_number, int initial, const struct tlv_ring_id *ring_id, int ring_id_is_valid,
  189. enum tlv_vote *vote)
  190. {
  191. log(LOG_INFO, "algo-test: Config node list reply");
  192. if (!ring_id_is_valid) {
  193. *vote = TLV_VOTE_NO_CHANGE;
  194. }
  195. return (0);
  196. }
  197. /*
  198. * Called when membership node list reply (reply for votequorum votequorum_nodelist_notify_fn)
  199. * is received. Vote is set to value returned by server (and can be overwriten by algorithm).
  200. *
  201. * Also if server returned TLV_VOTE_ASK_LATER, it's good idea to create timer (call timer_list_add
  202. * with instance->main_timer_list parameter) and ask for reply (qdevice_net_send_ask_for_vote).
  203. * Another option may be to wait for vote_info message (if server algorithm is configured so).
  204. *
  205. * ring_id and ring_id_is_valid have same meaning as for
  206. * qdevice_net_algo_test_config_node_list_reply_received
  207. *
  208. * Callback should return 0 on success or -1 on failure (-> disconnect client).
  209. */
  210. int
  211. qdevice_net_algo_test_membership_node_list_reply_received(struct qdevice_net_instance *instance,
  212. uint32_t seq_number, const struct tlv_ring_id *ring_id, int ring_id_is_valid,
  213. enum tlv_vote *vote)
  214. {
  215. log(LOG_INFO, "algo-test: Membership node list reply");
  216. if (!ring_id_is_valid) {
  217. *vote = TLV_VOTE_NO_CHANGE;
  218. }
  219. return (0);
  220. }
  221. /*
  222. * Called when quorum node list reply (reply for votequorum votequorum_quorum_notify_fn)
  223. * is received. Vote is set to value returned by server (and can be overwriten by algorithm).
  224. *
  225. * ring_id and ring_id_is_valid have same meaning as for
  226. * qdevice_net_algo_test_config_node_list_reply_received
  227. *
  228. * Callback should return 0 on success or -1 on failure (-> disconnect client).
  229. */
  230. int
  231. qdevice_net_algo_test_quorum_node_list_reply_received(struct qdevice_net_instance *instance,
  232. uint32_t seq_number, const struct tlv_ring_id *ring_id, int ring_id_is_valid,
  233. enum tlv_vote *vote)
  234. {
  235. log(LOG_INFO, "algo-test: Quorum node list reply");
  236. if (!ring_id_is_valid) {
  237. *vote = TLV_VOTE_NO_CHANGE;
  238. }
  239. return (0);
  240. }
  241. /*
  242. * Called when reply for ask for vote message was received.
  243. * Vote is set to value returned by server (and can be overwriten by algorithm).
  244. *
  245. * ring_id and ring_id_is_valid have same meaning as for
  246. * qdevice_net_algo_test_config_node_list_reply_received
  247. *
  248. * Callback should return 0 on success or -1 on failure (-> disconnect client).
  249. */
  250. int
  251. qdevice_net_algo_test_ask_for_vote_reply_received(struct qdevice_net_instance *instance,
  252. uint32_t seq_number, const struct tlv_ring_id *ring_id, int ring_id_is_valid, enum tlv_vote *vote)
  253. {
  254. log(LOG_INFO, "algo-test: Ask for vote reply received");
  255. if (!ring_id_is_valid) {
  256. *vote = TLV_VOTE_NO_CHANGE;
  257. }
  258. return (0);
  259. }
  260. /*
  261. * Called when vote info message from server was received.
  262. * Vote is set to value sent by server (and can be overwriten by algorithm).
  263. *
  264. * ring_id and ring_id_is_valid have same meaning as for
  265. * qdevice_net_algo_test_config_node_list_reply_received
  266. *
  267. * Callback should return 0 on success or -1 on failure (-> disconnect client).
  268. */
  269. int
  270. qdevice_net_algo_test_vote_info_received(struct qdevice_net_instance *instance,
  271. uint32_t seq_number, const struct tlv_ring_id *ring_id, int ring_id_is_valid, enum tlv_vote *vote)
  272. {
  273. log(LOG_INFO, "algo-test: Vote info received");
  274. if (!ring_id_is_valid) {
  275. *vote = TLV_VOTE_NO_CHANGE;
  276. }
  277. return (0);
  278. }
  279. /*
  280. * Called when echo reply message was received.
  281. * is_expected_seq_number is set to 1 if received seq_number was equal to last sent echo request.
  282. *
  283. * Callback should return 0 on success or -1 on failure (-> disconnect client).
  284. */
  285. int
  286. qdevice_net_algo_test_echo_reply_received(struct qdevice_net_instance *instance,
  287. uint32_t seq_number, int is_expected_seq_number)
  288. {
  289. log(LOG_INFO, "algo-test: Echo reply received");
  290. return (is_expected_seq_number ? 0 : -1);
  291. }
  292. /*
  293. * Called when client is about to send echo request but echo reply to previous echo request
  294. * was not yet received.
  295. *
  296. * Callback should return 0 if processing should continue (echo request is not sent but timer is
  297. * scheduled again) otherwise -1 (-> disconnect client).
  298. */
  299. int
  300. qdevice_net_algo_test_echo_reply_not_received(struct qdevice_net_instance *instance)
  301. {
  302. log(LOG_INFO, "algo-test: Echo reply not received");
  303. return (-1);
  304. }
  305. /*
  306. * Called when regular heuristics finished and it's result differs from previous heuristics.
  307. *
  308. * heuristics contains result of heuristics
  309. * send_msg distinquish if message should be sent to qnetd. Default value is 0 if qnetd is not
  310. * connected and 1 otherwise
  311. * vote can be set to change cast_vote_timer voting value (default is TLV_VOTE_NO_CHANGE)
  312. *
  313. * It's not possible to set send_msg to 1 and heuristics to TLV_HEURISTICS_UNDEFINED
  314. *
  315. * Callback should return 0 on success, -1 on failure (-> force exit)
  316. */
  317. int
  318. qdevice_net_algo_test_heuristics_change(struct qdevice_net_instance *instance,
  319. enum tlv_heuristics *heuristics, int *send_msg, enum tlv_vote *vote)
  320. {
  321. log(LOG_INFO, "algo-test: Heuristics change");
  322. return (0);
  323. }
  324. /*
  325. * Called when reply for heuristics change was received.
  326. * Vote is set to value returned by server (and can be overwriten by algorithm).
  327. *
  328. * ring_id and ring_id_is_valid have same meaning as for
  329. * qdevice_net_algo_test_config_node_list_reply_received
  330. *
  331. * heuristics is unmodified value sent to server (and set by qdevice_net_algo_test_heuristics_change)
  332. *
  333. * Callback should return 0 on success or -1 on failure (-> disconnect client).
  334. */
  335. int
  336. qdevice_net_algo_test_heuristics_change_reply_received(struct qdevice_net_instance *instance,
  337. uint32_t seq_number, const struct tlv_ring_id *ring_id, int ring_id_is_valid,
  338. enum tlv_heuristics heuristics, enum tlv_vote *vote)
  339. {
  340. log(LOG_INFO, "algo-test: heuristics change reply received");
  341. if (!ring_id_is_valid) {
  342. *vote = TLV_VOTE_NO_CHANGE;
  343. }
  344. return (0);
  345. }
  346. /*
  347. * Called when client disconnects from server.
  348. *
  349. * disconnect_reason contains one of QDEVICE_NET_DISCONNECT_REASON_
  350. * try_reconnect can be set to non zero value if reconnect to server should be tried
  351. * vote (default TLV_VOTE_NO_CHANGE) can be set to update voting timer
  352. *
  353. * Callback should return 0 on success, -1 on failure (-> force exit)
  354. */
  355. int
  356. qdevice_net_algo_test_disconnected(struct qdevice_net_instance *instance,
  357. enum qdevice_net_disconnect_reason disconnect_reason, int *try_reconnect, enum tlv_vote *vote)
  358. {
  359. log(LOG_INFO, "algo-test: Disconnected");
  360. return (0);
  361. }
  362. /*
  363. * Called when qdevice-net is going down.
  364. */
  365. void
  366. qdevice_net_algo_test_destroy(struct qdevice_net_instance *instance)
  367. {
  368. log(LOG_INFO, "algo-test: Destroy");
  369. }
  370. static struct qdevice_net_algorithm qdevice_net_algo_test = {
  371. .init = qdevice_net_algo_test_init,
  372. .connected = qdevice_net_algo_test_connected,
  373. .config_node_list_changed = qdevice_net_algo_test_config_node_list_changed,
  374. .votequorum_node_list_notify = qdevice_net_algo_test_votequorum_node_list_notify,
  375. .votequorum_node_list_heuristics_notify = qdevice_net_algo_test_votequorum_node_list_heuristics_notify,
  376. .votequorum_quorum_notify = qdevice_net_algo_test_votequorum_quorum_notify,
  377. .votequorum_expected_votes_notify = qdevice_net_algo_test_votequorum_expected_votes_notify,
  378. .config_node_list_reply_received = qdevice_net_algo_test_config_node_list_reply_received,
  379. .membership_node_list_reply_received = qdevice_net_algo_test_membership_node_list_reply_received,
  380. .quorum_node_list_reply_received = qdevice_net_algo_test_quorum_node_list_reply_received,
  381. .ask_for_vote_reply_received = qdevice_net_algo_test_ask_for_vote_reply_received,
  382. .vote_info_received = qdevice_net_algo_test_vote_info_received,
  383. .echo_reply_received = qdevice_net_algo_test_echo_reply_received,
  384. .echo_reply_not_received = qdevice_net_algo_test_echo_reply_not_received,
  385. .heuristics_change = qdevice_net_algo_test_heuristics_change,
  386. .heuristics_change_reply_received = qdevice_net_algo_test_heuristics_change_reply_received,
  387. .disconnected = qdevice_net_algo_test_disconnected,
  388. .destroy = qdevice_net_algo_test_destroy,
  389. };
  390. int
  391. qdevice_net_algo_test_register(void)
  392. {
  393. return (qdevice_net_algorithm_register(TLV_DECISION_ALGORITHM_TYPE_TEST, &qdevice_net_algo_test));
  394. }