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) */