qdevice-net-algo-test.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375
  1. /*
  2. * Copyright (c) 2015-2016 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 "qdevice-net-algo-test.h"
  37. #include "qdevice-log.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. qdevice_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. *
  59. * Callback should return 0 on success or -1 on failure (-> disconnect client).
  60. */
  61. int
  62. qdevice_net_algo_test_connected(struct qdevice_net_instance *instance, int *send_config_node_list,
  63. int *send_membership_node_list, int *send_quorum_node_list, enum tlv_vote *vote)
  64. {
  65. qdevice_log(LOG_INFO, "algo-test: Connected");
  66. return (0);
  67. }
  68. /*
  69. * Called after config node list changed.
  70. *
  71. * Callback can override send_node_list and vote.
  72. * Depending on net_instance->state, they are set acordingly:
  73. * If net_instance->state != QDEVICE_NET_INSTANCE_STATE_WAITING_VOTEQUORUM_CMAP_EVENTS
  74. * send_node_list = 0
  75. * if cast_vote_timer_vote != TLV_VOTE_ACK
  76. * vote = TLV_VOTE_NO_CHANGE
  77. * if cast_vote_timer_vote = TLV_VOTE_ACK
  78. * vote = TLV_VOTE_NACK.
  79. * Otherwise send_node_list = 1 and vote = TLV_VOTE_NO_CHANGE
  80. * If send_node_list is set to non zero, node list is sent to qnetd
  81. */
  82. int
  83. qdevice_net_algo_test_config_node_list_changed(struct qdevice_net_instance *instance,
  84. const struct node_list *nlist, int config_version_set, uint64_t config_version,
  85. int *send_node_list, enum tlv_vote *vote)
  86. {
  87. qdevice_log(LOG_INFO, "algo-test: Config node list changed");
  88. return (0);
  89. }
  90. /*
  91. * Called after votequorum node list notify is dispatched.
  92. *
  93. * Callback should return 0 on success or -1 on failure (-> disconnect client).
  94. *
  95. * If net_instance->state != QDEVICE_NET_INSTANCE_STATE_WAITING_VOTEQUORUM_CMAP_EVENTS
  96. * send_node_list = 0
  97. * if cast_vote_timer_vote != TLV_VOTE_ACK
  98. * vote = TLV_VOTE_NO_CHANGE
  99. * if cast_vote_timer_vote = TLV_VOTE_ACK
  100. * vote = TLV_VOTE_NACK.
  101. * Otherwise send_node_list = 1 and vote = TLV_VOTE_WAIT_FOR_REPLY
  102. * If send_node_list is set to non zero, node list is sent to qnetd
  103. */
  104. int
  105. qdevice_net_algo_test_votequorum_node_list_notify(struct qdevice_net_instance *instance,
  106. const struct tlv_ring_id *ring_id, uint32_t node_list_entries, uint32_t node_list[],
  107. int *send_node_list, enum tlv_vote *vote)
  108. {
  109. qdevice_log(LOG_INFO, "algo-test: Votequorum list notify");
  110. return (0);
  111. }
  112. /*
  113. * Called after votequorum quorum notify is dispatched.
  114. *
  115. * Callback should return 0 on success or -1 on failure (-> disconnect client).
  116. *
  117. * Callback can override send_node_list and vote.
  118. * Depending on net_instance->state, they are set acordingly:
  119. * If net_instance->state != QDEVICE_NET_INSTANCE_STATE_WAITING_VOTEQUORUM_CMAP_EVENTS
  120. * send_node_list = 0
  121. * if cast_vote_timer_vote != TLV_VOTE_ACK
  122. * vote = TLV_VOTE_NO_CHANGE
  123. * if cast_vote_timer_vote = TLV_VOTE_ACK
  124. * vote = TLV_VOTE_NACK.
  125. * Otherwise send_node_list = 1 and vote = TLV_VOTE_NO_CHANGE
  126. *
  127. * If send_node_list is set to non zero, node list is sent to qnetd
  128. */
  129. int
  130. qdevice_net_algo_test_votequorum_quorum_notify(struct qdevice_net_instance *instance,
  131. uint32_t quorate, uint32_t node_list_entries, votequorum_node_t node_list[], int *send_node_list,
  132. enum tlv_vote *vote)
  133. {
  134. qdevice_log(LOG_INFO, "algo-test: Votequorum quorum notify");
  135. return (0);
  136. }
  137. /*
  138. * Called after votequorum expected_votes notify is dispatched.
  139. *
  140. * Callback should return 0 on success or -1 on failure (-> disconnect client).
  141. *
  142. * Vote is set to TLV_VOTE_NO_CHANGE
  143. */
  144. int
  145. qdevice_net_algo_test_votequorum_expected_votes_notify(struct qdevice_net_instance *instance,
  146. uint32_t expected_votes, enum tlv_vote *vote)
  147. {
  148. qdevice_log(LOG_INFO, "algo-test: Votequorum expected votes notify");
  149. return (0);
  150. }
  151. /*
  152. * Called when config node list reply is received. Vote is set to value returned by server (and can
  153. * be overwriten by algorithm). ring_id is returned by server. ring_id_is_valid is set to 1 only if
  154. * received ring id matches last sent ring id. It usually makes sense to not update timer.
  155. *
  156. * Callback should return 0 on success or -1 on failure (-> disconnect client).
  157. */
  158. int
  159. qdevice_net_algo_test_config_node_list_reply_received(struct qdevice_net_instance *instance,
  160. uint32_t seq_number, int initial, const struct tlv_ring_id *ring_id, int ring_id_is_valid,
  161. enum tlv_vote *vote)
  162. {
  163. qdevice_log(LOG_INFO, "algo-test: Config node list reply");
  164. if (!ring_id_is_valid) {
  165. *vote = TLV_VOTE_NO_CHANGE;
  166. }
  167. return (0);
  168. }
  169. /*
  170. * Called when membership node list reply (reply for votequorum votequorum_nodelist_notify_fn)
  171. * is received. Vote is set to value returned by server (and can be overwriten by algorithm).
  172. *
  173. * Also if server returned TLV_VOTE_ASK_LATER, it's good idea to create timer (call timer_list_add
  174. * with instance->main_timer_list parameter) and ask for reply (qdevice_net_send_ask_for_vote).
  175. * Another option may be to wait for vote_info message (if server algorithm is configured so).
  176. *
  177. * ring_id and ring_id_is_valid have same meaning as for
  178. * qdevice_net_algo_test_config_node_list_reply_received
  179. *
  180. * Callback should return 0 on success or -1 on failure (-> disconnect client).
  181. */
  182. int
  183. qdevice_net_algo_test_membership_node_list_reply_received(struct qdevice_net_instance *instance,
  184. uint32_t seq_number, const struct tlv_ring_id *ring_id, int ring_id_is_valid,
  185. enum tlv_vote *vote)
  186. {
  187. qdevice_log(LOG_INFO, "algo-test: Membership node list reply");
  188. if (!ring_id_is_valid) {
  189. *vote = TLV_VOTE_NO_CHANGE;
  190. }
  191. return (0);
  192. }
  193. /*
  194. * Called when quorum node list reply (reply for votequorum votequorum_quorum_notify_fn)
  195. * is received. Vote is set to value returned by server (and can be overwriten by algorithm).
  196. *
  197. * ring_id and ring_id_is_valid have same meaning as for
  198. * qdevice_net_algo_test_config_node_list_reply_received
  199. *
  200. * Callback should return 0 on success or -1 on failure (-> disconnect client).
  201. */
  202. int
  203. qdevice_net_algo_test_quorum_node_list_reply_received(struct qdevice_net_instance *instance,
  204. uint32_t seq_number, const struct tlv_ring_id *ring_id, int ring_id_is_valid,
  205. enum tlv_vote *vote)
  206. {
  207. qdevice_log(LOG_INFO, "algo-test: Quorum node list reply");
  208. if (!ring_id_is_valid) {
  209. *vote = TLV_VOTE_NO_CHANGE;
  210. }
  211. return (0);
  212. }
  213. /*
  214. * Called when reply for ask for vote message was received.
  215. * Vote is set to value returned by server (and can be overwriten by algorithm).
  216. *
  217. * ring_id and ring_id_is_valid have same meaning as for
  218. * qdevice_net_algo_test_config_node_list_reply_received
  219. *
  220. * Callback should return 0 on success or -1 on failure (-> disconnect client).
  221. */
  222. int
  223. qdevice_net_algo_test_ask_for_vote_reply_received(struct qdevice_net_instance *instance,
  224. uint32_t seq_number, const struct tlv_ring_id *ring_id, int ring_id_is_valid, enum tlv_vote *vote)
  225. {
  226. qdevice_log(LOG_INFO, "algo-test: Ask for vote reply received");
  227. if (!ring_id_is_valid) {
  228. *vote = TLV_VOTE_NO_CHANGE;
  229. }
  230. return (0);
  231. }
  232. /*
  233. * Called when vote info message from server was received.
  234. * Vote is set to value sent by server (and can be overwriten by algorithm).
  235. *
  236. * ring_id and ring_id_is_valid have same meaning as for
  237. * qdevice_net_algo_test_config_node_list_reply_received
  238. *
  239. * Callback should return 0 on success or -1 on failure (-> disconnect client).
  240. */
  241. int
  242. qdevice_net_algo_test_vote_info_received(struct qdevice_net_instance *instance,
  243. uint32_t seq_number, const struct tlv_ring_id *ring_id, int ring_id_is_valid, enum tlv_vote *vote)
  244. {
  245. qdevice_log(LOG_INFO, "algo-test: Vote info received");
  246. if (!ring_id_is_valid) {
  247. *vote = TLV_VOTE_NO_CHANGE;
  248. }
  249. return (0);
  250. }
  251. /*
  252. * Called when echo reply message was received.
  253. * is_expected_seq_number is set to 1 if received seq_number was equal to last sent echo request.
  254. *
  255. * Callback should return 0 on success or -1 on failure (-> disconnect client).
  256. */
  257. int
  258. qdevice_net_algo_test_echo_reply_received(struct qdevice_net_instance *instance,
  259. uint32_t seq_number, int is_expected_seq_number)
  260. {
  261. qdevice_log(LOG_INFO, "algo-test: Echo reply received");
  262. return (is_expected_seq_number ? 0 : -1);
  263. }
  264. /*
  265. * Called when client is about to send echo request but echo reply to previous echo request
  266. * was not yet received.
  267. *
  268. * Callback should return 0 if processing should continue (echo request is not sent but timer is
  269. * scheduled again) otherwise -1 (-> disconnect client).
  270. */
  271. int
  272. qdevice_net_algo_test_echo_reply_not_received(struct qdevice_net_instance *instance)
  273. {
  274. qdevice_log(LOG_INFO, "algo-test: Echo reply not received");
  275. return (-1);
  276. }
  277. /*
  278. * Called when client disconnects from server.
  279. *
  280. * disconnect_reason contains one of QDEVICE_NET_DISCONNECT_REASON_
  281. * try_reconnect can be set to non zero value if reconnect to server should be tried
  282. * vote (default TLV_VOTE_NO_CHANGE) can be set to update voting timer
  283. *
  284. * Callback should return 0 on success, -1 on failure (-> force exit)
  285. */
  286. int
  287. qdevice_net_algo_test_disconnected(struct qdevice_net_instance *instance,
  288. enum qdevice_net_disconnect_reason disconnect_reason, int *try_reconnect, enum tlv_vote *vote)
  289. {
  290. qdevice_log(LOG_INFO, "algo-test: Disconnected");
  291. return (0);
  292. }
  293. /*
  294. * Called when qdevice-net is going down.
  295. */
  296. void
  297. qdevice_net_algo_test_destroy(struct qdevice_net_instance *instance)
  298. {
  299. qdevice_log(LOG_INFO, "algo-test: Destroy");
  300. }
  301. static struct qdevice_net_algorithm qdevice_net_algo_test = {
  302. .init = qdevice_net_algo_test_init,
  303. .connected = qdevice_net_algo_test_connected,
  304. .config_node_list_changed = qdevice_net_algo_test_config_node_list_changed,
  305. .votequorum_node_list_notify = qdevice_net_algo_test_votequorum_node_list_notify,
  306. .votequorum_quorum_notify = qdevice_net_algo_test_votequorum_quorum_notify,
  307. .votequorum_expected_votes_notify = qdevice_net_algo_test_votequorum_expected_votes_notify,
  308. .config_node_list_reply_received = qdevice_net_algo_test_config_node_list_reply_received,
  309. .membership_node_list_reply_received = qdevice_net_algo_test_membership_node_list_reply_received,
  310. .quorum_node_list_reply_received = qdevice_net_algo_test_quorum_node_list_reply_received,
  311. .ask_for_vote_reply_received = qdevice_net_algo_test_ask_for_vote_reply_received,
  312. .vote_info_received = qdevice_net_algo_test_vote_info_received,
  313. .echo_reply_received = qdevice_net_algo_test_echo_reply_received,
  314. .echo_reply_not_received = qdevice_net_algo_test_echo_reply_not_received,
  315. .disconnected = qdevice_net_algo_test_disconnected,
  316. .destroy = qdevice_net_algo_test_destroy,
  317. };
  318. int
  319. qdevice_net_algo_test_register(void)
  320. {
  321. return (qdevice_net_algorithm_register(TLV_DECISION_ALGORITHM_TYPE_TEST, &qdevice_net_algo_test));
  322. }