We currently don't do TSO if ip options are present. In case of IPv6, we look at
in6p_options to check that. That is incorrect as we carry ip options in in6p_outputopts. Also, just checking for in6p_outputopts being NULL won't suffice as we combine ip options and ip header fields both in that one field. The commit fixes this by using ip6_optlen() which correctly calculates length of only ip options for IPv6. Reviewed by: ae, bz MFC after: 3 weeks Sponsored by: Limelight Networks
This commit is contained in:
+21
-19
@@ -545,6 +545,11 @@ tcp_output(struct tcpcb *tp)
|
||||
* (except for the sequence number) for all generated packets. This
|
||||
* makes it impossible to transmit any options which vary per generated
|
||||
* segment or packet.
|
||||
*
|
||||
* IPv4 handling has a clear separation of ip options and ip header
|
||||
* flags while IPv6 combines both in in6p_outputopts. ip6_optlen() does
|
||||
* the right thing below to provide length of just ip options and thus
|
||||
* checking for ipoptlen is enough to decide if ip options are present.
|
||||
*/
|
||||
#ifdef IPSEC
|
||||
/*
|
||||
@@ -553,14 +558,25 @@ tcp_output(struct tcpcb *tp)
|
||||
*/
|
||||
ipsec_optlen = ipsec_hdrsiz_tcp(tp);
|
||||
#endif
|
||||
|
||||
#ifdef INET6
|
||||
if (isipv6)
|
||||
ipoptlen = ip6_optlen(tp->t_inpcb);
|
||||
else
|
||||
#endif
|
||||
if (tp->t_inpcb->inp_options)
|
||||
ipoptlen = tp->t_inpcb->inp_options->m_len -
|
||||
offsetof(struct ipoption, ipopt_list);
|
||||
else
|
||||
ipoptlen = 0;
|
||||
#ifdef IPSEC
|
||||
ipoptlen += ipsec_optlen;
|
||||
#endif
|
||||
|
||||
if ((tp->t_flags & TF_TSO) && V_tcp_do_tso && len > tp->t_maxseg &&
|
||||
((tp->t_flags & TF_SIGNATURE) == 0) &&
|
||||
tp->rcv_numsacks == 0 && sack_rxmit == 0 &&
|
||||
#ifdef IPSEC
|
||||
ipsec_optlen == 0 &&
|
||||
#endif
|
||||
tp->t_inpcb->inp_options == NULL &&
|
||||
tp->t_inpcb->in6p_options == NULL)
|
||||
ipoptlen == 0)
|
||||
tso = 1;
|
||||
|
||||
if (sack_rxmit) {
|
||||
@@ -833,20 +849,6 @@ tcp_output(struct tcpcb *tp)
|
||||
hdrlen += optlen = tcp_addoptions(&to, opt);
|
||||
}
|
||||
|
||||
#ifdef INET6
|
||||
if (isipv6)
|
||||
ipoptlen = ip6_optlen(tp->t_inpcb);
|
||||
else
|
||||
#endif
|
||||
if (tp->t_inpcb->inp_options)
|
||||
ipoptlen = tp->t_inpcb->inp_options->m_len -
|
||||
offsetof(struct ipoption, ipopt_list);
|
||||
else
|
||||
ipoptlen = 0;
|
||||
#ifdef IPSEC
|
||||
ipoptlen += ipsec_optlen;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Adjust data length if insertion of options will
|
||||
* bump the packet length beyond the t_maxseg length.
|
||||
|
||||
Reference in New Issue
Block a user