diff -urN Heartbeat-STABLE-2-1-STABLE-2.1.4/configure.in hb-ipv6/configure.in
--- Heartbeat-STABLE-2-1-STABLE-2.1.4/configure.in 2008-08-18 21:32:19.000000000 +0900
+++ hb-ipv6/configure.in 2009-09-29 11:49:09.000000000 +0900
@@ -81,6 +81,7 @@
*linux*) USE_MODULES=1
REBOOT_OPTIONS="-nf"
POWEROFF_OPTIONS="-nf"
+ AC_DEFINE_UNQUOTED(ON_LINUX, 1, Compiling for Linux platform)
;;
dnl anything?
darwin*)
@@ -2886,6 +2887,7 @@
dnl The Makefiles and shell scripts we output
AC_CONFIG_FILES(heartbeat.spec \
+hb-ipv6.spec \
Makefile \
README \
logd/Makefile \
diff -urN Heartbeat-STABLE-2-1-STABLE-2.1.4/hb-ipv6.spec.in hb-ipv6/hb-ipv6.spec.in
--- Heartbeat-STABLE-2-1-STABLE-2.1.4/hb-ipv6.spec.in 1970-01-01 09:00:00.000000000 +0900
+++ hb-ipv6/hb-ipv6.spec.in 2009-09-29 11:52:04.000000000 +0900
@@ -0,0 +1,124 @@
+########################################
+# Derived definitions
+########################################
+%define name hb-ipv6
+%define version 1.00
+%define release 1.hb214
+%define prefix @libdir@/@PACKAGE@
+%define ORGARCH Heartbeat-STABLE-2-1-STABLE-2.1.4
+#
+%define ocfdir @OCF_RA_DIR@/heartbeat
+%define installdir %{prefix}/hb-extras
+#
+%define __check_files %{nil}
+#
+#
+#
+Summary: Heartbeat command corresponding to IPv6.
+Name: %{name}
+Version: %{version}
+Release: %{release}
+Group: Applications
+Source: %{ORGARCH}.tar.gz
+License: GPL/LGPL
+Vendor: NIPPON TELEGRAPH AND TELEPHONE CORPORATION
+BuildRoot: %{_tmppath}/%{name}-%{version}
+BuildRequires: autoconf automake libtool
+Requires: heartbeat = 2.1.4
+Patch: %{name}-%{version}-%{release}.patch
+
+########################################
+%description
+########################################
+Heartbeat's tools and OCF Resource Agents corresponding to IPv6.
+ - pingd
+ - IPv6addr
+
+########################################
+%prep
+########################################
+rm -rf $RPM_BUILD_ROOT
+%setup -q -n %{ORGARCH}
+%patch -p1
+pushd $RPM_BUILD_DIR/%{ORGARCH}
+./ConfigureMe bootstrap
+popd
+
+########################################
+%build
+########################################
+pushd $RPM_BUILD_DIR/%{ORGARCH}/replace
+make DESTDIR=$RPM_BUILD_ROOT
+popd
+pushd $RPM_BUILD_DIR/%{ORGARCH}/libltdl
+make DESTDIR=$RPM_BUILD_ROOT
+popd
+pushd $RPM_BUILD_DIR/%{ORGARCH}/lib
+make DESTDIR=$RPM_BUILD_ROOT
+popd
+
+########################################
+%pre
+########################################
+if [ ! -e %{prefix}/pingd.org -a ! -L %{prefix}/pingd ]; then
+ mv %{prefix}/pingd %{prefix}/pingd.org
+fi
+
+if [ ! -e %{ocfdir}/IPv6addr.org -a ! -L %{ocfdir}/IPv6addr ]; then
+ mv %{ocfdir}/IPv6addr %{ocfdir}/IPv6addr.org
+fi
+
+########################################
+%install
+########################################
+pushd $RPM_BUILD_DIR/%{ORGARCH}/resources/OCF
+make DESTDIR=$RPM_BUILD_ROOT install
+popd
+pushd $RPM_BUILD_DIR/%{ORGARCH}/tools
+make DESTDIR=$RPM_BUILD_ROOT install
+popd
+
+########################################
+%clean
+########################################
+if [ -n "${RPM_BUILD_ROOT}" -a "${RPM_BUILD_ROOT}" != "/" ]; then
+ rm -rf $RPM_BUILD_ROOT
+fi
+rm -rf $RPM_BUILD_DIR/%{ORGARCH}
+
+########################################
+%post
+########################################
+ln -fs %{installdir}/pingd %{prefix}/pingd
+ln -fs %{installdir}/IPv6addr %{ocfdir}/IPv6addr
+
+########################################
+%preun
+########################################
+true
+
+########################################
+%postun
+########################################
+if [ ! -e %{installdir}/pingd ]; then
+ rm -f %{prefix}/pingd
+ if [ -e %{prefix}/pingd.org ]; then
+ mv %{prefix}/pingd.org %{prefix}/pingd
+ fi
+fi
+
+if [ ! -e %{installdir}/IPv6addr ]; then
+ rm -f %{ocfdir}/IPv6addr
+ if [ -e %{ocfdir}/IPv6addr.org ]; then
+ mv %{ocfdir}/IPv6addr.org %{ocfdir}/IPv6addr
+ fi
+fi
+
+########################################
+%files
+########################################
+%defattr(-,root,root)
+%dir %{installdir}
+%defattr(755,root,root)
+%{installdir}/pingd
+%{installdir}/IPv6addr
diff -urN Heartbeat-STABLE-2-1-STABLE-2.1.4/resources/OCF/IPv6addr.c hb-ipv6/resources/OCF/IPv6addr.c
--- Heartbeat-STABLE-2-1-STABLE-2.1.4/resources/OCF/IPv6addr.c 2008-08-18 21:32:19.000000000 +0900
+++ hb-ipv6/resources/OCF/IPv6addr.c 2009-09-29 11:49:09.000000000 +0900
@@ -45,6 +45,8 @@
*
* It should be passed by environment variant:
* OCF_RESKEY_ipv6addr=3ffe:ffff:0:f101::3
+ * OCF_RESKEY_cidr_netmask=64
+ * OCF_RESKEY_nic=eth0
*
*/
@@ -145,11 +147,11 @@
unsigned int ifr6_ifindex;
};
-static int start_addr6(struct in6_addr* addr6, int prefix_len);
-static int stop_addr6(struct in6_addr* addr6, int prefix_len);
-static int status_addr6(struct in6_addr* addr6, int prefix_len);
+static int start_addr6(struct in6_addr* addr6, int prefix_len, char* prov_ifname);
+static int stop_addr6(struct in6_addr* addr6, int prefix_len, char* prov_ifname);
+static int status_addr6(struct in6_addr* addr6, int prefix_len, char* prov_ifname);
static int monitor_addr6(struct in6_addr* addr6, int prefix_len);
-static int advt_addr6(struct in6_addr* addr6, int prefix_len);
+static int advt_addr6(struct in6_addr* addr6, int prefix_len, char* prov_ifname);
static int meta_data_addr6(void);
@@ -159,9 +161,9 @@
static void byebye(int nsig);
static char* scan_if(struct in6_addr* addr_target, int* plen_target,
- int use_mask);
-static char* find_if(struct in6_addr* addr_target, int* plen_target);
-static char* get_if(struct in6_addr* addr_target, int* plen_target);
+ int use_mask, char* prov_ifname);
+static char* find_if(struct in6_addr* addr_target, int* plen_target, char* prov_ifname);
+static char* get_if(struct in6_addr* addr_target, int* plen_target, char* prov_ifname);
static int assign_addr6(struct in6_addr* addr6, int prefix_len, char* if_name);
static int unassign_addr6(struct in6_addr* addr6, int prefix_len, char* if_name);
int is_addr6_available(struct in6_addr* addr6);
@@ -172,9 +174,11 @@
{
char pid_file[256];
char* ipv6addr;
+ char* cidr_netmask;
int ret;
char* cp;
- int prefix_len;
+ char* prov_ifname = NULL;
+ int prefix_len = -1;
struct in6_addr addr6;
/* Check the count of parameters first */
@@ -190,6 +194,7 @@
/* open system log */
cl_log_set_entity(APP_NAME);
cl_log_set_facility(HA_LOG_FACILITY);
+ cl_log_set_uselogd(TRUE);
/* the meta-data dont need any parameter */
if (0 == strncmp(META_DATA_CMD, argv[1], strlen(META_DATA_CMD))) {
@@ -204,6 +209,8 @@
usage(argv[0]);
return OCF_ERR_ARGS;
}
+
+ /* legacy option */
if ((cp = strchr(ipv6addr, '/'))) {
prefix_len = atol(cp + 1);
if ((prefix_len < 0) || (prefix_len > 128)) {
@@ -212,10 +219,30 @@
return OCF_ERR_ARGS;
}
*cp=0;
- } else {
+ }
+
+ /* get provided netmask (optional) */
+ cidr_netmask = getenv("OCF_RESKEY_cidr_netmask");
+ if (cidr_netmask != NULL) {
+ if ((atol(cidr_netmask) < 0) || (atol(cidr_netmask) > 128)) {
+ cl_log(LOG_ERR, "Invalid prefix_len [%s], "
+ "should be an integer in [0, 128]", cidr_netmask);
+ usage(argv[0]);
+ return OCF_ERR_ARGS;
+ }
+ if (prefix_len != -1 && prefix_len != atol(cidr_netmask)) {
+ cl_log(LOG_DEBUG, "prefix_len(%d) is overwritted by cidr_netmask(%s)",
+ prefix_len, cidr_netmask);
+ }
+ prefix_len = atol(cidr_netmask);
+
+ } else if (prefix_len == -1) {
prefix_len = 0;
}
+ /* get provided interface name (optional) */
+ prov_ifname = getenv("OCF_RESKEY_nic");
+
if (inet_pton(AF_INET6, ipv6addr, &addr6) <= 0) {
cl_log(LOG_ERR, "Invalid IPv6 address [%s]", ipv6addr);
usage(argv[0]);
@@ -244,11 +271,11 @@
/* switch the command */
if (0 == strncmp(START_CMD,argv[1], strlen(START_CMD))) {
- ret = start_addr6(&addr6, prefix_len);
+ ret = start_addr6(&addr6, prefix_len, prov_ifname);
}else if (0 == strncmp(STOP_CMD,argv[1], strlen(STOP_CMD))) {
- ret = stop_addr6(&addr6, prefix_len);
+ ret = stop_addr6(&addr6, prefix_len, prov_ifname);
}else if (0 == strncmp(STATUS_CMD,argv[1], strlen(STATUS_CMD))) {
- ret = status_addr6(&addr6, prefix_len);
+ ret = status_addr6(&addr6, prefix_len, prov_ifname);
}else if (0 ==strncmp(MONITOR_CMD,argv[1], strlen(MONITOR_CMD))) {
ret = monitor_addr6(&addr6, prefix_len);
}else if (0 ==strncmp(RELOAD_CMD,argv[1], strlen(RELOAD_CMD))) {
@@ -259,7 +286,7 @@
/* ipv6addr has been validated by inet_pton, hence a valid IPv6 address */
ret = OCF_SUCCESS;
}else if (0 ==strncmp(ADVT_CMD,argv[1], strlen(MONITOR_CMD))) {
- ret = advt_addr6(&addr6, prefix_len);
+ ret = advt_addr6(&addr6, prefix_len, prov_ifname);
}else{
usage(argv[0]);
ret = OCF_ERR_ARGS;
@@ -268,19 +295,20 @@
/* release the pid file */
unlink(pid_file);
+ cl_log(LOG_DEBUG, "%s %s : %d", getenv("OCF_RESOURCE_INSTANCE"), argv[1], ret);
return ret;
}
int
-start_addr6(struct in6_addr* addr6, int prefix_len)
+start_addr6(struct in6_addr* addr6, int prefix_len, char* prov_ifname)
{
int i;
char* if_name;
- if(OCF_SUCCESS == status_addr6(addr6,prefix_len)) {
+ if(OCF_SUCCESS == status_addr6(addr6,prefix_len,prov_ifname)) {
return OCF_SUCCESS;
}
/* we need to find a proper device to assign the address */
- if_name = find_if(addr6, &prefix_len);
+ if_name = find_if(addr6, &prefix_len, prov_ifname);
if (NULL == if_name) {
cl_log(LOG_ERR, "no valid mecahnisms");
return OCF_ERR_GENERIC;
@@ -313,10 +341,10 @@
}
int
-advt_addr6(struct in6_addr* addr6, int prefix_len)
+advt_addr6(struct in6_addr* addr6, int prefix_len, char* prov_ifname)
{
/* First, we need to find a proper device to assign the address */
- char* if_name = get_if(addr6, &prefix_len);
+ char* if_name = get_if(addr6, &prefix_len, prov_ifname);
int i;
if (NULL == if_name) {
cl_log(LOG_ERR, "no valid mecahnisms");
@@ -331,14 +359,14 @@
}
int
-stop_addr6(struct in6_addr* addr6, int prefix_len)
+stop_addr6(struct in6_addr* addr6, int prefix_len, char* prov_ifname)
{
char* if_name;
- if(OCF_NOT_RUNNING == status_addr6(addr6,prefix_len)) {
+ if(OCF_NOT_RUNNING == status_addr6(addr6,prefix_len,prov_ifname)) {
return OCF_SUCCESS;
}
- if_name = get_if(addr6, &prefix_len);
+ if_name = get_if(addr6, &prefix_len, prov_ifname);
if (NULL == if_name) {
cl_log(LOG_ERR, "no valid mechanisms.");
@@ -356,9 +384,9 @@
}
int
-status_addr6(struct in6_addr* addr6, int prefix_len)
+status_addr6(struct in6_addr* addr6, int prefix_len, char* prov_ifname)
{
- char* if_name = get_if(addr6, &prefix_len);
+ char* if_name = get_if(addr6, &prefix_len, prov_ifname);
if (NULL == if_name) {
return OCF_NOT_RUNNING;
}
@@ -387,12 +415,21 @@
struct libnet_in6_addr dst_ip;
struct libnet_ether_addr *mac_address;
char payload[24];
+ int ifindex;
if ((l=libnet_init(LIBNET_RAW6, if_name, errbuf)) == NULL) {
cl_log(LOG_ERR, "libnet_init failure on %s", if_name);
goto err;
}
+ /* set the outgoing interface */
+ ifindex = if_nametoindex(if_name);
+ if (setsockopt(libnet_getfd(l), IPPROTO_IPV6, IPV6_MULTICAST_IF,
+ &ifindex, sizeof(ifindex)) < 0) {
+ cl_log(LOG_ERR, "setsockopt(IPV6_MULTICAST_IF): %s",
+ strerror(errno));
+ goto err;
+ }
mac_address = libnet_get_hwaddr(l);
if (!mac_address) {
@@ -414,6 +451,9 @@
libnet_build_ipv6(0,0,LIBNET_ICMPV6_H + sizeof(payload),IPPROTO_ICMP6,
255,*(struct libnet_in6_addr*)src_ip,
dst_ip,NULL,0,l,0);
+ /* Hack: adjust the correct checksum offset. see LF #2034 */
+ libnet_pblock_record_ip_offset(l, l->total_size);
+
if (libnet_write(l) == -1)
{
@@ -429,7 +469,7 @@
/* find the network interface associated with an address */
char*
-scan_if(struct in6_addr* addr_target, int* plen_target, int use_mask)
+scan_if(struct in6_addr* addr_target, int* plen_target, int use_mask, char* prov_ifname)
{
FILE *f;
static char devname[21]="";
@@ -475,7 +515,15 @@
if (*plen_target!=0 && plen != *plen_target) {
continue;
}
- *plen_target = plen;
+
+ /* If interface name provided, only same devname entry
+ * would be considered
+ */
+ if (prov_ifname!=0 && *prov_ifname!=0)
+ {
+ if (strcmp(devname, prov_ifname))
+ continue;
+ }
for (i = 0; i< 4; i++) {
addr.s6_addr32[i] = htonl(addr6p[i]);
@@ -487,7 +535,10 @@
n = plen / 32;
memset(mask.s6_addr32 + n + 1, 0, (3 - n) * 4);
s = 32 - plen % 32;
- mask.s6_addr32[n] = 0xffffffff << s;
+ if (s == 32)
+ mask.s6_addr32[n] = 0x0;
+ else
+ mask.s6_addr32[n] = 0xffffffff << s;
mask.s6_addr32[n] = htonl(mask.s6_addr32[n]);
}
@@ -504,6 +555,7 @@
/* We found it! */
if (same) {
fclose(f);
+ *plen_target = plen;
return devname;
}
}
@@ -512,15 +564,15 @@
}
/* find a proper network interface to assign the address */
char*
-find_if(struct in6_addr* addr_target, int* plen_target)
+find_if(struct in6_addr* addr_target, int* plen_target, char* prov_ifname)
{
- return scan_if(addr_target, plen_target, 1);
+ return scan_if(addr_target, plen_target, 1, prov_ifname);
}
/* get the device name and the plen_target of a special address */
char*
-get_if(struct in6_addr* addr_target, int* plen_target)
+get_if(struct in6_addr* addr_target, int* plen_target, char* prov_ifname)
{
- return scan_if(addr_target, plen_target, 0);
+ return scan_if(addr_target, plen_target, 0, prov_ifname);
}
int
assign_addr6(struct in6_addr* addr6, int prefix_len, char* if_name)
@@ -836,12 +888,29 @@
" IPv6 address\n"
" \n"
" \n"
+ " \n"
+ " \n"
+ " The netmask for the interface in CIDR format. (ie, 24).\n"
+ " The value of this parameter overwrites the value of _prefix_\n"
+ " of ipv6addr parameter.\n"
+ " \n"
+ " Netmask\n"
+ " \n"
+ " \n"
+ " \n"
+ " \n"
+ " The base network interface on which the IPv6 address will\n"
+ " be brought online.\n"
+ " \n"
+ " Network interface\n"
+ " \n"
+ " \n"
" \n"
" \n"
" \n"
" \n"
- " \n"
- " \n"
+ " \n"
+ " \n"
" \n"
" \n"
" \n"
diff -urN Heartbeat-STABLE-2-1-STABLE-2.1.4/resources/OCF/Makefile.am hb-ipv6/resources/OCF/Makefile.am
--- Heartbeat-STABLE-2-1-STABLE-2.1.4/resources/OCF/Makefile.am 2008-08-18 21:32:19.000000000 +0900
+++ hb-ipv6/resources/OCF/Makefile.am 2009-09-29 11:49:09.000000000 +0900
@@ -24,15 +24,16 @@
dtddir = $(HA_NOARCHDATAHBDIR)
ocfdir = @OCF_RA_DIR@/heartbeat
+ocf2dir = $(libdir)/@HB_PKG@/hb-extras
dtd_SCRIPTS = ra-api-1.dtd
gliblib = @GLIBLIB@
if USE_IPV6ADDR
-ocf_PROGRAMS = IPv6addr
+ocf2_PROGRAMS = IPv6addr
else
-ocf_PROGRAMS =
+ocf2_PROGRAMS =
endif
IPv6addr_SOURCES = IPv6addr.c
diff -urN Heartbeat-STABLE-2-1-STABLE-2.1.4/resources/heartbeat/IPv6addr.in hb-ipv6/resources/heartbeat/IPv6addr.in
--- Heartbeat-STABLE-2-1-STABLE-2.1.4/resources/heartbeat/IPv6addr.in 2008-08-18 21:32:19.000000000 +0900
+++ hb-ipv6/resources/heartbeat/IPv6addr.in 2009-09-29 11:49:09.000000000 +0900
@@ -25,5 +25,24 @@
OCF_RESOURCE_INSTANCE=${OCF_TYPE}_$1
export OCF_TYPE OCF_RESOURCE_INSTANCE
-OCF_RESKEY_ipv6addr=$1; export OCF_RESKEY_ipv6addr
+# We need to split the argument into pieces that IPv6addr OCF RA can
+# recognize, sed is prefered over Bash specific builtin functions
+# for portability.
+BASEIP=`echo $1 | sed 's%/.*%%'`
+OCF_RESKEY_ipv6addr=$BASEIP; export OCF_RESKEY_ipv6addr
+
+str=`echo $1 | sed 's%^'$BASEIP'*%%'`
+if [ ! -z "$str" ]; then
+ NETMASK=`echo ${str#/} | sed 's%/.*%%'`
+ OCF_RESKEY_cidr_netmask=$NETMASK; export OCF_RESKEY_cidr_netmask
+
+ str=`echo $str | sed 's%^/'$NETMASK'/*%%'`
+ NIC=`echo $str | sed 's%/.*%%'`
+ case $NIC in
+ "") ;;
+ *) OCF_RESKEY_nic=$NIC; export OCF_RESKEY_nic
+ ;;
+ esac
+fi
+
ra_execocf $2
diff -urN Heartbeat-STABLE-2-1-STABLE-2.1.4/tools/Makefile.am hb-ipv6/tools/Makefile.am
--- Heartbeat-STABLE-2-1-STABLE-2.1.4/tools/Makefile.am 2008-08-18 21:32:19.000000000 +0900
+++ hb-ipv6/tools/Makefile.am 2009-09-29 11:49:09.000000000 +0900
@@ -28,6 +28,7 @@
apigid = @HA_APIGID@
habindir = @bindir@
halibdir = $(libdir)/@HB_PKG@
+halib2dir = $(libdir)/@HB_PKG@/hb-extras
hanoarchdir = @HA_NOARCHDATAHBDIR@
gliblib = @GLIBLIB@
@@ -37,7 +38,8 @@
sbin_SCRIPTS = ciblint hb_report ocf-tester
if CRM_BUILD
-halib_PROGRAMS = attrd pingd
+halib_PROGRAMS = attrd
+halib2_PROGRAMS = pingd
sbin_PROGRAMS = attrd_updater
endif
diff -urN Heartbeat-STABLE-2-1-STABLE-2.1.4/tools/pingd.c hb-ipv6/tools/pingd.c
--- Heartbeat-STABLE-2-1-STABLE-2.1.4/tools/pingd.c 2008-08-18 21:32:19.000000000 +0900
+++ hb-ipv6/tools/pingd.c 2009-09-29 11:49:09.000000000 +0900
@@ -19,63 +19,984 @@
#include
-#include
-
-#include
-
#include
-#include
-#include
#include
-
#include
#include
#include
#include
+#include
+#include
-#include
-#include
-#include
-#include
+#ifdef HAVE_SYS_SOCKET_H
+# include
+#endif
+
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+#include
+
+#ifdef ON_LINUX
+#include
+#include
+# ifndef ICMP_FILTER
+# define ICMP_FILTER 1
+struct icmp_filter {
+ uint32_t data;
+};
+# endif
+#endif
+#include
#include
#include
+#include
#ifdef HAVE_GETOPT_H
# include
#endif
+#define crm_perror(level, fmt, args...) do { \
+ const char *err = strerror(errno); \
+ do_crm_log(level, fmt ": %s (%d)", ##args, err, errno); \
+ } while(0)
+
+#define OPTARGS "?VDp:N:a:d:S:s:i:n:t:m:Uh:"
+
/* GMainLoop *mainloop = NULL; */
-#define OPTARGS "V?p:a:d:s:S:h:Dm:"
-IPC_Channel *attrd = NULL;
+GListPtr ping_list = NULL;
GMainLoop* mainloop = NULL;
GHashTable *ping_nodes = NULL;
const char *pingd_attr = "pingd";
gboolean do_filter = FALSE;
-ll_cluster_t *pingd_cluster = NULL;
gboolean need_shutdown = FALSE;
+gboolean stand_alone = FALSE;
+gboolean do_updates = TRUE;
+ll_cluster_t *pingd_cluster = NULL;
const char *attr_set = NULL;
const char *attr_section = NULL;
-const char *attr_dampen = NULL;
+int attr_dampen = 5000; /* 5s */
int attr_multiplier = 1;
+int pings_per_host = 2;
+int ping_timeout = 2;
+int re_ping_interval = 1000; /* 1s */
+
+int ident; /* our pid */
+
+unsigned char cmsgbuf[4096];
+int cmsglen = 0;
+
+typedef struct ping_node_s {
+ int fd; /* ping socket */
+ uint16_t iseq; /* sequence number */
+ gboolean type;
+ gboolean extra_filters;
+ union {
+ struct sockaddr raw;
+ struct sockaddr_in v4; /* ipv4 ping addr */
+ struct sockaddr_in6 v6; /* ipv6 ping addr */
+ } addr;
+ char dest[256];
+ char *host;
+} ping_node;
void pingd_nstatus_callback(
const char *node, const char *status, void *private_data);
void pingd_lstatus_callback(
const char *node, const char *link, const char *status,
void *private_data);
+void send_update(int active);
+int process_icmp6_error(ping_node *node, struct sockaddr_in6 *whereto);
+int process_icmp4_error(ping_node *node, struct sockaddr_in *whereto);
void do_node_walk(ll_cluster_t *hb_cluster);
-void send_update(void);
+
+/*
+ * in_cksum --
+ * Checksum routine for Internet Protocol family headers (C Version)
+ * This function taken from Mike Muuss' ping program.
+ */
+static int
+in_cksum (u_short *addr, size_t len)
+{
+ size_t nleft = len;
+ u_short * w = addr;
+ int sum = 0;
+ u_short answer = 0;
+
+ /*
+ * The IP checksum algorithm is simple: using a 32 bit accumulator (sum)
+ * add sequential 16 bit words to it, and at the end, folding back all
+ * the carry bits from the top 16 bits into the lower 16 bits.
+ */
+ while (nleft > 1) {
+ sum += *w++;
+ nleft -= 2;
+ }
+
+ /* Mop up an odd byte, if necessary */
+ if (nleft == 1) {
+ sum += *(u_char*)w;
+ }
+
+ /* Add back carry bits from top 16 bits to low 16 bits */
+
+ sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */
+ sum += (sum >> 16); /* add carry */
+ answer = ~sum; /* truncate to 16 bits */
+
+ return answer;
+}
+
+static const char *ping_desc(gboolean family, uint8_t type, uint8_t code)
+{
+ if(family == AF_INET6) {
+ switch(type) {
+ case ICMP6_DST_UNREACH:
+ switch(code) {
+ case ICMP6_DST_UNREACH_NOROUTE:
+ return "No Route to Destination";
+ case ICMP6_DST_UNREACH_ADMIN:
+ return "Destination Administratively Unreachable";
+ case ICMP6_DST_UNREACH_BEYONDSCOPE:
+ return "Destination Unreachable Beyond Scope";
+ case ICMP6_DST_UNREACH_ADDR:
+ return "Destination Address Unreachable";
+ case ICMP6_DST_UNREACH_NOPORT:
+ return "Destination Port Unreachable";
+ default:
+ crm_err("Unreachable: Unkown subtype: %d", code);
+ return "Unreachable: Unkown Subtype";
+ }
+ case ICMP6_PACKET_TOO_BIG:
+ return "Packet too big";
+ case ICMP6_TIME_EXCEEDED:
+ switch(code) {
+ case ICMP6_TIME_EXCEED_TRANSIT:
+ return "Time to live exceeded";
+ case ICMP6_TIME_EXCEED_REASSEMBLY:
+ return "Frag reassembly time exceeded";
+ default:
+ crm_err("Timeout: Unkown subtype: %d", code);
+ return "Timeout: Unkown Subtype";
+ }
+ case ICMP6_PARAM_PROB:
+ switch(code) {
+ case ICMP6_PARAMPROB_HEADER:
+ return "Parameter problem: Erroneous Header";
+ case ICMP6_PARAMPROB_NEXTHEADER:
+ return "Parameter problem: Unknown Nextheader";
+ case ICMP6_PARAMPROB_OPTION:
+ return "Parameter problem: Unrecognized Option";
+ default:
+ crm_err("Invalid header: Unkown subtype: %d", code);
+ return "Invalid header: Unkown Subtype";
+ }
+ case ICMP6_ECHO_REQUEST:
+ return "Echo Request";
+ case ICMP6_ECHO_REPLY:
+ return "Echo Reply";
+ case MLD_LISTENER_QUERY:
+ return "Multicast Listener Query";
+ case MLD_LISTENER_REPORT:
+ return "Multicast Listener Report";
+ case MLD_LISTENER_REDUCTION:
+ return "Multicast Listener Done";
+ case ND_ROUTER_SOLICIT:
+ return "Router Solicitation";
+ case ND_ROUTER_ADVERT:
+ return "Router Advertisement";
+ case ND_NEIGHBOR_SOLICIT:
+ return "Neighbor Solicitation";
+ case ND_NEIGHBOR_ADVERT:
+ return "Neighbor Advertisement";
+ case ND_REDIRECT:
+ return "Redirect";
+ case ICMP6_ROUTER_RENUMBERING:
+ return "Router renumbering";
+ default:
+ crm_err("Unknown type: %d", type);
+ return "Unknown type";
+ }
+ } else {
+ switch(type) {
+ case ICMP_ECHOREPLY:
+ return "Echo Reply";
+ case ICMP_ECHO:
+ return "Echo Request";
+ case ICMP_PARAMPROB:
+ return "Bad Parameter";
+ case ICMP_SOURCEQUENCH:
+ return "Packet lost, slow down";
+ case ICMP_TSTAMP:
+ return "Timestamp Request";
+ case ICMP_TSTAMPREPLY:
+ return "Timestamp Reply";
+ case ICMP_IREQ:
+ return "Information Request";
+ case ICMP_IREQREPLY:
+ return "Information Reply";
+
+ case ICMP_UNREACH:
+ switch(code) {
+ case ICMP_UNREACH_NET:
+ return "Unreachable Network";
+ case ICMP_UNREACH_HOST:
+ return "Unreachable Host";
+ case ICMP_UNREACH_PROTOCOL:
+ return "Unreachable Protocol";
+ case ICMP_UNREACH_PORT:
+ return "Unreachable Port";
+ case ICMP_UNREACH_NEEDFRAG:
+ return "Unreachable: Fragmentation needed";
+ case ICMP_UNREACH_SRCFAIL:
+ return "Unreachable Source Route";
+ case ICMP_UNREACH_NET_UNKNOWN:
+ return "Unknown Network";
+ case ICMP_UNREACH_HOST_UNKNOWN:
+ return "Unknown Host";
+ case ICMP_UNREACH_ISOLATED:
+ return "Unreachable: Isolated";
+ case ICMP_UNREACH_NET_PROHIB:
+ return "Prohibited network";
+ case ICMP_UNREACH_HOST_PROHIB:
+ return "Prohibited host";
+ case ICMP_UNREACH_FILTER_PROHIB:
+ return "Unreachable: Prohibited filter";
+ case ICMP_UNREACH_TOSNET:
+ return "Unreachable: Type of Service and Network";
+ case ICMP_UNREACH_TOSHOST:
+ return "Unreachable: Type of Service and Host";
+ case ICMP_UNREACH_HOST_PRECEDENCE:
+ return "Unreachable: Prec vio";
+ case ICMP_UNREACH_PRECEDENCE_CUTOFF:
+ return "Unreachable: Prec cutoff";
+ default:
+ crm_err("Unreachable: Unknown subtype: %d", code);
+ return "Unreachable: Unknown Subtype";
+ }
+ break;
+
+ case ICMP_REDIRECT:
+ switch(code) {
+ case ICMP_REDIRECT_NET:
+ return "Redirect: Network";
+ case ICMP_REDIRECT_HOST:
+ return "Redirect: Host";
+ case ICMP_REDIRECT_TOSNET:
+ return "Redirect: Type of Service and Network";
+ case ICMP_REDIRECT_TOSHOST:
+ return "Redirect: Type of Service and Host";
+ default:
+ crm_err("Redirect: Unknown subtype: %d", code);
+ return "Redirect: Unknown Subtype";
+ }
+
+ case ICMP_TIMXCEED:
+ switch(code) {
+ case ICMP_TIMXCEED_INTRANS:
+ return "Timeout: TTL";
+ case ICMP_TIMXCEED_REASS:
+ return "Timeout: Fragmentation reassembly";
+ default:
+ crm_err("Timeout: Unkown subtype: %d", code);
+ return "Timeout: Unkown Subtype";
+ }
+ break;
+
+ default:
+ crm_err("Unknown type: %d", type);
+ return "Unknown type";
+ }
+ }
+}
+
+#ifdef ON_LINUX
+# define MAX_HOST 1024
+int process_icmp6_error(ping_node *node, struct sockaddr_in6 *whereto)
+{
+ int rc = 0;
+ char buf[512];
+ struct iovec iov;
+ struct msghdr msg;
+ struct icmp6_hdr icmph;
+ struct sockaddr_in6 target;
+ struct cmsghdr *cmsg = NULL;
+ struct sock_extended_err *s_err = NULL;
+
+ iov.iov_base = &icmph;
+ iov.iov_len = sizeof(icmph);
+ msg.msg_name = (void*)⌖
+ msg.msg_namelen = sizeof(target);
+ msg.msg_iov = &iov;
+ msg.msg_iovlen = 1;
+ msg.msg_flags = 0;
+ msg.msg_control = buf;
+ msg.msg_controllen = sizeof(buf);
+
+ rc = recvmsg(node->fd, &msg, MSG_ERRQUEUE|MSG_DONTWAIT);
+ if (rc < 0 || rc < sizeof(icmph)) {
+ crm_perror(LOG_DEBUG, "No error message: %d", rc);
+ return 0;
+ }
+
+ for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
+ if (cmsg->cmsg_level == SOL_IPV6 && cmsg->cmsg_type == IPV6_RECVERR) {
+ s_err = (struct sock_extended_err *)CMSG_DATA(cmsg);
+ }
+ }
+
+ CRM_ASSERT(s_err != NULL);
+
+ if (s_err->ee_origin == SO_EE_ORIGIN_LOCAL) {
+ if (s_err->ee_errno == EMSGSIZE) {
+ crm_info("local error: Message too long, mtu=%u", s_err->ee_info);
+ } else {
+ crm_info("local error: %s", strerror(s_err->ee_errno));
+ }
+ return 0;
+
+ } else if (s_err->ee_origin == SO_EE_ORIGIN_ICMP6) {
+ struct sockaddr_in6 *sin = (struct sockaddr_in6*)(s_err+1);
+ const char *ping_result = ping_desc(node->type, s_err->ee_type, s_err->ee_code);
+ static char target_s[64], whereto_s[64], ping_host_s[64];
+ inet_ntop(AF_INET6, (struct in6_addr *)&(target.sin6_addr), target_s, sizeof(target_s));
+ inet_ntop(AF_INET6, (struct in6_addr *)&(whereto->sin6_addr), whereto_s, sizeof(whereto_s));
+
+ if (ntohs(icmph.icmp6_id) != ident) {
+ /* Result was not for us */
+ crm_debug("Not our error (ident): %d %d", ntohs(icmph.icmp6_id), ident);
+ return -1;
+
+ } else if (memcmp(&target.sin6_addr, &whereto->sin6_addr, 16)) {
+ /* Result was not for us */
+ crm_debug("Not our error (addr): %s %s", target_s, whereto_s);
+ return -1;
+
+ } else if (icmph.icmp6_type != ICMP6_ECHO_REQUEST) {
+ /* Not an error */
+ crm_info("Not an error: %d", icmph.icmp6_type);
+ return -1;
+ }
+
+ inet_ntop(AF_INET6, (struct in6_addr *)&(sin->sin6_addr), ping_host_s, sizeof(ping_host_s));
+ crm_debug("From %s icmp_seq=%u %s", ping_host_s, ntohs(icmph.icmp6_seq), ping_result);
+
+ } else {
+ crm_debug("else: %d", s_err->ee_origin);
+ }
+
+ return 0;
+}
+
+int process_icmp4_error(ping_node *node, struct sockaddr_in *whereto)
+{
+ int rc = 0;
+ char buf[512];
+ struct iovec iov;
+ struct msghdr msg;
+ struct icmphdr icmph;
+ struct sockaddr_in target;
+ struct cmsghdr *cmsg = NULL;
+ struct sock_extended_err *s_err = NULL;
+
+ iov.iov_base = &icmph;
+ iov.iov_len = sizeof(icmph);
+ msg.msg_name = (void*)⌖
+ msg.msg_namelen = sizeof(target);
+ msg.msg_iov = &iov;
+ msg.msg_iovlen = 1;
+ msg.msg_flags = 0;
+ msg.msg_control = buf;
+ msg.msg_controllen = sizeof(buf);
+
+ rc = recvmsg(node->fd, &msg, MSG_ERRQUEUE|MSG_DONTWAIT);
+ if (rc < 0 || rc < sizeof(icmph)) {
+ crm_perror(LOG_DEBUG, "No error message: %d", rc);
+ return 0;
+ }
+
+ for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
+ if (cmsg->cmsg_level == SOL_IP && cmsg->cmsg_type == IP_RECVERR) {
+ s_err = (struct sock_extended_err *)CMSG_DATA(cmsg);
+ }
+ }
+
+ CRM_ASSERT(s_err != NULL);
+
+ if (s_err->ee_origin == SO_EE_ORIGIN_LOCAL) {
+ if (s_err->ee_errno == EMSGSIZE) {
+ crm_info("local error: Message too long, mtu=%u", s_err->ee_info);
+ } else {
+ crm_info("local error: %s", strerror(s_err->ee_errno));
+ }
+ return 0;
+
+ } else if (s_err->ee_origin == SO_EE_ORIGIN_ICMP) {
+ char ping_host[MAX_HOST];
+ struct sockaddr_in *sin = (struct sockaddr_in*)(s_err+1);
+ const char *ping_result = ping_desc(node->type, s_err->ee_type, s_err->ee_code);
+ char *target_s = inet_ntoa(*(struct in_addr *)&(target.sin_addr.s_addr));
+ char *whereto_s = inet_ntoa(*(struct in_addr *)&(whereto->sin_addr.s_addr));
+
+ if (ntohs(icmph.un.echo.id) != ident) {
+ /* Result was not for us */
+ crm_debug("Not our error (ident): %d %d", ntohs(icmph.un.echo.id), ident);
+ return -1;
+
+ } else if (safe_str_neq(target_s, whereto_s)) {
+ /* Result was not for us */
+ crm_debug("Not our error (addr): %s %s", target_s, whereto_s);
+ return -1;
+
+ } else if (icmph.type != ICMP_ECHO) {
+ /* Not an error */
+ crm_info("Not an error: %d", icmph.type);
+ return -1;
+ }
+
+ /* snprintf(ping_host, MAX_HOST, "%s", inet_ntoa(*(struct in_addr *)&(sin->sin_addr.s_addr))); */
+ snprintf(ping_host, MAX_HOST, "%s", inet_ntoa(sin->sin_addr));
+
+ if (node->extra_filters == FALSE) {
+ /* Now that we got some sort of reply, add extra filters to
+ * ensure we keep getting the _right_ replies for dead hosts
+ */
+ struct icmp_filter filt;
+ crm_debug("Installing additional ICMP filters");
+ node->extra_filters = TRUE; /* only try once */
+
+ filt.data = ~((1<fd, SOL_RAW, ICMP_FILTER, (char*)&filt, sizeof(filt)) == -1) {
+ crm_perror(LOG_WARNING, "setsockopt failed: Cannot install ICMP filters for %s", ping_host);
+ }
+ }
+
+ crm_debug("From %s icmp_seq=%u %s", ping_host, ntohs(icmph.un.echo.sequence), ping_result);
+
+ } else {
+ crm_debug("else: %d", s_err->ee_origin);
+ }
+
+ return 0;
+}
+#else
+int process_icmp6_error(ping_node *node, struct sockaddr_in6 *whereto)
+{
+ /* dummy function */
+ return 0;
+}
+
+int process_icmp4_error(ping_node *node, struct sockaddr_in *whereto)
+{
+ /* dummy function */
+ return 0;
+}
+#endif
+
+static ping_node *ping_new(const char *host)
+{
+ ping_node *node;
+
+ crm_malloc0(node, sizeof(ping_node));
+
+ if(strstr(host, ":")) {
+ node->type = AF_INET6;
+ } else {
+ node->type = AF_INET;
+ }
+
+ node->host = crm_strdup(host);
+
+ return node;
+}
+
+static gboolean ping_open(ping_node *node)
+{
+ int ret_ga = 0;
+ char *hostname = NULL;
+ struct addrinfo *res = NULL;
+ struct addrinfo hints;
+ char *addr = NULL;
+ char *cp = NULL;
+
+ /* getaddrinfo */
+ bzero(&hints, sizeof(struct addrinfo));
+ hints.ai_flags = AI_CANONNAME;
+ hints.ai_family = node->type;
+ hints.ai_socktype = SOCK_RAW;
+
+ if(node->type == AF_INET6) {
+ hints.ai_protocol = IPPROTO_ICMPV6;
+ } else {
+ hints.ai_protocol = IPPROTO_ICMP;
+ }
+
+ addr = crm_strdup(node->host);
+ if ((cp = strchr(addr, '%'))) {
+ *cp = 0;
+ }
+ crm_debug("node->host[%s], addr[%s]", node->host, addr);
+ ret_ga = getaddrinfo(addr, NULL, &hints, &res);
+ crm_free(addr);
+ if (ret_ga) {
+ crm_warn("getaddrinfo: %s", gai_strerror(ret_ga));
+ goto bail;
+ }
+
+ if (res->ai_canonname) {
+ hostname = res->ai_canonname;
+ } else {
+ hostname = node->host;
+ }
+
+ crm_debug_2("Got address %s for %s", hostname, node->host);
+
+ if(!res->ai_addr) {
+ crm_warn("getaddrinfo failed: no address");
+ goto bail;
+ }
+
+ memcpy(&(node->addr.raw), res->ai_addr, res->ai_addrlen);
+ node->fd = socket(hints.ai_family, hints.ai_socktype, hints.ai_protocol);
+ /* node->fd = socket(res->ai_family, res->ai_socktype, res->ai_protocol); */
+
+ if(node->fd < 0) {
+ crm_perror(LOG_WARNING, "Can't open socket to %s", hostname);
+ goto bail;
+ }
+
+ if(node->type == AF_INET6) {
+ int sockopt;
+
+ inet_ntop(node->type, &node->addr.v6.sin6_addr, node->dest, sizeof(node->dest));
+
+ /* set recv buf for broadcast pings */
+ sockopt = 48 * 1024;
+ setsockopt(node->fd, SOL_SOCKET, SO_RCVBUF, (char *) &sockopt, sizeof(sockopt));
+
+ } else {
+ inet_ntop(node->type, &node->addr.v4.sin_addr, node->dest, sizeof(node->dest));
+ }
+
+ if(ping_timeout > 0) {
+ struct timeval timeout_opt;
+
+ timeout_opt.tv_sec = ping_timeout;
+ timeout_opt.tv_usec = 0;
+
+ setsockopt(node->fd, SOL_SOCKET, SO_RCVTIMEO, (char *) &timeout_opt, sizeof(timeout_opt));
+ }
+
+#ifdef ON_LINUX
+ {
+ int dummy = 1;
+
+ memset(&cmsgbuf, 0, sizeof(cmsgbuf));
+ cmsglen = 0;
+
+ if(node->type == AF_INET6) {
+ struct icmp6_filter filt;
+
+ ICMP6_FILTER_SETBLOCKALL(&filt);
+ ICMP6_FILTER_SETPASS(ICMP6_ECHO_REPLY, &filt);
+
+ if (setsockopt(node->fd, IPPROTO_ICMPV6, ICMP6_FILTER, (char*)&filt, sizeof(filt)) == -1) {
+ crm_perror(LOG_WARNING, "setsockopt failed: Cannot install ICMP6 filters for %s", node->dest);
+ }
+ setsockopt(node->fd, SOL_IPV6, IPV6_RECVERR, (char *)&dummy, sizeof(dummy));
+
+ if ((cp = strchr(node->host, '%'))) {
+ struct ifreq ifr;
+ struct cmsghdr *cmsg;
+ struct in6_pktinfo *ipi;
+
+ memset(&ifr, 0, sizeof(ifr));
+ cp++;
+ crm_debug("set interface: [%s]", cp);
+ strncpy(ifr.ifr_name, cp, IFNAMSIZ-1);
+
+ if (ioctl(node->fd, SIOCGIFINDEX, &ifr) >= 0) {
+ cmsg = (struct cmsghdr*)cmsgbuf;
+ cmsglen = CMSG_SPACE(sizeof(*ipi));
+ cmsg->cmsg_len = CMSG_LEN(sizeof(*ipi));
+ cmsg->cmsg_level = SOL_IPV6;
+ cmsg->cmsg_type = IPV6_PKTINFO;
+
+ ipi = (struct in6_pktinfo*)CMSG_DATA(cmsg);
+ memset(ipi, 0, sizeof(*ipi));
+ ipi->ipi6_ifindex = ifr.ifr_ifindex;
+ } else {
+ crm_warn("unknown interface %s specified", cp);
+ }
+ }
+ } else {
+ struct icmp_filter filt;
+ filt.data = ~((1<fd, SOL_RAW, ICMP_FILTER, (char*)&filt, sizeof(filt)) == -1) {
+ crm_perror(LOG_WARNING, "setsockopt failed: Cannot install ICMP filters for %s", node->dest);
+ }
+ setsockopt(node->fd, SOL_IP, IP_RECVERR, (char *)&dummy, sizeof(dummy));
+
+ if ((cp = strchr(node->host, '%'))) {
+ struct ifreq ifr;
+ struct cmsghdr *cmsg;
+ struct in_pktinfo *ipi;
+
+ memset(&ifr, 0, sizeof(ifr));
+ cp++;
+ crm_debug("set interface: [%s]", cp);
+ strncpy(ifr.ifr_name, cp, IFNAMSIZ-1);
+
+ if (ioctl(node->fd, SIOCGIFINDEX, &ifr) >= 0) {
+ cmsg = (struct cmsghdr*)cmsgbuf;
+ cmsglen = CMSG_SPACE(sizeof(*ipi));
+ cmsg->cmsg_len = CMSG_LEN(sizeof(*ipi));
+ cmsg->cmsg_level = SOL_IP;
+ cmsg->cmsg_type = IP_PKTINFO;
+
+ ipi = (struct in_pktinfo*)CMSG_DATA(cmsg);
+ memset(ipi, 0, sizeof(*ipi));
+ ipi->ipi_ifindex = ifr.ifr_ifindex;
+ } else {
+ crm_warn("unknown interface %s specified", cp);
+ }
+ }
+ }
+ }
+#endif
+
+ crm_debug_2("Opened connection to %s", node->dest);
+ freeaddrinfo(res);
+ return TRUE;
+
+ bail:
+ if(res) {
+ freeaddrinfo(res);
+ }
+ return FALSE;
+}
+
+static gboolean ping_close(ping_node *node)
+{
+ int tmp_fd = node->fd;
+ node->fd = -1;
+
+ if (tmp_fd >= 0) {
+ if(close(tmp_fd) < 0) {
+ crm_perror(LOG_ERR,"Could not close ping socket");
+ } else {
+ tmp_fd = -1;
+ crm_debug_2("Closed connection to %s", node->dest);
+ }
+ }
+ return (tmp_fd == -1);
+}
+
+#define MAXPACKETLEN 131072
+#define ICMP6ECHOLEN 8 /* icmp echo header len excluding time */
+#define ICMP6ECHOTMLEN 20
+#define DEFDATALEN ICMP6ECHOTMLEN
+#define EXTRA 256 /* for AH and various other headers. weird. */
+#define IP6LEN 40
+
+static int
+dump_v6_echo(ping_node *node, u_char *buf, int bytes, struct msghdr *hdr)
+{
+ int rc = -1; /* Try again */
+ int fromlen;
+ char from_host[1024];
+
+ struct icmp6_hdr *icp;
+ struct sockaddr *from;
+
+ if (!hdr || !hdr->msg_name || hdr->msg_namelen != sizeof(struct sockaddr_in6)
+ || ((struct sockaddr *)hdr->msg_name)->sa_family != AF_INET6) {
+ crm_warn("Invalid echo peer");
+ return rc;
+ }
+
+ fromlen = hdr->msg_namelen;
+ from = (struct sockaddr *)hdr->msg_name;
+ getnameinfo(from, fromlen, from_host, sizeof(from_host), NULL, 0, NI_NUMERICHOST | NI_NUMERICSERV);
+
+ if (bytes < (int)sizeof(struct icmp6_hdr)) {
+ crm_warn("Invalid echo packet (too short: %d bytes) from %s", bytes, from_host);
+ return rc;
+ }
+ icp = (struct icmp6_hdr *)buf;
+
+ if (icp->icmp6_type == ICMP6_ECHO_REPLY) {
+ if (ident == ntohs(icp->icmp6_id)
+ && node->iseq == ntohs(icp->icmp6_seq)) {
+ rc = 1; /* Alive */
+ }
+
+ } else if(icp->icmp6_type != ICMP6_ECHO_REQUEST) {
+ rc = process_icmp6_error(node, (struct sockaddr_in6*)&(node->addr));
+ }
+
+ do_crm_log(LOG_DEBUG_2,
+ "Echo from %s (exp=%d, seq=%d, id=%d, dest=%s, data=%s): %s",
+ from_host, node->iseq, ntohs(icp->icmp6_seq),
+ ntohs(icp->icmp6_id), node->dest, (char*)(buf + ICMP6ECHOLEN),
+ ping_desc(node->type, icp->icmp6_type, icp->icmp6_code));
+
+ return rc;
+}
+
+static int
+dump_v4_echo(ping_node *node, u_char *buf, int bytes, struct msghdr *hdr)
+{
+ int rc = -1; /* Try again */
+ int iplen, fromlen;
+ char from_host[1024];
+
+ struct ip *ip;
+ struct icmp *icp;
+ struct sockaddr *from;
+
+ if (hdr == NULL
+ || !hdr->msg_name
+ || hdr->msg_namelen != sizeof(struct sockaddr_in)
+ || ((struct sockaddr *)hdr->msg_name)->sa_family != AF_INET) {
+ crm_warn("Invalid echo peer");
+ return rc;
+ }
+
+ fromlen = hdr->msg_namelen;
+ from = (struct sockaddr *)hdr->msg_name;
+ getnameinfo(from, fromlen, from_host, sizeof(from_host), NULL, 0, NI_NUMERICHOST | NI_NUMERICSERV);
+
+ ip = (struct ip*)buf;
+ iplen = ip->ip_hl * 4;
+
+ if (bytes < (iplen + sizeof(struct icmp))) {
+ crm_warn("Invalid echo packet (too short: %d bytes) from %s", bytes, from_host);
+ return rc;
+ }
+
+ /* Check the IP header */
+ icp = (struct icmp*)(buf + iplen);
+
+ if (icp->icmp_type == ICMP_ECHOREPLY) {
+ if (ident == ntohs(icp->icmp_id)
+ && node->iseq == ntohs(icp->icmp_seq)) {
+ rc = 1; /* Alive */
+ }
+
+ } else if(icp->icmp_type != ICMP_ECHO) {
+ rc = process_icmp4_error(node, (struct sockaddr_in*)from);
+ }
+
+ /* TODO: Stop logging icmp_id once we're sure everything works */
+ do_crm_log(LOG_DEBUG_2,
+ "Echo from %s (exp=%d, seq=%d, id=%d, dest=%s, data=%s): %s",
+ from_host, node->iseq, ntohs(icp->icmp_seq),
+ ntohs(icp->icmp_id), node->dest, icp->icmp_data,
+ ping_desc(node->type, icp->icmp_type, icp->icmp_code));
+
+ return rc;
+}
+
+static int
+ping_read(ping_node *node, int *lenp)
+{
+ int bytes;
+ char fromaddr[128];
+ struct msghdr m;
+ struct cmsghdr *cm;
+ u_char buf[1024];
+ struct iovec iov[2];
+ int saved_errno = 0;
+
+ struct timeval recv_start_time;
+ struct timeval recv_time;
+ int packlen;
+ u_char *packet;
+
+ gettimeofday(&recv_start_time, NULL);
+ packlen = DEFDATALEN + IP6LEN + ICMP6ECHOLEN + EXTRA;
+
+ crm_malloc0(packet, packlen);
+
+ retry:
+ m.msg_name = &fromaddr;
+ m.msg_namelen = sizeof(fromaddr);
+ memset(&iov, 0, sizeof(iov));
+ iov[0].iov_base = (caddr_t)packet;
+ iov[0].iov_len = packlen;
+ m.msg_iov = iov;
+ m.msg_iovlen = 1;
+ cm = (struct cmsghdr *)buf;
+ m.msg_control = (caddr_t)buf;
+ m.msg_controllen = sizeof(buf);
+
+
+ bytes = recvmsg(node->fd, &m, 0);
+ saved_errno = errno;
+ crm_debug_2("Got %d bytes", bytes);
+
+ if(bytes < 0) {
+ crm_perror(LOG_DEBUG, "Read failed");
+ if (saved_errno != EAGAIN && saved_errno != EINTR) {
+ int rc = 0;
+ if(node->type == AF_INET6) {
+ rc = process_icmp6_error(node, (struct sockaddr_in6*)&(node->addr));
+ } else {
+ rc = process_icmp4_error(node, (struct sockaddr_in*)&fromaddr);
+ }
+
+ if(rc < 0) {
+ crm_info("Retrying...");
+ goto retry;
+ }
+ }
+
+ } else if (bytes > 0) {
+ int rc = 0;
+ if(node->type == AF_INET6) {
+ rc = dump_v6_echo(node, packet, bytes, &m);
+ } else {
+ rc = dump_v4_echo(node, packet, bytes, &m);
+ }
+
+ gettimeofday(&recv_time, NULL);
+ if ((recv_start_time.tv_sec + ping_timeout) < recv_time.tv_sec) {
+ crm_warn("failed to receive for timeout.");
+ crm_free(packet);
+ return FALSE;
+ }
+
+ if(rc < 0) {
+ crm_info("Retrying...");
+ goto retry;
+
+ } else if(rc > 0) {
+ crm_free(packet);
+ return TRUE;
+ }
+
+ } else {
+ crm_err("Unexpected reply");
+ }
+
+ crm_free(packet);
+ return FALSE;
+}
+
+static int
+ping_write(ping_node *node, const char *data, size_t size)
+{
+ struct iovec iov;
+ int rc, bytes, namelen;
+ /* static int ntransmitted = 9; */
+ struct msghdr smsghdr;
+ u_char outpack[MAXPACKETLEN];
+ memset(outpack, 0, MAXPACKETLEN);
+
+ node->iseq++;
+
+ if(node->type == AF_INET6) {
+ struct icmp6_hdr *icp;
+ namelen = sizeof(struct sockaddr_in6);
+ bytes = ICMP6ECHOLEN + DEFDATALEN;
+
+ icp = (struct icmp6_hdr *)outpack;
+
+ icp->icmp6_code = 0;
+ icp->icmp6_cksum = 0;
+ icp->icmp6_type = ICMP6_ECHO_REQUEST;
+ icp->icmp6_id = htons(ident);
+ icp->icmp6_seq = htons(node->iseq);
+
+ /* Sanity check */
+ if(ntohs(icp->icmp6_seq) != node->iseq) {
+ crm_debug("Wrapping at %u", node->iseq);
+ node->iseq = ntohs(icp->icmp6_seq);
+ }
+
+ memcpy(&outpack[ICMP6ECHOLEN], "pingd-v6", 8);
+
+ } else {
+ struct icmp *icp;
+ namelen = sizeof(struct sockaddr_in);
+ bytes = sizeof(struct icmp) + 11;
+
+ icp = (struct icmp *)outpack;
+
+ icp->icmp_code = 0;
+ icp->icmp_cksum = 0;
+ icp->icmp_type = ICMP_ECHO;
+ icp->icmp_id = htons(ident);
+ icp->icmp_seq = htons(node->iseq);
+
+ /* Sanity check */
+ if(ntohs(icp->icmp_seq) != node->iseq) {
+ crm_debug("Wrapping at %u", node->iseq);
+ node->iseq = ntohs(icp->icmp_seq);
+ }
+
+ memcpy(icp->icmp_data, "pingd-v4", 8);
+ icp->icmp_cksum = in_cksum((u_short *)icp, bytes);
+ }
+
+ memset(&iov, 0, sizeof(struct iovec));
+ memset(&smsghdr, 0, sizeof(struct msghdr));
+
+ smsghdr.msg_name = (caddr_t)&(node->addr);
+ smsghdr.msg_namelen = namelen;
+ iov.iov_base = (caddr_t)outpack;
+ iov.iov_len = bytes;
+ smsghdr.msg_iov = &iov;
+ smsghdr.msg_iovlen = 1;
+ smsghdr.msg_control = cmsgbuf;
+ smsghdr.msg_controllen = cmsglen;
+
+ rc = sendmsg(node->fd, &smsghdr, 0);
+
+ if (rc < 0 || rc != bytes) {
+ crm_perror(LOG_WARNING, "Wrote %d of %d chars", rc, bytes);
+ return FALSE;
+ }
+
+ crm_debug_2("Sent %d bytes to %s", rc, node->dest);
+ return TRUE;
+}
static gboolean
pingd_shutdown(int nsig, gpointer unused)
{
need_shutdown = TRUE;
- send_update();
- crm_info("Exiting");
+ send_update(0);
+ g_hash_table_destroy(ping_nodes);
+ slist_destroy(ping_node, p, ping_list,
+ crm_free(p->host);
+ crm_free(p);
+ );
+
if (mainloop != NULL && g_main_is_running(mainloop)) {
g_main_quit(mainloop);
} else {
@@ -91,28 +1012,31 @@
stream = exit_status ? stderr : stdout;
- fprintf(stream, "usage: %s [-%s]\n", cmd, OPTARGS);
- fprintf(stream, "\t--%s (-%c) \t\t\tThis text\n", "help", '?');
- fprintf(stream, "\t--%s (-%c) \t\tRun in daemon mode\n", "daemonize", 'D');
- fprintf(stream, "\t--%s (-%c) \tFile in which to store the process' PID\n"
- "\t\t\t\t\t* Default=/tmp/pingd.pid\n", "pid-file", 'p');
- fprintf(stream, "\t--%s (-%c) \tName of the node attribute to set\n"
- "\t\t\t\t\t* Default=pingd\n", "attr-name", 'a');
- fprintf(stream, "\t--%s (-%c) \tName of the set in which to set the attribute\n"
- "\t\t\t\t\t* Default=cib-bootstrap-options\n", "attr-set", 's');
- fprintf(stream, "\t--%s (-%c) \tWhich part of the CIB to put the attribute in\n"
- "\t\t\t\t\t* Default=status\n", "attr-section", 'S');
- fprintf(stream, "\t--%s (-%c) \tMonitor a subset of the ping nodes listed in ha.cf (can be specified multiple times)\n", "ping-host", 'h');
- fprintf(stream, "\t--%s (-%c) \t\tHow long to wait for no further changes to occur before updating the CIB with a changed attribute\n", "attr-dampen", 'd');
- fprintf(stream, "\t--%s (-%c) \tFor every connected node, add to the value set in the CIB\n"
- "\t\t\t\t\t\t* Default=1\n", "value-multiplier", 'm');
+ fprintf(stream, "usage: %s [-?VDp:N:a:d:S:s:i:n:t:m:]\n", cmd);
+
+ fprintf(stream, "\t--%s (-%c) \t\tThis text\n", "help", '?');
+ fprintf(stream, "\t--%s (-%c) \t\tIncrease debug output\n\n", "verbose", 'V');
+
+ fprintf(stream, "\t--%s (-%c) \tRun in daemon mode\n", "daemonize", 'D');
+ fprintf(stream, "\t--%s (-%c) \tFile in which to store the process' PID\n\n", "pid-file", 'p');
+
+ fprintf(stream, "\t--%s (-%c) \t\tDNS name or IP address of a host to check (can be specified more than once\n\n", "node", 'N');
+
+ fprintf(stream, "\t--%s (-%c) \tName of the node attribute to set\n", "attr-name", 'a');
+ fprintf(stream, "\t--%s (-%c) \tHow long to wait for no further changes to occur before updating the CIB with a changed attribute\n", "attr-dampen", 'd');
+ fprintf(stream, "\t--%s (-%c) \t(Advanced) Which part of the CIB to put the attribute in\n", "attr-section", 'S');
+ fprintf(stream, "\t--%s (-%c) \t(Advanced) Name of the set in which to put the attribute\n\n", "attr-set", 's');
+
+ fprintf(stream, "\t--%s (-%c) \tHow often, in seconds, to check for node liveliness (default=1)\n", "ping-interval", 'i');
+ fprintf(stream, "\t--%s (-%c) \tNumber of ping attempts, per host, before declaring it dead (default=2)\n", "ping-attempts", 'n');
+ fprintf(stream, "\t--%s (-%c) \tHow long, in seconds, to wait before declaring a ping lost (default=2)\n", "ping-timeout", 't');
+ fprintf(stream, "\t--%s (-%c) \tFor every connected node, add to the value set in the CIB\n", "ping-multiplier",'m');
fflush(stream);
exit(exit_status);
}
-
static gboolean
pingd_ha_dispatch(IPC_Channel *channel, gpointer user_data)
{
@@ -190,8 +1114,7 @@
if (pingd_cluster->llc_ops->set_ifstatus_callback(
pingd_cluster, pingd_lstatus_callback, NULL) != HA_OK) {
- cl_log(LOG_ERR, "Cannot set if status callback");
- crm_err("REASON: %s", pingd_cluster->llc_ops->errmsg(pingd_cluster));
+ crm_err("Cannot set if status callback: %s", pingd_cluster->llc_ops->errmsg(pingd_cluster));
return FALSE;
}
@@ -205,48 +1128,142 @@
return TRUE;
}
+void
+do_node_walk(ll_cluster_t *hb_cluster)
+{
+ const char *ha_node = NULL;
+
+ /* Async get client status information in the cluster */
+ crm_debug_2("Invoked");
+ crm_debug_3("Requesting an initial dump of CRMD client_status");
+ hb_cluster->llc_ops->client_status(
+ hb_cluster, NULL, CRM_SYSTEM_CRMD, -1);
+
+ crm_info("Requesting the list of configured nodes");
+ hb_cluster->llc_ops->init_nodewalk(hb_cluster);
+
+ do {
+ const char *ha_node_type = NULL;
+ const char *ha_node_status = NULL;
+
+ ha_node = hb_cluster->llc_ops->nextnode(hb_cluster);
+ if(ha_node == NULL) {
+ continue;
+ }
+
+ ha_node_type = hb_cluster->llc_ops->node_type(
+ hb_cluster, ha_node);
+ if(safe_str_neq("ping", ha_node_type)) {
+ crm_debug("Node %s: skipping '%s'",
+ ha_node, ha_node_type);
+ continue;
+ }
+
+ if(do_filter
+ && g_hash_table_lookup(ping_nodes, ha_node) == NULL) {
+ crm_debug("Filtering: %s", ha_node);
+ continue;
+ }
+
+ ha_node_status = hb_cluster->llc_ops->node_status(
+ hb_cluster, ha_node);
+
+ crm_debug("Adding: %s=%s", ha_node, ha_node_status);
+ g_hash_table_replace(ping_nodes, crm_strdup(ha_node),
+ crm_strdup(ha_node_status));
+
+ } while(ha_node != NULL);
+
+ hb_cluster->llc_ops->end_nodewalk(hb_cluster);
+ crm_debug_2("Complete");
+ send_update(-1);
+}
+
+static gboolean stand_alone_ping(gpointer data)
+{
+ int num_active = 0;
+
+ crm_debug_2("Checking connectivity");
+ slist_iter(
+ ping, ping_node, ping_list, num,
+
+ if(ping_open(ping)) {
+ int lpc = 0;
+ for(;lpc < pings_per_host; lpc++) {
+ int len = 0;
+ if(ping_write(ping, "test", 4) == FALSE) {
+ crm_info("Node %s is unreachable (write)", ping->host);
+
+ } else if(ping_read(ping, &len)) {
+ crm_debug("Node %s is alive", ping->host);
+ num_active++;
+ break;
+ } else {
+ crm_info("Node %s is unreachable (read)", ping->host);
+ }
+ sleep(1);
+ }
+ }
+
+ ping_close(ping);
+ );
+
+ send_update(num_active);
+
+ return TRUE;
+}
+
int
main(int argc, char **argv)
{
- int lpc;
int argerr = 0;
int flag;
- char *pid_file = NULL;
+ const char *pid_file = NULL;
gboolean daemonize = FALSE;
+ ping_node *p = NULL;
#ifdef HAVE_GETOPT_H
int option_index = 0;
static struct option long_options[] = {
/* Top-level Options */
- {"verbose", 0, 0, 'V'},
- {"help", 0, 0, '?'},
- {"pid-file", 1, 0, 'p'},
- {"ping-host", 1, 0, 'h'},
- {"attr-name", 1, 0, 'a'},
- {"attr-set", 1, 0, 's'},
- {"daemonize", 0, 0, 'D'},
- {"attr-section", 1, 0, 'S'},
- {"attr-dampen", 1, 0, 'd'},
- {"value-multiplier", 1, 0, 'm'},
+ {"help", 0, 0, '?'},
+ {"verbose", 0, 0, 'V'},
+ {"daemonize", 0, 0, 'D'},
+ {"pid-file", 1, 0, 'p'},
+ {"node", 1, 0, 'N'},
+ {"attr-name", 1, 0, 'a'},
+ {"attr-dampen", 1, 0, 'd'},
+ {"attr-section", 1, 0, 'S'},
+ {"attr-set", 1, 0, 's'},
+ {"ping-interval", 1, 0, 'i'},
+ {"ping-attempts", 1, 0, 'n'},
+ {"ping-timeout", 1, 0, 't'},
+ {"ping-multiplier", 1, 0, 'm'},
+ {"no-updates", 0, 0, 'U',},
+
+ /* Legacy */
+ {"ping-host", 1, 0, 'h'},
+ {"value-multiplier", 1, 0, 'm'},
+ {"interval", 1, 0, 'i'},
{0, 0, 0, 0}
};
#endif
- pid_file = crm_strdup("/tmp/pingd.pid");
+
+ pid_file = "/tmp/pingd.pid";
G_main_add_SignalHandler(
G_PRIORITY_HIGH, SIGTERM, pingd_shutdown, NULL, NULL);
-
+
ping_nodes = g_hash_table_new_full(
- g_str_hash, g_str_equal,
- g_hash_destroy_str, g_hash_destroy_str);
+ g_str_hash, g_str_equal,
+ g_hash_destroy_str, g_hash_destroy_str);
crm_log_init(basename(argv[0]), LOG_INFO, TRUE, FALSE, argc, argv);
-
+
while (1) {
#ifdef HAVE_GETOPT_H
- flag = getopt_long(argc, argv, OPTARGS,
- long_options, &option_index);
+ flag = getopt_long(argc, argv, OPTARGS, long_options, &option_index);
#else
flag = getopt(argc, argv, OPTARGS);
#endif
@@ -259,17 +1276,17 @@
alter_debug(DEBUG_INC);
break;
case 'p':
- pid_file = crm_strdup(optarg);
+ pid_file = optarg;
break;
case 'a':
- pingd_attr = crm_strdup(optarg);
+ pingd_attr = optarg;
break;
+ case 'N':
case 'h':
- do_filter = TRUE;
- fprintf(stdout, "Adding ping host %s", optarg);
- g_hash_table_insert(ping_nodes,
- crm_strdup(optarg),
- crm_strdup(optarg));
+ stand_alone = TRUE;
+ crm_debug("Adding ping host %s", optarg);
+ p = ping_new(optarg);
+ ping_list = g_list_append(ping_list, p);
break;
case 's':
attr_set = crm_strdup(optarg);
@@ -281,11 +1298,24 @@
attr_section = crm_strdup(optarg);
break;
case 'd':
- attr_dampen = crm_strdup(optarg);
+ attr_dampen = crm_get_msec(optarg);
+ break;
+ case 'i':
+ re_ping_interval = crm_get_msec(optarg);
+ break;
+ case 'n':
+ pings_per_host = crm_atoi(optarg, NULL);
+ break;
+ case 't':
+ ping_timeout = crm_atoi(optarg, NULL);
break;
case 'D':
daemonize = TRUE;
break;
+ case 'U':
+ cl_log_enable_stderr(TRUE);
+ do_updates = FALSE;
+ break;
case '?':
usage(crm_system_name, LSB_EXIT_GENERIC);
break;
@@ -301,39 +1331,44 @@
crm_err("non-option ARGV-elements: ");
printf("non-option ARGV-elements: ");
while (optind < argc) {
- crm_err("%s ", argv[optind++]);
+ crm_err("%s ", argv[optind]);
printf("%s ", argv[optind++]);
}
printf("\n");
}
if (argerr) {
- usage(crm_system_name, LSB_EXIT_GENERIC);
+ usage(crm_system_name, LSB_EXIT_GENERIC);
}
crm_make_daemon(crm_system_name, daemonize, pid_file);
+ ident = getpid();
- for(lpc = 0; attrd == NULL && lpc < 30; lpc++) {
- crm_debug("attrd registration attempt: %d", lpc);
- sleep(5);
- attrd = init_client_ipc_comms_nodispatch(T_ATTRD);
- }
-
- if(attrd == NULL) {
- crm_err("attrd registration failed");
- cl_flush_logs();
- exit(LSB_EXIT_GENERIC);
+ if(do_updates == FALSE) {
+ goto start_ping;
}
- if(register_with_ha() == FALSE) {
+ if(stand_alone == FALSE && register_with_ha() == FALSE) {
crm_err("HA registration failed");
cl_flush_logs();
exit(LSB_EXIT_GENERIC);
}
+
+ start_ping:
+ if(stand_alone && ping_list == NULL) {
+ crm_err("You must specify a list of hosts to monitor");
+ exit(LSB_EXIT_GENERIC);
+ }
crm_info("Starting %s", crm_system_name);
mainloop = g_main_new(FALSE);
+
+ if(stand_alone) {
+ stand_alone_ping(NULL);
+ g_timeout_add(re_ping_interval, stand_alone_ping, NULL);
+ }
+
g_main_run(mainloop);
-
+
crm_info("Exiting %s", crm_system_name);
return 0;
}
@@ -348,41 +1383,73 @@
return;
}
- if(safe_str_eq(value, PINGSTATUS)) {
+ if(safe_str_eq(value, "ping")) {
(*num_active)++;
- } else if(safe_str_eq(value, LINKUP)) {
+ } else if(safe_str_eq(value, "up")) {
(*num_active)++;
}
}
void
-send_update(void)
+send_update(int num_active)
{
- int num_active = 0;
+ int lpc = 0;
+ static IPC_Channel *attrd = NULL;
HA_Message *update = ha_msg_new(4);
ha_msg_add(update, F_TYPE, T_ATTRD);
ha_msg_add(update, F_ORIG, crm_system_name);
ha_msg_add(update, F_ATTRD_TASK, "update");
ha_msg_add(update, F_ATTRD_ATTRIBUTE, pingd_attr);
- g_hash_table_foreach(ping_nodes, count_ping_nodes, &num_active);
+ if(num_active < 0) {
+ num_active = 0;
+ g_hash_table_foreach(ping_nodes, count_ping_nodes, &num_active);
+ }
crm_info("%d active ping nodes", num_active);
ha_msg_add_int(update, F_ATTRD_VALUE, attr_multiplier*num_active);
-
+
if(attr_set != NULL) {
- ha_msg_add(update, F_ATTRD_SET, attr_set);
+ ha_msg_add(update, F_ATTRD_SET, attr_set);
}
if(attr_section != NULL) {
ha_msg_add(update, F_ATTRD_SECTION, attr_section);
}
- if(attr_dampen != NULL) {
- ha_msg_add(update, F_ATTRD_DAMPEN, attr_dampen);
+ if(attr_dampen > 0) {
+ ha_msg_add_int(update, F_ATTRD_DAMPEN, attr_dampen/1000);
+ }
+
+ if(do_updates && attrd == NULL) {
+ crm_info("Attempting attrd (re-)registration");
+ attrd = init_client_ipc_comms_nodispatch(T_ATTRD);
+ for(lpc = 0; attrd == NULL && lpc < 10; lpc++) {
+ sleep(1);
+ crm_debug("attrd registration attempt: %d", lpc);
+ attrd = init_client_ipc_comms_nodispatch(T_ATTRD);
+ }
}
- if(send_ipc_message(attrd, update) == FALSE) {
- crm_err("Could not send update");
- exit(1);
+ if(do_updates == FALSE) {
+ char *buf = NULL;
+ if ((buf = dump_xml_formatted(update))) {
+ if ((strlen(buf)>0) && (buf[strlen(buf)-1]=='\n')) {
+ buf[strlen(buf)-1] = 0;
+ }
+ crm_info("%s", buf);
+ crm_free(buf);
+ }
+
+ } else if(attrd == NULL) {
+ crm_err("Could not send update: %s=%d (Not connected)",
+ pingd_attr, attr_multiplier*num_active);
+
+ } else if(send_ipc_message(attrd, update) == FALSE) {
+ crm_err("Could not send update: %s=%d (Connection failed)",
+ pingd_attr, attr_multiplier*num_active);
+ attrd = NULL;
+ } else {
+ crm_debug("Sent update: %s=%d (%d active ping nodes)",
+ pingd_attr, attr_multiplier*num_active, num_active);
}
crm_msg_del(update);
}
@@ -397,7 +1464,7 @@
if(g_hash_table_lookup(ping_nodes, node) != NULL) {
g_hash_table_replace(
ping_nodes, crm_strdup(node), crm_strdup(status));
- send_update();
+ send_update(-1);
}
}
@@ -410,53 +1477,3 @@
pingd_nstatus_callback(node, status, private);
}
-void
-do_node_walk(ll_cluster_t *hb_cluster)
-{
- const char *ha_node = NULL;
-
- /* Async get client status information in the cluster */
- crm_debug_2("Invoked");
- crm_debug_3("Requesting an initial dump of CRMD client_status");
- hb_cluster->llc_ops->client_status(
- hb_cluster, NULL, CRM_SYSTEM_CRMD, -1);
-
- crm_info("Requesting the list of configured nodes");
- hb_cluster->llc_ops->init_nodewalk(hb_cluster);
-
- do {
- const char *ha_node_type = NULL;
- const char *ha_node_status = NULL;
-
- ha_node = hb_cluster->llc_ops->nextnode(hb_cluster);
- if(ha_node == NULL) {
- continue;
- }
-
- ha_node_type = hb_cluster->llc_ops->node_type(
- hb_cluster, ha_node);
- if(safe_str_neq(PINGNODE, ha_node_type)) {
- crm_debug("Node %s: skipping '%s'",
- ha_node, ha_node_type);
- continue;
- }
-
- if(do_filter
- && g_hash_table_lookup(ping_nodes, ha_node) == NULL) {
- crm_debug("Filtering: %s", ha_node);
- continue;
- }
-
- ha_node_status = hb_cluster->llc_ops->node_status(
- hb_cluster, ha_node);
-
- crm_debug("Adding: %s=%s", ha_node, ha_node_status);
- g_hash_table_replace(ping_nodes, crm_strdup(ha_node),
- crm_strdup(ha_node_status));
-
- } while(ha_node != NULL);
-
- hb_cluster->llc_ops->end_nodewalk(hb_cluster);
- crm_debug_2("Complete");
- send_update();
-}