Index: sys/netinet/ip_fastfwd.c =================================================================== --- sys/netinet/ip_fastfwd.c +++ sys/netinet/ip_fastfwd.c @@ -105,6 +105,7 @@ #include #include #include +#include #include @@ -160,7 +161,7 @@ struct sockaddr_in *dst = NULL; struct ifnet *ifp; struct in_addr odest, dest; - uint16_t ip_len, ip_off; + uint16_t ip_len, ip_off, tcp_len; int error = 0; int mtu; struct m_tag *fwd_tag = NULL; @@ -429,7 +430,37 @@ else mtu = ifp->if_mtu; - if (ip_len <= mtu) { + /* + * Allow forwarding TSO packets directly if the outbound + * interface also supports TSO. + * + * This is very important when using VMs to perform intra-host + * packet routing. Since the packet never hits the wire the + * TCP segments are not actually generated until it reaches a + * physical interface, and thus we get to see TSO packets on + * input. + * + * Not doing this means that the backend domain (usually Dom0) + * would have to perform software TCP segmentation for us, which + * will introduce a huge performance penalty. + */ + if ((m->m_pkthdr.csum_flags & CSUM_TSO) != 0 && + ip->ip_p == IPPROTO_TCP) { + struct tcphdr th; + + m_copydata(m, sizeof(struct ip), sizeof(struct tcphdr), + (caddr_t) &th); + tcp_len = ip_len - (sizeof(struct ip) + (th.th_off << 2)); + } + + if ((ip_len <= mtu) || (ip->ip_p == IPPROTO_TCP && + (m->m_pkthdr.csum_flags & CSUM_TSO) != 0 && + (ifp->if_hwassist & CSUM_TSO) != 0 && + (ifp->if_capenable & IFCAP_TSO4) != 0 && + (m->m_pkthdr.tso_segsz <= ifp->if_hw_tsomaxsegsize) && + howmany(tcp_len, m->m_pkthdr.tso_segsz) <= + ifp->if_hw_tsomaxsegcount && + tcp_len <= ifp->if_hw_tsomax)) { /* * Avoid confusing lower layers. */