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