Index: sys/netinet/ip6.h =================================================================== --- sys/netinet/ip6.h +++ sys/netinet/ip6.h @@ -108,6 +108,9 @@ #define IP6TOS_ECT 0x02 /* ECN-capable transport */ #endif +#define IPV6_FLOW_TOS_SHIFT 20 +#define IPV6_FLOW_TOS_MASK 0xff + /* * Extension Headers */ Index: sys/netinet/tcp_input.c =================================================================== --- sys/netinet/tcp_input.c +++ sys/netinet/tcp_input.c @@ -735,7 +735,8 @@ #ifdef INET6 if (isipv6) - iptos = (ntohl(ip6->ip6_flow) >> 20) & 0xff; + iptos = (ntohl(ip6->ip6_flow) >> IPV6_FLOW_TOS_SHIFT) & + IPV6_FLOW_TOS_MASK; #endif #if defined(INET) && defined(INET6) else Index: sys/netinet/tcp_lro.h =================================================================== --- sys/netinet/tcp_lro.h +++ sys/netinet/tcp_lro.h @@ -67,6 +67,7 @@ uint32_t tsecr; uint16_t window; uint16_t timestamp; /* flag, not a TCP hdr field. */ + uint8_t ecn; /* ECN bits from IP TOS field */ struct timeval mtime; }; LIST_HEAD(lro_head, lro_entry); Index: sys/netinet/tcp_lro.c =================================================================== --- sys/netinet/tcp_lro.c +++ sys/netinet/tcp_lro.c @@ -309,6 +309,8 @@ void tcp_lro_flush(struct lro_ctrl *lc, struct lro_entry *le) { + uint32_t ipv6_flow; + uint8_t tos; if (le->append_cnt > 0) { struct tcphdr *th; @@ -323,6 +325,10 @@ ip6 = le->le_ip6; 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); le->m_head->m_pkthdr.csum_flags = CSUM_DATA_VALID | CSUM_PSEUDO_HDR; @@ -358,6 +364,10 @@ le->m_head->m_pkthdr.csum_flags = CSUM_DATA_VALID | CSUM_PSEUDO_HDR | CSUM_IP_CHECKED | CSUM_IP_VALID; le->p_len += ETHER_HDR_LEN; + tos = ip4->ip_tos; + tos &= ~IPTOS_ECN_MASK; + tos |= le->ecn; + ip4->ip_tos = tos; break; } #endif @@ -615,6 +625,7 @@ uint16_t eh_type, tcp_data_len; struct lro_head *bucket; int force_flush = 0; + uint8_t ecn; /* We expect a contiguous header [eh, ip, tcp]. */ @@ -637,6 +648,8 @@ return (error); tcp_data_len = ntohs(ip6->ip6_plen); ip_len = sizeof(*ip6) + tcp_data_len; + ecn = (ntohl(ip6->ip6_flow) >> IPV6_FLOW_TOS_SHIFT) & + IPTOS_ECN_MASK; break; } #endif @@ -656,6 +669,7 @@ return (error); ip_len = ntohs(ip4->ip_len); tcp_data_len = ip_len - sizeof(*ip4); + ecn = ip4->ip_tos & IPTOS_ECN_MASK; break; } #endif @@ -822,6 +836,13 @@ tcp_data_len, ~csum); #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) { m_freem(m); /* @@ -888,6 +909,7 @@ le->dest_ip6 = ip6->ip6_dst; le->eh_type = eh_type; le->p_len = m->m_pkthdr.len - ETHER_HDR_LEN - sizeof(*ip6); + le->ecn = ecn; break; #endif #ifdef INET @@ -897,6 +919,7 @@ le->dest_ip4 = ip4->ip_dst.s_addr; le->eh_type = eh_type; le->p_len = m->m_pkthdr.len - ETHER_HDR_LEN; + le->ecn = ecn; break; #endif } Index: sys/netinet/tcp_output.c =================================================================== --- sys/netinet/tcp_output.c +++ sys/netinet/tcp_output.c @@ -1146,7 +1146,8 @@ !((tp->t_flags & TF_FORCEDATA) && len == 1)) { #ifdef INET6 if (isipv6) - ip6->ip6_flow |= htonl(IPTOS_ECN_ECT0 << 20); + ip6->ip6_flow |= htonl(IPTOS_ECN_ECT0 << + IPV6_FLOW_TOS_SHIFT); else #endif ip->ip_tos |= IPTOS_ECN_ECT0;