Changeset View
Changeset View
Standalone View
Standalone View
sys/netinet/tcp_lro.c
Show First 20 Lines • Show All 303 Lines • ▼ Show 20 Lines | if (timevalcmp(&tv, &le->mtime, >=)) { | ||||
tcp_lro_flush(lc, le); | tcp_lro_flush(lc, le); | ||||
} | } | ||||
} | } | ||||
} | } | ||||
void | void | ||||
tcp_lro_flush(struct lro_ctrl *lc, struct lro_entry *le) | tcp_lro_flush(struct lro_ctrl *lc, struct lro_entry *le) | ||||
{ | { | ||||
uint32_t ipv6_flow; | |||||
uint8_t tos; | |||||
if (le->append_cnt > 0) { | if (le->append_cnt > 0) { | ||||
struct tcphdr *th; | struct tcphdr *th; | ||||
uint16_t p_len; | uint16_t p_len; | ||||
p_len = htons(le->p_len); | p_len = htons(le->p_len); | ||||
switch (le->eh_type) { | switch (le->eh_type) { | ||||
#ifdef INET6 | #ifdef INET6 | ||||
case ETHERTYPE_IPV6: | case ETHERTYPE_IPV6: | ||||
{ | { | ||||
struct ip6_hdr *ip6; | struct ip6_hdr *ip6; | ||||
ip6 = le->le_ip6; | ip6 = le->le_ip6; | ||||
ip6->ip6_plen = p_len; | ip6->ip6_plen = p_len; | ||||
ipv6_flow = ntohl(ip6->ip6_flow); | |||||
ipv6_flow &= ~(IPTOS_ECN_MASK << IPV6_FLOW_TOS_SHIFT); | |||||
ipv6_flow |= le->ecn << IPV6_FLOW_TOS_SHIFT; | |||||
ip6->ip6_flow = htonl(ipv6_flow); | |||||
th = (struct tcphdr *)(ip6 + 1); | th = (struct tcphdr *)(ip6 + 1); | ||||
le->m_head->m_pkthdr.csum_flags = CSUM_DATA_VALID | | le->m_head->m_pkthdr.csum_flags = CSUM_DATA_VALID | | ||||
CSUM_PSEUDO_HDR; | CSUM_PSEUDO_HDR; | ||||
le->p_len += ETHER_HDR_LEN + sizeof(*ip6); | le->p_len += ETHER_HDR_LEN + sizeof(*ip6); | ||||
break; | break; | ||||
} | } | ||||
#endif | #endif | ||||
#ifdef INET | #ifdef INET | ||||
Show All 19 Lines | |||||
#else | #else | ||||
ip4->ip_sum = TCP_LRO_INVALID_CSUM; | ip4->ip_sum = TCP_LRO_INVALID_CSUM; | ||||
#endif | #endif | ||||
ip4->ip_len = p_len; | ip4->ip_len = p_len; | ||||
th = (struct tcphdr *)(ip4 + 1); | th = (struct tcphdr *)(ip4 + 1); | ||||
le->m_head->m_pkthdr.csum_flags = CSUM_DATA_VALID | | le->m_head->m_pkthdr.csum_flags = CSUM_DATA_VALID | | ||||
CSUM_PSEUDO_HDR | CSUM_IP_CHECKED | CSUM_IP_VALID; | CSUM_PSEUDO_HDR | CSUM_IP_CHECKED | CSUM_IP_VALID; | ||||
le->p_len += ETHER_HDR_LEN; | le->p_len += ETHER_HDR_LEN; | ||||
tos = ip4->ip_tos; | |||||
tos &= ~IPTOS_ECN_MASK; | |||||
tos |= le->ecn; | |||||
ip4->ip_tos = tos; | |||||
break; | break; | ||||
} | } | ||||
#endif | #endif | ||||
default: | default: | ||||
th = NULL; /* Keep compiler happy. */ | th = NULL; /* Keep compiler happy. */ | ||||
} | } | ||||
le->m_head->m_pkthdr.csum_data = 0xffff; | le->m_head->m_pkthdr.csum_data = 0xffff; | ||||
le->m_head->m_pkthdr.len = le->p_len; | le->m_head->m_pkthdr.len = le->p_len; | ||||
▲ Show 20 Lines • Show All 241 Lines • ▼ Show 20 Lines | #endif | ||||
struct tcphdr *th; | struct tcphdr *th; | ||||
void *l3hdr = NULL; /* Keep compiler happy. */ | void *l3hdr = NULL; /* Keep compiler happy. */ | ||||
uint32_t *ts_ptr; | uint32_t *ts_ptr; | ||||
tcp_seq seq; | tcp_seq seq; | ||||
int error, ip_len, l; | int error, ip_len, l; | ||||
uint16_t eh_type, tcp_data_len; | uint16_t eh_type, tcp_data_len; | ||||
struct lro_head *bucket; | struct lro_head *bucket; | ||||
int force_flush = 0; | int force_flush = 0; | ||||
uint8_t ecn; | |||||
/* We expect a contiguous header [eh, ip, tcp]. */ | /* We expect a contiguous header [eh, ip, tcp]. */ | ||||
eh = mtod(m, struct ether_header *); | eh = mtod(m, struct ether_header *); | ||||
eh_type = ntohs(eh->ether_type); | eh_type = ntohs(eh->ether_type); | ||||
switch (eh_type) { | switch (eh_type) { | ||||
#ifdef INET6 | #ifdef INET6 | ||||
case ETHERTYPE_IPV6: | case ETHERTYPE_IPV6: | ||||
{ | { | ||||
CURVNET_SET(lc->ifp->if_vnet); | CURVNET_SET(lc->ifp->if_vnet); | ||||
if (V_ip6_forwarding != 0) { | if (V_ip6_forwarding != 0) { | ||||
/* XXX-BZ stats but changing lro_ctrl is a problem. */ | /* XXX-BZ stats but changing lro_ctrl is a problem. */ | ||||
CURVNET_RESTORE(); | CURVNET_RESTORE(); | ||||
return (TCP_LRO_CANNOT); | return (TCP_LRO_CANNOT); | ||||
} | } | ||||
CURVNET_RESTORE(); | CURVNET_RESTORE(); | ||||
l3hdr = ip6 = (struct ip6_hdr *)(eh + 1); | l3hdr = ip6 = (struct ip6_hdr *)(eh + 1); | ||||
error = tcp_lro_rx_ipv6(lc, m, ip6, &th); | error = tcp_lro_rx_ipv6(lc, m, ip6, &th); | ||||
if (error != 0) | if (error != 0) | ||||
return (error); | return (error); | ||||
tcp_data_len = ntohs(ip6->ip6_plen); | tcp_data_len = ntohs(ip6->ip6_plen); | ||||
ip_len = sizeof(*ip6) + tcp_data_len; | ip_len = sizeof(*ip6) + tcp_data_len; | ||||
ecn = (ntohl(ip6->ip6_flow) >> IPV6_FLOW_TOS_SHIFT) & | |||||
IPTOS_ECN_MASK; | |||||
break; | break; | ||||
} | } | ||||
#endif | #endif | ||||
#ifdef INET | #ifdef INET | ||||
case ETHERTYPE_IP: | case ETHERTYPE_IP: | ||||
{ | { | ||||
CURVNET_SET(lc->ifp->if_vnet); | CURVNET_SET(lc->ifp->if_vnet); | ||||
if (V_ipforwarding != 0) { | if (V_ipforwarding != 0) { | ||||
/* XXX-BZ stats but changing lro_ctrl is a problem. */ | /* XXX-BZ stats but changing lro_ctrl is a problem. */ | ||||
CURVNET_RESTORE(); | CURVNET_RESTORE(); | ||||
return (TCP_LRO_CANNOT); | return (TCP_LRO_CANNOT); | ||||
} | } | ||||
CURVNET_RESTORE(); | CURVNET_RESTORE(); | ||||
l3hdr = ip4 = (struct ip *)(eh + 1); | l3hdr = ip4 = (struct ip *)(eh + 1); | ||||
error = tcp_lro_rx_ipv4(lc, m, ip4, &th); | error = tcp_lro_rx_ipv4(lc, m, ip4, &th); | ||||
if (error != 0) | if (error != 0) | ||||
return (error); | return (error); | ||||
ip_len = ntohs(ip4->ip_len); | ip_len = ntohs(ip4->ip_len); | ||||
tcp_data_len = ip_len - sizeof(*ip4); | tcp_data_len = ip_len - sizeof(*ip4); | ||||
ecn = ip4->ip_tos & IPTOS_ECN_MASK; | |||||
break; | break; | ||||
} | } | ||||
#endif | #endif | ||||
/* XXX-BZ what happens in case of VLAN(s)? */ | /* XXX-BZ what happens in case of VLAN(s)? */ | ||||
default: | default: | ||||
return (TCP_LRO_NOT_SUPPORTED); | return (TCP_LRO_NOT_SUPPORTED); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 150 Lines • ▼ Show 20 Lines | #endif | ||||
le->window = th->th_win; | le->window = th->th_win; | ||||
le->append_cnt++; | le->append_cnt++; | ||||
#ifdef TCP_LRO_UPDATE_CSUM | #ifdef TCP_LRO_UPDATE_CSUM | ||||
le->ulp_csum += tcp_lro_rx_csum_fixup(le, l3hdr, th, | le->ulp_csum += tcp_lro_rx_csum_fixup(le, l3hdr, th, | ||||
tcp_data_len, ~csum); | tcp_data_len, ~csum); | ||||
#endif | #endif | ||||
/* | |||||
* If CE has been flagged on any packet, then CE needs to be set | |||||
* on the IP header when we send the packet up the stack. | |||||
*/ | |||||
if (ecn == IPTOS_ECN_CE) | |||||
le->ecn = ecn; | |||||
if (tcp_data_len == 0) { | if (tcp_data_len == 0) { | ||||
m_freem(m); | m_freem(m); | ||||
/* | /* | ||||
* Flush this LRO entry, if this ACK should not | * Flush this LRO entry, if this ACK should not | ||||
* be further delayed. | * be further delayed. | ||||
*/ | */ | ||||
if (le->append_cnt >= lc->lro_ackcnt_lim) { | if (le->append_cnt >= lc->lro_ackcnt_lim) { | ||||
tcp_lro_active_remove(le); | tcp_lro_active_remove(le); | ||||
▲ Show 20 Lines • Show All 50 Lines • ▼ Show 20 Lines | #endif | ||||
switch (eh_type) { | switch (eh_type) { | ||||
#ifdef INET6 | #ifdef INET6 | ||||
case ETHERTYPE_IPV6: | case ETHERTYPE_IPV6: | ||||
le->le_ip6 = ip6; | le->le_ip6 = ip6; | ||||
le->source_ip6 = ip6->ip6_src; | le->source_ip6 = ip6->ip6_src; | ||||
le->dest_ip6 = ip6->ip6_dst; | le->dest_ip6 = ip6->ip6_dst; | ||||
le->eh_type = eh_type; | le->eh_type = eh_type; | ||||
le->p_len = m->m_pkthdr.len - ETHER_HDR_LEN - sizeof(*ip6); | le->p_len = m->m_pkthdr.len - ETHER_HDR_LEN - sizeof(*ip6); | ||||
le->ecn = ecn; | |||||
break; | break; | ||||
#endif | #endif | ||||
#ifdef INET | #ifdef INET | ||||
case ETHERTYPE_IP: | case ETHERTYPE_IP: | ||||
le->le_ip4 = ip4; | le->le_ip4 = ip4; | ||||
le->source_ip4 = ip4->ip_src.s_addr; | le->source_ip4 = ip4->ip_src.s_addr; | ||||
le->dest_ip4 = ip4->ip_dst.s_addr; | le->dest_ip4 = ip4->ip_dst.s_addr; | ||||
le->eh_type = eh_type; | le->eh_type = eh_type; | ||||
le->p_len = m->m_pkthdr.len - ETHER_HDR_LEN; | le->p_len = m->m_pkthdr.len - ETHER_HDR_LEN; | ||||
le->ecn = ecn; | |||||
break; | break; | ||||
#endif | #endif | ||||
} | } | ||||
le->source_port = th->th_sport; | le->source_port = th->th_sport; | ||||
le->dest_port = th->th_dport; | le->dest_port = th->th_dport; | ||||
le->next_seq = seq + tcp_data_len; | le->next_seq = seq + tcp_data_len; | ||||
le->ack_seq = th->th_ack; | le->ack_seq = th->th_ack; | ||||
▲ Show 20 Lines • Show All 73 Lines • Show Last 20 Lines |