Le driver CARP de FreeBSD 8.x contient un bug au niveau de la gestion IPv6. Au lieu d’ajouter chaque adresse IPv6 de l’interface CARP au groupe multicast ff02::1, le driver n’ajoute que la première adresse. Ainsi la prise en compte des alias n’est pas effective et la découverte du voisinage IPv6 n’aboutit pas :

ipv6_ifconfig_carp0="2001:1610:4::102 prefixlen 64"
ipv6_ifconfig_carp0_alias0="2001:1610:4::113 prefixlen 64"
0.000000 fe80::223:4ff:fe17:f840 -> ff02::1:ff00:113 ICMPv6 86 Neighbor Solicitation
0.999052 fe80::223:4ff:fe17:f840 -> ff02::1:ff00:113 ICMPv6 86 Neighbor Solicitation
1.999103 fe80::223:4ff:fe17:f840 -> ff02::1:ff00:113 ICMPv6 86 Neighbor Solicitation
3.000220 fe80::223:4ff:fe17:f840 -> ff02::1:ff00:113 ICMPv6 86 Neighbor Solicitation

Pour corriger ce bug, Paul Herman propose un patch à appliquer aux sources de FreeBSD :

# cd /usr/src
# zcat /path/to/carp_ip6_alias.patch.gz | patch
--- sys/netinet6/in6.c.orig    2011-08-19 07:08:30.000000000 +0000
+++ sys/netinet6/in6.c    2011-08-19 07:09:53.000000000 +0000
@@ -1743,7 +1743,7 @@

ia->ia_addr = *sin6;

-    if (ifacount <= 1 && ifp->if_ioctl) {
+    if ((ifacount <= 1 || ifp->if_type == IFT_CARP) && ifp->if_ioctl) {
error = (*ifp->if_ioctl)(ifp, SIOCSIFADDR, (caddr_t)ia);
if (error) {
splx(s);
--- sys/netinet/ip_carp.c.orig    2011-08-19 07:52:56.000000000 +0000
+++ sys/netinet/ip_carp.c    2011-08-19 07:15:03.000000000 +0000
@@ -1670,9 +1670,11 @@
struct carp_if *cif;
struct in6_ifaddr *ia, *ia_if;
struct ip6_moptions *im6o = &sc->sc_im6o;
+    struct in6_multi *in6m;
struct in6_addr in6;
int own, error;

+
error = 0;

if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
@@ -1729,8 +1731,6 @@
}

if (!sc->sc_naddrs6) {
-        struct in6_multi *in6m;
-
im6o->im6o_multicast_ifp = ifp;

/* join CARP multicast address */
@@ -1745,24 +1745,24 @@
goto cleanup;
im6o->im6o_membership[0] = in6m;
im6o->im6o_num_memberships++;
-
-        /* join solicited multicast address */
-        bzero(&in6, sizeof(in6));
-        in6.s6_addr16[0] = htons(0xff02);
-        in6.s6_addr32[1] = 0;
-        in6.s6_addr32[2] = htonl(1);
-        in6.s6_addr32[3] = sin6->sin6_addr.s6_addr32[3];
-        in6.s6_addr8[12] = 0xff;
-        if (in6_setscope(&in6, ifp, NULL) != 0)
-            goto cleanup;
-        in6m = NULL;
-        error = in6_mc_join(ifp, &in6, NULL, &in6m, 0);
-        if (error)
-            goto cleanup;
-        im6o->im6o_membership[1] = in6m;
-        im6o->im6o_num_memberships++;
}

+    /* join solicited multicast address */
+    bzero(&in6, sizeof(in6));
+    in6.s6_addr16[0] = htons(0xff02);
+    in6.s6_addr32[1] = 0;
+    in6.s6_addr32[2] = htonl(1);
+    in6.s6_addr32[3] = sin6->sin6_addr.s6_addr32[3];
+    in6.s6_addr8[12] = 0xff;
+    if (in6_setscope(&in6, ifp, NULL) != 0)
+        goto cleanup;
+    in6m = NULL;
+    error = in6_mc_join(ifp, &in6, NULL, &in6m, 0);
+    if (error)
+        goto cleanup;
+    im6o->im6o_membership[1] = in6m;
+    im6o->im6o_num_memberships++;
+
if (!ifp->if_carp) {
cif = malloc(sizeof(*cif), M_CARP,
M_WAITOK|M_ZERO);

Une fois le noyau de l’hôte patché, le test par ping externe est concluant.

Patch : [Téléchargement introuvable]