diff --git a/share/man/man4/epair.4 b/share/man/man4/epair.4 --- 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 March 18, 2015 +.Dd July 30, 2025 .Dt EPAIR 4 .Os .Sh NAME @@ -96,6 +96,21 @@ can have a .Xr vlan 4 configured on top of it. +.Pp +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. +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). .Sh SEE ALSO .Xr ioctl 2 , .Xr altq 4 , diff --git a/sys/net/if_epair.c b/sys/net/if_epair.c --- a/sys/net/if_epair.c +++ b/sys/net/if_epair.c @@ -66,9 +66,9 @@ #include #include #include -#include #include #include +#include #include #ifdef RSS #include @@ -96,6 +96,7 @@ #define EPAIR_LOCK_DESTROY() mtx_destroy(&epair_n_index_mtx) #define EPAIR_LOCK() mtx_lock(&epair_n_index_mtx) #define EPAIR_UNLOCK() mtx_unlock(&epair_n_index_mtx) +#define EPAIR_LOCK_ASSERT() mtx_assert(&epair_n_index_mtx, MA_OWNED); struct epair_softc; struct epair_queue { @@ -425,6 +426,23 @@ imr->ifm_active = IFM_ETHER | IFM_10G_T | IFM_FDX; } +/* + * To be called under EPAIR_LOCK. 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; + + EPAIR_LOCK_ASSERT(); + 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) { @@ -452,6 +470,33 @@ error = 0; break; + case SIOCGIFCAP: + ifr->ifr_reqcap = ifp->if_capabilities; + ifr->ifr_curcap = ifp->if_capenable; + error = 0; + break; + case SIOCSIFCAP: + sc = ifp->if_softc; + EPAIR_LOCK(); + ifp->if_capenable = ifr->ifr_reqcap; + epair_caps_changed(ifp); + /* + * If IFCAP_TXCSUM(_IPV6) has been changed, change it on the + * other epair interface as well. + */ + 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); + } + EPAIR_UNLOCK(); + VLAN_CAPABILITIES(ifp); + error = 0; + break; + default: /* Let the common ethernet handler process this. */ error = ether_ioctl(ifp, cmd, data); @@ -549,8 +594,12 @@ ifp->if_dname = epairname; ifp->if_dunit = unit; ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; - ifp->if_capabilities = IFCAP_VLAN_MTU; + EPAIR_LOCK(); + ifp->if_capabilities = IFCAP_VLAN_MTU | IFCAP_TXCSUM | + IFCAP_TXCSUM_IPV6 | IFCAP_RXCSUM | IFCAP_RXCSUM_IPV6; ifp->if_capenable = IFCAP_VLAN_MTU; + epair_caps_changed(ifp); + EPAIR_UNLOCK(); ifp->if_transmit = epair_transmit; ifp->if_qflush = epair_qflush; ifp->if_start = epair_start;