Index | Thread | Search

From:
Stefan Sperling <stsp@stsp.name>
Subject:
ice(4) multicast fix
To:
tech@openbsd.org
Date:
Mon, 31 Mar 2025 18:38:08 +0200

Download raw body.

Thread
  • Stefan Sperling:

    ice(4) multicast fix

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;