On Tue, Oct 07, 2014 at 01:50:12PM +0200, Martin Pieuchot wrote: > On 03/10/14(Fri) 14:46, Stefan Sperling wrote: > > The IPv6 source address selection algorithm breaks ties by performing a > > bitwise match of each candidate source address against the destination > > address. The longest matching source address wins, regardless of which > > interface the source address came from. > > > > In my carp setup, this is causing a problem. > > > > Consider the carp address 2001:DB8:10::14, which is configured on > > firewall A (carp master state) and firewall B (carp backup state), > > each of which has another address in the same prefix on a non-carp > > interface (A has 2001:DB8:10::1 and B has 2001:DB8:10::11). > > > > In this setup, connecting from A to B or from B to A via IPv6 is impossible. > > A will use 2001:DB8:10::14 as source address when it sends neighbour > > solicitations to B (2001:DB8:10::11). Since 2001:DB8:10::14 is a local > > address from B's point of view, B doesn't reply to neighbour solicitations > > sent by A. The only currently available workaround is to re-configure > > addresses in a way that outsmarts the longest match check such that a > > carp address always loses the tie. (Another workaround is to use IPv4 > > which doesn't have this problem.) > > > > The hack below special-cases carp interfaces: If there is a tie, then a > > carp interface is not allowed to win even if it has a longer bitwise match. > > (The carp interface is in master state here -- carp interfaces in backup > > state are never considered for source addresses in the first place.) > > > > This hack makes communication between A and B work over IPv6 in the > > above scenario. > > I think this hack makes sense. I'm really afraid of the carp tentacles, > but I don't think there's a better way of solving this problem right > now. > > This change is similar to the "let's move the cloning route" hack for > IPv4, since it gives a higher ``priority'' to any non-carp interface > when selecting source addresses, right? > > > I also considered another solution: Make carp backups treat their > > local carp address as a non-local address. However, this would > > be a much more invasive change and would also affect IPv4. > > This is certainly not an easy change, and it definitively comes with its > own specific dragons, but I believe that it would remove a lot of hacks > in the stack. > > > - if (matchcmp > 0) /* (8) */ > > + if (matchcmp > 0) { /* (8) */ > > +#if NCARP > 0 > > + /* > [...] > > + */ > > + if (ifp->if_type == IFT_CARP) > > + continue; > > +#endif > > goto replace; > > + } > > What if oifp is also a carp interface? Is it possible? Shouldn't you > use the pattern of in_addprefix(): > > if (ifp->if_type == IFT_CARP && > oifp->if_type != IFT_CARP) > continue; > > > Either way I'm ok with your diff.
Makes sense and works for me. Does anyone else have an opinion about this? Index: in6.c =================================================================== RCS file: /cvs/src/sys/netinet6/in6.c,v retrieving revision 1.138 diff -u -p -r1.138 in6.c --- in6.c 12 Jul 2014 18:44:23 -0000 1.138 +++ in6.c 17 Oct 2014 09:40:12 -0000 @@ -2027,8 +2027,26 @@ in6_ifawithscope(struct ifnet *oifp, str } tlen = in6_matchlen(IFA_IN6(ifa), dst); matchcmp = tlen - blen; - if (matchcmp > 0) /* (8) */ + if (matchcmp > 0) { /* (8) */ +#if NCARP > 0 + /* + * Don't let carp interfaces win a tie against + * the output interface based on matchlen. + * We should only use a carp address if no + * other interface has a usable address. + * Otherwise, when communicating from a carp + * master to a carp slave, the slave won't + * respond since the carp address is also + * configured as a local address on the slave. + * Note that carp interfaces in backup state + * were already skipped above. + */ + if (ifp->if_type == IFT_CARP && + oifp->if_type != IFT_CARP) + continue; +#endif goto replace; + } if (matchcmp < 0) /* (9) */ continue; if (oifp == ifp) /* (a) */