Index | Thread | Search

From:
YASUOKA Masahiko <yasuoka@openbsd.org>
Subject:
carp: embed scope-id when sending NA
To:
tech@openbsd.org
Date:
Thu, 05 Dec 2024 12:26:21 +0900

Download raw body.

Thread
Hi,

My colleague noticed that all unsolicited NAs when carp becomes master
are ignored by the received hosts.  This is because the source address
is ::1.

  20:32:08.676523 00:50:56:xx:xx:xx 33:33:00:00:00:01 86dd 86: ::1 > ff02::1: icmp6: neighbor adv: tgt is xxxx:xxxx:bb5e:1823::1:250

We must embed a scope-id to the destination when calling
nd6_na_output().  Also the route the "ff02:1" is not RTF_UP at that
time.  We need to wait until if state change task is completed.


comments? ok?

Embed scope-id when sending NA.  Also, do it when the link state is
up because the route entry to the mutlicast is not ready yet when the
carp becomes master.

Index: sys/netinet/ip_carp.c
===================================================================
RCS file: /disk/cvs/openbsd/src/sys/netinet/ip_carp.c,v
diff -u -p -r1.363 ip_carp.c
--- sys/netinet/ip_carp.c	14 Jul 2024 18:53:39 -0000	1.363
+++ sys/netinet/ip_carp.c	5 Dec 2024 03:19:34 -0000
@@ -138,6 +138,7 @@ struct carp_softc {
 	struct ip_moptions sc_imo;
 #ifdef INET6
 	struct ip6_moptions sc_im6o;
+	struct task sc_itask;
 #endif /* INET6 */
 
 	SRPL_ENTRY(carp_softc) sc_list;
@@ -171,6 +172,9 @@ struct carp_softc {
 	u_int32_t sc_lsmask;		/* load sharing mask */
 	int sc_lscount;			/* # load sharing interfaces (max 32) */
 	int sc_delayed_arp;		/* delayed ARP request countdown */
+#ifdef INET6
+	int sc_send_na;			/* send NA when link state up */
+#endif /* INET6 */
 	int sc_realmac;			/* using real mac */
 
 	struct in_addr sc_peer;
@@ -250,6 +254,7 @@ int	carp_join_multicast(struct carp_soft
 void	carp_send_na(struct carp_softc *);
 int	carp_set_addr6(struct carp_softc *, struct sockaddr_in6 *);
 int	carp_join_multicast6(struct carp_softc *);
+void	carp_if_linkstate(void *);
 #endif
 int	carp_clone_create(struct if_clone *, int);
 int	carp_clone_destroy(struct ifnet *);
@@ -811,6 +816,9 @@ carp_clone_create(struct if_clone *ifc, 
 	task_set(&sc->sc_atask, carp_addr_updated, sc);
 	task_set(&sc->sc_ltask, carp_carpdev_state, sc);
 	task_set(&sc->sc_dtask, carpdetach, sc);
+#ifdef INET6
+	task_set(&sc->sc_itask, carp_if_linkstate, sc);
+#endif /* INET6 */
 
 	sc->sc_suppress = 0;
 	sc->sc_advbase = CARP_DFLTINTV;
@@ -843,6 +851,9 @@ carp_clone_create(struct if_clone *ifc, 
 
 	/* Hook carp_addr_updated to cope with address and route changes. */
 	if_addrhook_add(&sc->sc_if, &sc->sc_atask);
+#ifdef INET6
+	if_linkstatehook_add(&sc->sc_if, &sc->sc_itask);
+#endif /* INET6 */
 
 	return (0);
 }
@@ -894,6 +905,9 @@ carp_clone_destroy(struct ifnet *ifp)
 	struct carp_softc *sc = ifp->if_softc;
 
 	if_addrhook_del(&sc->sc_if, &sc->sc_atask);
+#ifdef INET6
+	if_linkstatehook_del(&sc->sc_if, &sc->sc_itask);
+#endif /* INET6 */
 
 	NET_LOCK();
 	carpdetach(sc);
@@ -1285,13 +1299,13 @@ void
 carp_send_na(struct carp_softc *sc)
 {
 	struct ifaddr *ifa;
-	struct in6_addr *in6;
-	static struct in6_addr mcast = IN6ADDR_LINKLOCAL_ALLNODES_INIT;
+	struct in6_addr *in6, mcast = IN6ADDR_LINKLOCAL_ALLNODES_INIT;
 	int i_am_router = (atomic_load_int(&ip6_forwarding) != 0);
 	int flags = ND_NA_FLAG_OVERRIDE;
 
 	if (i_am_router)
 		flags |= ND_NA_FLAG_ROUTER;
+	mcast.s6_addr16[1] = htons(sc->sc_if.if_index);
 
 	TAILQ_FOREACH(ifa, &sc->sc_if.if_addrlist, ifa_list) {
 
@@ -1534,7 +1548,8 @@ carp_master_down(struct carp_vhost_entry
 			/* Schedule a delayed ARP to deal w/ some L3 switches */
 			sc->sc_delayed_arp = 2;
 #ifdef INET6
-			carp_send_na(sc);
+			/* routing entry is not ready yet.  do it later */
+			sc->sc_send_na = 1;
 #endif /* INET6 */
 		}
 		carp_setrun(vhe, 0);
@@ -1955,6 +1970,17 @@ carp_join_multicast6(struct carp_softc *
 	return (0);
 }
 
+void
+carp_if_linkstate(void *v)
+{
+	struct carp_softc *sc = v;
+
+	if (sc->sc_send_na) {
+		if (sc->sc_if.if_link_state == LINK_STATE_UP)
+			carp_send_na(sc);
+		sc->sc_send_na = 0;
+	}
+}
 #endif /* INET6 */
 
 int