Ignore IPv6 NA and drop IPv6 NS when BACKUP CARP address is used

When system acts as CARP BACKUP ignore received IPv6 Neighbor Advertisements
to ensure that neighbor cache will not be changed.
Also do not send IPv6 Neighbor Solicitation from CARP BACKUP source address.
Such packets can confuse network switch and it detects MAC addresses
flapping.

Obtained from:	Yandex LLC
MFC after:	2 weeks
Sponsored by:	Yandex LLC
Differential Revision:	    https://reviews.freebsd.org/D36649
This commit is contained in:
Andrey V. Elsukov 2022-10-06 19:50:33 +03:00
parent 9bce114106
commit ccd69bd573

View File

@ -465,6 +465,7 @@ nd6_ns_output_fib(struct ifnet *ifp, const struct in6_addr *saddr6,
goto bad;
}
if (nonce == NULL) {
char ip6buf[INET6_ADDRSTRLEN];
struct ifaddr *ifa = NULL;
/*
@ -480,14 +481,9 @@ nd6_ns_output_fib(struct ifnet *ifp, const struct in6_addr *saddr6,
* (saddr6), if saddr6 belongs to the outgoing interface.
* Otherwise, we perform the source address selection as usual.
*/
if (saddr6 != NULL)
ifa = (struct ifaddr *)in6ifa_ifpwithaddr(ifp, saddr6);
if (ifa != NULL) {
/* ip6_src set already. */
ip6->ip6_src = *saddr6;
ifa_free(ifa);
} else {
if (ifa == NULL) {
int error;
struct in6_addr dst6, src6;
uint32_t scopeid;
@ -496,7 +492,6 @@ nd6_ns_output_fib(struct ifnet *ifp, const struct in6_addr *saddr6,
error = in6_selectsrc_addr(fibnum, &dst6,
scopeid, ifp, &src6, NULL);
if (error) {
char ip6buf[INET6_ADDRSTRLEN];
nd6log((LOG_DEBUG, "%s: source can't be "
"determined: dst=%s, error=%d\n", __func__,
ip6_sprintf(ip6buf, &dst6),
@ -504,7 +499,31 @@ nd6_ns_output_fib(struct ifnet *ifp, const struct in6_addr *saddr6,
goto bad;
}
ip6->ip6_src = src6;
} else
ip6->ip6_src = *saddr6;
if (ifp->if_carp != NULL) {
/*
* Check that selected source address belongs to
* CARP addresses.
*/
if (ifa == NULL)
ifa = (struct ifaddr *)in6ifa_ifpwithaddr(ifp,
&ip6->ip6_src);
/*
* Do not send NS for CARP address if we are not
* the CARP master.
*/
if (ifa != NULL && !(*carp_master_p)(ifa)) {
log(LOG_DEBUG,
"nd6_ns_output: NS from BACKUP CARP address %s\n",
ip6_sprintf(ip6buf, &ip6->ip6_src));
ifa_free(ifa);
goto bad;
}
}
if (ifa != NULL)
ifa_free(ifa);
} else {
/*
* Source address for DAD packet must always be IPv6
@ -714,15 +733,20 @@ nd6_na_input(struct mbuf *m, int off, int icmp6len)
lladdrlen = ndopts.nd_opts_tgt_lladdr->nd_opt_len << 3;
}
/*
* This effectively disables the DAD check on a non-master CARP
* address.
*/
if (ifp->if_carp)
ifa = (*carp_iamatch6_p)(ifp, &taddr6);
else
ifa = (struct ifaddr *)in6ifa_ifpwithaddr(ifp, &taddr6);
ifa = (struct ifaddr *)in6ifa_ifpwithaddr(ifp, &taddr6);
if (ifa != NULL && ifa->ifa_carp != NULL) {
/*
* Silently ignore NAs for CARP addresses if we are not
* the CARP master.
*/
if (!(*carp_master_p)(ifa)) {
log(LOG_DEBUG,
"nd6_na_input: NA for BACKUP CARP address %s\n",
ip6_sprintf(ip6bufs, &taddr6));
ifa_free(ifa);
goto freeit;
}
}
/*
* Target address matches one of my interface address.
*