corosync
totempg.c
Go to the documentation of this file.
1/*
2 * Copyright (c) 2003-2005 MontaVista Software, Inc.
3 * Copyright (c) 2005 OSDL.
4 * Copyright (c) 2006-2012 Red Hat, Inc.
5 *
6 * All rights reserved.
7 *
8 * Author: Steven Dake (sdake@redhat.com)
9 * Author: Mark Haverkamp (markh@osdl.org)
10 *
11 * This software licensed under BSD license, the text of which follows:
12 *
13 * Redistribution and use in source and binary forms, with or without
14 * modification, are permitted provided that the following conditions are met:
15 *
16 * - Redistributions of source code must retain the above copyright notice,
17 * this list of conditions and the following disclaimer.
18 * - Redistributions in binary form must reproduce the above copyright notice,
19 * this list of conditions and the following disclaimer in the documentation
20 * and/or other materials provided with the distribution.
21 * - Neither the name of the MontaVista Software, Inc. nor the names of its
22 * contributors may be used to endorse or promote products derived from this
23 * software without specific prior written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
26 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
29 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
30 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
31 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
32 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
33 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
34 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
35 * THE POSSIBILITY OF SUCH DAMAGE.
36 */
37
38/*
39 * FRAGMENTATION AND PACKING ALGORITHM:
40 *
41 * Assemble the entire message into one buffer
42 * if full fragment
43 * store fragment into lengths list
44 * for each full fragment
45 * multicast fragment
46 * set length and fragment fields of pg mesage
47 * store remaining multicast into head of fragmentation data and set lens field
48 *
49 * If a message exceeds the maximum packet size allowed by the totem
50 * single ring protocol, the protocol could lose forward progress.
51 * Statically calculating the allowed data amount doesn't work because
52 * the amount of data allowed depends on the number of fragments in
53 * each message. In this implementation, the maximum fragment size
54 * is dynamically calculated for each fragment added to the message.
55
56 * It is possible for a message to be two bytes short of the maximum
57 * packet size. This occurs when a message or collection of
58 * messages + the mcast header + the lens are two bytes short of the
59 * end of the packet. Since another len field consumes two bytes, the
60 * len field would consume the rest of the packet without room for data.
61 *
62 * One optimization would be to forgo the final len field and determine
63 * it from the size of the udp datagram. Then this condition would no
64 * longer occur.
65 */
66
67/*
68 * ASSEMBLY AND UNPACKING ALGORITHM:
69 *
70 * copy incoming packet into assembly data buffer indexed by current
71 * location of end of fragment
72 *
73 * if not fragmented
74 * deliver all messages in assembly data buffer
75 * else
76 * if msg_count > 1 and fragmented
77 * deliver all messages except last message in assembly data buffer
78 * copy last fragmented section to start of assembly data buffer
79 * else
80 * if msg_count = 1 and fragmented
81 * do nothing
82 *
83 */
84
85#include <config.h>
86
87#ifdef HAVE_ALLOCA_H
88#include <alloca.h>
89#endif
90#include <sys/types.h>
91#include <sys/socket.h>
92#include <netinet/in.h>
93#include <arpa/inet.h>
94#include <sys/uio.h>
95#include <stdio.h>
96#include <stdlib.h>
97#include <string.h>
98#include <assert.h>
99#include <pthread.h>
100#include <errno.h>
101#include <limits.h>
102
103#include <corosync/swab.h>
104#include <qb/qblist.h>
105#include <qb/qbloop.h>
106#include <qb/qbipcs.h>
108#define LOGSYS_UTILS_ONLY 1
109#include <corosync/logsys.h>
110
111#include "util.h"
112#include "totemsrp.h"
113
115 short version;
116 short type;
117};
118
119#if !(defined(__i386__) || defined(__x86_64__))
120/*
121 * Need align on architectures different then i386 or x86_64
122 */
123#define TOTEMPG_NEED_ALIGN 1
124#endif
125
126/*
127 * totempg_mcast structure
128 *
129 * header: Identify the mcast.
130 * fragmented: Set if this message continues into next message
131 * continuation: Set if this message is a continuation from last message
132 * msg_count Indicates how many packed messages are contained
133 * in the mcast.
134 * Also, the size of each packed message and the messages themselves are
135 * appended to the end of this structure when sent.
136 */
139 unsigned char fragmented;
140 unsigned char continuation;
141 unsigned short msg_count;
142 /*
143 * short msg_len[msg_count];
144 */
145 /*
146 * data for messages
147 */
148};
149
150/*
151 * Maximum packet size for totem pg messages
152 */
153#define TOTEMPG_PACKET_SIZE (totempg_totem_config->net_mtu - \
154 sizeof (struct totempg_mcast))
155
156/*
157 * Local variables used for packing small messages
158 */
159static unsigned short mcast_packed_msg_lens[FRAME_SIZE_MAX];
160
161static int mcast_packed_msg_count = 0;
162
163static int totempg_reserved = 1;
164
165static unsigned int totempg_size_limit;
166
167static totem_queue_level_changed_fn totem_queue_level_changed = NULL;
168
169static uint32_t totempg_threaded_mode = 0;
170
171static void *totemsrp_context;
172
173/*
174 * Function and data used to log messages
175 */
176static int totempg_log_level_security;
177static int totempg_log_level_error;
178static int totempg_log_level_warning;
179static int totempg_log_level_notice;
180static int totempg_log_level_debug;
181static int totempg_subsys_id;
182static void (*totempg_log_printf) (
183 int level,
184 int subsys,
185 const char *function,
186 const char *file,
187 int line,
188 const char *format, ...) __attribute__((format(printf, 6, 7)));
189
191
192static totempg_stats_t totempg_stats;
193
198
207
208static void assembly_deref (struct assembly *assembly);
209
210static int callback_token_received_fn (enum totem_callback_token_type type,
211 const void *data);
212
214
215/*
216 * Free list is used both for transitional and operational assemblies
217 */
219
221
223
224/*
225 * Staging buffer for packed messages. Messages are staged in this buffer
226 * before sending. Multiple messages may fit which cuts down on the
227 * number of mcasts sent. If a message doesn't completely fit, then
228 * the mcast header has a fragment bit set that says that there are more
229 * data to follow. fragment_size is an index into the buffer. It indicates
230 * the size of message data and where to place new message data.
231 * fragment_contuation indicates whether the first packed message in
232 * the buffer is a continuation of a previously packed fragment.
233 */
234static unsigned char *fragmentation_data;
235
236static int fragment_size = 0;
237
238static int fragment_continuation = 0;
239
240static int totempg_waiting_transack = 0;
241
244 unsigned int nodeid,
245 const void *msg,
246 unsigned int msg_len,
248
251 const unsigned int *member_list, size_t member_list_entries,
252 const unsigned int *left_list, size_t left_list_entries,
253 const unsigned int *joined_list, size_t joined_list_entries,
254 const struct memb_ring_id *ring_id);
255
257
260
262};
263
264static unsigned char next_fragment = 1;
265
266static pthread_mutex_t totempg_mutex = PTHREAD_MUTEX_INITIALIZER;
267
268static pthread_mutex_t callback_token_mutex = PTHREAD_MUTEX_INITIALIZER;
269
270static pthread_mutex_t mcast_msg_mutex = PTHREAD_MUTEX_INITIALIZER;
271
272#define log_printf(level, format, args...) \
273do { \
274 totempg_log_printf(level, \
275 totempg_subsys_id, \
276 __FUNCTION__, __FILE__, __LINE__, \
277 format, ##args); \
278} while (0);
279
280static int msg_count_send_ok (int msg_count);
281
282static int byte_count_send_ok (int byte_count);
283
284static void totempg_waiting_trans_ack_cb (int waiting_trans_ack)
285{
286 log_printf(LOG_DEBUG, "waiting_trans_ack changed to %u", waiting_trans_ack);
287 totempg_waiting_transack = waiting_trans_ack;
288}
289
290static struct assembly *assembly_ref (unsigned int nodeid)
291{
292 struct assembly *assembly;
293 struct qb_list_head *list;
295
296 if (totempg_waiting_transack) {
298 } else {
300 }
301
302 /*
303 * Search inuse list for node id and return assembly buffer if found
304 */
306 assembly = qb_list_entry (list, struct assembly, list);
307
308 if (nodeid == assembly->nodeid) {
309 return (assembly);
310 }
311 }
312
313 /*
314 * Nothing found in inuse list get one from free list if available
315 */
316 if (qb_list_empty (&assembly_list_free) == 0) {
321 assembly->index = 0;
324 return (assembly);
325 }
326
327 /*
328 * Nothing available in inuse or free list, so allocate a new one
329 */
330 assembly = malloc (sizeof (struct assembly));
331 /*
332 * TODO handle memory allocation failure here
333 */
336 assembly->data[0] = 0;
337 assembly->index = 0;
342
343 return (assembly);
344}
345
346static void assembly_deref (struct assembly *assembly)
347{
350}
351
352static void assembly_deref_from_normal_and_trans (int nodeid)
353{
354 int j;
355 struct qb_list_head *list, *tmp_iter;
357 struct assembly *assembly;
358
359 for (j = 0; j < 2; j++) {
360 if (j == 0) {
362 } else {
364 }
365
368
369 if (nodeid == assembly->nodeid) {
372 }
373 }
374 }
375
376}
377
378static inline void app_confchg_fn (
380 const unsigned int *member_list, size_t member_list_entries,
381 const unsigned int *left_list, size_t left_list_entries,
382 const unsigned int *joined_list, size_t joined_list_entries,
383 const struct memb_ring_id *ring_id)
384{
385 int i;
386 struct totempg_group_instance *instance;
387 struct qb_list_head *list;
388
389 /*
390 * For every leaving processor, add to free list
391 * This also has the side effect of clearing out the dataset
392 * In the leaving processor's assembly buffer.
393 */
394 for (i = 0; i < left_list_entries; i++) {
395 assembly_deref_from_normal_and_trans (left_list[i]);
396 }
397
399 instance = qb_list_entry (list, struct totempg_group_instance, list);
400
401 if (instance->confchg_fn) {
402 instance->confchg_fn (
404 member_list,
405 member_list_entries,
406 left_list,
410 ring_id);
411 }
412 }
413}
414
415static inline void group_endian_convert (
416 void *msg,
417 int msg_len)
418{
419 unsigned short *group_len;
420 int i;
421 char *aligned_msg;
422
423#ifdef TOTEMPG_NEED_ALIGN
424 /*
425 * Align data structure for not i386 or x86_64
426 */
427 if ((size_t)msg % sizeof(char *) != 0) {
428 aligned_msg = alloca(msg_len);
429 memcpy(aligned_msg, msg, msg_len);
430 } else {
431 aligned_msg = msg;
432 }
433#else
434 aligned_msg = msg;
435#endif
436
437 group_len = (unsigned short *)aligned_msg;
438 group_len[0] = swab16(group_len[0]);
439 for (i = 1; i < group_len[0] + 1; i++) {
440 group_len[i] = swab16(group_len[i]);
441 }
442
443 if (aligned_msg != msg) {
444 memcpy(msg, aligned_msg, msg_len);
445 }
446}
447
448static inline int group_matches (
449 struct iovec *iovec,
450 unsigned int iov_len,
451 struct totempg_group *groups_b,
452 unsigned int group_b_cnt,
453 unsigned int *adjust_iovec)
454{
455 unsigned short *group_len;
456 char *group_name;
457 int i;
458 int j;
459#ifdef TOTEMPG_NEED_ALIGN
460 struct iovec iovec_aligned = { NULL, 0 };
461#endif
462
463 assert (iov_len == 1);
464
465#ifdef TOTEMPG_NEED_ALIGN
466 /*
467 * Align data structure for not i386 or x86_64
468 */
469 if ((size_t)iovec->iov_base % sizeof(char *) != 0) {
470 iovec_aligned.iov_base = alloca(iovec->iov_len);
471 memcpy(iovec_aligned.iov_base, iovec->iov_base, iovec->iov_len);
472 iovec_aligned.iov_len = iovec->iov_len;
474 }
475#endif
476
477 group_len = (unsigned short *)iovec->iov_base;
478 group_name = ((char *)iovec->iov_base) +
479 sizeof (unsigned short) * (group_len[0] + 1);
480
481
482 /*
483 * Calculate amount to adjust the iovec by before delivering to app
484 */
485 *adjust_iovec = sizeof (unsigned short) * (group_len[0] + 1);
486 for (i = 1; i < group_len[0] + 1; i++) {
487 *adjust_iovec += group_len[i];
488 }
489
490 /*
491 * Determine if this message should be delivered to this instance
492 */
493 for (i = 1; i < group_len[0] + 1; i++) {
494 for (j = 0; j < group_b_cnt; j++) {
495 if ((group_len[i] == groups_b[j].group_len) &&
496 (memcmp (groups_b[j].group, group_name, group_len[i]) == 0)) {
497 return (1);
498 }
499 }
500 group_name += group_len[i];
501 }
502 return (0);
503}
504
505
506static inline void app_deliver_fn (
507 unsigned int nodeid,
508 void *msg,
509 unsigned int msg_len,
511{
512 struct totempg_group_instance *instance;
513 struct iovec stripped_iovec;
514 unsigned int adjust_iovec;
515 struct iovec *iovec;
516 struct qb_list_head *list;
517
518 struct iovec aligned_iovec = { NULL, 0 };
519
521 group_endian_convert (msg, msg_len);
522 }
523
524 /*
525 * TODO: segmentation/assembly need to be redesigned to provide aligned access
526 * in all cases to avoid memory copies on non386 archs. Probably broke backwars
527 * compatibility
528 */
529
530#ifdef TOTEMPG_NEED_ALIGN
531 /*
532 * Align data structure for not i386 or x86_64
533 */
534 aligned_iovec.iov_base = alloca(msg_len);
535 aligned_iovec.iov_len = msg_len;
536 memcpy(aligned_iovec.iov_base, msg, msg_len);
537#else
538 aligned_iovec.iov_base = msg;
539 aligned_iovec.iov_len = msg_len;
540#endif
541
543
545 instance = qb_list_entry (list, struct totempg_group_instance, list);
546 if (group_matches (iovec, 1, instance->groups, instance->groups_cnt, &adjust_iovec)) {
547 stripped_iovec.iov_len = iovec->iov_len - adjust_iovec;
548 stripped_iovec.iov_base = (char *)iovec->iov_base + adjust_iovec;
549
550#ifdef TOTEMPG_NEED_ALIGN
551 /*
552 * Align data structure for not i386 or x86_64
553 */
554 if ((uintptr_t)((char *)iovec->iov_base + adjust_iovec) % (sizeof(char *)) != 0) {
555 /*
556 * Deal with misalignment
557 */
558 stripped_iovec.iov_base =
559 alloca (stripped_iovec.iov_len);
560 memcpy (stripped_iovec.iov_base,
561 (char *)iovec->iov_base + adjust_iovec,
562 stripped_iovec.iov_len);
563 }
564#endif
565 instance->deliver_fn (
566 nodeid,
567 stripped_iovec.iov_base,
568 stripped_iovec.iov_len,
570 }
571 }
572}
573
574static void totempg_confchg_fn (
576 const unsigned int *member_list, size_t member_list_entries,
577 const unsigned int *left_list, size_t left_list_entries,
578 const unsigned int *joined_list, size_t joined_list_entries,
579 const struct memb_ring_id *ring_id)
580{
581// TODO optimize this
582 app_confchg_fn (configuration_type,
583 member_list, member_list_entries,
586 ring_id);
587}
588
589static void totempg_deliver_fn (
590 unsigned int nodeid,
591 const void *msg,
592 unsigned int msg_len,
594{
595 struct totempg_mcast *mcast;
596 unsigned short *msg_lens;
597 int i;
598 struct assembly *assembly;
600 int msg_count;
601 int continuation;
602 int start;
603 const char *data;
604 int datasize;
605 struct iovec iov_delv;
606 size_t expected_msg_len;
607
608 assembly = assembly_ref (nodeid);
610
611 if (msg_len < sizeof(struct totempg_mcast)) {
613 "Message (totempg_mcast) received from node " CS_PRI_NODE_ID " is too short... Ignoring.", nodeid);
614
615 return ;
616 }
617
618 /*
619 * Assemble the header into one block of data and
620 * assemble the packet contents into one block of data to simplify delivery
621 */
622
623 mcast = (struct totempg_mcast *)msg;
625 mcast->msg_count = swab16 (mcast->msg_count);
626 }
627
628 msg_count = mcast->msg_count;
629 datasize = sizeof (struct totempg_mcast) +
630 msg_count * sizeof (unsigned short);
631
632 if (msg_len < datasize) {
634 "Message (totempg_mcast datasize) received from node " CS_PRI_NODE_ID
635 " is too short... Ignoring.", nodeid);
636
637 return ;
638 }
639
640 memcpy (header, msg, datasize);
641 data = msg;
642
643 msg_lens = (unsigned short *) (header + sizeof (struct totempg_mcast));
645 for (i = 0; i < mcast->msg_count; i++) {
647 msg_lens[i] = swab16 (msg_lens[i]);
648 }
649
651 }
652
653 if (msg_len != expected_msg_len) {
655 "Message (totempg_mcast) received from node " CS_PRI_NODE_ID
656 " doesn't have expected length of %zu (has %u) bytes... Ignoring.",
657 nodeid, expected_msg_len, msg_len);
658
659 return ;
660 }
661
662 if (assembly->index + msg_len >= sizeof(assembly->data)) {
664 "Message (totempg_mcast) received from node " CS_PRI_NODE_ID
665 " would create too long message of %u bytes... Ignoring.",
666 nodeid, assembly->index + msg_len);
667
668 return ;
669 }
671 msg_len - datasize);
672
673 /*
674 * If the last message in the buffer is a fragment, then we
675 * can't deliver it. We'll first deliver the full messages
676 * then adjust the assembly buffer so we can add the rest of the
677 * fragment when it arrives.
678 */
679 msg_count = mcast->fragmented ? mcast->msg_count - 1 : mcast->msg_count;
680 continuation = mcast->continuation;
681 iov_delv.iov_base = (void *)&assembly->data[0];
682 iov_delv.iov_len = assembly->index + msg_lens[0];
683
684 /*
685 * Make sure that if this message is a continuation, that it
686 * matches the sequence number of the previous fragment.
687 * Also, if the first packed message is a continuation
688 * of a previous message, but the assembly buffer
689 * is empty, then we need to discard it since we can't
690 * assemble a complete message. Likewise, if this message isn't a
691 * continuation and the assembly buffer is empty, we have to discard
692 * the continued message.
693 */
694 start = 0;
695
697 /* Throw away the first msg block */
698 if (mcast->fragmented == 0 || mcast->fragmented == 1) {
700
701 assembly->index += msg_lens[0];
702 iov_delv.iov_base = (void *)&assembly->data[assembly->index];
703 iov_delv.iov_len = msg_lens[1];
704 start = 1;
705 }
706 } else
709 assembly->last_frag_num = mcast->fragmented;
710 for (i = start; i < msg_count; i++) {
711 app_deliver_fn(nodeid, iov_delv.iov_base, iov_delv.iov_len,
714 iov_delv.iov_base = (void *)&assembly->data[assembly->index];
715 if (i < (msg_count - 1)) {
716 iov_delv.iov_len = msg_lens[i + 1];
717 }
718 }
719 } else {
720 log_printf (LOG_DEBUG, "fragmented continuation %u is not equal to assembly last_frag_num %u",
723 }
724 }
725
726 if (mcast->fragmented == 0) {
727 /*
728 * End of messages, dereference assembly struct
729 */
731 assembly->index = 0;
732 assembly_deref (assembly);
733 } else {
734 /*
735 * Message is fragmented, keep around assembly list
736 */
737 if (mcast->msg_count > 1) {
738 memmove (&assembly->data[0],
741
742 assembly->index = 0;
743 }
745 }
746}
747
748/*
749 * Totem Process Group Abstraction
750 * depends on poll abstraction, POSIX, IPV4
751 */
752
754
755int callback_token_received_fn (enum totem_callback_token_type type,
756 const void *data)
757{
758 struct totempg_mcast mcast;
759 struct iovec iovecs[3];
760
761 if (totempg_threaded_mode == 1) {
762 pthread_mutex_lock (&mcast_msg_mutex);
763 }
764 if (mcast_packed_msg_count == 0) {
765 if (totempg_threaded_mode == 1) {
766 pthread_mutex_unlock (&mcast_msg_mutex);
767 }
768 return (0);
769 }
770 if (totemsrp_avail(totemsrp_context) == 0) {
771 if (totempg_threaded_mode == 1) {
772 pthread_mutex_unlock (&mcast_msg_mutex);
773 }
774 return (0);
775 }
776 mcast.header.version = 0;
777 mcast.header.type = 0;
778 mcast.fragmented = 0;
779
780 /*
781 * Was the first message in this buffer a continuation of a
782 * fragmented message?
783 */
784 mcast.continuation = fragment_continuation;
785 fragment_continuation = 0;
786
787 mcast.msg_count = mcast_packed_msg_count;
788
789 iovecs[0].iov_base = (void *)&mcast;
790 iovecs[0].iov_len = sizeof (struct totempg_mcast);
791 iovecs[1].iov_base = (void *)mcast_packed_msg_lens;
792 iovecs[1].iov_len = mcast_packed_msg_count * sizeof (unsigned short);
793 iovecs[2].iov_base = (void *)&fragmentation_data[0];
794 iovecs[2].iov_len = fragment_size;
795 (void)totemsrp_mcast (totemsrp_context, iovecs, 3, 0);
796
797 mcast_packed_msg_count = 0;
798 fragment_size = 0;
799
800 if (totempg_threaded_mode == 1) {
801 pthread_mutex_unlock (&mcast_msg_mutex);
802 }
803 return (0);
804}
805
806/*
807 * Initialize the totem process group abstraction
808 */
810 qb_loop_t *poll_handle,
812{
813 int res;
814
816 totempg_log_level_security = totem_config->totem_logging_configuration.log_level_security;
823
824 fragmentation_data = malloc (TOTEMPG_PACKET_SIZE);
825 if (fragmentation_data == 0) {
826 return (-1);
827 }
828
830
832 poll_handle,
833 &totemsrp_context,
835 &totempg_stats,
836 totempg_deliver_fn,
837 totempg_confchg_fn,
838 totempg_waiting_trans_ack_cb);
839
840 if (res == -1) {
841 goto error_exit;
842 }
843
845 totemsrp_context,
848 0,
849 callback_token_received_fn,
850 0);
851
852 totempg_size_limit = (totemsrp_avail(totemsrp_context) - 1) *
854 sizeof (struct totempg_mcast) - 16);
855
857
859 return (res);
860}
861
863{
864 if (totempg_threaded_mode == 1) {
865 pthread_mutex_lock (&totempg_mutex);
866 }
867 // coverity[SLEEP:SUPPRESS] sleep is not a problem because it is shutdown
868 totemsrp_finalize (totemsrp_context);
869 if (totempg_threaded_mode == 1) {
870 pthread_mutex_unlock (&totempg_mutex);
871 }
872}
873
874/*
875 * Multicast a message
876 */
877static int mcast_msg (
878 struct iovec *iovec_in,
879 unsigned int iov_len,
880 int guarantee)
881{
882 int res = 0;
883 struct totempg_mcast mcast;
884 struct iovec iovecs[3];
885 struct iovec iovec[64];
886 int i;
887 int dest, src;
888 int max_packet_size = 0;
889 int copy_len = 0;
890 int copy_base = 0;
891 int total_size = 0;
892
893 if (totempg_threaded_mode == 1) {
894 pthread_mutex_lock (&mcast_msg_mutex);
895 }
896 totemsrp_event_signal (totemsrp_context, TOTEM_EVENT_NEW_MSG, 1);
897
898 /*
899 * Remove zero length iovectors from the list
900 */
901 assert (iov_len < 64);
902 for (dest = 0, src = 0; src < iov_len; src++) {
903 if (iovec_in[src].iov_len) {
904 memcpy (&iovec[dest++], &iovec_in[src],
905 sizeof (struct iovec));
906 }
907 }
908 iov_len = dest;
909
911 (sizeof (unsigned short) * (mcast_packed_msg_count + 1));
912
913 mcast_packed_msg_lens[mcast_packed_msg_count] = 0;
914
915 /*
916 * Check if we would overwrite new message queue
917 */
918 for (i = 0; i < iov_len; i++) {
919 total_size += iovec[i].iov_len;
920 }
921
922 if (byte_count_send_ok (total_size + sizeof(unsigned short) *
923 (mcast_packed_msg_count)) == 0) {
924
925 if (totempg_threaded_mode == 1) {
926 pthread_mutex_unlock (&mcast_msg_mutex);
927 }
928 return(-1);
929 }
930
931 memset(&mcast, 0, sizeof(mcast));
932
933 mcast.header.version = 0;
934 for (i = 0; i < iov_len; ) {
935 mcast.fragmented = 0;
936 mcast.continuation = fragment_continuation;
937 copy_len = iovec[i].iov_len - copy_base;
938
939 /*
940 * If it all fits with room left over, copy it in.
941 * We need to leave at least sizeof(short) + 1 bytes in the
942 * fragment_buffer on exit so that max_packet_size + fragment_size
943 * doesn't exceed the size of the fragment_buffer on the next call.
944 */
945 if ((iovec[i].iov_len + fragment_size) <
946 (max_packet_size - sizeof (unsigned short))) {
947
948 memcpy (&fragmentation_data[fragment_size],
949 (char *)iovec[i].iov_base + copy_base, copy_len);
950 fragment_size += copy_len;
951 mcast_packed_msg_lens[mcast_packed_msg_count] += copy_len;
952 next_fragment = 1;
953 // coverity[UNUSED_VALUE:SUPPRESS] defensive programming
954 copy_len = 0;
955 copy_base = 0;
956 i++;
957 continue;
958
959 /*
960 * If it just fits or is too big, then send out what fits.
961 */
962 } else {
963 unsigned char *data_ptr;
964
965 copy_len = min(copy_len, max_packet_size - fragment_size);
967 data_ptr = (unsigned char *)iovec[i].iov_base + copy_base;
968 else {
969 data_ptr = fragmentation_data;
970 }
971
972 memcpy (&fragmentation_data[fragment_size],
973 (unsigned char *)iovec[i].iov_base + copy_base, copy_len);
974 mcast_packed_msg_lens[mcast_packed_msg_count] += copy_len;
975
976 /*
977 * if we're not on the last iovec or the iovec is too large to
978 * fit, then indicate a fragment. This also means that the next
979 * message will have the continuation of this one.
980 */
981 if ((i < (iov_len - 1)) ||
982 ((copy_base + copy_len) < iovec[i].iov_len)) {
983 if (!next_fragment) {
984 next_fragment++;
985 }
986 fragment_continuation = next_fragment;
987 mcast.fragmented = next_fragment++;
988 assert(fragment_continuation != 0);
989 assert(mcast.fragmented != 0);
990 } else {
991 fragment_continuation = 0;
992 }
993
994 /*
995 * assemble the message and send it
996 */
997 mcast.msg_count = ++mcast_packed_msg_count;
998 iovecs[0].iov_base = (void *)&mcast;
999 iovecs[0].iov_len = sizeof(struct totempg_mcast);
1000 iovecs[1].iov_base = (void *)mcast_packed_msg_lens;
1001 iovecs[1].iov_len = mcast_packed_msg_count *
1002 sizeof(unsigned short);
1003 iovecs[2].iov_base = (void *)data_ptr;
1004 iovecs[2].iov_len = fragment_size + copy_len;
1005 assert (totemsrp_avail(totemsrp_context) > 0);
1006 res = totemsrp_mcast (totemsrp_context, iovecs, 3, guarantee);
1007 if (res == -1) {
1008 goto error_exit;
1009 }
1010
1011 /*
1012 * Recalculate counts and indexes for the next.
1013 */
1014 mcast_packed_msg_lens[0] = 0;
1015 mcast_packed_msg_count = 0;
1016 fragment_size = 0;
1017 max_packet_size = TOTEMPG_PACKET_SIZE - (sizeof(unsigned short));
1018
1019 /*
1020 * If the iovec all fit, go to the next iovec
1021 */
1022 if ((copy_base + copy_len) == iovec[i].iov_len) {
1023 // coverity[UNUSED_VALUE:SUPPRESS] defensive programming
1024 copy_len = 0;
1025 copy_base = 0;
1026 i++;
1027
1028 /*
1029 * Continue with the rest of the current iovec.
1030 */
1031 } else {
1033 }
1034 }
1035 }
1036
1037 /*
1038 * Bump only if we added message data. This may be zero if
1039 * the last buffer just fit into the fragmentation_data buffer
1040 * and we were at the last iovec.
1041 */
1042 if (mcast_packed_msg_lens[mcast_packed_msg_count]) {
1043 mcast_packed_msg_count++;
1044 }
1045
1047 if (totempg_threaded_mode == 1) {
1048 pthread_mutex_unlock (&mcast_msg_mutex);
1049 }
1050 return (res);
1051}
1052
1053/*
1054 * Determine if a message of msg_size could be queued
1055 */
1056static int msg_count_send_ok (
1057 int msg_count)
1058{
1059 int avail = 0;
1060
1061 avail = totemsrp_avail (totemsrp_context);
1062 totempg_stats.msg_queue_avail = avail;
1063
1064 return ((avail - totempg_reserved) > msg_count);
1065}
1066
1067static int byte_count_send_ok (
1068 int byte_count)
1069{
1070 unsigned int msg_count = 0;
1071 int avail = 0;
1072
1073 avail = totemsrp_avail (totemsrp_context);
1074
1075 msg_count = (byte_count / (totempg_totem_config->net_mtu - sizeof (struct totempg_mcast) - 16)) + 1;
1076
1077 return (avail >= msg_count);
1078}
1079
1080static int send_reserve (
1081 int msg_size)
1082{
1083 unsigned int msg_count = 0;
1084
1085 msg_count = (msg_size / (totempg_totem_config->net_mtu - sizeof (struct totempg_mcast) - 16)) + 1;
1086 totempg_reserved += msg_count;
1087 totempg_stats.msg_reserved = totempg_reserved;
1088
1089 return (msg_count);
1090}
1091
1092static void send_release (
1093 int msg_count)
1094{
1095 totempg_reserved -= msg_count;
1096 totempg_stats.msg_reserved = totempg_reserved;
1097}
1098
1099#ifndef HAVE_SMALL_MEMORY_FOOTPRINT
1100#undef MESSAGE_QUEUE_MAX
1101#define MESSAGE_QUEUE_MAX ((4 * MESSAGE_SIZE_MAX) / totempg_totem_config->net_mtu)
1102#endif /* HAVE_SMALL_MEMORY_FOOTPRINT */
1103
1104static uint32_t q_level_precent_used(void)
1105{
1106 return (100 - (((totemsrp_avail(totemsrp_context) - totempg_reserved) * 100) / MESSAGE_QUEUE_MAX));
1107}
1108
1110 void **handle_out,
1112 int delete,
1113 int (*callback_fn) (enum totem_callback_token_type type, const void *),
1114 const void *data)
1115{
1116 int res;
1117 if (totempg_threaded_mode == 1) {
1118 pthread_mutex_lock (&callback_token_mutex);
1119 }
1120 res = totemsrp_callback_token_create (totemsrp_context, handle_out, type, delete,
1121 callback_fn, data);
1122 if (totempg_threaded_mode == 1) {
1123 pthread_mutex_unlock (&callback_token_mutex);
1124 }
1125 return (res);
1126}
1127
1129 void *handle_out)
1130{
1131 if (totempg_threaded_mode == 1) {
1132 pthread_mutex_lock (&callback_token_mutex);
1133 }
1134 totemsrp_callback_token_destroy (totemsrp_context, handle_out);
1135 if (totempg_threaded_mode == 1) {
1136 pthread_mutex_unlock (&callback_token_mutex);
1137 }
1138}
1139
1140/*
1141 * vi: set autoindent tabstop=4 shiftwidth=4 :
1142 */
1143
1146
1147 void (*deliver_fn) (
1148 unsigned int nodeid,
1149 const void *msg,
1150 unsigned int msg_len,
1152
1153 void (*confchg_fn) (
1155 const unsigned int *member_list, size_t member_list_entries,
1156 const unsigned int *left_list, size_t left_list_entries,
1157 const unsigned int *joined_list, size_t joined_list_entries,
1158 const struct memb_ring_id *ring_id))
1159{
1160 struct totempg_group_instance *instance;
1161
1162 if (totempg_threaded_mode == 1) {
1163 pthread_mutex_lock (&totempg_mutex);
1164 }
1165
1166 instance = malloc (sizeof (struct totempg_group_instance));
1167 if (instance == NULL) {
1168 goto error_exit;
1169 }
1170
1171 instance->deliver_fn = deliver_fn;
1172 instance->confchg_fn = confchg_fn;
1173 instance->groups = 0;
1174 instance->groups_cnt = 0;
1175 instance->q_level = QB_LOOP_MED;
1176 qb_list_init (&instance->list);
1177 qb_list_add (&instance->list, &totempg_groups_list);
1178
1179 if (totempg_threaded_mode == 1) {
1180 pthread_mutex_unlock (&totempg_mutex);
1181 }
1182 *totempg_groups_instance = instance;
1183 return (0);
1184
1186 if (totempg_threaded_mode == 1) {
1187 pthread_mutex_unlock (&totempg_mutex);
1188 }
1189 return (-1);
1190}
1191
1194 const struct totempg_group *groups,
1195 size_t group_cnt)
1196{
1198 struct totempg_group *new_groups;
1199 int res = 0;
1200
1201 if (totempg_threaded_mode == 1) {
1202 pthread_mutex_lock (&totempg_mutex);
1203 }
1204
1205 new_groups = realloc (instance->groups,
1206 sizeof (struct totempg_group) *
1207 (instance->groups_cnt + group_cnt));
1208 if (new_groups == 0) {
1209 res = -1;
1210 goto error_exit;
1211 }
1212 memcpy (&new_groups[instance->groups_cnt],
1213 groups, group_cnt * sizeof (struct totempg_group));
1214 instance->groups = new_groups;
1215 instance->groups_cnt += group_cnt;
1216
1218 if (totempg_threaded_mode == 1) {
1219 pthread_mutex_unlock (&totempg_mutex);
1220 }
1221 return (res);
1222}
1223
1226 const struct totempg_group *groups,
1227 size_t group_cnt)
1228{
1229 if (totempg_threaded_mode == 1) {
1230 pthread_mutex_lock (&totempg_mutex);
1231 }
1232
1233 if (totempg_threaded_mode == 1) {
1234 pthread_mutex_unlock (&totempg_mutex);
1235 }
1236 return (0);
1237}
1238
1239#define MAX_IOVECS_FROM_APP 32
1240#define MAX_GROUPS_PER_MSG 32
1241
1244 const struct iovec *iovec,
1245 unsigned int iov_len,
1246 int guarantee)
1247{
1249 unsigned short group_len[MAX_GROUPS_PER_MSG + 1];
1251 int i;
1252 int res;
1253
1254 if (totempg_threaded_mode == 1) {
1255 pthread_mutex_lock (&totempg_mutex);
1256 }
1257
1258 /*
1259 * Build group_len structure and the iovec_mcast structure
1260 */
1261 group_len[0] = instance->groups_cnt;
1262 for (i = 0; i < instance->groups_cnt; i++) {
1263 group_len[i + 1] = instance->groups[i].group_len;
1264 iovec_mcast[i + 1].iov_len = instance->groups[i].group_len;
1265 iovec_mcast[i + 1].iov_base = (void *) instance->groups[i].group;
1266 }
1267 iovec_mcast[0].iov_len = (instance->groups_cnt + 1) * sizeof (unsigned short);
1268 iovec_mcast[0].iov_base = (char *)group_len;
1269 for (i = 0; i < iov_len; i++) {
1270 iovec_mcast[i + instance->groups_cnt + 1].iov_len = iovec[i].iov_len;
1271 iovec_mcast[i + instance->groups_cnt + 1].iov_base = iovec[i].iov_base;
1272 }
1273
1274 res = mcast_msg (iovec_mcast, iov_len + instance->groups_cnt + 1, guarantee);
1275
1276 if (totempg_threaded_mode == 1) {
1277 pthread_mutex_unlock (&totempg_mutex);
1278 }
1279
1280 return (res);
1281}
1282
1283static void check_q_level(
1285{
1287 int32_t old_level = instance->q_level;
1288 int32_t percent_used = q_level_precent_used();
1289
1290 if (percent_used >= 75 && instance->q_level != TOTEM_Q_LEVEL_CRITICAL) {
1291 instance->q_level = TOTEM_Q_LEVEL_CRITICAL;
1293 instance->q_level = TOTEM_Q_LEVEL_LOW;
1295 instance->q_level = TOTEM_Q_LEVEL_GOOD;
1297 instance->q_level = TOTEM_Q_LEVEL_HIGH;
1298 }
1299 if (totem_queue_level_changed && old_level != instance->q_level) {
1300 totem_queue_level_changed(instance->q_level);
1301 }
1302}
1303
1306{
1308
1309 check_q_level(instance);
1310}
1311
1314 const struct iovec *iovec,
1315 unsigned int iov_len)
1316{
1318 unsigned int size = 0;
1319 unsigned int i;
1320 unsigned int reserved = 0;
1321
1322 if (totempg_threaded_mode == 1) {
1323 pthread_mutex_lock (&totempg_mutex);
1324 pthread_mutex_lock (&mcast_msg_mutex);
1325 }
1326
1327 for (i = 0; i < instance->groups_cnt; i++) {
1328 size += instance->groups[i].group_len;
1329 }
1330 for (i = 0; i < iov_len; i++) {
1331 size += iovec[i].iov_len;
1332 }
1333
1334 if (size >= totempg_size_limit) {
1335 reserved = -1;
1336 goto error_exit;
1337 }
1338
1339 if (byte_count_send_ok (size)) {
1340 reserved = send_reserve (size);
1341 } else {
1342 reserved = 0;
1343 }
1344
1346 check_q_level(instance);
1347
1348 if (totempg_threaded_mode == 1) {
1349 pthread_mutex_unlock (&mcast_msg_mutex);
1350 pthread_mutex_unlock (&totempg_mutex);
1351 }
1352 return (reserved);
1353}
1354
1355
1357{
1358 if (totempg_threaded_mode == 1) {
1359 pthread_mutex_lock (&totempg_mutex);
1360 pthread_mutex_lock (&mcast_msg_mutex);
1361 }
1362 send_release (msg_count);
1363 if (totempg_threaded_mode == 1) {
1364 pthread_mutex_unlock (&mcast_msg_mutex);
1365 pthread_mutex_unlock (&totempg_mutex);
1366 }
1367 return 0;
1368}
1369
1372 int guarantee,
1373 const struct totempg_group *groups,
1374 size_t groups_cnt,
1375 const struct iovec *iovec,
1376 unsigned int iov_len)
1377{
1378 unsigned short group_len[MAX_GROUPS_PER_MSG + 1];
1380 int i;
1381 int res;
1382
1383 if (totempg_threaded_mode == 1) {
1384 pthread_mutex_lock (&totempg_mutex);
1385 }
1386
1387 /*
1388 * Build group_len structure and the iovec_mcast structure
1389 */
1390 group_len[0] = groups_cnt;
1391 for (i = 0; i < groups_cnt; i++) {
1392 group_len[i + 1] = groups[i].group_len;
1393 iovec_mcast[i + 1].iov_len = groups[i].group_len;
1394 iovec_mcast[i + 1].iov_base = (void *) groups[i].group;
1395 }
1396 iovec_mcast[0].iov_len = (groups_cnt + 1) * sizeof (unsigned short);
1397 iovec_mcast[0].iov_base = (char *)group_len;
1398 for (i = 0; i < iov_len; i++) {
1399 iovec_mcast[i + groups_cnt + 1].iov_len = iovec[i].iov_len;
1400 iovec_mcast[i + groups_cnt + 1].iov_base = iovec[i].iov_base;
1401 }
1402
1403 res = mcast_msg (iovec_mcast, iov_len + groups_cnt + 1, guarantee);
1404
1405 if (totempg_threaded_mode == 1) {
1406 pthread_mutex_unlock (&totempg_mutex);
1407 }
1408 return (res);
1409}
1410
1411/*
1412 * Returns -1 if error, 0 if can't send, 1 if can send the message
1413 */
1416 const struct totempg_group *groups,
1417 size_t groups_cnt,
1418 const struct iovec *iovec,
1419 unsigned int iov_len)
1420{
1421 unsigned int size = 0;
1422 unsigned int i;
1423 unsigned int res;
1424
1425 if (totempg_threaded_mode == 1) {
1426 pthread_mutex_lock (&totempg_mutex);
1427 }
1428
1429 for (i = 0; i < groups_cnt; i++) {
1430 size += groups[i].group_len;
1431 }
1432 for (i = 0; i < iov_len; i++) {
1433 size += iovec[i].iov_len;
1434 }
1435
1436 res = msg_count_send_ok (size);
1437
1438 if (totempg_threaded_mode == 1) {
1439 pthread_mutex_unlock (&totempg_mutex);
1440 }
1441 return (res);
1442}
1443
1446 unsigned short ip_port,
1447 unsigned int iface_no)
1448{
1449 int res;
1450
1452 totemsrp_context,
1454 ip_port,
1455 iface_no);
1456
1457 return (res);
1458}
1459
1462{
1463 memset(node_status, 0, sizeof(struct totem_node_status));
1464 return totemsrp_nodestatus_get (totemsrp_context, nodeid, node_status);
1465}
1466
1468 unsigned int nodeid,
1469 unsigned int *interface_id,
1470 struct totem_ip_address *interfaces,
1471 unsigned int interfaces_size,
1472 char ***status,
1473 unsigned int *iface_count)
1474{
1475 int res;
1476
1478 totemsrp_context,
1479 nodeid,
1481 interfaces,
1483 status,
1484 iface_count);
1485
1486 return (res);
1487}
1488
1490{
1491 totemsrp_event_signal (totemsrp_context, type, value);
1492}
1493
1495{
1496 return &totempg_stats;
1497}
1498
1500 const char *cipher_type,
1501 const char *hash_type)
1502{
1503 int res;
1504
1505 res = totemsrp_crypto_set (totemsrp_context, cipher_type, hash_type);
1506
1507 return (res);
1508}
1509
1510#define ONE_IFACE_LEN 63
1511const char *totempg_ifaces_print (unsigned int nodeid)
1512{
1513 static char iface_string[256 * INTERFACE_MAX];
1514 char one_iface[ONE_IFACE_LEN+1];
1515 struct totem_ip_address interfaces[INTERFACE_MAX];
1516 unsigned int iface_count;
1517 unsigned int iface_ids[INTERFACE_MAX];
1518 unsigned int i;
1519 int res;
1520
1521 iface_string[0] = '\0';
1522
1524 if (res == -1) {
1525 return ("no interface found for nodeid");
1526 }
1527
1529
1530 for (i = 0; i < iface_count; i++) {
1531 if (!interfaces[i].family) {
1532 continue;
1533 }
1535 "r(%d) ip(%s) ",
1536 i, totemip_print (&interfaces[i]));
1538 }
1539 return (iface_string);
1540}
1541
1542unsigned int totempg_my_nodeid_get (void)
1543{
1544 return (totemsrp_my_nodeid_get(totemsrp_context));
1545}
1546
1548{
1549 return (totemsrp_my_family_get(totemsrp_context));
1550}
1552 void (*totem_service_ready) (void))
1553{
1555}
1556
1558{
1559 totem_queue_level_changed = fn;
1560}
1561
1563 const struct totem_ip_address *member,
1564 int ring_no)
1565{
1566 return totemsrp_member_add (totemsrp_context, member, ring_no);
1567}
1568
1570 const struct totem_ip_address *member,
1571 int ring_no)
1572{
1573 return totemsrp_member_remove (totemsrp_context, member, ring_no);
1574}
1575
1576extern int totempg_reconfigure (void)
1577{
1578 return totemsrp_reconfigure (totemsrp_context, totempg_totem_config);
1579}
1580
1585
1587{
1589 totempg_stats.msg_reserved = 0;
1590 totempg_stats.msg_queue_avail = 0;
1591 }
1592 return totemsrp_stats_clear (totemsrp_context, flags);
1593}
1594
1596{
1597 totempg_threaded_mode = 1;
1598 totemsrp_threaded_mode_enable (totemsrp_context);
1599}
1600
1602{
1603 totemsrp_trans_ack (totemsrp_context);
1604}
1605
1607{
1608 totemsrp_force_gather(totemsrp_context);
1609}
1610
1611/* Assumes ->orig_interfaces is already allocated */
1613{
1614 struct totem_interface *temp_if = config->orig_interfaces;
1615
1617 config->orig_interfaces = temp_if;
1618 memcpy(config->orig_interfaces, totempg_totem_config->interfaces, sizeof(struct totem_interface) * INTERFACE_MAX);
1619 config->interfaces = NULL;
1620}
1621
1623{
1625
1626 /* Preseve the existing interfaces[] array as transports might have pointers saved */
1630}
totem_configuration_type
The totem_configuration_type enum.
Definition coroapi.h:132
#define INTERFACE_MAX
Definition coroapi.h:88
unsigned short family
Definition coroapi.h:1
#define MESSAGE_SIZE_MAX
Definition coroapi.h:97
unsigned int nodeid
the ID of the node whose info needs updating
Definition coroapi.h:0
totem_callback_token_type
The totem_callback_token_type enum.
Definition coroapi.h:142
@ TOTEM_CALLBACK_TOKEN_RECEIVED
Definition coroapi.h:143
#define CS_PRI_NODE_ID
Definition corotypes.h:59
#define min(a, b)
Definition exec/util.h:66
uint32_t flags
uint32_t value
int index
Definition totempg.c:202
struct qb_list_head list
Definition totempg.c:205
unsigned int nodeid
Definition totempg.c:200
unsigned char last_frag_num
Definition totempg.c:203
enum throw_away_mode throw_away_mode
Definition totempg.c:204
unsigned char data[MESSAGE_SIZE_MAX+KNET_MAX_PACKET_SIZE]
Definition totempg.c:201
struct totem_message_header header
Definition totemsrp.c:184
The memb_ring_id struct.
Definition coroapi.h:122
struct totem_logging_configuration totem_logging_configuration
Definition totem.h:214
struct totem_interface * interfaces
Definition totem.h:171
unsigned int net_mtu
Definition totem.h:216
The totem_ip_address struct.
Definition coroapi.h:111
void(* log_printf)(int level, int subsys, const char *function_name, const char *file_name, int file_line, const char *format,...) __attribute__((format(printf
Definition totem.h:101
void(*) in log_level_security)
Definition totem.h:110
struct qb_list_head list
Definition totempg.c:261
void(* confchg_fn)(enum totem_configuration_type configuration_type, const unsigned int *member_list, size_t member_list_entries, const unsigned int *left_list, size_t left_list_entries, const unsigned int *joined_list, size_t joined_list_entries, const struct memb_ring_id *ring_id)
Definition totempg.c:249
struct totempg_group * groups
Definition totempg.c:256
void(* deliver_fn)(unsigned int nodeid, const void *msg, unsigned int msg_len, int endian_conversion_required)
Definition totempg.c:243
const void * group
Definition totempg.h:56
size_t group_len
Definition totempg.h:57
unsigned short msg_count
Definition totempg.c:141
unsigned char fragmented
Definition totempg.c:139
struct totempg_mcast_header header
Definition totempg.c:138
unsigned char continuation
Definition totempg.c:140
uint32_t msg_queue_avail
Definition totemstats.h:98
uint32_t msg_reserved
Definition totemstats.h:97
#define swab16(x)
The swab16 macro.
Definition swab.h:39
typedef __attribute__
totem_event_type
Definition totem.h:298
@ TOTEM_EVENT_NEW_MSG
Definition totem.h:300
#define FRAME_SIZE_MAX
Definition totem.h:52
cfg_message_crypto_reconfig_phase_t
Definition totem.h:160
char type
Definition totem.h:2
const char * totemip_print(const struct totem_ip_address *addr)
Definition totemip.c:256
int totempg_my_family_get(void)
Definition totempg.c:1547
unsigned int totempg_my_nodeid_get(void)
Definition totempg.c:1542
static void(*) struct totem_config totempg_totem_config)
Definition totempg.c:190
int totempg_groups_leave(void *totempg_groups_instance, const struct totempg_group *groups, size_t group_cnt)
Definition totempg.c:1224
void totempg_check_q_level(void *totempg_groups_instance)
Definition totempg.c:1304
int totempg_callback_token_create(void **handle_out, enum totem_callback_token_type type, int delete, int(*callback_fn)(enum totem_callback_token_type type, const void *), const void *data)
Definition totempg.c:1109
#define log_printf(level, format, args...)
Definition totempg.c:272
throw_away_mode
Definition totempg.c:194
@ THROW_AWAY_INACTIVE
Definition totempg.c:195
@ THROW_AWAY_ACTIVE
Definition totempg.c:196
const char * totempg_ifaces_print(unsigned int nodeid)
Definition totempg.c:1511
#define ONE_IFACE_LEN
Definition totempg.c:1510
int totempg_groups_joined_reserve(void *totempg_groups_instance, const struct iovec *iovec, unsigned int iov_len)
Definition totempg.c:1312
QB_LIST_DECLARE(assembly_list_inuse)
int totempg_groups_initialize(void **totempg_groups_instance, void(*deliver_fn)(unsigned int nodeid, const void *msg, unsigned int msg_len, int endian_conversion_required), void(*confchg_fn)(enum totem_configuration_type configuration_type, const unsigned int *member_list, size_t member_list_entries, const unsigned int *left_list, size_t left_list_entries, const unsigned int *joined_list, size_t joined_list_entries, const struct memb_ring_id *ring_id))
Initialize a groups instance.
Definition totempg.c:1144
#define MAX_IOVECS_FROM_APP
Definition totempg.c:1239
int totempg_crypto_set(const char *cipher_type, const char *hash_type)
Definition totempg.c:1499
void totempg_get_config(struct totem_config *config)
Definition totempg.c:1612
void * callback_token_received_handle
Definition totempg.c:753
#define MESSAGE_QUEUE_MAX
Definition totempg.c:1101
int totempg_iface_set(struct totem_ip_address *interface_addr, unsigned short ip_port, unsigned int iface_no)
Definition totempg.c:1444
int totempg_nodestatus_get(unsigned int nodeid, struct totem_node_status *node_status)
Definition totempg.c:1460
void totempg_put_config(struct totem_config *config)
Definition totempg.c:1622
int totempg_reconfigure(void)
Definition totempg.c:1576
#define TOTEMPG_PACKET_SIZE
Definition totempg.c:153
int totempg_crypto_reconfigure_phase(cfg_message_crypto_reconfig_phase_t phase)
Definition totempg.c:1581
void totempg_trans_ack(void)
Definition totempg.c:1601
void totempg_force_gather(void)
Definition totempg.c:1606
int totempg_member_remove(const struct totem_ip_address *member, int ring_no)
Definition totempg.c:1569
void totempg_queue_level_register_callback(totem_queue_level_changed_fn fn)
Definition totempg.c:1557
int totempg_initialize(qb_loop_t *poll_handle, struct totem_config *totem_config)
Initialize the totem process groups abstraction.
Definition totempg.c:809
int totempg_groups_joined_release(int msg_count)
Definition totempg.c:1356
#define MAX_GROUPS_PER_MSG
Definition totempg.c:1240
void totempg_service_ready_register(void(*totem_service_ready)(void))
Definition totempg.c:1551
int totempg_ifaces_get(unsigned int nodeid, unsigned int *interface_id, struct totem_ip_address *interfaces, unsigned int interfaces_size, char ***status, unsigned int *iface_count)
Definition totempg.c:1467
void totempg_callback_token_destroy(void *handle_out)
Definition totempg.c:1128
void totempg_event_signal(enum totem_event_type type, int value)
Definition totempg.c:1489
void totempg_stats_clear(int flags)
Definition totempg.c:1586
void totempg_finalize(void)
Definition totempg.c:862
void * totempg_get_stats(void)
Definition totempg.c:1494
int totempg_groups_mcast_joined(void *totempg_groups_instance, const struct iovec *iovec, unsigned int iov_len, int guarantee)
Definition totempg.c:1242
void totempg_threaded_mode_enable(void)
Definition totempg.c:1595
int totempg_groups_send_ok_groups(void *totempg_groups_instance, const struct totempg_group *groups, size_t groups_cnt, const struct iovec *iovec, unsigned int iov_len)
Definition totempg.c:1414
int totempg_groups_mcast_groups(void *totempg_groups_instance, int guarantee, const struct totempg_group *groups, size_t groups_cnt, const struct iovec *iovec, unsigned int iov_len)
Definition totempg.c:1370
int totempg_member_add(const struct totem_ip_address *member, int ring_no)
Definition totempg.c:1562
int totempg_groups_join(void *totempg_groups_instance, const struct totempg_group *groups, size_t group_cnt)
Definition totempg.c:1192
Totem Single Ring Protocol.
void(* totem_queue_level_changed_fn)(enum totem_q_level level)
Definition totempg.h:189
@ TOTEM_Q_LEVEL_GOOD
Definition totempg.h:182
@ TOTEM_Q_LEVEL_HIGH
Definition totempg.h:183
@ TOTEM_Q_LEVEL_LOW
Definition totempg.h:181
@ TOTEM_Q_LEVEL_CRITICAL
Definition totempg.h:184
int totemsrp_my_family_get(void *srp_context)
Definition totemsrp.c:1133
void totemsrp_force_gather(void *context)
Definition totemsrp.c:5287
void totemsrp_service_ready_register(void *context, void(*totem_service_ready)(void))
Definition totemsrp.c:5208
int totemsrp_initialize(qb_loop_t *poll_handle, void **srp_context, struct totem_config *totem_config, totempg_stats_t *stats, void(*deliver_fn)(unsigned int nodeid, const void *msg, unsigned int msg_len, int endian_conversion_required), void(*confchg_fn)(enum totem_configuration_type configuration_type, const unsigned int *member_list, size_t member_list_entries, const unsigned int *left_list, size_t left_list_entries, const unsigned int *joined_list, size_t joined_list_entries, const struct memb_ring_id *ring_id), void(*waiting_trans_ack_cb_fn)(int waiting_trans_ack))
Create a protocol instance.
Definition totemsrp.c:818
int totemsrp_callback_token_create(void *srp_context, void **handle_out, enum totem_callback_token_type type, int delete, int(*callback_fn)(enum totem_callback_token_type type, const void *), const void *data)
Definition totemsrp.c:3498
void totemsrp_threaded_mode_enable(void *context)
Definition totemsrp.c:5243
void totemsrp_net_mtu_adjust(struct totem_config *totem_config)
Definition totemsrp.c:5204
int totemsrp_nodestatus_get(void *srp_context, unsigned int nodeid, struct totem_node_status *node_status)
Definition totemsrp.c:1041
int guarantee
Definition totemsrp.c:6
int totemsrp_crypto_set(void *srp_context, const char *cipher_type, const char *hash_type)
Definition totemsrp.c:1108
int totemsrp_avail(void *srp_context)
Return number of available messages that can be queued.
Definition totemsrp.c:2568
void totemsrp_stats_clear(void *context, int flags)
Definition totemsrp.c:5277
int totemsrp_iface_set(void *context, const struct totem_ip_address *interface_addr, unsigned short ip_port, unsigned int iface_no)
Definition totemsrp.c:5124
void totemsrp_finalize(void *srp_context)
Definition totemsrp.c:1026
struct memb_ring_id ring_id
Definition totemsrp.c:4
void totemsrp_trans_ack(void *context)
Definition totemsrp.c:5250
struct totem_message_header header
Definition totemsrp.c:0
int totemsrp_crypto_reconfigure_phase(void *context, struct totem_config *totem_config, cfg_message_crypto_reconfig_phase_t phase)
Definition totemsrp.c:5268
unsigned int totemsrp_my_nodeid_get(void *srp_context)
Definition totemsrp.c:1122
void totemsrp_event_signal(void *srp_context, enum totem_event_type type, int value)
Definition totemsrp.c:2488
void totemsrp_callback_token_destroy(void *srp_context, void **handle_out)
Definition totemsrp.c:3533
int totemsrp_member_add(void *context, const struct totem_ip_address *member, int iface_no)
Definition totemsrp.c:5217
int totemsrp_ifaces_get(void *srp_context, unsigned int nodeid, unsigned int *interface_id, struct totem_ip_address *interfaces, unsigned int interfaces_size, char ***status, unsigned int *iface_count)
Definition totemsrp.c:1070
int totemsrp_reconfigure(void *context, struct totem_config *totem_config)
Definition totemsrp.c:5259
int totemsrp_member_remove(void *context, const struct totem_ip_address *member, int iface_no)
Definition totemsrp.c:5230
int totemsrp_mcast(void *srp_context, struct iovec *iovec, unsigned int iov_len, int guarantee)
Multicast a message.
Definition totemsrp.c:2497
Totem Single Ring Protocol.
#define TOTEMPG_STATS_CLEAR_TOTEM
Definition totemstats.h:115