FreeBSD : patch pour la gestion des alias IPv6 sur interface CARP

Boris HUISGEN
|
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"
Par capture réseau :
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 : [download id=“16” ]