aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrey V. Elsukov <ae@FreeBSD.org>2022-10-06 16:50:33 +0000
committerAndrey V. Elsukov <ae@FreeBSD.org>2022-10-06 17:01:16 +0000
commitccd69bd573f185308e7652190ff64b50f7fba381 (patch)
treefc4ade9a488aa275d2e7c34ffc87c0642edc3dbe
parent9bce11410645f4e84521c2ee44d3082aad8ae1e9 (diff)
downloadsrc-ccd69bd573f185308e7652190ff64b50f7fba381.tar.gz
src-ccd69bd573f185308e7652190ff64b50f7fba381.zip
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
-rw-r--r--sys/netinet6/nd6_nbr.c56
1 files changed, 40 insertions, 16 deletions
diff --git a/sys/netinet6/nd6_nbr.c b/sys/netinet6/nd6_nbr.c
index f96bf8e58dc3..7bca7fa59ac7 100644
--- a/sys/netinet6/nd6_nbr.c
+++ b/sys/netinet6/nd6_nbr.c
@@ -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.
*