hyperv/hn: Set tcp header offset for CSUM/LSO offloading.

No observable effect; better safe than sorry.

MFC after:	1 week
Sponsored by:	Microsoft
Differential Revision:	https://reviews.freebsd.org/D12417
This commit is contained in:
Sepherosa Ziehau 2017-09-27 04:42:40 +00:00
parent a79d52d739
commit c49d47daf3
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=324048
2 changed files with 70 additions and 27 deletions

View File

@ -727,6 +727,7 @@ hn_tso_fixup(struct mbuf *m_head)
ehlen = ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN;
else
ehlen = ETHER_HDR_LEN;
m_head->m_pkthdr.l2hlen = ehlen;
#ifdef INET
if (m_head->m_pkthdr.csum_flags & CSUM_IP_TSO) {
@ -736,6 +737,7 @@ hn_tso_fixup(struct mbuf *m_head)
PULLUP_HDR(m_head, ehlen + sizeof(*ip));
ip = mtodo(m_head, ehlen);
iphlen = ip->ip_hl << 2;
m_head->m_pkthdr.l3hlen = iphlen;
PULLUP_HDR(m_head, ehlen + iphlen + sizeof(*th));
th = mtodo(m_head, ehlen + iphlen);
@ -759,6 +761,7 @@ hn_tso_fixup(struct mbuf *m_head)
m_freem(m_head);
return (NULL);
}
m_head->m_pkthdr.l3hlen = sizeof(*ip6);
PULLUP_HDR(m_head, ehlen + sizeof(*ip6) + sizeof(*th));
th = mtodo(m_head, ehlen + sizeof(*ip6));
@ -768,41 +771,34 @@ hn_tso_fixup(struct mbuf *m_head)
}
#endif
return (m_head);
}
/*
* NOTE: If this function failed, the m_head would be freed.
*/
static __inline struct mbuf *
hn_check_tcpsyn(struct mbuf *m_head, int *tcpsyn)
hn_set_hlen(struct mbuf *m_head)
{
const struct ether_vlan_header *evl;
const struct tcphdr *th;
int ehlen;
*tcpsyn = 0;
PULLUP_HDR(m_head, sizeof(*evl));
evl = mtod(m_head, const struct ether_vlan_header *);
if (evl->evl_encap_proto == ntohs(ETHERTYPE_VLAN))
ehlen = ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN;
else
ehlen = ETHER_HDR_LEN;
m_head->m_pkthdr.l2hlen = ehlen;
#ifdef INET
if (m_head->m_pkthdr.csum_flags & CSUM_IP_TCP) {
if (m_head->m_pkthdr.csum_flags & (CSUM_IP_TCP | CSUM_IP_UDP)) {
const struct ip *ip;
int iphlen;
PULLUP_HDR(m_head, ehlen + sizeof(*ip));
ip = mtodo(m_head, ehlen);
iphlen = ip->ip_hl << 2;
PULLUP_HDR(m_head, ehlen + iphlen + sizeof(*th));
th = mtodo(m_head, ehlen + iphlen);
if (th->th_flags & TH_SYN)
*tcpsyn = 1;
m_head->m_pkthdr.l3hlen = iphlen;
}
#endif
#if defined(INET6) && defined(INET)
@ -814,18 +810,36 @@ hn_check_tcpsyn(struct mbuf *m_head, int *tcpsyn)
PULLUP_HDR(m_head, ehlen + sizeof(*ip6));
ip6 = mtodo(m_head, ehlen);
if (ip6->ip6_nxt != IPPROTO_TCP)
return (m_head);
PULLUP_HDR(m_head, ehlen + sizeof(*ip6) + sizeof(*th));
th = mtodo(m_head, ehlen + sizeof(*ip6));
if (th->th_flags & TH_SYN)
*tcpsyn = 1;
if (ip6->ip6_nxt != IPPROTO_TCP) {
m_freem(m_head);
return (NULL);
}
m_head->m_pkthdr.l3hlen = sizeof(*ip6);
}
#endif
return (m_head);
}
/*
* NOTE: If this function failed, the m_head would be freed.
*/
static __inline struct mbuf *
hn_check_tcpsyn(struct mbuf *m_head, int *tcpsyn)
{
const struct tcphdr *th;
int ehlen, iphlen;
*tcpsyn = 0;
ehlen = m_head->m_pkthdr.l2hlen;
iphlen = m_head->m_pkthdr.l3hlen;
PULLUP_HDR(m_head, ehlen + iphlen + sizeof(*th));
th = mtodo(m_head, ehlen + iphlen);
if (th->th_flags & TH_SYN)
*tcpsyn = 1;
return (m_head);
}
#undef PULLUP_HDR
#endif /* INET6 || INET */
@ -3010,7 +3024,8 @@ hn_encap(struct ifnet *ifp, struct hn_tx_ring *txr, struct hn_txdesc *txd,
NDIS_LSO2_INFO_SIZE, NDIS_PKTINFO_TYPE_LSO);
#ifdef INET
if (m_head->m_pkthdr.csum_flags & CSUM_IP_TSO) {
*pi_data = NDIS_LSO2_INFO_MAKEIPV4(0,
*pi_data = NDIS_LSO2_INFO_MAKEIPV4(
m_head->m_pkthdr.l2hlen + m_head->m_pkthdr.l3hlen,
m_head->m_pkthdr.tso_segsz);
}
#endif
@ -3019,7 +3034,8 @@ hn_encap(struct ifnet *ifp, struct hn_tx_ring *txr, struct hn_txdesc *txd,
#endif
#ifdef INET6
{
*pi_data = NDIS_LSO2_INFO_MAKEIPV6(0,
*pi_data = NDIS_LSO2_INFO_MAKEIPV6(
m_head->m_pkthdr.l2hlen + m_head->m_pkthdr.l3hlen,
m_head->m_pkthdr.tso_segsz);
}
#endif
@ -3036,11 +3052,15 @@ hn_encap(struct ifnet *ifp, struct hn_tx_ring *txr, struct hn_txdesc *txd,
*pi_data |= NDIS_TXCSUM_INFO_IPCS;
}
if (m_head->m_pkthdr.csum_flags & (CSUM_IP_TCP | CSUM_IP6_TCP))
*pi_data |= NDIS_TXCSUM_INFO_TCPCS;
else if (m_head->m_pkthdr.csum_flags &
(CSUM_IP_UDP | CSUM_IP6_UDP))
*pi_data |= NDIS_TXCSUM_INFO_UDPCS;
if (m_head->m_pkthdr.csum_flags &
(CSUM_IP_TCP | CSUM_IP6_TCP)) {
*pi_data |= NDIS_TXCSUM_INFO_MKTCPCS(
m_head->m_pkthdr.l2hlen + m_head->m_pkthdr.l3hlen);
} else if (m_head->m_pkthdr.csum_flags &
(CSUM_IP_UDP | CSUM_IP6_UDP)) {
*pi_data |= NDIS_TXCSUM_INFO_MKUDPCS(
m_head->m_pkthdr.l2hlen + m_head->m_pkthdr.l3hlen);
}
}
pkt_hlen = pkt->rm_pktinfooffset + pkt->rm_pktinfolen;
@ -5566,6 +5586,13 @@ hn_start_locked(struct hn_tx_ring *txr, int len)
if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
continue;
}
} else if (m_head->m_pkthdr.csum_flags &
(CSUM_IP_UDP | CSUM_IP_TCP | CSUM_IP6_UDP | CSUM_IP6_TCP)) {
m_head = hn_set_hlen(m_head);
if (__predict_false(m_head == NULL)) {
if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
continue;
}
}
#endif
@ -5846,8 +5873,8 @@ hn_transmit(struct ifnet *ifp, struct mbuf *m)
#if defined(INET6) || defined(INET)
/*
* Perform TSO packet header fixup now, since the TSO
* packet header should be cache-hot.
* Perform TSO packet header fixup or get l2/l3 header length now,
* since packet headers should be cache-hot.
*/
if (m->m_pkthdr.csum_flags & CSUM_TSO) {
m = hn_tso_fixup(m);
@ -5855,6 +5882,13 @@ hn_transmit(struct ifnet *ifp, struct mbuf *m)
if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
return EIO;
}
} else if (m->m_pkthdr.csum_flags &
(CSUM_IP_UDP | CSUM_IP_TCP | CSUM_IP6_UDP | CSUM_IP6_TCP)) {
m = hn_set_hlen(m);
if (__predict_false(m == NULL)) {
if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
return EIO;
}
}
#endif

View File

@ -402,4 +402,13 @@ struct ndis_offload {
#define NDIS_TXCSUM_INFO_IPCS 0x00000010
#define NDIS_TXCSUM_INFO_THOFF 0x03ff0000
#define NDIS_TXCSUM_INFO_MKL4CS(thoff, flag) \
((((uint32_t)(thoff)) << 16) | (flag))
#define NDIS_TXCSUM_INFO_MKTCPCS(thoff) \
NDIS_TXCSUM_INFO_MKL4CS((thoff), NDIS_TXCSUM_INFO_TCPCS)
#define NDIS_TXCSUM_INFO_MKUDPCS(thoff) \
NDIS_TXCSUM_INFO_MKL4CS((thoff), NDIS_TXCSUM_INFO_UDPCS)
#endif /* !_NET_NDIS_H_ */