TSO broken with jumbo MTU
Ben Hutchings
bhutchings at solarflare.com
Thu Sep 29 15:25:11 UTC 2011
tcp_output() does:
if (... && len > tp->t_maxseg && ...)
tso = 1;
Then:
if (len + optlen + ipoptlen > tp->t_maxopd) {
...
if (tso) {
...
if (sendalot && off + len < so->so_snd.sb_cc) {
len -= len % (tp->t_maxopd - optlen);
sendalot = 1;
}
Then later:
if (tso) {
KASSERT(len > tp->t_maxopd - optlen,
("%s: len <= tso_segsz", __func__));
m->m_pkthdr.csum_flags |= CSUM_TSO;
m->m_pkthdr.tso_segsz = tp->t_maxopd - optlen;
}
So there is an assumption here that
tp->t_maxseg >= tp->t_maxopd - optlen.
But tcp_mss_update() does not ensure that at all, because it rounds down
tp->t_maxseg to a multiple of MCLBYTES and does not change tp->t_maxopd
accordingly:
tp->t_maxopd = mss;
if (...)
mss -= TCPOLEN_TSTAMP_APPA;
#if (MCLBYTES & (MCLBYTES - 1)) == 0
if (mss > MCLBYTES)
mss &= ~(MCLBYTES-1);
#else
if (mss > MCLBYTES)
mss = mss / MCLBYTES * MCLBYTES;
#endif
tp->t_maxseg = mss;
(All the above code is from 9, but I found the assertion failure on 8.2
which has fairly similar code.)
Ben.
--
Ben Hutchings, Staff Engineer, Solarflare
Not speaking for my employer; that's the marketing department's job.
They asked us to note that Solarflare product names are trademarked.
More information about the freebsd-net
mailing list