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/
