From: Stefan Sperling Subject: ice(4) multicast fix To: tech@openbsd.org Date: Mon, 31 Mar 2025 18:38:08 +0200 bluhm@ noticed that IPv6 NDP is not working correctly on ice(4). It currently works properly only while tcpdump is running, i.e. while the interface is in promiscuous mode. The root cause of the issue is that ice(4) does not yet handle the ADDMULTI and DELMULTI ioctls. Adding IPv6 multicast addresses to the MAC filter via these ioctls, like ixl(4) does, fixes the issue. ok? unbreak IPv6 neighbor discovery on ice(4) problem reported by bluhm@ M sys/dev/pci/if_ice.c | 47+ 3- 1 file changed, 47 insertions(+), 3 deletions(-) commit - 3314f3c49c16885c1e42fcde96fce99f30954425 commit + 803e615fd1e7da4fab993ecf916b966072a51874 blob - 834fdda20f541449cdfffd0cafa1d684497606b5 blob + 553c541acdad4bf060f205eb3e94652b673be950 --- sys/dev/pci/if_ice.c +++ sys/dev/pci/if_ice.c @@ -11787,10 +11787,12 @@ ice_if_promisc_set(struct ice_softc *sc) ice_set_default_promisc_mask(promisc_mask); - if (multi_enable) - return (EOPNOTSUPP); + if (multi_enable && !promisc_enable) { + ice_clear_bit(ICE_PROMISC_UCAST_TX, promisc_mask); + ice_clear_bit(ICE_PROMISC_UCAST_RX, promisc_mask); + } - if (promisc_enable) { + if (promisc_enable || multi_enable) { status = ice_set_vsi_promisc(hw, sc->pf_vsi.idx, promisc_mask, 0); if (status && status != ICE_ERR_ALREADY_EXISTS) { @@ -13521,6 +13523,7 @@ ice_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) { struct ice_softc *sc = ifp->if_softc; struct ifreq *ifr = (struct ifreq *)data; + uint8_t addrhi[ETHER_ADDR_LEN], addrlo[ETHER_ADDR_LEN]; int s, error = 0; s = splnet(); @@ -13545,6 +13548,47 @@ ice_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) case SIOCGIFMEDIA: error = ifmedia_ioctl(ifp, ifr, &sc->media, cmd); break; + case SIOCADDMULTI: + error = ether_addmulti(ifr, &sc->sc_ac); + if (error == ENETRESET) { + struct ice_vsi *vsi = &sc->pf_vsi; + + error = ether_multiaddr(&ifr->ifr_addr, addrlo, addrhi); + if (error) + break; + + error = ice_add_vsi_mac_filter(vsi, addrlo); + if (error) + break; + + if (sc->sc_ac.ac_multirangecnt > 0) { + SET(ifp->if_flags, IFF_ALLMULTI); + error = ENETRESET; + } + } + break; + + case SIOCDELMULTI: + error = ether_delmulti(ifr, &sc->sc_ac); + if (error == ENETRESET) { + struct ice_vsi *vsi = &sc->pf_vsi; + + error = ether_multiaddr(&ifr->ifr_addr, addrlo, addrhi); + if (error) + break; + + error = ice_remove_vsi_mac_filter(vsi, addrlo); + if (error) + break; + + if (ISSET(ifp->if_flags, IFF_ALLMULTI) && + sc->sc_ac.ac_multirangecnt == 0) { + CLR(ifp->if_flags, IFF_ALLMULTI); + error = ENETRESET; + } + } + break; + default: error = ether_ioctl(ifp, &sc->sc_ac, cmd, data); break;