Index | Thread | Search

From:
Jan Klemkow <jan@openbsd.org>
Subject:
refactor LRO turn off
To:
tech@openbsd.org
Date:
Wed, 23 Oct 2024 20:14:13 +0200

Download raw body.

Thread
Hi,

This diff refactors the mechanism to turn off LRO on network interfaces.
First, it improves the handling of pseudo devices.  It no longer uses
their data structures from the outside.  It just forwards the
SIOCSIFXFLAGS command to their ioctl(2) handler.  So, devices like
trunk(4) can call ifsetlro() for all its parents interfaces by themself.
Now, the LRO turn off call is forwarded through trunk(4), vlan(4) and
friends to their parent interfaces.

Second, we just need reinit the ix(4) interface to turn off/no LRO. So,
vio(4) and vmx(4) can switch this feature without going down and up
again.

Tests in different environments are welcome.

Bye,
Jan

Index: dev/pci/if_ix.c
===================================================================
RCS file: /cvs/src/sys/dev/pci/if_ix.c,v
diff -u -p -r1.218 if_ix.c
--- dev/pci/if_ix.c	4 Oct 2024 05:22:10 -0000	1.218
+++ dev/pci/if_ix.c	23 Oct 2024 07:29:22 -0000
@@ -550,6 +550,19 @@ ixgbe_ioctl(struct ifnet * ifp, u_long c
 		}
 		break;
 
+	case SIOCSIFXFLAGS:
+		if (ISSET(ifr->ifr_flags, IFXF_LRO) !=
+		    ISSET(ifp->if_xflags, IFXF_LRO)) {
+			if (ISSET(ifr->ifr_flags, IFXF_LRO))
+				SET(ifp->if_xflags, IFXF_LRO);
+			else
+				CLR(ifp->if_xflags, IFXF_LRO);
+
+			if (ifp->if_flags & IFF_UP)
+				ixgbe_init(sc);
+		}
+		break;
+
 	case SIOCSIFMEDIA:
 	case SIOCGIFMEDIA:
 		IOCTL_DEBUGOUT("ioctl: SIOCxIFMEDIA (Get/Set Interface Media)");
Index: dev/pci/if_vmx.c
===================================================================
RCS file: /cvs/src/sys/dev/pci/if_vmx.c,v
diff -u -p -r1.89 if_vmx.c
--- dev/pci/if_vmx.c	1 Sep 2024 03:08:59 -0000	1.89
+++ dev/pci/if_vmx.c	23 Oct 2024 07:38:01 -0000
@@ -1370,6 +1370,19 @@ vmxnet3_reset(struct vmxnet3_softc *sc)
 	WRITE_CMD(sc, VMXNET3_CMD_RESET);
 }
 
+void
+vmxnet4_set_features(struct vmxnet3_softc *sc)
+{
+	struct ifnet *ifp = &sc->sc_arpcom.ac_if;
+
+	/* TCP Large Receive Offload */
+	if (ISSET(ifp->if_xflags, IFXF_LRO))
+		SET(sc->sc_ds->upt_features, UPT1_F_LRO);
+	else
+		CLR(sc->sc_ds->upt_features, UPT1_F_LRO);
+	WRITE_CMD(sc, VMXNET3_CMD_SET_FEATURE);
+}
+
 int
 vmxnet3_init(struct vmxnet3_softc *sc)
 {
@@ -1403,12 +1416,7 @@ vmxnet3_init(struct vmxnet3_softc *sc)
 		return EIO;
 	}
 
-	/* TCP Large Receive Offload */
-	if (ISSET(ifp->if_xflags, IFXF_LRO))
-		SET(sc->sc_ds->upt_features, UPT1_F_LRO);
-	else
-		CLR(sc->sc_ds->upt_features, UPT1_F_LRO);
-	WRITE_CMD(sc, VMXNET3_CMD_SET_FEATURE);
+	vmxnet4_set_features(sc);
 
 	/* Program promiscuous mode and multicast filters. */
 	vmxnet3_iff(sc);
@@ -1474,6 +1482,17 @@ vmxnet3_ioctl(struct ifnet *ifp, u_long 
 		} else {
 			if (ifp->if_flags & IFF_RUNNING)
 				vmxnet3_stop(ifp);
+		}
+		break;
+	case SIOCSIFXFLAGS:
+		if (ISSET(ifr->ifr_flags, IFXF_LRO) !=
+		    ISSET(ifp->if_xflags, IFXF_LRO)) {
+			if (ISSET(ifr->ifr_flags, IFXF_LRO))
+				SET(ifp->if_xflags, IFXF_LRO);
+			else
+				CLR(ifp->if_xflags, IFXF_LRO);
+
+			vmxnet4_set_features(sc);
 		}
 		break;
 	case SIOCSIFMEDIA:
Index: dev/pv/if_vio.c
===================================================================
RCS file: /cvs/src/sys/dev/pv/if_vio.c,v
diff -u -p -r1.57 if_vio.c
--- dev/pv/if_vio.c	3 Oct 2024 08:59:49 -0000	1.57
+++ dev/pv/if_vio.c	23 Oct 2024 07:29:22 -0000
@@ -316,6 +316,7 @@ int	vio_set_rx_filter(struct vio_softc *
 void	vio_iff(struct vio_softc *);
 int	vio_media_change(struct ifnet *);
 void	vio_media_status(struct ifnet *, struct ifmediareq *);
+void	vio_set_offloads(struct ifnet *);
 int	vio_ctrleof(struct virtqueue *);
 int	vio_ctrl_start(struct vio_softc *, uint8_t, uint8_t, int, int *);
 int	vio_ctrl_submit(struct vio_softc *, int);
@@ -800,6 +801,28 @@ vio_media_status(struct ifnet *ifp, stru
 		imr->ifm_status |= IFM_ACTIVE|IFM_FDX;
 }
 
+void
+vio_set_offloads(struct ifnet *ifp)
+{
+	struct vio_softc	*sc = ifp->if_softc;
+	struct virtio_softc	*vsc = sc->sc_virtio;
+	uint64_t		 features = 0;
+
+	if (virtio_has_feature(vsc, VIRTIO_NET_F_CTRL_GUEST_OFFLOADS)) {
+		if (virtio_has_feature(vsc, VIRTIO_NET_F_GUEST_CSUM))
+			SET(features, VIRTIO_NET_F_GUEST_CSUM);
+
+		if (ISSET(ifp->if_xflags, IFXF_LRO)) {
+			if (virtio_has_feature(vsc, VIRTIO_NET_F_GUEST_TSO4))
+				SET(features, VIRTIO_NET_F_GUEST_TSO4);
+			if (virtio_has_feature(vsc, VIRTIO_NET_F_GUEST_TSO6))
+				SET(features, VIRTIO_NET_F_GUEST_TSO6);
+		}
+
+		vio_ctrl_guest_offloads(sc, features);
+	}
+}
+
 /*
  * Interface functions for ifnet
  */
@@ -807,7 +830,6 @@ int
 vio_init(struct ifnet *ifp)
 {
 	struct vio_softc *sc = ifp->if_softc;
-	struct virtio_softc *vsc = sc->sc_virtio;
 	int qidx;
 
 	vio_stop(ifp, 0);
@@ -822,22 +844,7 @@ vio_init(struct ifnet *ifp)
 	ifq_clr_oactive(&ifp->if_snd);
 	vio_iff(sc);
 	vio_link_state(ifp);
-
-	if (virtio_has_feature(vsc, VIRTIO_NET_F_CTRL_GUEST_OFFLOADS)) {
-		uint64_t features = 0;
-
-		if (virtio_has_feature(vsc, VIRTIO_NET_F_GUEST_CSUM))
-			SET(features, VIRTIO_NET_F_GUEST_CSUM);
-
-		if (ISSET(ifp->if_xflags, IFXF_LRO)) {
-			if (virtio_has_feature(vsc, VIRTIO_NET_F_GUEST_TSO4))
-				SET(features, VIRTIO_NET_F_GUEST_TSO4);
-			if (virtio_has_feature(vsc, VIRTIO_NET_F_GUEST_TSO6))
-				SET(features, VIRTIO_NET_F_GUEST_TSO6);
-		}
-
-		vio_ctrl_guest_offloads(sc, features);
-	}
+	vio_set_offloads(ifp);
 
 	SET(ifp->if_flags, IFF_RUNNING);
 
@@ -1101,6 +1108,17 @@ vio_ioctl(struct ifnet *ifp, u_long cmd,
 		} else {
 			if (ifp->if_flags & IFF_RUNNING)
 				vio_stop(ifp, 1);
+		}
+		break;
+	case SIOCSIFXFLAGS:
+		if (ISSET(ifr->ifr_flags, IFXF_LRO) !=
+		    ISSET(ifp->if_xflags, IFXF_LRO)) {
+			if (ISSET(ifr->ifr_flags, IFXF_LRO))
+				SET(ifp->if_xflags, IFXF_LRO);
+			else
+				CLR(ifp->if_xflags, IFXF_LRO);
+
+			vio_set_offloads(ifp);
 		}
 		break;
 	case SIOCGIFMEDIA:
Index: net/if.c
===================================================================
RCS file: /cvs/src/sys/net/if.c,v
diff -u -p -r1.721 if.c
--- net/if.c	17 Oct 2024 05:02:12 -0000	1.721
+++ net/if.c	23 Oct 2024 07:29:22 -0000
@@ -3240,29 +3240,26 @@ ifpromisc(struct ifnet *ifp, int pswitch
 int
 ifsetlro(struct ifnet *ifp, int on)
 {
-	struct ifreq ifrq;
 	int error = 0;
 	int s = splnet();
-	struct if_parent parent;
+	struct ifreq ifr;
 
-	memset(&parent, 0, sizeof(parent));
-	if ((*ifp->if_ioctl)(ifp, SIOCGIFPARENT, (caddr_t)&parent) != -1) {
-		struct ifnet *ifp0 = if_unit(parent.ifp_parent);
-
-		if (ifp0 != NULL) {
-			ifsetlro(ifp0, on);
-			if_put(ifp0);
-		}
-	}
+	NET_ASSERT_LOCKED();	/* for ioctl */
+	KERNEL_ASSERT_LOCKED();	/* for if_flags */
+
+	memset(&ifr, 0, sizeof ifr);
+	if (on)
+		SET(ifr.ifr_flags, IFXF_LRO);
+
+	error = ((*ifp->if_ioctl)(ifp, SIOCSIFXFLAGS, (caddr_t)&ifr));
+	if (error == 0)
+		goto out;
 
 	if (!ISSET(ifp->if_capabilities, IFCAP_LRO)) {
 		error = ENOTSUP;
 		goto out;
 	}
 
-	NET_ASSERT_LOCKED();	/* for ioctl */
-	KERNEL_ASSERT_LOCKED();	/* for if_flags */
-
 	if (on && !ISSET(ifp->if_xflags, IFXF_LRO)) {
 		if (ifp->if_type == IFT_ETHER && ether_brport_isset(ifp)) {
 			error = EBUSY;
@@ -3271,21 +3268,7 @@ ifsetlro(struct ifnet *ifp, int on)
 		SET(ifp->if_xflags, IFXF_LRO);
 	} else if (!on && ISSET(ifp->if_xflags, IFXF_LRO))
 		CLR(ifp->if_xflags, IFXF_LRO);
-	else
-		goto out;
 
-	/* restart interface */
-	if (ISSET(ifp->if_flags, IFF_UP)) {
-		/* go down for a moment... */
-		CLR(ifp->if_flags, IFF_UP);
-		ifrq.ifr_flags = ifp->if_flags;
-		(*ifp->if_ioctl)(ifp, SIOCSIFFLAGS, (caddr_t)&ifrq);
-
-		/* ... and up again */
-		SET(ifp->if_flags, IFF_UP);
-		ifrq.ifr_flags = ifp->if_flags;
-		(*ifp->if_ioctl)(ifp, SIOCSIFFLAGS, (caddr_t)&ifrq);
-	}
  out:
 	splx(s);
 
Index: net/if_aggr.c
===================================================================
RCS file: /cvs/src/sys/net/if_aggr.c,v
diff -u -p -r1.46 if_aggr.c
--- net/if_aggr.c	4 Sep 2024 07:54:52 -0000	1.46
+++ net/if_aggr.c	23 Oct 2024 07:29:22 -0000
@@ -833,6 +833,7 @@ aggr_ioctl(struct ifnet *ifp, u_long cmd
 {
 	struct aggr_softc *sc = ifp->if_softc;
 	struct ifreq *ifr = (struct ifreq *)data;
+	struct aggr_port *p;
 	int error = 0;
 
 	if (sc->sc_dead)
@@ -852,6 +853,11 @@ aggr_ioctl(struct ifnet *ifp, u_long cmd
 			if (ISSET(ifp->if_flags, IFF_RUNNING))
 				error = aggr_down(sc);
 		}
+		break;
+
+	case SIOCSIFXFLAGS:
+		TAILQ_FOREACH(p, &sc->sc_ports, p_entry)
+			ifsetlro(p->p_ifp0, ISSET(ifr->ifr_flags, IFXF_LRO));
 		break;
 
 	case SIOCSIFLLADDR:
Index: net/if_bpe.c
===================================================================
RCS file: /cvs/src/sys/net/if_bpe.c,v
diff -u -p -r1.22 if_bpe.c
--- net/if_bpe.c	23 Dec 2023 10:52:54 -0000	1.22
+++ net/if_bpe.c	23 Oct 2024 07:29:22 -0000
@@ -305,6 +305,7 @@ bpe_ioctl(struct ifnet *ifp, u_long cmd,
 	struct bpe_softc *sc = ifp->if_softc;
 	struct ifreq *ifr = (struct ifreq *)data;
 	struct ifbrparam *bparam = (struct ifbrparam *)data;
+	struct ifnet *ifp0;
 	int error = 0;
 
 	switch (cmd) {
@@ -317,6 +318,13 @@ bpe_ioctl(struct ifnet *ifp, u_long cmd,
 		} else {
 			if (ISSET(ifp->if_flags, IFF_RUNNING))
 				error = bpe_down(sc);
+		}
+		break;
+
+	case SIOCSIFXFLAGS:
+		if ((ifp0 = if_get(sc->sc_key.k_if)) != NULL) {
+			ifsetlro(ifp0, ISSET(ifr->ifr_flags, IFXF_LRO));
+			if_put(ifp0);
 		}
 		break;
 
Index: net/if_trunk.c
===================================================================
RCS file: /cvs/src/sys/net/if_trunk.c,v
diff -u -p -r1.154 if_trunk.c
--- net/if_trunk.c	23 Dec 2023 10:52:54 -0000	1.154
+++ net/if_trunk.c	23 Oct 2024 07:29:22 -0000
@@ -846,6 +846,12 @@ trunk_ioctl(struct ifnet *ifp, u_long cm
 	case SIOCSIFFLAGS:
 		error = ENETRESET;
 		break;
+
+	case SIOCSIFXFLAGS:
+		SLIST_FOREACH(tp, &tr->tr_ports, tp_entries)
+			ifsetlro(tp->tp_if, ISSET(ifr->ifr_flags, IFXF_LRO));
+		break;
+
 	case SIOCADDMULTI:
 		error = trunk_ether_addmulti(tr, ifr);
 		break;
Index: net/if_vlan.c
===================================================================
RCS file: /cvs/src/sys/net/if_vlan.c,v
diff -u -p -r1.219 if_vlan.c
--- net/if_vlan.c	9 Jun 2024 16:25:28 -0000	1.219
+++ net/if_vlan.c	23 Oct 2024 07:29:22 -0000
@@ -701,6 +701,13 @@ vlan_ioctl(struct ifnet *ifp, u_long cmd
 		}
 		break;
 
+	case SIOCSIFXFLAGS:
+		if ((ifp0 = if_get(sc->sc_ifidx0)) != NULL) {
+			ifsetlro(ifp0, ISSET(ifr->ifr_flags, IFXF_LRO));
+			if_put(ifp0);
+		}
+		break;
+
 	case SIOCSVNETID:
 		if (ifr->ifr_vnetid < EVL_VLID_MIN ||
 		    ifr->ifr_vnetid > EVL_VLID_MAX) {
Index: net/if_vxlan.c
===================================================================
RCS file: /cvs/src/sys/net/if_vxlan.c,v
diff -u -p -r1.99 if_vxlan.c
--- net/if_vxlan.c	23 Dec 2023 10:52:54 -0000	1.99
+++ net/if_vxlan.c	23 Oct 2024 07:29:22 -0000
@@ -729,6 +729,7 @@ vxlan_ioctl(struct ifnet *ifp, u_long cm
 	struct vxlan_softc *sc = ifp->if_softc;
 	struct ifreq *ifr = (struct ifreq *)data;
 	struct ifbrparam *bparam = (struct ifbrparam *)data;
+	struct ifnet *ifp0;
 	int error = 0;
 
 	switch (cmd) {
@@ -743,6 +744,13 @@ vxlan_ioctl(struct ifnet *ifp, u_long cm
 		} else {
 			if (ISSET(ifp->if_flags, IFF_RUNNING))
 				error = vxlan_down(sc);
+		}
+		break;
+
+	case SIOCSIFXFLAGS:
+		if ((ifp0 = if_get(sc->sc_if_index0)) != NULL) {
+			ifsetlro(ifp0, ISSET(ifr->ifr_flags, IFXF_LRO));
+			if_put(ifp0);
 		}
 		break;
 
Index: netinet/ip_carp.c
===================================================================
RCS file: /cvs/src/sys/netinet/ip_carp.c,v
diff -u -p -r1.363 ip_carp.c
--- netinet/ip_carp.c	14 Jul 2024 18:53:39 -0000	1.363
+++ netinet/ip_carp.c	23 Oct 2024 07:29:22 -0000
@@ -2012,6 +2012,13 @@ carp_ioctl(struct ifnet *ifp, u_long cmd
 		}
 		break;
 
+	case SIOCSIFXFLAGS:
+		if ((ifp0 = if_get(sc->sc_carpdevidx)) != NULL) {
+			ifsetlro(ifp0, ISSET(ifr->ifr_flags, IFXF_LRO));
+			if_put(ifp0);
+		}
+		break;
+
 	case SIOCSVH:
 		KERNEL_ASSERT_LOCKED(); /* touching carp_vhosts */
 		vhe = SRPL_FIRST_LOCKED(&sc->carp_vhosts);