aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Tuexen <tuexen@FreeBSD.org>2023-11-19 14:57:53 +0000
committerMichael Tuexen <tuexen@FreeBSD.org>2024-01-12 17:02:35 +0000
commitfded38cde763e77ec13c8df041788ac3a473ca00 (patch)
treee676979f22978f1e66471c91c0ca8265e1dcfb30
parent83e524e8f6567f7f336304eb3f2f9ceeea68cd66 (diff)
downloadsrc-fded38cde763e77ec13c8df041788ac3a473ca00.tar.gz
src-fded38cde763e77ec13c8df041788ac3a473ca00.zip
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)
-rw-r--r--sys/net/if_tuntap.c31
1 files changed, 29 insertions, 2 deletions
diff --git a/sys/net/if_tuntap.c b/sys/net/if_tuntap.c
index 0de5b0d2d521..98c5044d6867 100644
--- a/sys/net/if_tuntap.c
+++ b/sys/net/if_tuntap.c
@@ -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 */