The branch main has been updated by tuexen: URL: https://cgit.FreeBSD.org/src/commit/?id=39d4094173f9a49ff52f5f4408e4dbd5d6ef0409
commit 39d4094173f9a49ff52f5f4408e4dbd5d6ef0409 Author: Timo Völker <timo.voel...@fh-muenster.de> AuthorDate: 2025-09-04 12:06:20 +0000 Commit: Michael Tuexen <tue...@freebsd.org> CommitDate: 2025-09-04 12:06:20 +0000 epair: add support for checksum offloading Add capabilities RXCSUM and RXCSUM6 as well as TXCSUM and TXCSUM6 for for receive and transmit checksum offloading for TCP and UDP to the epair interface and enable them by default. RXCSUM and RXCSUM6 are enabled because an epair interface may receive a packet with the csum_flag CSUM_DATA_VALID set, which is expected only if these capabilities are enabled. Since it seems not helpful to remove this flag, it is not possible to disable these capabilities. TXCSUM and TXCSUM6 are synchronized between the two epair interface ends. If enabled/disabled on one end, it will be enabled/disabled on the other end. If the sending epair interface end has TXCSUM or TXCSUM6 enabled and the receiving end is in a bridge, it is assumed that all interfaces in the bridge have that capability enabled. Otherwise the bridge would have disabled that capability on the receiving epair interface end in the bridge which would have disabled that capability on the sending epair interface end as well due to the synchronization. This change was committed and reverted earlier, since several pf tests were failing. This has been addressed. Reviewed by: bcr, Seyed Pouria Mousavizadeh Tehrani, tuexen MFC after: 4 weeks Differential Revision: https://reviews.freebsd.org/D51639 --- share/man/man4/epair.4 | 25 ++++++++++++++++++++- sys/net/if_epair.c | 61 ++++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 83 insertions(+), 3 deletions(-) diff --git a/share/man/man4/epair.4 b/share/man/man4/epair.4 index 342b15b5612a..b406c423361b 100644 --- a/share/man/man4/epair.4 +++ b/share/man/man4/epair.4 @@ -25,7 +25,7 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.Dd August 12, 2025 +.Dd September 4, 2025 .Dt EPAIR 4 .Os .Sh NAME @@ -108,6 +108,29 @@ As with any other Ethernet interface, can have a .Xr vlan 4 configured on top of it. +.Pp +The +.Nm +has RXCSUM and RXCSUM6 enabled because it may receive a packet where the +checksum has already been validated by a physical interface. +The +.Nm +supports TXCSUM and TXCSUM6 for TCP and UDP, but only by forwarding the order +to compute the checksum. +Thus, when using an +.Nm +interface, a TCP or UDP sender can offload checksum computation +to a physical interface. +Note that, in case the packet does not leave the host, the checksum is +unnecessary and will be ignored if offloaded. +Such packets contain an incorrect checksum, since it is not computed yet. +TXCSUM and TXCSUM6 are synchronized between the +.Nm +interface pair (i.e., enabling/disabling the capability on one end +enables/disables it on the other end). +In case one end is in a bridge and the bridge disabled TXCSUM or TXCSUM6, +this avoids a sender to send packets with checksum offloading into the +bridge by using the other end. .Sh SEE ALSO .Xr ioctl 2 , .Xr altq 4 , diff --git a/sys/net/if_epair.c b/sys/net/if_epair.c index 581c2434b8fb..fbffa8f359a0 100644 --- a/sys/net/if_epair.c +++ b/sys/net/if_epair.c @@ -69,6 +69,7 @@ #include <net/if_media.h> #include <net/if_private.h> #include <net/if_types.h> +#include <net/if_vlan_var.h> #include <net/netisr.h> #ifdef RSS #include <net/rss_config.h> @@ -434,6 +435,21 @@ epair_media_status(struct ifnet *ifp __unused, struct ifmediareq *imr) imr->ifm_active = IFM_ETHER | IFM_10G_T | IFM_FDX; } +/* + * Update ifp->if_hwassist according to the current value of ifp->if_capenable. + */ +static void +epair_caps_changed(struct ifnet *ifp) +{ + uint64_t hwassist = 0; + + if (ifp->if_capenable & IFCAP_TXCSUM) + hwassist |= CSUM_IP_TCP | CSUM_IP_UDP; + if (ifp->if_capenable & IFCAP_TXCSUM_IPV6) + hwassist |= CSUM_IP6_TCP | CSUM_IP6_UDP; + ifp->if_hwassist = hwassist; +} + static int epair_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) { @@ -461,6 +477,44 @@ epair_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) error = 0; break; + case SIOCGIFCAP: + ifr->ifr_reqcap = ifp->if_capabilities; + ifr->ifr_curcap = ifp->if_capenable; + error = 0; + break; + case SIOCSIFCAP: + /* + * Enable/disable capabilities as requested, besides + * IFCAP_RXCSUM(_IPV6), which always remain enabled. + * Incoming packets may have the mbuf flag CSUM_DATA_VALID set. + * Without IFCAP_RXCSUM(_IPV6), this flag would have to be + * removed, which does not seem helpful. + */ + ifp->if_capenable = ifr->ifr_reqcap | IFCAP_RXCSUM | + IFCAP_RXCSUM_IPV6; + epair_caps_changed(ifp); + /* + * If IFCAP_TXCSUM(_IPV6) has been changed, change it on the + * other epair interface as well. + * A bridge disables IFCAP_TXCSUM(_IPV6) when adding one epair + * interface if another interface in the bridge has it disabled. + * In that case this capability needs to be disabled on the + * other epair interface to avoid sending packets in the bridge + * that rely on this capability. + */ + sc = ifp->if_softc; + if ((ifp->if_capenable ^ sc->oifp->if_capenable) & + (IFCAP_TXCSUM | IFCAP_TXCSUM_IPV6)) { + sc->oifp->if_capenable &= + ~(IFCAP_TXCSUM | IFCAP_TXCSUM_IPV6); + sc->oifp->if_capenable |= ifp->if_capenable & + (IFCAP_TXCSUM | IFCAP_TXCSUM_IPV6); + epair_caps_changed(sc->oifp); + } + VLAN_CAPABILITIES(ifp); + error = 0; + break; + default: /* Let the common ethernet handler process this. */ error = ether_ioctl(ifp, cmd, data); @@ -572,8 +626,11 @@ epair_setup_ifp(struct epair_softc *sc, char *name, int unit) ifp->if_dname = epairname; ifp->if_dunit = unit; ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; - ifp->if_capabilities = IFCAP_VLAN_MTU; - ifp->if_capenable = IFCAP_VLAN_MTU; + ifp->if_capabilities = IFCAP_VLAN_MTU | IFCAP_TXCSUM | + IFCAP_TXCSUM_IPV6 | IFCAP_RXCSUM | IFCAP_RXCSUM_IPV6; + ifp->if_capenable = IFCAP_VLAN_MTU | IFCAP_TXCSUM | + IFCAP_TXCSUM_IPV6 | IFCAP_RXCSUM | IFCAP_RXCSUM_IPV6; + epair_caps_changed(ifp); ifp->if_transmit = epair_transmit; ifp->if_qflush = epair_qflush; ifp->if_start = epair_start;