Index | Thread | Search

From:
Jan Klemkow <jan@openbsd.org>
Subject:
Re: Use SoftLRO in em(4)
To:
tech@openbsd.org
Date:
Tue, 11 Nov 2025 19:01:34 +0100

Download raw body.

Thread
Hi Stefan,

On Tue, Nov 11, 2025 at 03:05:02PM +0100, Stefan Sperling wrote:
> On Tue, Nov 04, 2025 at 01:27:20PM +0100, Jan Klemkow wrote:
> > This diff adds the use of SoftLRO in em(4).
> > 
> > It uses the E1000_RXD_STAT_TCPCS and E1000_RXD_STAT_UDPCS flags to
> > distinguish between TCP and non-TCP packets.  Both flags are set on UDP
> > packets and just E1000_RXD_STAT_TCPCS and TCP ones.  Thus, I ended up
> > with the TCP and !UDP logic below.
> > 
> > More tests especially on older hardware are welcome.
> > 
> > I tested it with:
> > em0 at pci2 dev 0 function 0 "Intel I210" rev 0x03: msi, address a8:a1:59:f2:a4:81
> > em1 at pci3 dev 0 function 0 "Intel I210" rev 0x03: msi, address a8:a1:59:f2:a4:82
> > 
> > ok?
> > 
> > bye,
> > Jan
> 
> This diff breaks the RAMDISK_CD build:
> 
>   ld: error: undefined symbol: tcp_softlro_glue
>   >>> referenced by if_em.c:3196 (/usr/src/sys/dev/pci/if_em.c:3196)
>   >>>               if_em.o:(em_rxeof)
> 
> Looks like some more ifndef SMALL will be needed.

Yes, I missed that.

ok?

Thanks,
Jan

Index: dev/pci/if_em.c
===================================================================
RCS file: /cvs/src/sys/dev/pci/if_em.c,v
diff -u -p -r1.379 if_em.c
--- dev/pci/if_em.c	14 Jul 2025 11:52:43 -0000	1.379
+++ dev/pci/if_em.c	11 Nov 2025 17:40:38 -0000
@@ -2013,6 +2013,9 @@ em_setup_interface(struct em_softc *sc)
 		ifp->if_capabilities |= IFCAP_TSOv4 | IFCAP_TSOv6;
 	}
 
+	ifp->if_capabilities |= IFCAP_LRO;
+	ifp->if_xflags |= IFXF_LRO;
+
 	/* 
 	 * Specify the media types supported by this adapter and register
 	 * callbacks to update media and link information
@@ -3066,12 +3069,13 @@ em_rxeof(struct em_queue *que)
 {
 	struct em_softc	    *sc = que->sc;
 	struct ifnet	    *ifp = &sc->sc_ac.ac_if;
+	struct mbuf_list    mltcp = MBUF_LIST_INITIALIZER();
 	struct mbuf_list    ml = MBUF_LIST_INITIALIZER();
 	struct mbuf	    *m;
 	u_int8_t	    accept_frame = 0;
 	u_int8_t	    eop = 0;
 	u_int16_t	    len, desc_len, prev_len_adj;
-	int		    i, rv = 0;
+	int		    i, rv = 0, livelocked = 0;
 
 	/* Pointer to the receive descriptor being examined. */
 	struct em_rx_desc   *desc;
@@ -3186,7 +3190,14 @@ em_rxeof(struct em_queue *que)
 					m->m_flags |= M_VLANTAG;
 				}
 #endif
-				ml_enqueue(&ml, m);
+#ifndef SMALL_KERNEL
+				if (ISSET(ifp->if_xflags, IFXF_LRO) &&
+				    desc->status & E1000_RXD_STAT_TCPCS &&
+				    !(desc->status & E1000_RXD_STAT_UDPCS))
+					tcp_softlro_glue(&mltcp, m, ifp);
+				else
+#endif
+					ml_enqueue(&ml, m);
 
 				que->rx.fmp = NULL;
 				que->rx.lmp = NULL;
@@ -3214,7 +3225,11 @@ em_rxeof(struct em_queue *que)
 
 	que->rx.sc_rx_desc_tail = i;
 
+	if (ifiq_input(&ifp->if_rcv, &mltcp))
+		livelocked = 1;
 	if (ifiq_input(&ifp->if_rcv, &ml))
+		livelocked = 1;
+	if (livelocked)
 		if_rxr_livelocked(&que->rx.sc_rx_ring);
 
 	return (rv);