summaryrefslogtreecommitdiff
path: root/sys/netinet6
diff options
context:
space:
mode:
authorAlexander Bluhm <bluhm@cvs.openbsd.org>2023-05-10 12:07:18 +0000
committerAlexander Bluhm <bluhm@cvs.openbsd.org>2023-05-10 12:07:18 +0000
commit0e232e06e2a4a77df94f87d0ee99d98fb69ee3ee (patch)
tree26c382a6d5d3f2da26433865efada283fbeec0b2 /sys/netinet6
parentfb26bef824305de795cd43d0ca1b581776074f80 (diff)
Implement TCP send offloading, for now in software only. This is
meant as a fallback if network hardware does not support TSO. Driver support is still work in progress. TCP output generates large packets. In IP output the packet is chopped to TCP maximum segment size. This reduces the CPU cycles used by pf. The regular output could be assisted by hardware later, but pf route-to and IPsec needs the software fallback in general. For performance comparison or to workaround possible bugs, sysctl net.inet.tcp.tso=0 disables the feature. netstat -s -p tcp shows TSO counter with chopped and generated packets. based on work from jan@ tested by jmc@ jan@ Hrvoje Popovski OK jan@ claudio@
Diffstat (limited to 'sys/netinet6')
-rw-r--r--sys/netinet6/ip6_output.c63
1 files changed, 50 insertions, 13 deletions
diff --git a/sys/netinet6/ip6_output.c b/sys/netinet6/ip6_output.c
index dfa2a3c5245..b14ffbe4106 100644
--- a/sys/netinet6/ip6_output.c
+++ b/sys/netinet6/ip6_output.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ip6_output.c,v 1.274 2023/05/08 13:22:13 bluhm Exp $ */
+/* $OpenBSD: ip6_output.c,v 1.275 2023/05/10 12:07:17 bluhm Exp $ */
/* $KAME: ip6_output.c,v 1.172 2001/03/25 09:55:56 itojun Exp $ */
/*
@@ -686,7 +686,9 @@ reroute:
dontfrag = 1;
else
dontfrag = 0;
- if (dontfrag && tlen > ifp->if_mtu) { /* case 2-b */
+ if (dontfrag && /* case 2-b */
+ (ISSET(m->m_pkthdr.csum_flags, M_TCP_TSO) ?
+ m->m_pkthdr.csum_flags : tlen) > ifp->if_mtu) {
#ifdef IPSEC
if (ip_mtudisc)
ipsec_adjust_mtu(m, mtu);
@@ -698,12 +700,22 @@ reroute:
/*
* transmit packet without fragmentation
*/
- if (dontfrag || (tlen <= mtu)) { /* case 1-a and 2-a */
+ if (dontfrag || tlen <= mtu) { /* case 1-a and 2-a */
in6_proto_cksum_out(m, ifp);
error = ifp->if_output(ifp, m, sin6tosa(dst), ro->ro_rt);
goto done;
}
+ if (ISSET(m->m_pkthdr.csum_flags, M_TCP_TSO) &&
+ m->m_pkthdr.ph_mss <= mtu) {
+ if ((error = tcp_chopper(m, &ml, ifp, m->m_pkthdr.ph_mss)) ||
+ (error = if_output_ml(ifp, &ml, sin6tosa(dst), ro->ro_rt)))
+ goto done;
+ tcpstat_inc(tcps_outswtso);
+ goto done;
+ }
+ CLR(m->m_pkthdr.csum_flags, M_TCP_TSO);
+
/*
* try to fragment the packet. case 1-b
*/
@@ -2829,12 +2841,12 @@ int
ip6_output_ipsec_send(struct tdb *tdb, struct mbuf *m, struct route_in6 *ro,
int tunalready, int fwd)
{
-#if NPF > 0
- struct ifnet *encif;
-#endif
+ struct mbuf_list ml;
+ struct ifnet *encif = NULL;
struct ip6_hdr *ip6;
struct in6_addr dst;
- int error, ifidx, rtableid;
+ u_int len;
+ int error, ifidx, rtableid, tso = 0;
#if NPF > 0
/*
@@ -2854,17 +2866,23 @@ ip6_output_ipsec_send(struct tdb *tdb, struct mbuf *m, struct route_in6 *ro,
* Until now the change was not reconsidered.
* What's the behaviour?
*/
- in6_proto_cksum_out(m, encif);
#endif
- /* Check if we are allowed to fragment */
+ /* Check if we can chop the TCP packet */
ip6 = mtod(m, struct ip6_hdr *);
+ if (ISSET(m->m_pkthdr.csum_flags, M_TCP_TSO) &&
+ m->m_pkthdr.ph_mss <= tdb->tdb_mtu) {
+ tso = 1;
+ len = m->m_pkthdr.ph_mss;
+ } else
+ len = sizeof(struct ip6_hdr) + ntohs(ip6->ip6_plen);
+
+ /* Check if we are allowed to fragment */
dst = ip6->ip6_dst;
ifidx = m->m_pkthdr.ph_ifidx;
rtableid = m->m_pkthdr.ph_rtableid;
if (ip_mtudisc && tdb->tdb_mtu &&
- sizeof(struct ip6_hdr) + ntohs(ip6->ip6_plen) > tdb->tdb_mtu &&
- tdb->tdb_mtutimeout > gettime()) {
+ len > tdb->tdb_mtu && tdb->tdb_mtutimeout > gettime()) {
int transportmode;
transportmode = (tdb->tdb_dst.sa.sa_family == AF_INET6) &&
@@ -2891,14 +2909,33 @@ ip6_output_ipsec_send(struct tdb *tdb, struct mbuf *m, struct route_in6 *ro,
*/
m->m_flags &= ~(M_BCAST | M_MCAST);
- /* Callee frees mbuf */
+ if (tso) {
+ error = tcp_chopper(m, &ml, encif, len);
+ if (error)
+ goto done;
+ } else {
+ CLR(m->m_pkthdr.csum_flags, M_TCP_TSO);
+ in6_proto_cksum_out(m, encif);
+ ml_init(&ml);
+ ml_enqueue(&ml, m);
+ }
+
KERNEL_LOCK();
- error = ipsp_process_packet(m, tdb, AF_INET6, tunalready);
+ while ((m = ml_dequeue(&ml)) != NULL) {
+ /* Callee frees mbuf */
+ error = ipsp_process_packet(m, tdb, AF_INET6, tunalready);
+ if (error)
+ break;
+ }
KERNEL_UNLOCK();
+ done:
if (error) {
+ ml_purge(&ml);
ipsecstat_inc(ipsec_odrops);
tdbstat_inc(tdb, tdb_odrops);
}
+ if (!error && tso)
+ tcpstat_inc(tcps_outswtso);
if (ip_mtudisc && error == EMSGSIZE)
ip6_output_ipsec_pmtu_update(tdb, ro, &dst, ifidx, rtableid, 0);
return error;