The attached patch is to remove libnet dependency from IPv6addr RA
by replacing the same functionality using the standard socket API.

Currently there are following problems with resource-agents package:

 - IPv6addr RA requires an extra libnet package on the run-time environment.
  That is pretty inconvenient particularly for RHEL users because
  it's not included in the standard distribution.

 - The pre-built RPMs from ClusterLabs does not include IPv6addr RA.
  This was once reported in the pacemaker list:
  http://www.gossamer-threads.com/lists/linuxha/pacemaker/64295#64295

The patch will resolve those issues.
I believe that none of Pacemaker/Heartbeat related packages would be
depending on libnet library any more after patched.

Regards,

-- 
Keisuke MORI
# HG changeset patch
# User Keisuke MORI <[email protected]>
# Date 1279802861 -32400
# Branch ipv6
# Node ID 40d5dbdca9cc089b6514c7525cd2dbd678299711
# Parent  b3142fd9cc672f2217e632608bc986b46265b193
IPv6addr: remove libnet dependency

diff -r b3142fd9cc67 -r 40d5dbdca9cc configure.in
--- a/configure.in	Fri Jul 16 09:46:38 2010 +0200
+++ b/configure.in	Thu Jul 22 21:47:41 2010 +0900
@@ -607,6 +607,7 @@
       [new_libnet=yes; AC_DEFINE(HAVE_LIBNET_1_1_API, 1, Libnet 1.1 API)],
       [new_libnet=no; AC_DEFINE(HAVE_LIBNET_1_0_API, 1, Libnet 1.0 API)],$LIBNETLIBS)
    AC_SUBST(LIBNETLIBS)
+   AC_DEFINE(HAVE_LIBNET_API, 1, Libnet API)
 fi
 
 if test "$new_libnet" = yes; then
@@ -634,7 +635,7 @@
 dnl ************************************************************************
 dnl * Check for netinet/icmp6.h to enable the IPv6addr resource agent
 AC_CHECK_HEADERS(netinet/icmp6.h,[],[],[#include <sys/types.h>])
-AM_CONDITIONAL(USE_IPV6ADDR, test "$ac_cv_header_netinet_icmp6_h" = yes -a "$new_libnet" = yes )
+AM_CONDITIONAL(USE_IPV6ADDR, test "$ac_cv_header_netinet_icmp6_h" = yes )
 
 dnl ========================================================================
 dnl Compiler flags
diff -r b3142fd9cc67 -r 40d5dbdca9cc heartbeat/IPv6addr.c
--- a/heartbeat/IPv6addr.c	Fri Jul 16 09:46:38 2010 +0200
+++ b/heartbeat/IPv6addr.c	Thu Jul 22 21:47:41 2010 +0900
@@ -87,13 +87,25 @@
 
 #include <config.h>
 
+#include <stdio.h>
 #include <stdlib.h>
+#include <unistd.h>
 #include <sys/types.h>
+#include <sys/socket.h>
 #include <netinet/icmp6.h>
+#include <arpa/inet.h> /* for inet_pton */
+#include <net/if.h> /* for if_nametoindex */
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <fcntl.h>
 #include <libgen.h>
 #include <syslog.h>
+#include <signal.h>
+#include <errno.h>
 #include <clplumbing/cl_log.h>
+#ifdef HAVE_LIBNET_API
 #include <libnet.h>
+#endif
 
 
 #define PIDFILE_BASE HA_RSCTMPDIR  "/IPv6addr-"
@@ -400,8 +412,11 @@
 	return OCF_NOT_RUNNING;
 }
 
+#ifdef HAVE_LIBNET_API
 /* Send an unsolicited advertisement packet
  * Please refer to rfc2461
+ *
+ * Libnet based implementation.
  */
 int
 send_ua(struct in6_addr* src_ip, char* if_name)
@@ -466,6 +481,108 @@
 	libnet_destroy(l);
 	return status;
 }
+#else /* HAVE_LIBNET_API */
+/* Send an unsolicited advertisement packet
+ * Please refer to rfc4861 / rfc3542
+ *
+ * Libnet independent implementation.
+ */
+int
+send_ua(struct in6_addr* src_ip, char* if_name)
+{
+	int status = -1;
+	int fd;
+
+	int ifindex;
+	int hop;
+	struct ifreq ifr;
+#define HWADDR_LEN 6 /* mac address length */
+	u_int8_t payload[sizeof(struct nd_neighbor_advert)
+			 + sizeof(struct nd_opt_hdr) + HWADDR_LEN];
+	struct nd_neighbor_advert *na;
+	struct nd_opt_hdr *opt;
+	struct sockaddr_in6 src_sin6;
+	struct sockaddr_in6 dst_sin6;
+
+	if ((fd = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6)) == 0) {
+		cl_log(LOG_ERR, "socket(IPPROTO_ICMPV6) failed: %s",
+		       strerror(errno));
+		goto err;
+	}
+	/* set the outgoing interface */
+	ifindex = if_nametoindex(if_name);
+	if (setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_IF,
+		       &ifindex, sizeof(ifindex)) < 0) {
+		cl_log(LOG_ERR, "setsockopt(IPV6_MULTICAST_IF) failed: %s",
+		       strerror(errno));
+		goto err;
+	}
+	/* set the hop limit */
+	hop = 255; /* 255 is required. see rfc4861 7.1.2 */
+	if (setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS,
+		       &hop, sizeof(hop)) < 0) {
+		cl_log(LOG_ERR, "setsockopt(IPV6_MULTICAST_HOPS) failed: %s",
+		       strerror(errno));
+		goto err;
+	}
+	
+	/* set the source address */
+	memset(&src_sin6, 0, sizeof(src_sin6));
+	src_sin6.sin6_family = AF_INET6;
+	src_sin6.sin6_addr = *src_ip;
+	src_sin6.sin6_port = 0;
+	if (bind(fd, (struct sockaddr *)&src_sin6, sizeof(src_sin6)) < 0) {
+		cl_log(LOG_ERR, "bind() failed: %s", strerror(errno));
+		goto err;
+	}
+
+
+	/* get the hardware address */
+	memset(&ifr, 0, sizeof(ifr));
+	strncpy(ifr.ifr_name, if_name, sizeof(ifr.ifr_name) - 1);
+	if (ioctl(fd, SIOCGIFHWADDR, &ifr) < 0) {
+		cl_log(LOG_ERR, "ioctl(SIOCGIFHWADDR) failed: %s", strerror(errno));
+		goto err;
+	}
+
+	/* build a neighbor advertisement message */
+	memset(&payload, 0, sizeof(payload));
+
+	na = (struct nd_neighbor_advert *)&payload;
+	na->nd_na_type = ND_NEIGHBOR_ADVERT;
+	na->nd_na_code = 0;
+	na->nd_na_cksum = 0; /* calculated by kernel */
+	na->nd_na_flags_reserved = ND_NA_FLAG_OVERRIDE;
+	na->nd_na_target = (*src_ip);
+
+	/* options field; set the target link-layer address */
+	opt = (struct nd_opt_hdr *)&payload[sizeof(struct nd_neighbor_advert)];
+	opt->nd_opt_type = ND_OPT_TARGET_LINKADDR;
+	opt->nd_opt_len = 1; /* The length of the option in units of 8 octets */
+	memcpy(&payload[sizeof(struct nd_neighbor_advert)
+			+ sizeof(struct nd_opt_hdr)],
+	       &ifr.ifr_hwaddr.sa_data, HWADDR_LEN);
+
+	/* sending an unsolicited neighbor advertisement to all */
+	memset(&dst_sin6, 0, sizeof(dst_sin6));
+	dst_sin6.sin6_family = AF_INET6;
+	inet_pton(AF_INET6, BCAST_ADDR, &dst_sin6.sin6_addr); /* should not fail */
+
+	if (sendto(fd, &payload, sizeof(payload), 0,
+		   (struct sockaddr *)&dst_sin6, sizeof(dst_sin6))
+	    != sizeof(payload)) {
+		cl_log(LOG_ERR, "sendto(%s) failed: %s",
+		       if_name, strerror(errno));
+		goto err;
+	}
+
+	status = 0;
+
+err:
+	close(fd);
+	return status;
+}
+#endif /* HAVE_LIBNET_API */
 
 /* find the network interface associated with an address */
 char*
@@ -643,7 +760,7 @@
 is_addr6_available(struct in6_addr* addr6)
 {
 	struct sockaddr_in6		addr;
-	struct libnet_icmpv6_hdr	icmph;
+	struct icmp6_hdr		icmph;
 	u_char				outpack[MINPACKSIZE];
 	int				icmp_sock;
 	int				ret;
@@ -653,11 +770,11 @@
 
 	icmp_sock = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6);
 	memset(&icmph, 0, sizeof(icmph));
-	icmph.icmp_type = ICMP6_ECHO;
-	icmph.icmp_code = 0;
-	icmph.icmp_sum = 0;
-	icmph.seq = htons(0);
-	icmph.id = 0;
+	icmph.icmp6_type = ICMP6_ECHO_REQUEST;
+	icmph.icmp6_code = 0;
+	icmph.icmp6_cksum = 0;
+	icmph.icmp6_seq = htons(0);
+	icmph.icmp6_id = 0;
 
 	memset(&outpack, 0, sizeof(outpack));
 	memcpy(&outpack, &icmph, sizeof(icmph));
_______________________________________________________
Linux-HA-Dev: [email protected]
http://lists.linux-ha.org/mailman/listinfo/linux-ha-dev
Home Page: http://linux-ha.org/

Reply via email to