Index: ip_carp.c =================================================================== RCS file: /cvs/src/sys/netinet/ip_carp.c,v retrieving revision 1.343 diff -u -p -r1.343 ip_carp.c --- ip_carp.c 29 Apr 2020 07:04:32 -0000 1.343 +++ ip_carp.c 29 Apr 2020 09:49:57 -0000 @@ -233,6 +233,8 @@ int carp_check_dup_vhids(struct carp_sof void carp_ifgroup_ioctl(struct ifnet *, u_long, caddr_t); void carp_ifgattr_ioctl(struct ifnet *, u_long, caddr_t); void carp_start(struct ifnet *); +int carp_enqueue(struct ifnet *, struct mbuf *); +void carp_transmit(struct carp_softc *, struct ifnet *, struct mbuf *); void carp_setrun_all(struct carp_softc *, sa_family_t); void carp_setrun(struct carp_vhost_entry *, sa_family_t); void carp_set_state_all(struct carp_softc *, int); @@ -451,19 +453,9 @@ carp_proto_input_if(struct ifnet *ifp, s ismulti = IN_MULTICAST(ip->ip_dst.s_addr); - /* check if received on a valid carp interface */ - switch (ifp->if_type) { - case IFT_CARP: - break; - case IFT_ETHER: - if (ismulti || !SRPL_EMPTY_LOCKED(&ifp->if_carp)) - break; - /* FALLTHROUGH */ - default: + /* check if received on a valid interface */ + if (ifp->if_type != IFT_ETHER || SRPL_EMPTY_LOCKED(&ifp->if_carp)) { carpstat_inc(carps_badif); - CARP_LOG(LOG_INFO, sc, - ("packet received on non-carp interface: %s", - ifp->if_xname)); m_freem(m); return IPPROTO_DONE; } @@ -548,11 +540,9 @@ carp6_proto_input_if(struct ifnet *ifp, return IPPROTO_DONE; } - /* check if received on a valid carp interface */ - if (ifp->if_type != IFT_CARP) { + /* check if received on a valid interface */ + if (ifp->if_type != IFT_ETHER || SRPL_EMPTY_LOCKED(&ifp->if_carp)) { carpstat_inc(carps_badif); - CARP_LOG(LOG_INFO, sc, ("packet received on non-carp interface: %s", - ifp->if_xname)); m_freem(m); return IPPROTO_DONE; } @@ -604,18 +594,7 @@ carp_proto_input_c(struct ifnet *ifp, st KERNEL_ASSERT_LOCKED(); /* touching if_carp + carp_vhosts */ - if (ifp->if_type == IFT_CARP) { - /* - * If the parent of this carp(4) got destroyed while - * `m' was being processed, silently drop it. - */ - if (ifp->if_carpdev == NULL) { - m_freem(m); - return; - } - cif = &ifp->if_carpdev->if_carp; - } else - cif = &ifp->if_carp; + cif = &ifp->if_carp; SRPL_FOREACH_LOCKED(sc, cif, sc_list) { if (af == AF_INET && @@ -636,8 +615,8 @@ carp_proto_input_c(struct ifnet *ifp, st } getmicrotime(&sc->sc_if.if_lastchange); - sc->sc_if.if_ipackets++; - sc->sc_if.if_ibytes += m->m_pkthdr.len; + //sc->sc_if.if_ipackets++; + //sc->sc_if.if_ibytes += m->m_pkthdr.len; /* verify the CARP version. */ if (ch->carp_version != CARP_VERSION) { @@ -830,8 +809,8 @@ carp_clone_create(struct if_clone *ifc, ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; ifp->if_ioctl = carp_ioctl; ifp->if_start = carp_start; + ifp->if_enqueue = carp_enqueue; ifp->if_xflags = IFXF_CLONED; - IFQ_SET_MAXLEN(&ifp->if_snd, 1); if_counters_alloc(ifp); if_attach(ifp); ether_ifattach(ifp); @@ -1135,8 +1114,8 @@ carp_send_ad(struct carp_vhost_entry *vh m->m_data -= sizeof(*ip); getmicrotime(&sc->sc_if.if_lastchange); - sc->sc_if.if_opackets++; - sc->sc_if.if_obytes += len; + //sc->sc_if.if_opackets++; + //sc->sc_if.if_obytes += len; carpstat_inc(carps_opackets); error = ip_output(m, NULL, NULL, IP_RAWOUTPUT, &sc->sc_imo, @@ -1223,8 +1202,8 @@ carp_send_ad(struct carp_vhost_entry *vh m->m_data -= sizeof(*ip6); getmicrotime(&sc->sc_if.if_lastchange); - sc->sc_if.if_opackets++; - sc->sc_if.if_obytes += len; + //sc->sc_if.if_opackets++; + //sc->sc_if.if_obytes += len; carpstat_inc(carps_opackets6); error = ip6_output(m, NULL, NULL, 0, &sc->sc_im6o, NULL); @@ -1437,16 +1416,18 @@ carp_input(struct ifnet *ifp0, struct mb * for each CARP interface _before_ copying. */ SRPL_FOREACH(sc, &sr, cif, sc_list) { + struct ifnet *ifp = &sc->sc_if; struct mbuf *m0; - if (!(sc->sc_if.if_flags & IFF_UP)) + if (!ISSET(ifp->if_flags, IFF_UP) || + !LINK_STATE_IS_UP(ifp->if_link_state)) continue; m0 = m_dup_pkt(m, ETHER_ALIGN, M_DONTWAIT); if (m0 == NULL) continue; - if_vinput(&sc->sc_if, m0); + if_vinput(ifp, m0); } SRPL_LEAVE(&sr); @@ -1706,6 +1687,13 @@ carp_set_ifp(struct carp_softc *sc, stru sc->sc_if.if_capabilities = ifp0->if_capabilities & IFCAP_CSUM_MASK; + if (sc->sc_naddrs) + carp_join_multicast(sc); +#ifdef INET6 + if (sc->sc_naddrs6) + carp_join_multicast6(sc); +#endif + SRPL_FOREACH_LOCKED(vr, cif, sc_list) { struct carp_vhost_entry *vrhead, *schead; last = vr; @@ -1825,23 +1813,6 @@ carp_addr_updated(void *v) sc->sc_naddrs = new_naddrs; sc->sc_naddrs6 = new_naddrs6; - /* Re-establish multicast membership removed by in_control */ - if (IN_MULTICAST(sc->sc_peer.s_addr)) { - if (!in_hasmulti(&sc->sc_peer, &sc->sc_if)) { - struct in_multi **imm = - sc->sc_imo.imo_membership; - u_int16_t maxmem = - sc->sc_imo.imo_max_memberships; - - memset(&sc->sc_imo, 0, sizeof(sc->sc_imo)); - sc->sc_imo.imo_membership = imm; - sc->sc_imo.imo_max_memberships = maxmem; - - if (sc->sc_carpdev != NULL && sc->sc_naddrs > 0) - carp_join_multicast(sc); - } - } - if (sc->sc_naddrs == 0 && sc->sc_naddrs6 == 0) { sc->sc_if.if_flags &= ~IFF_UP; carp_set_state_all(sc, INIT); @@ -1877,6 +1848,7 @@ carp_set_addr(struct carp_softc *sc, str int carp_join_multicast(struct carp_softc *sc) { + struct ifnet *ifp0 = sc->sc_carpdev; struct ip_moptions *imo = &sc->sc_imo; struct in_multi *imm; struct in_addr addr; @@ -1885,12 +1857,12 @@ carp_join_multicast(struct carp_softc *s return (0); addr.s_addr = sc->sc_peer.s_addr; - if ((imm = in_addmulti(&addr, &sc->sc_if)) == NULL) + if ((imm = in_addmulti(&addr, ifp0)) == NULL) return (ENOBUFS); imo->imo_membership[0] = imm; imo->imo_num_memberships = 1; - imo->imo_ifidx = sc->sc_if.if_index; + imo->imo_ifidx = ifp0->if_index; imo->imo_ttl = CARP_DFLTTL; imo->imo_loop = 0; return (0); @@ -1921,44 +1893,37 @@ carp_set_addr6(struct carp_softc *sc, st int carp_join_multicast6(struct carp_softc *sc) { + struct ifnet *ifp0 = sc->sc_carpdev; struct in6_multi_mship *imm, *imm2; struct ip6_moptions *im6o = &sc->sc_im6o; - struct sockaddr_in6 addr6; + struct in6_addr addr6; int error; /* Join IPv6 CARP multicast group */ memset(&addr6, 0, sizeof(addr6)); - addr6.sin6_family = AF_INET6; - addr6.sin6_len = sizeof(addr6); - addr6.sin6_addr.s6_addr16[0] = htons(0xff02); - addr6.sin6_addr.s6_addr16[1] = htons(sc->sc_if.if_index); - addr6.sin6_addr.s6_addr8[15] = 0x12; - if ((imm = in6_joingroup(&sc->sc_if, - &addr6.sin6_addr, &error)) == NULL) { + addr6.s6_addr16[0] = htons(0xff02); + addr6.s6_addr16[1] = htons(ifp0->if_index); + addr6.s6_addr8[15] = 0x12; + if ((imm = in6_joingroup(ifp0, &addr6, &error)) == NULL) { return (error); } /* join solicited multicast address */ - memset(&addr6.sin6_addr, 0, sizeof(addr6.sin6_addr)); - addr6.sin6_addr.s6_addr16[0] = htons(0xff02); - addr6.sin6_addr.s6_addr16[1] = htons(sc->sc_if.if_index); - addr6.sin6_addr.s6_addr32[1] = 0; - addr6.sin6_addr.s6_addr32[2] = htonl(1); - addr6.sin6_addr.s6_addr32[3] = 0; - addr6.sin6_addr.s6_addr8[12] = 0xff; - if ((imm2 = in6_joingroup(&sc->sc_if, - &addr6.sin6_addr, &error)) == NULL) { + memset(&addr6, 0, sizeof(addr6)); + addr6.s6_addr16[0] = htons(0xff02); + addr6.s6_addr16[1] = htons(ifp0->if_index); + addr6.s6_addr32[1] = 0; + addr6.s6_addr32[2] = htonl(1); + addr6.s6_addr32[3] = 0; + addr6.s6_addr8[12] = 0xff; + if ((imm2 = in6_joingroup(ifp0, &addr6, &error)) == NULL) { in6_leavegroup(imm); return (error); } /* apply v6 multicast membership */ - im6o->im6o_ifidx = sc->sc_if.if_index; - if (imm) - LIST_INSERT_HEAD(&im6o->im6o_memberships, imm, - i6mm_chain); - if (imm2) - LIST_INSERT_HEAD(&im6o->im6o_memberships, imm2, - i6mm_chain); + im6o->im6o_ifidx = ifp0->if_index; + LIST_INSERT_HEAD(&im6o->im6o_memberships, imm, i6mm_chain); + LIST_INSERT_HEAD(&im6o->im6o_memberships, imm2, i6mm_chain); return (0); } @@ -1984,12 +1949,10 @@ carp_ioctl(struct ifnet *ifp, u_long cmd switch (ifa->ifa_addr->sa_family) { case AF_INET: - sc->sc_if.if_flags |= IFF_UP; error = carp_set_addr(sc, satosin(ifa->ifa_addr)); break; #ifdef INET6 case AF_INET6: - sc->sc_if.if_flags |= IFF_UP; error = carp_set_addr6(sc, satosin6(ifa->ifa_addr)); break; #endif /* INET6 */ @@ -2263,65 +2226,87 @@ void carp_start(struct ifnet *ifp) { struct carp_softc *sc = ifp->if_softc; + struct ifnet *ifp0 = sc->sc_carpdev; struct mbuf *m; - for (;;) { - IFQ_DEQUEUE(&ifp->if_snd, m); - if (m == NULL) - break; + if (ifp0 == NULL) { + ifq_purge(&ifp->if_snd); + return; + } -#if NBPFILTER > 0 - if (ifp->if_bpf) - bpf_mtap_ether(ifp->if_bpf, m, BPF_DIRECTION_OUT); -#endif /* NBPFILTER > 0 */ + while ((m = ifq_dequeue(&ifp->if_snd)) != NULL) + carp_transmit(sc, ifp0, m); +} - if ((ifp->if_carpdev->if_flags & (IFF_UP|IFF_RUNNING)) != - (IFF_UP|IFF_RUNNING)) { - ifp->if_oerrors++; - m_freem(m); - continue; - } +void +carp_transmit(struct carp_softc *sc, struct ifnet *ifp0, struct mbuf *m) +{ + struct ifnet *ifp = &sc->sc_if; - /* - * Do not leak the multicast address when sending - * advertisements in 'ip' and 'ip-stealth' balacing - * modes. - */ - if (sc->sc_balancing == CARP_BAL_IP || - sc->sc_balancing == CARP_BAL_IPSTEALTH) { - struct ether_header *eh; - uint8_t *esrc; - - eh = mtod(m, struct ether_header *); - esrc = ((struct arpcom*)ifp->if_carpdev)->ac_enaddr; - memcpy(eh->ether_shost, esrc, sizeof(eh->ether_shost)); +#if NBPFILTER > 0 + { + caddr_t if_bpf = ifp->if_bpf; + if (if_bpf) { + if (bpf_mtap_ether(if_bpf, m, BPF_DIRECTION_OUT)) + m_freem(m); } + } +#endif /* NBPFILTER > 0 */ - if (if_enqueue(ifp->if_carpdev, m)) { - ifp->if_oerrors++; - continue; - } - ifp->if_opackets++; + if (!ISSET(ifp0->if_flags, IFF_RUNNING)) { + counters_inc(ifp->if_counters, ifc_oerrors); + m_freem(m); + return; } + + /* + * Do not leak the multicast address when sending + * advertisements in 'ip' and 'ip-stealth' balacing + * modes. + */ + if (sc->sc_balancing == CARP_BAL_IP || + sc->sc_balancing == CARP_BAL_IPSTEALTH) { + struct ether_header *eh = mtod(m, struct ether_header *); + memcpy(eh->ether_shost, sc->sc_ac.ac_enaddr, + sizeof(eh->ether_shost)); + } + + if (if_enqueue(ifp0, m)) + counters_inc(ifp->if_counters, ifc_oerrors); } int -carp_output(struct ifnet *ifp, struct mbuf *m, struct sockaddr *sa, - struct rtentry *rt) +carp_enqueue(struct ifnet *ifp, struct mbuf *m) { - struct carp_softc *sc = ((struct carp_softc *)ifp->if_softc); - struct carp_vhost_entry *vhe; - struct srp_ref sr; - int ismaster; + struct carp_softc *sc = ifp->if_softc; + struct ifnet *ifp0 = sc->sc_carpdev; + + /* no ifq_is_priq, cos hfsc on carp doesn't make sense */ /* * If the parent of this carp(4) got destroyed while * `m' was being processed, silently drop it. */ - if (sc->sc_carpdev == NULL) { + if (ifp0 == NULL) { m_freem(m); return (0); } + + counters_pkt(ifp->if_counters, + ifc_opackets, ifc_obytes, m->m_pkthdr.len); + carp_transmit(sc, ifp0, m); + + return (0); +} + +int +carp_output(struct ifnet *ifp, struct mbuf *m, struct sockaddr *sa, + struct rtentry *rt) +{ + struct carp_softc *sc = ((struct carp_softc *)ifp->if_softc); + struct carp_vhost_entry *vhe; + struct srp_ref sr; + int ismaster; if (sc->cur_vhe == NULL) { vhe = SRPL_FIRST(&sr, &sc->carp_vhosts);