if_tuntap: add LRO support to tap devices

This allows testing the LRO code with packetdrill in local mode.

Reviewed by:		rscheff
Sponsored by:		Netflix, Inc.
Differential Revision:	https://reviews.freebsd.org/D42548

(cherry picked from commit 99c79cab422705f92f05a2924a29bdf823372ebf)
This commit is contained in:
Michael Tuexen 2023-11-19 15:57:53 +01:00
parent 83e524e8f6
commit fded38cde7

View file

@ -97,6 +97,7 @@
#endif
#include <netinet/udp.h>
#include <netinet/tcp.h>
#include <netinet/tcp_lro.h>
#include <net/bpf.h>
#include <net/if_tap.h>
#include <net/if_tun.h>
@ -144,6 +145,8 @@ struct tuntap_softc {
struct ether_addr tun_ether; /* remote address */
int tun_busy; /* busy count */
int tun_vhdrlen; /* virtio-net header length */
struct lro_ctrl tun_lro; /* for TCP LRO */
bool tun_lro_ready; /* TCP LRO initialized */
};
#define TUN2IFP(sc) ((sc)->tun_ifp)
@ -978,7 +981,8 @@ tuncreate(struct cdev *dev)
IFQ_SET_MAXLEN(&ifp->if_snd, ifqmaxlen);
ifp->if_capabilities |= IFCAP_LINKSTATE;
if ((tp->tun_flags & TUN_L2) != 0)
ifp->if_capabilities |= IFCAP_RXCSUM | IFCAP_RXCSUM_IPV6;
ifp->if_capabilities |=
IFCAP_RXCSUM | IFCAP_RXCSUM_IPV6 | IFCAP_LRO;
ifp->if_capenable |= IFCAP_LINKSTATE;
if ((tp->tun_flags & TUN_L2) != 0) {
@ -1175,6 +1179,12 @@ tundtor(void *data)
(l2tun && (ifp->if_flags & IFF_LINK0) != 0))
goto out;
if (l2tun && tp->tun_lro_ready) {
TUNDEBUG (ifp, "LRO disabled\n");
tcp_lro_free(&tp->tun_lro);
tp->tun_lro_ready = false;
}
if (ifp->if_flags & IFF_UP) {
TUN_UNLOCK(tp);
if_down(ifp);
@ -1219,6 +1229,14 @@ tuninit(struct ifnet *ifp)
getmicrotime(&ifp->if_lastchange);
TUN_UNLOCK(tp);
} else {
if (tcp_lro_init(&tp->tun_lro) == 0) {
TUNDEBUG(ifp, "LRO enabled\n");
tp->tun_lro.ifp = ifp;
tp->tun_lro_ready = true;
} else {
TUNDEBUG(ifp, "Could not enable LRO\n");
tp->tun_lro_ready = false;
}
ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
TUN_UNLOCK(tp);
/* attempt to start output */
@ -1765,6 +1783,7 @@ tunwrite_l2(struct tuntap_softc *tp, struct mbuf *m,
struct epoch_tracker et;
struct ether_header *eh;
struct ifnet *ifp;
int result;
ifp = TUN2IFP(tp);
@ -1820,7 +1839,15 @@ tunwrite_l2(struct tuntap_softc *tp, struct mbuf *m,
/* Pass packet up to parent. */
CURVNET_SET(ifp->if_vnet);
NET_EPOCH_ENTER(et);
(*ifp->if_input)(ifp, m);
if (tp->tun_lro_ready && ifp->if_capenable & IFCAP_LRO) {
result = tcp_lro_rx(&tp->tun_lro, m, 0);
TUNDEBUG(ifp, "tcp_lro_rx() returned %d\n", result);
} else
result = TCP_LRO_CANNOT;
if (result == 0)
tcp_lro_flush_all(&tp->tun_lro);
else
(*ifp->if_input)(ifp, m);
NET_EPOCH_EXIT(et);
CURVNET_RESTORE();
/* ibytes are counted in parent */