Changeset View
Changeset View
Standalone View
Standalone View
head/sys/dev/hyperv/netvsc/if_hn.c
Show First 20 Lines • Show All 721 Lines • ▼ Show 20 Lines | hn_tso_fixup(struct mbuf *m_head) | ||||
KASSERT(M_WRITABLE(m_head), ("TSO mbuf not writable")); | KASSERT(M_WRITABLE(m_head), ("TSO mbuf not writable")); | ||||
PULLUP_HDR(m_head, sizeof(*evl)); | PULLUP_HDR(m_head, sizeof(*evl)); | ||||
evl = mtod(m_head, struct ether_vlan_header *); | evl = mtod(m_head, struct ether_vlan_header *); | ||||
if (evl->evl_encap_proto == ntohs(ETHERTYPE_VLAN)) | if (evl->evl_encap_proto == ntohs(ETHERTYPE_VLAN)) | ||||
ehlen = ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN; | ehlen = ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN; | ||||
else | else | ||||
ehlen = ETHER_HDR_LEN; | ehlen = ETHER_HDR_LEN; | ||||
m_head->m_pkthdr.l2hlen = ehlen; | |||||
#ifdef INET | #ifdef INET | ||||
if (m_head->m_pkthdr.csum_flags & CSUM_IP_TSO) { | if (m_head->m_pkthdr.csum_flags & CSUM_IP_TSO) { | ||||
struct ip *ip; | struct ip *ip; | ||||
int iphlen; | int iphlen; | ||||
PULLUP_HDR(m_head, ehlen + sizeof(*ip)); | PULLUP_HDR(m_head, ehlen + sizeof(*ip)); | ||||
ip = mtodo(m_head, ehlen); | ip = mtodo(m_head, ehlen); | ||||
iphlen = ip->ip_hl << 2; | iphlen = ip->ip_hl << 2; | ||||
m_head->m_pkthdr.l3hlen = iphlen; | |||||
PULLUP_HDR(m_head, ehlen + iphlen + sizeof(*th)); | PULLUP_HDR(m_head, ehlen + iphlen + sizeof(*th)); | ||||
th = mtodo(m_head, ehlen + iphlen); | th = mtodo(m_head, ehlen + iphlen); | ||||
ip->ip_len = 0; | ip->ip_len = 0; | ||||
ip->ip_sum = 0; | ip->ip_sum = 0; | ||||
th->th_sum = in_pseudo(ip->ip_src.s_addr, | th->th_sum = in_pseudo(ip->ip_src.s_addr, | ||||
ip->ip_dst.s_addr, htons(IPPROTO_TCP)); | ip->ip_dst.s_addr, htons(IPPROTO_TCP)); | ||||
} | } | ||||
#endif | #endif | ||||
#if defined(INET6) && defined(INET) | #if defined(INET6) && defined(INET) | ||||
else | else | ||||
#endif | #endif | ||||
#ifdef INET6 | #ifdef INET6 | ||||
{ | { | ||||
struct ip6_hdr *ip6; | struct ip6_hdr *ip6; | ||||
PULLUP_HDR(m_head, ehlen + sizeof(*ip6)); | PULLUP_HDR(m_head, ehlen + sizeof(*ip6)); | ||||
ip6 = mtodo(m_head, ehlen); | ip6 = mtodo(m_head, ehlen); | ||||
if (ip6->ip6_nxt != IPPROTO_TCP) { | if (ip6->ip6_nxt != IPPROTO_TCP) { | ||||
m_freem(m_head); | m_freem(m_head); | ||||
return (NULL); | return (NULL); | ||||
} | } | ||||
m_head->m_pkthdr.l3hlen = sizeof(*ip6); | |||||
PULLUP_HDR(m_head, ehlen + sizeof(*ip6) + sizeof(*th)); | PULLUP_HDR(m_head, ehlen + sizeof(*ip6) + sizeof(*th)); | ||||
th = mtodo(m_head, ehlen + sizeof(*ip6)); | th = mtodo(m_head, ehlen + sizeof(*ip6)); | ||||
ip6->ip6_plen = 0; | ip6->ip6_plen = 0; | ||||
th->th_sum = in6_cksum_pseudo(ip6, 0, IPPROTO_TCP, 0); | th->th_sum = in6_cksum_pseudo(ip6, 0, IPPROTO_TCP, 0); | ||||
} | } | ||||
#endif | #endif | ||||
return (m_head); | return (m_head); | ||||
} | } | ||||
/* | /* | ||||
* NOTE: If this function failed, the m_head would be freed. | * NOTE: If this function failed, the m_head would be freed. | ||||
*/ | */ | ||||
static __inline struct mbuf * | 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 ether_vlan_header *evl; | ||||
const struct tcphdr *th; | |||||
int ehlen; | int ehlen; | ||||
*tcpsyn = 0; | |||||
PULLUP_HDR(m_head, sizeof(*evl)); | PULLUP_HDR(m_head, sizeof(*evl)); | ||||
evl = mtod(m_head, const struct ether_vlan_header *); | evl = mtod(m_head, const struct ether_vlan_header *); | ||||
if (evl->evl_encap_proto == ntohs(ETHERTYPE_VLAN)) | if (evl->evl_encap_proto == ntohs(ETHERTYPE_VLAN)) | ||||
ehlen = ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN; | ehlen = ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN; | ||||
else | else | ||||
ehlen = ETHER_HDR_LEN; | ehlen = ETHER_HDR_LEN; | ||||
m_head->m_pkthdr.l2hlen = ehlen; | |||||
#ifdef INET | #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; | const struct ip *ip; | ||||
int iphlen; | int iphlen; | ||||
PULLUP_HDR(m_head, ehlen + sizeof(*ip)); | PULLUP_HDR(m_head, ehlen + sizeof(*ip)); | ||||
ip = mtodo(m_head, ehlen); | ip = mtodo(m_head, ehlen); | ||||
iphlen = ip->ip_hl << 2; | 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); | |||||
if (th->th_flags & TH_SYN) | |||||
*tcpsyn = 1; | |||||
} | } | ||||
#endif | #endif | ||||
#if defined(INET6) && defined(INET) | #if defined(INET6) && defined(INET) | ||||
else | else | ||||
#endif | #endif | ||||
#ifdef INET6 | #ifdef INET6 | ||||
{ | { | ||||
const struct ip6_hdr *ip6; | const struct ip6_hdr *ip6; | ||||
PULLUP_HDR(m_head, ehlen + sizeof(*ip6)); | PULLUP_HDR(m_head, ehlen + sizeof(*ip6)); | ||||
ip6 = mtodo(m_head, ehlen); | ip6 = mtodo(m_head, ehlen); | ||||
if (ip6->ip6_nxt != IPPROTO_TCP) | if (ip6->ip6_nxt != IPPROTO_TCP) { | ||||
m_freem(m_head); | |||||
return (NULL); | |||||
} | |||||
m_head->m_pkthdr.l3hlen = sizeof(*ip6); | |||||
} | |||||
#endif | |||||
return (m_head); | return (m_head); | ||||
} | |||||
PULLUP_HDR(m_head, ehlen + sizeof(*ip6) + sizeof(*th)); | /* | ||||
th = mtodo(m_head, ehlen + sizeof(*ip6)); | * 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) | if (th->th_flags & TH_SYN) | ||||
*tcpsyn = 1; | *tcpsyn = 1; | ||||
} | |||||
#endif | |||||
return (m_head); | return (m_head); | ||||
} | } | ||||
#undef PULLUP_HDR | #undef PULLUP_HDR | ||||
#endif /* INET6 || INET */ | #endif /* INET6 || INET */ | ||||
static int | static int | ||||
▲ Show 20 Lines • Show All 2,171 Lines • ▼ Show 20 Lines | hn_encap(struct ifnet *ifp, struct hn_tx_ring *txr, struct hn_txdesc *txd, | ||||
} | } | ||||
if (m_head->m_pkthdr.csum_flags & CSUM_TSO) { | if (m_head->m_pkthdr.csum_flags & CSUM_TSO) { | ||||
#if defined(INET6) || defined(INET) | #if defined(INET6) || defined(INET) | ||||
pi_data = hn_rndis_pktinfo_append(pkt, HN_RNDIS_PKT_LEN, | pi_data = hn_rndis_pktinfo_append(pkt, HN_RNDIS_PKT_LEN, | ||||
NDIS_LSO2_INFO_SIZE, NDIS_PKTINFO_TYPE_LSO); | NDIS_LSO2_INFO_SIZE, NDIS_PKTINFO_TYPE_LSO); | ||||
#ifdef INET | #ifdef INET | ||||
if (m_head->m_pkthdr.csum_flags & CSUM_IP_TSO) { | 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); | m_head->m_pkthdr.tso_segsz); | ||||
} | } | ||||
#endif | #endif | ||||
#if defined(INET6) && defined(INET) | #if defined(INET6) && defined(INET) | ||||
else | else | ||||
#endif | #endif | ||||
#ifdef INET6 | #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); | m_head->m_pkthdr.tso_segsz); | ||||
} | } | ||||
#endif | #endif | ||||
#endif /* INET6 || INET */ | #endif /* INET6 || INET */ | ||||
} else if (m_head->m_pkthdr.csum_flags & txr->hn_csum_assist) { | } else if (m_head->m_pkthdr.csum_flags & txr->hn_csum_assist) { | ||||
pi_data = hn_rndis_pktinfo_append(pkt, HN_RNDIS_PKT_LEN, | pi_data = hn_rndis_pktinfo_append(pkt, HN_RNDIS_PKT_LEN, | ||||
NDIS_TXCSUM_INFO_SIZE, NDIS_PKTINFO_TYPE_CSUM); | NDIS_TXCSUM_INFO_SIZE, NDIS_PKTINFO_TYPE_CSUM); | ||||
if (m_head->m_pkthdr.csum_flags & | if (m_head->m_pkthdr.csum_flags & | ||||
(CSUM_IP6_TCP | CSUM_IP6_UDP)) { | (CSUM_IP6_TCP | CSUM_IP6_UDP)) { | ||||
*pi_data = NDIS_TXCSUM_INFO_IPV6; | *pi_data = NDIS_TXCSUM_INFO_IPV6; | ||||
} else { | } else { | ||||
*pi_data = NDIS_TXCSUM_INFO_IPV4; | *pi_data = NDIS_TXCSUM_INFO_IPV4; | ||||
if (m_head->m_pkthdr.csum_flags & CSUM_IP) | if (m_head->m_pkthdr.csum_flags & CSUM_IP) | ||||
*pi_data |= NDIS_TXCSUM_INFO_IPCS; | *pi_data |= NDIS_TXCSUM_INFO_IPCS; | ||||
} | } | ||||
if (m_head->m_pkthdr.csum_flags & (CSUM_IP_TCP | CSUM_IP6_TCP)) | if (m_head->m_pkthdr.csum_flags & | ||||
*pi_data |= NDIS_TXCSUM_INFO_TCPCS; | (CSUM_IP_TCP | CSUM_IP6_TCP)) { | ||||
else if (m_head->m_pkthdr.csum_flags & | *pi_data |= NDIS_TXCSUM_INFO_MKTCPCS( | ||||
(CSUM_IP_UDP | CSUM_IP6_UDP)) | m_head->m_pkthdr.l2hlen + m_head->m_pkthdr.l3hlen); | ||||
*pi_data |= NDIS_TXCSUM_INFO_UDPCS; | } 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; | pkt_hlen = pkt->rm_pktinfooffset + pkt->rm_pktinfolen; | ||||
/* Fixup RNDIS packet message total length */ | /* Fixup RNDIS packet message total length */ | ||||
pkt->rm_len += pkt_hlen; | pkt->rm_len += pkt_hlen; | ||||
/* Convert RNDIS packet message offsets */ | /* Convert RNDIS packet message offsets */ | ||||
pkt->rm_dataoffset = hn_rndis_pktmsg_offset(pkt_hlen); | pkt->rm_dataoffset = hn_rndis_pktmsg_offset(pkt_hlen); | ||||
pkt->rm_pktinfooffset = hn_rndis_pktmsg_offset(pkt->rm_pktinfooffset); | pkt->rm_pktinfooffset = hn_rndis_pktmsg_offset(pkt->rm_pktinfooffset); | ||||
▲ Show 20 Lines • Show All 2,508 Lines • ▼ Show 20 Lines | |||||
#if defined(INET6) || defined(INET) | #if defined(INET6) || defined(INET) | ||||
if (m_head->m_pkthdr.csum_flags & CSUM_TSO) { | if (m_head->m_pkthdr.csum_flags & CSUM_TSO) { | ||||
m_head = hn_tso_fixup(m_head); | m_head = hn_tso_fixup(m_head); | ||||
if (__predict_false(m_head == NULL)) { | if (__predict_false(m_head == NULL)) { | ||||
if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); | if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); | ||||
continue; | 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 | #endif | ||||
txd = hn_txdesc_get(txr); | txd = hn_txdesc_get(txr); | ||||
if (txd == NULL) { | if (txd == NULL) { | ||||
txr->hn_no_txdescs++; | txr->hn_no_txdescs++; | ||||
IFQ_DRV_PREPEND(&ifp->if_snd, m_head); | IFQ_DRV_PREPEND(&ifp->if_snd, m_head); | ||||
atomic_set_int(&ifp->if_drv_flags, IFF_DRV_OACTIVE); | atomic_set_int(&ifp->if_drv_flags, IFF_DRV_OACTIVE); | ||||
break; | break; | ||||
▲ Show 20 Lines • Show All 263 Lines • ▼ Show 20 Lines | if (__predict_true(sc->hn_xvf_flags & HN_XVFFLAG_ENABLED)) { | ||||
} | } | ||||
return (error); | return (error); | ||||
} | } | ||||
rm_runlock(&sc->hn_vf_lock, &pt); | rm_runlock(&sc->hn_vf_lock, &pt); | ||||
} | } | ||||
#if defined(INET6) || defined(INET) | #if defined(INET6) || defined(INET) | ||||
/* | /* | ||||
* Perform TSO packet header fixup now, since the TSO | * Perform TSO packet header fixup or get l2/l3 header length now, | ||||
* packet header should be cache-hot. | * since packet headers should be cache-hot. | ||||
*/ | */ | ||||
if (m->m_pkthdr.csum_flags & CSUM_TSO) { | if (m->m_pkthdr.csum_flags & CSUM_TSO) { | ||||
m = hn_tso_fixup(m); | m = hn_tso_fixup(m); | ||||
if (__predict_false(m == NULL)) { | |||||
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 (__predict_false(m == NULL)) { | ||||
if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); | if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); | ||||
return EIO; | return EIO; | ||||
} | } | ||||
} | } | ||||
#endif | #endif | ||||
/* | /* | ||||
▲ Show 20 Lines • Show All 1,524 Lines • Show Last 20 Lines |