On Fri, Jul 23, 2010 at 09:19:44AM +0900, Keisuke MORI wrote: > 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.
Hi Mori-san, I will add that libnet seems to be more or less unmaintained. You seem to make using libnet optional, is there a reason not to just remove it? portability? > # HG changeset patch > # User Keisuke MORI <kskm...@intellilink.co.jp> > # 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 */ Personally I'd prefer the define outside of the function. > + 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); There is no need to enclose *src_ip in brackets. > + > + /* 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; > + } Is it valid to assume that there will never be a partial write? > + 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: Linux-HA-Dev@lists.linux-ha.org > http://lists.linux-ha.org/mailman/listinfo/linux-ha-dev > Home Page: http://linux-ha.org/ _______________________________________________________ Linux-HA-Dev: Linux-HA-Dev@lists.linux-ha.org http://lists.linux-ha.org/mailman/listinfo/linux-ha-dev Home Page: http://linux-ha.org/