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